iov_iter_alignment(): don't bother with iterate_all_kinds()
authorAl Viro <viro@zeniv.linux.org.uk>
Sun, 25 Apr 2021 04:44:35 +0000 (00:44 -0400)
committerAl Viro <viro@zeniv.linux.org.uk>
Thu, 10 Jun 2021 15:45:10 +0000 (11:45 -0400)
It's easier to go over the array manually.  We need to watch out
for truncated iov_iter, though - iovec array might cover more
than i->count.

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
lib/iov_iter.c

index 2b543be..ed93183 100644 (file)
@@ -1328,27 +1328,70 @@ void iov_iter_discard(struct iov_iter *i, unsigned int direction, size_t count)
 }
 EXPORT_SYMBOL(iov_iter_discard);
 
-unsigned long iov_iter_alignment(const struct iov_iter *i)
+static unsigned long iov_iter_alignment_iovec(const struct iov_iter *i)
 {
        unsigned long res = 0;
        size_t size = i->count;
+       size_t skip = i->iov_offset;
+       unsigned k;
+
+       for (k = 0; k < i->nr_segs; k++, skip = 0) {
+               size_t len = i->iov[k].iov_len - skip;
+               if (len) {
+                       res |= (unsigned long)i->iov[k].iov_base + skip;
+                       if (len > size)
+                               len = size;
+                       res |= len;
+                       size -= len;
+                       if (!size)
+                               break;
+               }
+       }
+       return res;
+}
 
-       if (unlikely(iov_iter_is_pipe(i))) {
+static unsigned long iov_iter_alignment_bvec(const struct iov_iter *i)
+{
+       unsigned res = 0;
+       size_t size = i->count;
+       unsigned skip = i->iov_offset;
+       unsigned k;
+
+       for (k = 0; k < i->nr_segs; k++, skip = 0) {
+               size_t len = i->bvec[k].bv_len - skip;
+               res |= (unsigned long)i->bvec[k].bv_offset + skip;
+               if (len > size)
+                       len = size;
+               res |= len;
+               size -= len;
+               if (!size)
+                       break;
+       }
+       return res;
+}
+
+unsigned long iov_iter_alignment(const struct iov_iter *i)
+{
+       /* iovec and kvec have identical layouts */
+       if (likely(iter_is_iovec(i) || iov_iter_is_kvec(i)))
+               return iov_iter_alignment_iovec(i);
+
+       if (iov_iter_is_bvec(i))
+               return iov_iter_alignment_bvec(i);
+
+       if (iov_iter_is_pipe(i)) {
                unsigned int p_mask = i->pipe->ring_size - 1;
+               size_t size = i->count;
 
                if (size && i->iov_offset && allocated(&i->pipe->bufs[i->head & p_mask]))
                        return size | i->iov_offset;
                return size;
        }
-       if (unlikely(iov_iter_is_xarray(i)))
+
+       if (iov_iter_is_xarray(i))
                return (i->xarray_start + i->iov_offset) | i->count;
-       iterate_all_kinds(i, size, v,
-               (res |= (unsigned long)v.iov_base | v.iov_len, 0),
-               res |= v.bv_offset | v.bv_len,
-               res |= (unsigned long)v.iov_base | v.iov_len,
-               res |= v.bv_offset | v.bv_len
-       )
-       return res;
+
+       return 0;
 }
 EXPORT_SYMBOL(iov_iter_alignment);