diff --git a/include/sys/abd_impl.h b/include/sys/abd_impl.h index f67329dd35d7..990575dccb8a 100644 --- a/include/sys/abd_impl.h +++ b/include/sys/abd_impl.h @@ -277,6 +277,28 @@ abd_chunk_unmap(abd_chunk_t *ch) { abd_iter_unmap(&ch->ch_iter); } +/* + * Macro to iterate over an ABD in the most common case, where you want to + * do some operation on the actual data. + * + * void *data; + * size_t dsize; + * abd_for_each_chunk(abd, off, size, data, dsize) { + * // do work on data an dsize + * } + * + * XXX Can't be used if we need to break out of the loop early, because it + * would leave the chunk mapped. Also sucks that we have declare data and + * dsize every time, and outside the scope -- robn, 2024-11-21 + */ +#define abd_for_each_chunk(abd, off, size, __data, __dsize) \ + for (abd_chunk_t __ai = abd_chunk_start(abd, off, size); \ + !abd_chunk_done(&__ai) && \ + (__data = abd_chunk_map(&__ai)) && \ + (__dsize = abd_chunk_size(&__ai)); \ + abd_chunk_unmap(&__ai), abd_chunk_advance(&__ai)) + + #ifdef __cplusplus } #endif diff --git a/module/zfs/abd.c b/module/zfs/abd.c index 82ae71896a99..672ce8bd247b 100644 --- a/module/zfs/abd.c +++ b/module/zfs/abd.c @@ -831,12 +831,12 @@ void abd_copy_to_buf_off(void *buf, abd_t *abd, size_t off, size_t size) { char *c = buf; - for (abd_chunk_t ch = abd_chunk_start(abd, off, size); - !abd_chunk_done(&ch); abd_chunk_advance(&ch)) { - void *addr = abd_chunk_map(&ch); - memcpy(c, addr, abd_chunk_size(&ch)); - c += abd_chunk_size(&ch); - abd_chunk_unmap(&ch); + void *data; + size_t dsize; + + abd_for_each_chunk(abd, off, size, data, dsize) { + memcpy(c, data, dsize); + c += dsize; } } @@ -870,12 +870,12 @@ void abd_copy_from_buf_off(abd_t *abd, const void *buf, size_t off, size_t size) { const char *c = buf; - for (abd_chunk_t ch = abd_chunk_start(abd, off, size); - !abd_chunk_done(&ch); abd_chunk_advance(&ch)) { - void *addr = abd_chunk_map(&ch); - memcpy(addr, c, abd_chunk_size(&ch)); - c += abd_chunk_size(&ch); - abd_chunk_unmap(&ch); + void *data; + size_t dsize; + + abd_for_each_chunk(abd, off, size, data, dsize) { + memcpy(data, c, dsize); + c += dsize; } } @@ -885,12 +885,11 @@ abd_copy_from_buf_off(abd_t *abd, const void *buf, size_t off, size_t size) void abd_zero_off(abd_t *abd, size_t off, size_t size) { - for (abd_chunk_t ch = abd_chunk_start(abd, off, size); - !abd_chunk_done(&ch); abd_chunk_advance(&ch)) { - void *addr = abd_chunk_map(&ch); - memset(addr, 0, abd_chunk_size(&ch)); - abd_chunk_unmap(&ch); - } + void *data; + size_t dsize; + + abd_for_each_chunk(abd, off, size, data, dsize) + memset(data, 0, dsize); } /*