diff options
author | Jens Axboe <axboe@kernel.dk> | 2023-03-28 23:21:06 +0300 |
---|---|---|
committer | Jens Axboe <axboe@kernel.dk> | 2023-03-30 17:12:29 +0300 |
commit | 747b1f65d39ae729b7914075899b0c82d7f667db (patch) | |
tree | b5d46fc0d7d9804008356a0c01630287a1b588a4 | |
parent | cd0bd57a9de59019fe99e9305a2337a66a4f9d39 (diff) | |
download | linux-747b1f65d39ae729b7914075899b0c82d7f667db.tar.xz |
iov_iter: overlay struct iovec and ubuf/len
Add an internal struct iovec that we can return as a pointer, with the
fields of the iovec overlapping with the ITER_UBUF ubuf and length
fields.
Then we can have iter_iov() check for the appropriate type, and return
&iter->__ubuf_iovec for ITER_UBUF and iter->__iov for ITER_IOVEC and
things will magically work out for a single segment request regardless
of either type.
Signed-off-by: Jens Axboe <axboe@kernel.dk>
-rw-r--r-- | include/linux/uio.h | 44 |
1 files changed, 35 insertions, 9 deletions
diff --git a/include/linux/uio.h b/include/linux/uio.h index 5dbd2dcab35c..ed35f4427a0a 100644 --- a/include/linux/uio.h +++ b/include/linux/uio.h @@ -49,15 +49,35 @@ struct iov_iter { size_t iov_offset; int last_offset; }; - size_t count; + /* + * Hack alert: overlay ubuf_iovec with iovec + count, so + * that the members resolve correctly regardless of the type + * of iterator used. This means that you can use: + * + * &iter->__ubuf_iovec or iter->__iov + * + * interchangably for the user_backed cases, hence simplifying + * some of the cases that need to deal with both. + */ union { - /* use iter_iov() to get the current vec */ - const struct iovec *__iov; - const struct kvec *kvec; - const struct bio_vec *bvec; - struct xarray *xarray; - struct pipe_inode_info *pipe; - void __user *ubuf; + /* + * This really should be a const, but we cannot do that without + * also modifying any of the zero-filling iter init functions. + * Leave it non-const for now, but it should be treated as such. + */ + struct iovec __ubuf_iovec; + struct { + union { + /* use iter_iov() to get the current vec */ + const struct iovec *__iov; + const struct kvec *kvec; + const struct bio_vec *bvec; + struct xarray *xarray; + struct pipe_inode_info *pipe; + void __user *ubuf; + }; + size_t count; + }; }; union { unsigned long nr_segs; @@ -69,7 +89,13 @@ struct iov_iter { }; }; -#define iter_iov(iter) (iter)->__iov +static inline const struct iovec *iter_iov(const struct iov_iter *iter) +{ + if (iter->iter_type == ITER_UBUF) + return (const struct iovec *) &iter->__ubuf_iovec; + return iter->__iov; +} + #define iter_iov_addr(iter) (iter_iov(iter)->iov_base + (iter)->iov_offset) #define iter_iov_len(iter) (iter_iov(iter)->iov_len - (iter)->iov_offset) |