From: Keith Busch <kbusch@xxxxxxxxxx> Introduce a new iov_iter type representing a pre-registered DMA address tag. The tag is an opaque cookie specific to the lower level driver that created it, and can be referenced at any arbitrary offset. Signed-off-by: Keith Busch <kbusch@xxxxxxxxxx> --- include/linux/uio.h | 9 +++++++++ lib/iov_iter.c | 25 ++++++++++++++++++++++--- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/include/linux/uio.h b/include/linux/uio.h index 34ba4a731179..de8af68eacb3 100644 --- a/include/linux/uio.h +++ b/include/linux/uio.h @@ -26,6 +26,7 @@ enum iter_type { ITER_PIPE, ITER_XARRAY, ITER_DISCARD, + ITER_DMA_TAG, }; struct iov_iter_state { @@ -46,6 +47,7 @@ struct iov_iter { const struct bio_vec *bvec; struct xarray *xarray; struct pipe_inode_info *pipe; + void *dma_tag; }; union { unsigned long nr_segs; @@ -85,6 +87,11 @@ static inline bool iov_iter_is_bvec(const struct iov_iter *i) return iov_iter_type(i) == ITER_BVEC; } +static inline bool iov_iter_is_dma_tag(const struct iov_iter *i) +{ + return iov_iter_type(i) == ITER_DMA_TAG; +} + static inline bool iov_iter_is_pipe(const struct iov_iter *i) { return iov_iter_type(i) == ITER_PIPE; @@ -229,6 +236,8 @@ void iov_iter_kvec(struct iov_iter *i, unsigned int direction, const struct kvec unsigned long nr_segs, size_t count); void iov_iter_bvec(struct iov_iter *i, unsigned int direction, const struct bio_vec *bvec, unsigned long nr_segs, size_t count); +void iov_iter_dma_tag(struct iov_iter *i, unsigned int direction, void *dma_tag, + unsigned int dma_offset, unsigned long nr_segs, size_t count); void iov_iter_pipe(struct iov_iter *i, unsigned int direction, struct pipe_inode_info *pipe, size_t count); void iov_iter_discard(struct iov_iter *i, unsigned int direction, size_t count); diff --git a/lib/iov_iter.c b/lib/iov_iter.c index 507e732ef7cf..e26cb0889820 100644 --- a/lib/iov_iter.c +++ b/lib/iov_iter.c @@ -1077,6 +1077,9 @@ void iov_iter_advance(struct iov_iter *i, size_t size) i->count -= size; } else if (iov_iter_is_discard(i)) { i->count -= size; + } else if (iov_iter_is_dma_tag(i)) { + i->iov_offset += size; + i->count -= size; } } EXPORT_SYMBOL(iov_iter_advance); @@ -1201,6 +1204,22 @@ void iov_iter_bvec(struct iov_iter *i, unsigned int direction, } EXPORT_SYMBOL(iov_iter_bvec); +void iov_iter_dma_tag(struct iov_iter *i, unsigned int direction, + void *dma_tag, unsigned int dma_offset, + unsigned long nr_segs, size_t count) +{ + WARN_ON(direction & ~(READ | WRITE)); + *i = (struct iov_iter){ + .iter_type = ITER_DMA_TAG, + .data_source = direction, + .nr_segs = nr_segs, + .dma_tag = dma_tag, + .iov_offset = dma_offset, + .count = count + }; +} +EXPORT_SYMBOL(iov_iter_dma_tag); + void iov_iter_pipe(struct iov_iter *i, unsigned int direction, struct pipe_inode_info *pipe, size_t count) @@ -2124,8 +2143,8 @@ EXPORT_SYMBOL(import_single_range); */ void iov_iter_restore(struct iov_iter *i, struct iov_iter_state *state) { - if (WARN_ON_ONCE(!iov_iter_is_bvec(i) && !iter_is_iovec(i)) && - !iov_iter_is_kvec(i)) + if (WARN_ON_ONCE(!iov_iter_is_bvec(i) && !iter_is_iovec(i) && + !iov_iter_is_dma_tag(i)) && !iov_iter_is_kvec(i)) return; i->iov_offset = state->iov_offset; i->count = state->count; @@ -2141,7 +2160,7 @@ void iov_iter_restore(struct iov_iter *i, struct iov_iter_state *state) BUILD_BUG_ON(sizeof(struct iovec) != sizeof(struct kvec)); if (iov_iter_is_bvec(i)) i->bvec -= state->nr_segs - i->nr_segs; - else + else if (!iov_iter_is_dma_tag(i)) i->iov -= state->nr_segs - i->nr_segs; i->nr_segs = state->nr_segs; } -- 2.30.2