diff --git a/include/linux/uio.h b/include/linux/uio.h index 5dbd2dcab35c8..ed35f4427a0ad 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)