diff --git a/lib/ftl/ftl_io.c b/lib/ftl/ftl_io.c index 5d400ff3a..0896da4a9 100644 --- a/lib/ftl/ftl_io.c +++ b/lib/ftl/ftl_io.c @@ -463,3 +463,38 @@ ftl_io_free(struct ftl_io *io) _ftl_io_free(io); } + +void +ftl_io_call_foreach_child(struct ftl_io *io, int (*callback)(struct ftl_io *)) +{ + struct ftl_io *child, *tmp; + + assert(!io->done); + + /* + * If the IO doesn't have any children, it means that it directly describes a request (i.e. + * all of the buffers, LBAs, etc. are filled). Otherwise the IO only groups together several + * requests and may be partially filled, so the callback needs to be called on all of its + * children instead. + */ + if (LIST_EMPTY(&io->children)) { + callback(io); + return; + } + + LIST_FOREACH_SAFE(child, &io->children, child_entry, tmp) { + int rc = callback(child); + if (rc) { + assert(rc != -EAGAIN); + ftl_io_fail(io, rc); + break; + } + } + + /* + * If all the callbacks were processed or an error occurred, treat this IO as completed. + * Multiple calls to ftl_io_call_foreach_child are not supported, resubmissions are supposed + * to be handled in the callback. + */ + ftl_io_complete(io); +} diff --git a/lib/ftl/ftl_io.h b/lib/ftl/ftl_io.h index 25ec1ce38..2c3b3ffd6 100644 --- a/lib/ftl/ftl_io.h +++ b/lib/ftl/ftl_io.h @@ -281,5 +281,6 @@ void ftl_io_complete(struct ftl_io *io); void ftl_io_shrink_iovec(struct ftl_io *io, size_t lbk_cnt); void ftl_io_process_error(struct ftl_io *io, const struct spdk_nvme_cpl *status); void ftl_io_reset(struct ftl_io *io); +void ftl_io_call_foreach_child(struct ftl_io *io, int (*callback)(struct ftl_io *)); #endif /* FTL_IO_H */