Add extraction kunit tests for ITER_UBUF- and ITER_IOVEC-type iterators.
This attaches a userspace VM with a mapped file in it temporarily to the
test thread.

[!] Note that this requires the kernel thread running the test to obtain
and deploy an mm_struct so that a user-side buffer can be created with mmap
- basically it has to emulated part of execve().  Doing so requires access
to additional core symbols: mm_alloc(), vm_area_alloc(), insert_vm_struct()
and arch_pick_mmap_layout().  See the iov_kunit_create_user_buf() function
added in the patch.

Signed-off-by: David Howells <dhowe...@redhat.com>
cc: Andrew Morton <a...@linux-foundation.org>
cc: Christoph Hellwig <h...@lst.de>
cc: Christian Brauner <brau...@kernel.org>
cc: Jens Axboe <ax...@kernel.dk>
cc: Al Viro <v...@zeniv.linux.org.uk>
cc: Matthew Wilcox <wi...@infradead.org>
cc: David Hildenbrand <da...@redhat.com>
cc: John Hubbard <jhubb...@nvidia.com>
cc: Brendan Higgins <brendanhigg...@google.com>
cc: David Gow <david...@google.com>
cc: linux...@kvack.org
cc: linux-fsde...@vger.kernel.org
cc: linux-kselftest@vger.kernel.org
cc: kunit-...@googlegroups.com
---
 lib/kunit_iov_iter.c | 164 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 164 insertions(+)

diff --git a/lib/kunit_iov_iter.c b/lib/kunit_iov_iter.c
index 34f0d82674ee..fdf598e49c0b 100644
--- a/lib/kunit_iov_iter.c
+++ b/lib/kunit_iov_iter.c
@@ -863,6 +863,168 @@ static void __init iov_kunit_copy_from_xarray(struct 
kunit *test)
        KUNIT_SUCCEED();
 }
 
+/*
+ * Test the extraction of ITER_UBUF-type iterators.
+ */
+static void __init iov_kunit_extract_pages_ubuf(struct kunit *test)
+{
+       const struct iov_kunit_range *pr;
+       struct iov_iter iter;
+       struct page **bpages, *pagelist[8], **pages = pagelist;
+       ssize_t len;
+       size_t bufsize, size = 0, npages;
+       int i, from;
+       u8 __user *buffer;
+
+       bufsize = 0x100000;
+       npages = bufsize / PAGE_SIZE;
+
+       buffer = iov_kunit_create_user_buf(test, npages, &bpages);
+
+       for (pr = kvec_test_ranges; pr->page >= 0; pr++) {
+               from = pr->from;
+               size = pr->to - from;
+               KUNIT_ASSERT_LE(test, pr->to, bufsize);
+
+               iov_iter_ubuf(&iter, ITER_SOURCE, buffer + pr->from, size);
+
+               do {
+                       size_t offset0 = LONG_MAX;
+
+                       for (i = 0; i < ARRAY_SIZE(pagelist); i++)
+                               pagelist[i] = (void *)POISON_POINTER_DELTA + 
0x5a;
+
+                       len = iov_iter_extract_pages(&iter, &pages, 100 * 1024,
+                                                    ARRAY_SIZE(pagelist), 0, 
&offset0);
+                       KUNIT_EXPECT_GE(test, len, 0);
+                       if (len < 0)
+                               break;
+                       KUNIT_EXPECT_LE(test, len, size);
+                       KUNIT_EXPECT_EQ(test, iter.count, size - len);
+                       if (len == 0)
+                               break;
+                       size -= len;
+                       KUNIT_EXPECT_GE(test, (ssize_t)offset0, 0);
+                       KUNIT_EXPECT_LT(test, offset0, PAGE_SIZE);
+
+                       /* We're only checking the page pointers */
+                       unpin_user_pages(pages, (offset0 + len) / PAGE_SIZE);
+
+                       for (i = 0; i < ARRAY_SIZE(pagelist); i++) {
+                               struct page *p;
+                               ssize_t part = min_t(ssize_t, len, PAGE_SIZE - 
offset0);
+                               int ix;
+
+                               KUNIT_ASSERT_GE(test, part, 0);
+                               ix = from / PAGE_SIZE;
+                               KUNIT_ASSERT_LT(test, ix, npages);
+                               p = bpages[ix];
+                               KUNIT_EXPECT_PTR_EQ(test, pagelist[i], p);
+                               KUNIT_EXPECT_EQ(test, offset0, from % 
PAGE_SIZE);
+                               from += part;
+                               len -= part;
+                               KUNIT_ASSERT_GE(test, len, 0);
+                               if (len == 0)
+                                       break;
+                               offset0 = 0;
+                       }
+
+                       if (test->status == KUNIT_FAILURE)
+                               goto stop;
+               } while (iov_iter_count(&iter) > 0);
+
+               KUNIT_EXPECT_EQ(test, size, 0);
+               KUNIT_EXPECT_EQ(test, iter.count, 0);
+               KUNIT_EXPECT_EQ(test, iter.iov_offset, pr->to - pr->from);
+       }
+
+stop:
+       KUNIT_SUCCEED();
+}
+
+/*
+ * Test the extraction of ITER_IOVEC-type iterators.
+ */
+static void __init iov_kunit_extract_pages_iovec(struct kunit *test)
+{
+       const struct iov_kunit_range *pr;
+       struct iov_iter iter;
+       struct iovec iov[8];
+       struct page **bpages, *pagelist[8], **pages = pagelist;
+       ssize_t len;
+       size_t bufsize, size = 0, npages;
+       int i, from;
+       u8 __user *buffer;
+
+       bufsize = 0x100000;
+       npages = bufsize / PAGE_SIZE;
+
+       buffer = iov_kunit_create_user_buf(test, npages, &bpages);
+
+       iov_kunit_load_iovec(test, &iter, ITER_SOURCE, iov, ARRAY_SIZE(iov),
+                            buffer, bufsize, kvec_test_ranges);
+       size = iter.count;
+
+       pr = kvec_test_ranges;
+       from = pr->from;
+       do {
+               size_t offset0 = LONG_MAX;
+
+               for (i = 0; i < ARRAY_SIZE(pagelist); i++)
+                       pagelist[i] = (void *)POISON_POINTER_DELTA + 0x5a;
+
+               len = iov_iter_extract_pages(&iter, &pages, 100 * 1024,
+                                            ARRAY_SIZE(pagelist), 0, &offset0);
+               KUNIT_EXPECT_GE(test, len, 0);
+               if (len < 0)
+                       break;
+               KUNIT_EXPECT_LE(test, len, size);
+               KUNIT_EXPECT_EQ(test, iter.count, size - len);
+               if (len == 0)
+                       break;
+               size -= len;
+               KUNIT_EXPECT_GE(test, (ssize_t)offset0, 0);
+               KUNIT_EXPECT_LT(test, offset0, PAGE_SIZE);
+
+               /* We're only checking the page pointers */
+               unpin_user_pages(pages, (offset0 + len) / PAGE_SIZE);
+
+               for (i = 0; i < ARRAY_SIZE(pagelist); i++) {
+                       struct page *p;
+                       ssize_t part = min_t(ssize_t, len, PAGE_SIZE - offset0);
+                       int ix;
+
+                       KUNIT_ASSERT_GE(test, part, 0);
+                       while (from == pr->to) {
+                               pr++;
+                               from = pr->from;
+                               if (pr->page < 0)
+                                       goto stop;
+                       }
+
+                       ix = from / PAGE_SIZE;
+                       KUNIT_ASSERT_LT(test, ix, npages);
+                       p = bpages[ix];
+                       KUNIT_EXPECT_PTR_EQ(test, pagelist[i], p);
+                       KUNIT_EXPECT_EQ(test, offset0, from % PAGE_SIZE);
+                       from += part;
+                       len -= part;
+                       KUNIT_ASSERT_GE(test, len, 0);
+                       if (len == 0)
+                               break;
+                       offset0 = 0;
+               }
+
+               if (test->status == KUNIT_FAILURE)
+                       break;
+       } while (iov_iter_count(&iter) > 0);
+
+stop:
+       KUNIT_EXPECT_EQ(test, size, 0);
+       KUNIT_EXPECT_EQ(test, iter.count, 0);
+       KUNIT_SUCCEED();
+}
+
 /*
  * Test the extraction of ITER_KVEC-type iterators.
  */
@@ -1111,6 +1273,8 @@ static struct kunit_case __refdata iov_kunit_cases[] = {
        KUNIT_CASE(iov_kunit_copy_from_bvec),
        KUNIT_CASE(iov_kunit_copy_to_xarray),
        KUNIT_CASE(iov_kunit_copy_from_xarray),
+       KUNIT_CASE(iov_kunit_extract_pages_ubuf),
+       KUNIT_CASE(iov_kunit_extract_pages_iovec),
        KUNIT_CASE(iov_kunit_extract_pages_kvec),
        KUNIT_CASE(iov_kunit_extract_pages_bvec),
        KUNIT_CASE(iov_kunit_extract_pages_xarray),

Reply via email to