iov_iter: Kunit tests for page extraction
authorDavid Howells <dhowells@redhat.com>
Fri, 8 Sep 2023 16:03:22 +0000 (17:03 +0100)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 9 Sep 2023 22:11:49 +0000 (15:11 -0700)
Add some kunit tests for page extraction for ITER_BVEC, ITER_KVEC and
ITER_XARRAY type iterators.  ITER_UBUF and ITER_IOVEC aren't dealt with
as they require userspace VM interaction.  ITER_DISCARD isn't dealt with
either as that can't be extracted.

Signed-off-by: David Howells <dhowells@redhat.com>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Christian Brauner <brauner@kernel.org>
Cc: Jens Axboe <axboe@kernel.dk>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: David Hildenbrand <david@redhat.com>
Cc: John Hubbard <jhubbard@nvidia.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
lib/kunit_iov_iter.c

index 25a9101..859b67c 100644 (file)
@@ -519,6 +519,243 @@ stop:
        KUNIT_SUCCEED();
 }
 
+/*
+ * Test the extraction of ITER_KVEC-type iterators.
+ */
+static void __init iov_kunit_extract_pages_kvec(struct kunit *test)
+{
+       const struct kvec_test_range *pr;
+       struct iov_iter iter;
+       struct page **bpages, *pagelist[8], **pages = pagelist;
+       struct kvec kvec[8];
+       u8 *buffer;
+       ssize_t len;
+       size_t bufsize, size = 0, npages;
+       int i, from;
+
+       bufsize = 0x100000;
+       npages = bufsize / PAGE_SIZE;
+
+       buffer = iov_kunit_create_buffer(test, &bpages, npages);
+
+       iov_kunit_load_kvec(test, &iter, READ, kvec, ARRAY_SIZE(kvec),
+                           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 *)(unsigned long)0xaa55aa55aa55aa55ULL;
+
+               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_GE(test, (ssize_t)offset0, 0);
+               KUNIT_EXPECT_LT(test, offset0, PAGE_SIZE);
+               KUNIT_EXPECT_LE(test, len, size);
+               KUNIT_EXPECT_EQ(test, iter.count, size - len);
+               size -= len;
+
+               if (len == 0)
+                       break;
+
+               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 (from < 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_BVEC-type iterators.
+ */
+static void __init iov_kunit_extract_pages_bvec(struct kunit *test)
+{
+       const struct bvec_test_range *pr;
+       struct iov_iter iter;
+       struct page **bpages, *pagelist[8], **pages = pagelist;
+       struct bio_vec bvec[8];
+       ssize_t len;
+       size_t bufsize, size = 0, npages;
+       int i, from;
+
+       bufsize = 0x100000;
+       npages = bufsize / PAGE_SIZE;
+
+       iov_kunit_create_buffer(test, &bpages, npages);
+       iov_kunit_load_bvec(test, &iter, READ, bvec, ARRAY_SIZE(bvec),
+                           bpages, npages, bufsize, bvec_test_ranges);
+       size = iter.count;
+
+       pr = bvec_test_ranges;
+       from = pr->from;
+       do {
+               size_t offset0 = LONG_MAX;
+
+               for (i = 0; i < ARRAY_SIZE(pagelist); i++)
+                       pagelist[i] = (void *)(unsigned long)0xaa55aa55aa55aa55ULL;
+
+               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_GE(test, (ssize_t)offset0, 0);
+               KUNIT_EXPECT_LT(test, offset0, PAGE_SIZE);
+               KUNIT_EXPECT_LE(test, len, size);
+               KUNIT_EXPECT_EQ(test, iter.count, size - len);
+               size -= len;
+
+               if (len == 0)
+                       break;
+
+               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 (from < 0)
+                                       goto stop;
+                       }
+                       ix = pr->page + 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_XARRAY-type iterators.
+ */
+static void __init iov_kunit_extract_pages_xarray(struct kunit *test)
+{
+       const struct kvec_test_range *pr;
+       struct iov_iter iter;
+       struct xarray *xarray;
+       struct page **bpages, *pagelist[8], **pages = pagelist;
+       ssize_t len;
+       size_t bufsize, size = 0, npages;
+       int i, from;
+
+       bufsize = 0x100000;
+       npages = bufsize / PAGE_SIZE;
+
+       xarray = iov_kunit_create_xarray(test);
+
+       iov_kunit_create_buffer(test, &bpages, npages);
+       iov_kunit_load_xarray(test, &iter, READ, xarray, bpages, npages);
+
+       for (pr = kvec_test_ranges; pr->from >= 0; pr++) {
+               from = pr->from;
+               size = pr->to - from;
+               KUNIT_ASSERT_LE(test, pr->to, bufsize);
+
+               iov_iter_xarray(&iter, WRITE, xarray, from, size);
+
+               do {
+                       size_t offset0 = LONG_MAX;
+
+                       for (i = 0; i < ARRAY_SIZE(pagelist); i++)
+                               pagelist[i] = (void *)(unsigned long)0xaa55aa55aa55aa55ULL;
+
+                       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);
+
+                       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();
+}
+
 static struct kunit_case __refdata iov_kunit_cases[] = {
        KUNIT_CASE(iov_kunit_copy_to_kvec),
        KUNIT_CASE(iov_kunit_copy_from_kvec),
@@ -526,6 +763,9 @@ 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_kvec),
+       KUNIT_CASE(iov_kunit_extract_pages_bvec),
+       KUNIT_CASE(iov_kunit_extract_pages_xarray),
        {}
 };