[rh7,21/30] bio_vec-backed iov_iter

Submitted by Kirill Tkhai on May 20, 2020, 4:05 p.m.

Details

Message ID 158999072347.2234365.1030429625845483276.stgit@localhost.localdomain
State New
Series "fs, direct_IO: Switch to iov_iter and allow bio_vec for ext4"
Headers show

Commit Message

Kirill Tkhai May 20, 2020, 4:05 p.m.
From: Al Viro <viro@zeniv.linux.org.uk>

ms commit 62a8067a7f35 (partial)

New variant of iov_iter - ITER_BVEC in iter->type, backed with
bio_vec array instead of iovec one.  Primitives taught to deal
with such beasts, __swap_write() switched to using that kind
of iov_iter.

Note that bio_vec is just a <page, offset, length> triple - there's
nothing block-specific about it.  I've left the definition where it
was, but took it from under ifdef CONFIG_BLOCK.

Next target: ->splice_write()...

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Kirill Tkhai <ktkhai@virtuozzo.com>
---
 mm/iov-iter.c |   67 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 63 insertions(+), 4 deletions(-)

Patch hide | download patch | download mbox

diff --git a/mm/iov-iter.c b/mm/iov-iter.c
index 3a3a51cf3b59..04d92fb9bfcf 100644
--- a/mm/iov-iter.c
+++ b/mm/iov-iter.c
@@ -912,9 +912,26 @@  unsigned long iov_iter_alignment(struct iov_iter *i)
 }
 EXPORT_SYMBOL(iov_iter_alignment);
 
-ssize_t iov_iter_get_pages(struct iov_iter *i,
-		   struct page **pages, size_t maxsize,
-		   size_t *start, int rw)
+static ssize_t get_pages_bvec(struct iov_iter *i,
+		struct page **pages, size_t maxsize,
+		size_t *start)
+{
+	struct bio_vec *bvec = iov_iter_bvec(i);
+	size_t len = bvec->bv_len - i->iov_offset;
+	if (len > i->count)
+		len = i->count;
+	if (len > maxsize)
+		len = maxsize;
+	*start = bvec->bv_offset + i->iov_offset;
+
+	get_page(*pages = bvec->bv_page);
+
+	return len;
+}
+
+static ssize_t get_pages_iovec(struct iov_iter *i,
+		struct page **pages, size_t maxsize,
+		size_t *start, int rw)
 {
 	size_t offset = i->iov_offset;
 	const struct iovec *iov = iov_iter_iovec(i);
@@ -937,9 +954,43 @@  ssize_t iov_iter_get_pages(struct iov_iter *i,
 		return res;
 	return (res == n ? len : res * PAGE_SIZE) - *start;
 }
+
+ssize_t iov_iter_get_pages(struct iov_iter *i,
+			   struct page **pages, size_t maxsize,
+			   size_t *start, int rw)
+{
+	if (iov_iter_has_bvec(i))
+		return get_pages_bvec(i, pages, maxsize, start);
+	else
+		return get_pages_iovec(i, pages, maxsize, start, rw);
+}
 EXPORT_SYMBOL(iov_iter_get_pages);
 
-int iov_iter_npages(const struct iov_iter *i, int maxpages)
+static int iov_iter_npages_bvec(struct iov_iter *i, int maxpages)
+{
+	size_t offset = i->iov_offset;
+	size_t size = i->count;
+	struct bio_vec *bvec = iov_iter_bvec(i);
+	int npages = 0;
+	int n;
+
+	for (n = 0; size && n < i->nr_segs; n++, bvec++) {
+		size_t len = bvec->bv_len - offset;
+		offset = 0;
+		if (unlikely(!len))	/* empty segment */
+			continue;
+		if (len > size)
+			len = size;
+		npages++;
+		if (npages >= maxpages)	/* don't bother going further */
+			return maxpages;
+		size -= len;
+		offset = 0;
+	}
+	return min(npages, maxpages);
+}
+
+static int iov_iter_npages_iovec(const struct iov_iter *i, int maxpages)
 {
 	size_t offset = i->iov_offset;
 	size_t size = i->count;
@@ -964,4 +1015,12 @@  int iov_iter_npages(const struct iov_iter *i, int maxpages)
 	}
 	return min(npages, maxpages);
 }
+
+int iov_iter_npages(struct iov_iter *i, int maxpages)
+{
+	if (iov_iter_has_bvec(i))
+		return iov_iter_npages_bvec(i, maxpages);
+	else
+		return iov_iter_npages_iovec(i, maxpages);
+}
 EXPORT_SYMBOL(iov_iter_npages);