Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RFC: ABD chunk iterator #16848

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
156 changes: 156 additions & 0 deletions include/sys/abd_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,162 @@ void abd_iter_page(struct abd_iter *);
#define ABD_LINEAR_BUF(abd) ((abd)->abd_u.abd_linear.abd_buf)
#define ABD_GANG(abd) ((abd)->abd_u.abd_gang)

/*
* Chunk iterators.
*
* This is a new type of ABD iterator that iterates over data chunks. The idea
* is that since ABDs are effectively a wrapper over a set of memory regions,
* an iterator that yields data chunks can be smaller and simpler.
*
* The iterator object abd_chunk_t can be thought of as a pointer to a chunk
* within an array of chunks. There are three main functions involved with
* setting up and using an iterator:
*
* - abd_chunk_t ch = abd_chunk_start(abd_t *abd, size_t off, size_t size)
*
* Create a new iterator over the given ABD, starting at off bytes, for size
* bytes. If off and size would fall outside of the ABD, the returned
* iterator will be unusable (already "done").
*
* - void abd_chunk_advance(abd_chunk_t *ch)
*
* Move the iterator to the next chunk. If there is no next chunk, the
* iterator is changed to the "done" state and is no longer useable.
*
* - boolean_t abd_chunk_done(abd_chunk_t *ch)
*
* If true, the iterator is pointing to a valid chunk, and the underlying
* memory can be accessed with the access functions. If false, the iterator
* is exhausted and no longer useable.
Comment on lines +141 to +150
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Definitions of "done" in those paragraphs seems to be opposite.

*
* Together, these allow an ABD to be processed in a for loop:
*
* for (abd_chunk_t ch = abd_chunk_start(abd, off, size);
* !abd_chunk_done(&ch); abd_chunk_advance(&ch))
*
* With a valid chunk iterator, the following functions can be used to work
* with the underlying data or memory:
*
* - size_t abd_chunk_size(abd_chunk_t *ch)
*
* The number of data bytes within the chunk.
*
* - void *data = abd_chunk_map(abd_chunk_t *ch)
*
* Map the memory within the chunk into the address space, and return a
* pointer to the start of the data.
*
* - void abd_chunk_unmap(abd_chunk_t *ch)
*
* Unmap previously-mapped chunk memory. For convenience, if there is nothing
* mapped, nothing happens.
*/

/* XXX temp exposing old iterator control functions for use in chunk iters */
abd_t *abd_init_abd_iter(abd_t *abd, struct abd_iter *aiter, size_t off);
abd_t *abd_advance_abd_iter(abd_t *abd, abd_t *cabd, struct abd_iter *aiter,
size_t len);

typedef struct {
abd_t *ch_abd; /* ABD being iterated over */

size_t ch_coff; /* chunk offset within ABD */
size_t ch_csize; /* size of chunk within ABD */
size_t ch_doff; /* data offset within chunk */
size_t ch_dsize; /* size of data remaining in iter */

struct abd_iter ch_iter; /* XXX old-style iterator */
abd_t *ch_cabd; /* XXX child abd, for gang iter */
} abd_chunk_t;

static inline abd_chunk_t
abd_chunk_start(abd_t *abd, size_t off, size_t size)
{
abd_chunk_t ch = {
.ch_abd = abd,
};

if (size == 0 || (off + size > abd_get_size(abd))) {
ch.ch_dsize = 0;
ch.ch_doff = 0;
return (ch);
}

abd_verify(abd);
ASSERT3U(off + size, <=, abd->abd_size);

/* start of data, size of data */
ch.ch_doff = off;
ch.ch_dsize = size;

ch.ch_cabd = abd_init_abd_iter(abd, &ch.ch_iter, 0);

/* size of first chunk */
ch.ch_coff = 0;
ch.ch_csize = abd_iter_size(&ch.ch_iter);

/* roll chunks forward until we reach the one with the data start */
while (ch.ch_doff >= ch.ch_csize) {
ch.ch_doff -= ch.ch_csize;
ch.ch_coff += ch.ch_csize;

ch.ch_cabd = abd_advance_abd_iter(ch.ch_abd, ch.ch_cabd,
&ch.ch_iter, ch.ch_csize);

ch.ch_csize = abd_iter_size(&ch.ch_iter);
}

return (ch);
}

static inline void
abd_chunk_advance(abd_chunk_t *ch)
{
ASSERT3U(ch->ch_dsize, >, 0);

/* consume data up to the end of the chunk */
ch->ch_dsize -= MIN(ch->ch_dsize, ch->ch_csize - ch->ch_doff);

/* next data will be at the start of the next chunk */
ch->ch_doff = 0;

/* no more data, so return */
if (ch->ch_dsize == 0)
return;

ch->ch_cabd = abd_advance_abd_iter(ch->ch_abd, ch->ch_cabd,
&ch->ch_iter, ch->ch_csize);

ch->ch_coff += ch->ch_csize;
ch->ch_csize = abd_iter_size(&ch->ch_iter);
}

static inline boolean_t
abd_chunk_done(abd_chunk_t *ch)
{
return (ch->ch_dsize == 0);
}

static inline size_t
abd_chunk_size(abd_chunk_t *ch)
{
return (MIN(ch->ch_dsize, ch->ch_csize - ch->ch_doff));
}

static inline void *
abd_chunk_map(abd_chunk_t *ch) {
abd_iter_map(&ch->ch_iter);
ASSERT3U(ch->ch_iter.iter_mapsize, ==, ch->ch_csize);
return (ch->ch_iter.iter_mapaddr + ch->ch_doff);
}

static inline void
abd_chunk_unmap(abd_chunk_t *ch) {
if (ch->ch_iter.iter_mapaddr == NULL)
return;
abd_iter_unmap(&ch->ch_iter);
}

#ifdef __cplusplus
}
#endif
Expand Down
4 changes: 2 additions & 2 deletions module/zfs/abd.c
Original file line number Diff line number Diff line change
Expand Up @@ -718,7 +718,7 @@ abd_take_ownership_of_buf(abd_t *abd, boolean_t is_metadata)
* Initializes an abd_iter based on whether the abd is a gang ABD
* or just a single ABD.
*/
static inline abd_t *
abd_t *
abd_init_abd_iter(abd_t *abd, struct abd_iter *aiter, size_t off)
{
abd_t *cabd = NULL;
Expand All @@ -741,7 +741,7 @@ abd_init_abd_iter(abd_t *abd, struct abd_iter *aiter, size_t off)
* advancing could mean that we are at the end of a particular ABD and
* must grab the ABD in the gang ABD's list.
*/
static inline abd_t *
abd_t *
abd_advance_abd_iter(abd_t *abd, abd_t *cabd, struct abd_iter *aiter,
size_t len)
{
Expand Down