Commit a3c57ab7 authored by David Howells's avatar David Howells Committed by Linus Torvalds
Browse files

iov_iter: Kunit tests for page extraction



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: default avatarDavid 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: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 2d71340f
Loading
Loading
Loading
Loading
+240 −0
Original line number Diff line number Diff line
@@ -519,6 +519,243 @@ static void __init iov_kunit_copy_from_xarray(struct kunit *test)
	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),
	{}
};