linux-fsdevel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Kent Overstreet <kent.overstreet@linux.dev>
To: linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org
Cc: Jens Axboe <axboe@kernel.dk>,
	Kent Overstreet <kent.overstreet@linux.dev>,
	brauner@kernel.org, viro@zeniv.linux.org.uk,
	Bernd Schubert <bernd.schubert@fastmail.fm>,
	linux-mm@kvack.org, Josef Bacik <josef@toxicpanda.com>
Subject: [PATCH 4/5] ringbuffer: Test device
Date: Sun,  2 Jun 2024 20:33:01 -0400	[thread overview]
Message-ID: <20240603003306.2030491-5-kent.overstreet@linux.dev> (raw)
In-Reply-To: <20240603003306.2030491-1-kent.overstreet@linux.dev>

This adds /dev/ringbuffer-test, which supports reading and writing a
sequence of integers, to test performance and correctness.

Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
---
 fs/Makefile          |   1 +
 fs/ringbuffer_test.c | 209 +++++++++++++++++++++++++++++++++++++++++++
 lib/Kconfig.debug    |   5 ++
 3 files changed, 215 insertions(+)
 create mode 100644 fs/ringbuffer_test.c

diff --git a/fs/Makefile b/fs/Makefile
index 48e54ac01fb1..91061f281f0a 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -29,6 +29,7 @@ obj-$(CONFIG_EVENTFD)		+= eventfd.o
 obj-$(CONFIG_USERFAULTFD)	+= userfaultfd.o
 obj-$(CONFIG_AIO)               += aio.o
 obj-$(CONFIG_RINGBUFFER)        += ringbuffer.o
+obj-$(CONFIG_RINGBUFFER_TEST)   += ringbuffer_test.o
 obj-$(CONFIG_FS_DAX)		+= dax.o
 obj-$(CONFIG_FS_ENCRYPTION)	+= crypto/
 obj-$(CONFIG_FS_VERITY)		+= verity/
diff --git a/fs/ringbuffer_test.c b/fs/ringbuffer_test.c
new file mode 100644
index 000000000000..01aa9c55120d
--- /dev/null
+++ b/fs/ringbuffer_test.c
@@ -0,0 +1,209 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#define pr_fmt(fmt) "%s() " fmt "\n", __func__
+
+#include <linux/device.h>
+#include <linux/errname.h>
+#include <linux/fs.h>
+#include <linux/kthread.h>
+#include <linux/ringbuffer_sys.h>
+#include <linux/uio.h>
+
+struct ringbuffer_test_file {
+	struct ringbuffer_test_rw {
+		struct mutex		lock;
+		struct ringbuffer	*rb;
+		struct task_struct	*thr;
+	} rw[2];
+};
+
+#define BUF_NR	4
+
+static int ringbuffer_test_writer(void *p)
+{
+	struct file *file = p;
+	struct ringbuffer_test_file *f = file->private_data;
+	struct ringbuffer *rb = f->rw[READ].rb;
+	u32 idx = 0;
+	u32 buf[BUF_NR];
+
+	while (!kthread_should_stop()) {
+		cond_resched();
+
+		struct kvec vec = { buf, sizeof(buf) };
+		struct iov_iter iter;
+		iov_iter_kvec(&iter, ITER_SOURCE, &vec, 1, sizeof(buf));
+
+		for (unsigned i = 0; i < ARRAY_SIZE(buf); i++)
+			buf[i] = idx + i;
+
+		ssize_t ret = ringbuffer_write_iter(rb, &iter, false);
+		if (ret < 0)
+			continue;
+		idx += ret / sizeof(buf[0]);
+	}
+
+	return 0;
+}
+
+static int ringbuffer_test_reader(void *p)
+{
+	struct file *file = p;
+	struct ringbuffer_test_file *f = file->private_data;
+	struct ringbuffer *rb = f->rw[WRITE].rb;
+	u32 idx = 0;
+	u32 buf[BUF_NR];
+
+	while (!kthread_should_stop()) {
+		cond_resched();
+
+		struct kvec vec = { buf, sizeof(buf) };
+		struct iov_iter iter;
+		iov_iter_kvec(&iter, ITER_DEST, &vec, 1, sizeof(buf));
+
+		ssize_t ret = ringbuffer_read_iter(rb, &iter, false);
+		if (ret < 0)
+			continue;
+
+		unsigned nr = ret / sizeof(buf[0]);
+		for (unsigned i = 0; i < nr; i++)
+			if (buf[i] != idx + i)
+				pr_err("read wrong data");
+		idx += ret / sizeof(buf[0]);
+	}
+
+	return 0;
+}
+
+static void ringbuffer_test_free(struct ringbuffer_test_file *f)
+{
+	for (unsigned i = 0; i < ARRAY_SIZE(f->rw); i++)
+		if (!IS_ERR_OR_NULL(f->rw[i].thr))
+			kthread_stop_put(f->rw[i].thr);
+	for (unsigned i = 0; i < ARRAY_SIZE(f->rw); i++)
+		if (!IS_ERR_OR_NULL(f->rw[i].rb))
+			ringbuffer_free(f->rw[i].rb);
+	kfree(f);
+}
+
+static int ringbuffer_test_open(struct inode *inode, struct file *file)
+{
+	static const char * const rw_str[] = { "reader", "writer" };
+	int ret = 0;
+
+	struct ringbuffer_test_file *f = kzalloc(sizeof(*f), GFP_KERNEL);
+	if (!f)
+		return -ENOMEM;
+
+	for (struct ringbuffer_test_rw *i = f->rw;
+	     i < f->rw + ARRAY_SIZE(f->rw);
+	     i++) {
+		unsigned idx = i - f->rw;
+
+		mutex_init(&i->lock);
+
+		i->rb = ringbuffer_alloc(PAGE_SIZE * 4);
+		ret = PTR_ERR_OR_ZERO(i->rb);
+		if (ret)
+			goto err;
+
+		i->thr = kthread_create(idx == READ
+					? ringbuffer_test_reader
+					: ringbuffer_test_writer,
+					file, "ringbuffer_%s", rw_str[idx]);
+		ret = PTR_ERR_OR_ZERO(i->thr);
+		if (ret)
+			goto err;
+		get_task_struct(i->thr);
+	}
+
+	file->private_data = f;
+	wake_up_process(f->rw[0].thr);
+	wake_up_process(f->rw[1].thr);
+	return 0;
+err:
+	ringbuffer_test_free(f);
+	return ret;
+}
+
+static int ringbuffer_test_release(struct inode *inode, struct file *file)
+{
+	ringbuffer_test_free(file->private_data);
+	return 0;
+}
+
+static ssize_t ringbuffer_test_read_iter(struct kiocb *iocb, struct iov_iter *iter)
+{
+	struct file *file = iocb->ki_filp;
+	struct ringbuffer_test_file *f = file->private_data;
+	struct ringbuffer_test_rw *i = &f->rw[READ];
+
+	ssize_t ret = mutex_lock_interruptible(&i->lock);
+	if (ret)
+		return ret;
+
+	ret = ringbuffer_read_iter(i->rb, iter, file->f_flags & O_NONBLOCK);
+	mutex_unlock(&i->lock);
+	return ret;
+}
+
+static ssize_t ringbuffer_test_write_iter(struct kiocb *iocb, struct iov_iter *iter)
+{
+	struct file *file = iocb->ki_filp;
+	struct ringbuffer_test_file *f = file->private_data;
+	struct ringbuffer_test_rw *i = &f->rw[WRITE];
+
+	ssize_t ret = mutex_lock_interruptible(&i->lock);
+	if (ret)
+		return ret;
+
+	ret = ringbuffer_write_iter(i->rb, iter, file->f_flags & O_NONBLOCK);
+	mutex_unlock(&i->lock);
+	return ret;
+}
+
+static struct ringbuffer *ringbuffer_test_ringbuffer(struct file *file, int rw)
+{
+	struct ringbuffer_test_file *i = file->private_data;
+
+	BUG_ON(rw > WRITE);
+
+	return i->rw[rw].rb;
+}
+
+static const struct file_operations ringbuffer_fops = {
+	.owner		= THIS_MODULE,
+	.read_iter	= ringbuffer_test_read_iter,
+	.write_iter	= ringbuffer_test_write_iter,
+	.ringbuffer	= ringbuffer_test_ringbuffer,
+	.open		= ringbuffer_test_open,
+	.release	= ringbuffer_test_release,
+};
+
+static int __init ringbuffer_test_init(void)
+{
+	int ringbuffer_major = register_chrdev(0, "ringbuffer-test", &ringbuffer_fops);
+	if (ringbuffer_major < 0)
+		return ringbuffer_major;
+
+	static const struct class ringbuffer_class = { .name = "ringbuffer_test" };
+	int ret = class_register(&ringbuffer_class);
+	if (ret)
+		goto major_out;
+
+	struct device *ringbuffer_device = device_create(&ringbuffer_class, NULL,
+				    MKDEV(ringbuffer_major, 0),
+				    NULL, "ringbuffer-test");
+	ret = PTR_ERR_OR_ZERO(ringbuffer_device);
+	if (ret)
+		goto class_out;
+
+	return 0;
+
+class_out:
+	class_unregister(&ringbuffer_class);
+major_out:
+	unregister_chrdev(ringbuffer_major, "ringbuffer-test");
+	return ret;
+}
+__initcall(ringbuffer_test_init);
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 59b6765d86b8..bb16762af575 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -2957,6 +2957,11 @@ config TEST_OBJPOOL
 
 	  If unsure, say N.
 
+config RINGBUFFER_TEST
+	bool "Test driver for sys_ringbuffer"
+	default n
+	depends on RINGBUFFER
+
 endif # RUNTIME_TESTING_MENU
 
 config ARCH_USE_MEMTEST
-- 
2.45.1


  parent reply	other threads:[~2024-06-03  0:33 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-06-03  0:32 [PATCH 0/5] sys_ringbuffer Kent Overstreet
2024-06-03  0:32 ` [PATCH 1/5] darray: lift from bcachefs Kent Overstreet
2024-06-03  0:32 ` [PATCH 2/5] darray: Fix darray_for_each_reverse() when darray is empty Kent Overstreet
2024-06-03  0:33 ` [PATCH 3/5] fs: sys_ringbuffer Kent Overstreet
2024-06-03  4:16   ` kernel test robot
2024-06-03  4:38   ` kernel test robot
2024-06-23 22:13   ` Thomas Gleixner
2024-06-23 22:21     ` Kent Overstreet
2024-06-23 23:16       ` Thomas Gleixner
2024-06-24  0:27         ` Kent Overstreet
2024-06-03  0:33 ` Kent Overstreet [this message]
2024-06-03  0:33 ` [PATCH 5/5] ringbuffer: Userspace test helper Kent Overstreet
2024-06-07  1:49 ` [PATCH 0/5] sys_ringbuffer Stefan Hajnoczi

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=20240603003306.2030491-5-kent.overstreet@linux.dev \
    --to=kent.overstreet@linux.dev \
    --cc=axboe@kernel.dk \
    --cc=bernd.schubert@fastmail.fm \
    --cc=brauner@kernel.org \
    --cc=josef@toxicpanda.com \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=viro@zeniv.linux.org.uk \
    /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;
as well as URLs for NNTP newsgroup(s).