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
next prev parent reply other threads:[~2024-06-03 0:33 UTC|newest]
Thread overview: 14+ 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 5:00 ` kernel test robot
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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.