mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Alex Markuze <amarkuze@redhat.com>
To: Jens Axboe <axboe@kernel.dk>,
	"David S . Miller" <davem@davemloft.net>,
	Eric Dumazet <edumazet@kernel.org>,
	Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>
Cc: Pavel Begunkov <asml.silence@gmail.com>,
	Simon Horman <horms@kernel.org>,
	Kuniyuki Iwashima <kuniyu@google.com>,
	Willem de Bruijn <willemb@google.com>,
	Neal Cardwell <ncardwell@google.com>,
	John Fastabend <john.fastabend@gmail.com>,
	Jakub Sitnicki <jakub@cloudflare.com>,
	Jiayuan Chen <jiayuan.chen@linux.dev>,
	io-uring@vger.kernel.org, netdev@vger.kernel.org,
	bpf@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: [RFC PATCH net-next 12/12] io_uring/opaque: add basic KUnit tests
Date: Tue, 10 Nov 2026 13:20:06 +0000	[thread overview]
Message-ID: <20261110132006.3280986-13-amarkuze@redhat.com> (raw)
In-Reply-To: <20261110132006.3280986-1-amarkuze@redhat.com>

Check receive-budget admission and watermark transitions, then build a
page-backed immutable version and check its vector, payload, held version
reference and final backing/reference release.

Use existing internal helpers without adding production test hooks. These
are basic helper checks; the matching liburing example exercises a real
ring and loopback TCP connection.

Signed-off-by: Alex Markuze <amarkuze@redhat.com>
---
 io_uring/Kconfig       |  10 ++++
 io_uring/Makefile      |   1 +
 io_uring/opaque_test.c | 128 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 139 insertions(+)
 create mode 100644 io_uring/opaque_test.c

diff --git a/io_uring/Kconfig b/io_uring/Kconfig
index 5b696cf266f6..db6e3c5a317d 100644
--- a/io_uring/Kconfig
+++ b/io_uring/Kconfig
@@ -30,3 +30,13 @@ config IO_URING_BPF_OPS
 	def_bool y
 	depends on IO_URING
 	depends on BPF_SYSCALL && BPF_JIT && DEBUG_INFO_BTF
+
+config IO_URING_OPAQUE_OBJ_KUNIT_TEST
+	bool "KUnit smoke tests for opaque objects" if !KUNIT_ALL_TESTS
+	depends on KUNIT=y && IO_URING_OPAQUE_OBJ
+	default KUNIT_ALL_TESTS
+	help
+	  Check receive-budget admission and watermark transitions, and the
+	  vector representation and reference lifetime of an immutable version.
+	  The tests call internal helpers without a userspace ring or TCP socket.
+	  They are a small smoke test, not a pressure or concurrency suite.
diff --git a/io_uring/Makefile b/io_uring/Makefile
index 912b1861c0a5..b7fcc2d3c714 100644
--- a/io_uring/Makefile
+++ b/io_uring/Makefile
@@ -18,6 +18,7 @@ obj-$(CONFIG_IO_URING)		+= io_uring.o opdef.o kbuf.o rsrc.o notif.o \
 
 obj-$(CONFIG_IO_URING_ZCRX)	+= zcrx.o
 obj-$(CONFIG_IO_URING_OPAQUE_OBJ)	+= opaque.o opaque_register.o opaque_compact.o
+obj-$(CONFIG_IO_URING_OPAQUE_OBJ_KUNIT_TEST) += opaque_test.o
 obj-$(CONFIG_IO_WQ)		+= io-wq.o
 obj-$(CONFIG_FUTEX)		+= futex.o
 obj-$(CONFIG_EPOLL)		+= epoll.o
diff --git a/io_uring/opaque_test.c b/io_uring/opaque_test.c
new file mode 100644
index 000000000000..cba5829de05f
--- /dev/null
+++ b/io_uring/opaque_test.c
@@ -0,0 +1,128 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <kunit/test.h>
+#include <linux/highmem.h>
+
+#include "opaque_internal.h"
+
+struct opaque_basic {
+	struct io_opaque_store *store;
+	struct io_opaque_data *data;
+	struct page *page;
+};
+
+static void opaque_basic_release(void *arg)
+{
+	struct opaque_basic *c = arg;
+
+	if (!IS_ERR_OR_NULL(c->store)) {
+		io_opaque_data_put(c->store, c->data);
+		/* Also release a budget assertion's unfinished reservation. */
+		if (atomic64_read(&c->store->bytes) > 0)
+			io_opaque_uncharge(c->store, atomic64_read(&c->store->bytes));
+		io_opaque_free(c->store);
+	}
+	if (c->page)
+		put_page(c->page);
+}
+
+static struct opaque_basic *opaque_basic_new(struct kunit *test)
+{
+	struct io_uring_opaque_config config = {
+		.hard_limit = 8 * PAGE_SIZE,
+		.compact_headroom = 2 * PAGE_SIZE,
+		.reply_reserve = PAGE_SIZE,
+		.high_watermark = 4 * PAGE_SIZE,
+		.low_watermark = 2 * PAGE_SIZE,
+		.max_object_size = PAGE_SIZE,
+		.max_objects = 4,
+		.max_streams = 1,
+		.max_extents = 8,
+	};
+	struct opaque_basic *c = kunit_kzalloc(test, sizeof(*c), GFP_KERNEL);
+	struct io_ring_ctx *ctx;
+
+	KUNIT_ASSERT_NOT_NULL(test, c);
+	KUNIT_ASSERT_EQ(test,
+			kunit_add_action_or_reset(test, opaque_basic_release, c), 0);
+	/* No user/mm accounting in this internal-helper fixture. */
+	ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, ctx);
+	c->store = io_opaque_alloc(ctx, &config);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, c->store);
+	return c;
+}
+
+static void opaque_basic_budget(struct kunit *test)
+{
+	struct opaque_basic *c = opaque_basic_new(test);
+	struct io_opaque_store *store = c->store;
+
+	KUNIT_ASSERT_TRUE(test, io_opaque_charge(store, 3 * PAGE_SIZE, true));
+	KUNIT_EXPECT_EQ(test, io_opaque_memory_mode(store), IORING_OPAQUE_MEMORY_NORMAL);
+	KUNIT_ASSERT_TRUE(test, io_opaque_charge(store, PAGE_SIZE, true));
+	KUNIT_EXPECT_EQ(test, io_opaque_memory_mode(store), IORING_OPAQUE_MEMORY_LOWMEM);
+	KUNIT_EXPECT_FALSE(test, io_opaque_charge(store, 2 * PAGE_SIZE, true));
+	KUNIT_EXPECT_EQ(test, atomic64_read(&store->bytes), (s64)(4 * PAGE_SIZE));
+	io_opaque_uncharge(store, 2 * PAGE_SIZE);
+	KUNIT_EXPECT_EQ(test, io_opaque_memory_mode(store), IORING_OPAQUE_MEMORY_NORMAL);
+	io_opaque_uncharge(store, 2 * PAGE_SIZE);
+	KUNIT_EXPECT_EQ(test, atomic64_read(&store->bytes), 0LL);
+}
+
+static void opaque_basic_version(struct kunit *test)
+{
+	static const char payload[] = "opaque";
+	struct opaque_basic *c = opaque_basic_new(test);
+	struct io_opaque_extent *extent;
+	void *mapped;
+
+	c->data = io_opaque_data_alloc();
+	KUNIT_ASSERT_NOT_NULL(test, c->data);
+	c->page = alloc_page(GFP_KERNEL | __GFP_ZERO);
+	KUNIT_ASSERT_NOT_NULL(test, c->page);
+	mapped = kmap_local_page(c->page);
+	memcpy(mapped + 17, payload, sizeof(payload));
+	kunmap_local(mapped);
+	get_page(c->page);
+	extent = io_opaque_extent_new(c->store, c->page, 17, sizeof(payload), 0, false);
+	if (IS_ERR(extent))
+		put_page(c->page);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, extent);
+	list_add_tail(&extent->list, &c->data->extents);
+	c->data->length = sizeof(payload);
+	KUNIT_ASSERT_EQ(test, io_opaque_vector(c->data), 0);
+	KUNIT_ASSERT_EQ(test, c->data->nr, 1U);
+	KUNIT_EXPECT_PTR_EQ(test, c->data->bvec[0].bv_page, c->page);
+	KUNIT_EXPECT_EQ(test, c->data->bvec[0].bv_offset, 17U);
+	KUNIT_EXPECT_EQ(test, c->data->bvec[0].bv_len, (unsigned int)sizeof(payload));
+	KUNIT_EXPECT_EQ(test, c->data->charge, (u64)PAGE_SIZE);
+	KUNIT_EXPECT_EQ(test, atomic64_read(&c->store->bytes), (s64)PAGE_SIZE);
+	KUNIT_EXPECT_EQ(test, atomic_read(&c->store->extents), 1);
+	refcount_inc(&c->data->refs);
+	io_opaque_data_put(c->store, c->data);
+	KUNIT_EXPECT_EQ(test, refcount_read(&c->data->refs), 1U);
+	KUNIT_EXPECT_EQ(test, page_ref_count(c->page), 2);
+	mapped = kmap_local_page(c->data->bvec[0].bv_page);
+	KUNIT_EXPECT_MEMEQ(test, mapped + c->data->bvec[0].bv_offset, payload, sizeof(payload));
+	kunmap_local(mapped);
+	io_opaque_data_put(c->store, c->data);
+	c->data = NULL;
+	KUNIT_EXPECT_EQ(test, page_ref_count(c->page), 1);
+	KUNIT_EXPECT_EQ(test, atomic64_read(&c->store->bytes), 0LL);
+	KUNIT_EXPECT_EQ(test, atomic_read(&c->store->extents), 0);
+}
+
+static struct kunit_case opaque_basic_cases[] = {
+	KUNIT_CASE(opaque_basic_budget),
+	KUNIT_CASE(opaque_basic_version),
+	{}
+};
+
+static struct kunit_suite opaque_basic_suite = {
+	.name = "io_opaque_basic",
+	.test_cases = opaque_basic_cases,
+};
+
+kunit_test_suite(opaque_basic_suite);
+
+MODULE_LICENSE("GPL");
-- 
2.34.1


      parent reply	other threads:[~2026-11-10 13:20 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-10 13:19 [RFC PATCH net-next 00/12] io_uring: opaque TCP payload objects Alex Markuze
2026-11-10 13:19 ` [RFC PATCH net-next 01/12] net: add an exclusive TCP receive claim Alex Markuze
2026-11-10 13:19 ` [RFC PATCH net-next 02/12] io_uring/opaque: add data structures and the UAPI header Alex Markuze
2026-11-10 13:19 ` [RFC PATCH net-next 03/12] io_uring/opaque: add backing accounting and immutable versions Alex Markuze
2026-11-10 13:19 ` [RFC PATCH net-next 04/12] io_uring/opaque: add owned-page helpers for dense copies Alex Markuze
2026-11-10 13:19 ` [RFC PATCH net-next 05/12] io_uring/opaque: add store registration and IORING_OP_OPAQUE_OBJ Alex Markuze
2026-11-10 13:20 ` [RFC PATCH net-next 06/12] io_uring/opaque: allow rings to share a store Alex Markuze
2026-11-10 13:20 ` [RFC PATCH net-next 07/12] io_uring/opaque: add IORING_OP_OPAQUE_OBJ_SEND Alex Markuze
2026-11-10 13:20 ` [RFC PATCH net-next 08/12] io_uring/opaque: add vectored IORING_OP_OPAQUE_OBJ_SEND Alex Markuze
2026-11-10 13:20 ` [RFC PATCH net-next 09/12] io_uring/opaque: add IORING_OP_OPAQUE_COLLECT Alex Markuze
2026-11-10 13:20 ` [RFC PATCH net-next 10/12] io_uring/opaque: add IORING_OPAQUE_CREATE Alex Markuze
2026-11-10 13:20 ` [RFC PATCH net-next 11/12] io_uring/opaque: add manual and automatic compaction Alex Markuze
2026-11-10 13:20 ` Alex Markuze [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261110132006.3280986-13-amarkuze@redhat.com \
    --to=amarkuze@redhat.com \
    --cc=asml.silence@gmail.com \
    --cc=axboe@kernel.dk \
    --cc=bpf@vger.kernel.org \
    --cc=davem@davemloft.net \
    --cc=edumazet@kernel.org \
    --cc=horms@kernel.org \
    --cc=io-uring@vger.kernel.org \
    --cc=jakub@cloudflare.com \
    --cc=jiayuan.chen@linux.dev \
    --cc=john.fastabend@gmail.com \
    --cc=kuba@kernel.org \
    --cc=kuniyu@google.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=ncardwell@google.com \
    --cc=netdev@vger.kernel.org \
    --cc=pabeni@redhat.com \
    --cc=willemb@google.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®