Merge tag 'mm-stable-2023-04-27-15-30' of git://git.kernel.org/pub/scm/linux/kernel...
[linux-block.git] / include / linux / uio.h
index 29eb18bb6feb12a10008941ff5f4b86b501f9a4f..3d386849a7584906453a43431316990bababd6dd 100644 (file)
@@ -49,14 +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 {
-               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;
@@ -68,6 +89,16 @@ struct iov_iter {
        };
 };
 
+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)
+
 static inline enum iter_type iov_iter_type(const struct iov_iter *i)
 {
        return i->iter_type;
@@ -143,15 +174,6 @@ static inline size_t iov_length(const struct iovec *iov, unsigned long nr_segs)
        return ret;
 }
 
-static inline struct iovec iov_iter_iovec(const struct iov_iter *iter)
-{
-       return (struct iovec) {
-               .iov_base = iter->iov->iov_base + iter->iov_offset,
-               .iov_len = min(iter->count,
-                              iter->iov->iov_len - iter->iov_offset),
-       };
-}
-
 size_t copy_page_from_iter_atomic(struct page *page, unsigned offset,
                                  size_t bytes, struct iov_iter *i);
 void iov_iter_advance(struct iov_iter *i, size_t bytes);
@@ -361,7 +383,8 @@ static inline void iov_iter_ubuf(struct iov_iter *i, unsigned int direction,
                .user_backed = true,
                .data_source = direction,
                .ubuf = buf,
-               .count = count
+               .count = count,
+               .nr_segs = 1
        };
 }
 /* Flags for iov_iter_get/extract_pages*() */