[Devel] [PATCH RHEL7 COMMIT] fuse kio: Add nullio engine

Konstantin Khorenko khorenko at virtuozzo.com
Mon Feb 19 14:16:29 MSK 2018


The commit is pushed to "branch-rh7-3.10.0-693.17.1.vz7.45.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-693.17.1.vz7.43.7
------>
commit 34a199e9c19a6c6a98efee904caf35c11e13dccd
Author: Dmitry Monakhov <dmonakhov at openvz.org>
Date:   Mon Feb 19 14:16:29 2018 +0300

    fuse kio: Add nullio engine
    
    Add debugging fake-io kdirect io engine.
    
    It allow to test fuse-kio throughput performance
    Available options:
    - fake_read:  Fake read request  (0=off, 1=on, default on) (int)
    - fake_write: Fake write request (0=off, 1=on, default off) (int)
    - payload_sz: Payload size for added to fuse_req, default 0 (uint)
    
    TODO:
     1) may be it is reasonable to make fake_op=N to act means to drop each N'th
        request. #THINK!
    
    #Example:
    modprobe fuse_kio_nullio payload_sz=1024
    vstorage-mount -c pcs_test_sandy -p kdirect=nullio /mnt
    
    https://jira.sw.ru/browse/PSBM-80680
    Signed-off-by: Dmitry Monakhov <dmonakhov at openvz.org>
---
 fs/fuse/Kconfig          |   6 ++
 fs/fuse/Makefile         |   3 +
 fs/fuse/kio/kio_nullio.c | 194 +++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 203 insertions(+)

diff --git a/fs/fuse/Kconfig b/fs/fuse/Kconfig
index fcbb5a565fc6..a0591e4b3a04 100644
--- a/fs/fuse/Kconfig
+++ b/fs/fuse/Kconfig
@@ -33,3 +33,9 @@ config FUSE_KIO_NOOP
 	  This FUSE extension allows to handle io requests directly inside kernel
 
 	  This is for kdirect io feature debugging only, answer Y or M.
+
+config FUSE_KIO_NULLIO
+	tristate "Enable kdirect null io io engine"
+	depends on FUSE_FS
+	help
+	  This FUSE extension allows to handle io requests directly inside kernel
diff --git a/fs/fuse/Makefile b/fs/fuse/Makefile
index 4a250c083f0d..f7500f0e832e 100644
--- a/fs/fuse/Makefile
+++ b/fs/fuse/Makefile
@@ -8,4 +8,7 @@ obj-$(CONFIG_CUSE) += cuse.o
 obj-$(CONFIG_FUSE_KIO_NOOP)	+= fuse_kio_noop.o
 fuse_kio_noop-objs := kio/kio_noop.o
 
+obj-$(CONFIG_FUSE_KIO_NULLIO)	+= fuse_kio_nullio.o
+fuse_kio_nullio-objs := kio/kio_nullio.o
+
 fuse-objs := dev.o dir.o file.o inode.o control.o
diff --git a/fs/fuse/kio/kio_nullio.c b/fs/fuse/kio/kio_nullio.c
new file mode 100644
index 000000000000..973c25453449
--- /dev/null
+++ b/fs/fuse/kio/kio_nullio.c
@@ -0,0 +1,194 @@
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+
+#include "../fuse_i.h"
+
+static struct fuse_kio_ops nullio_ops;
+static struct kmem_cache *nullio_req_cachep;
+
+struct nullio_req {
+	struct fuse_req req;
+	char payload[0];
+};
+
+static inline struct nullio_req *nullreq_from_fuse(struct fuse_req *req)
+{
+	return container_of(req, struct nullio_req, req);
+}
+
+static int fake_read = 1;
+static int fake_write = 0;
+static unsigned int payload_sz = 0;
+
+module_param(fake_read, int, S_IRUGO);
+MODULE_PARM_DESC(fake_read, "Fake read request (0=off, 1=on, default on)");
+
+module_param(fake_write, int, S_IRUGO);
+MODULE_PARM_DESC(fake_write, "Fake write request (0=off, 1=on, default off)");
+
+module_param(payload_sz, uint, S_IRUGO);
+MODULE_PARM_DESC(payload_sz, "Payload size for added to fuse_req, default 0");
+
+/* Conn hooks */
+static int nullio_probe(struct fuse_conn *fc, char *name)
+{
+	if (!strncmp(name, nullio_ops.name, FUSE_KIO_NAME))
+		return 1;
+
+	return 0;
+}
+
+static int nullio_conn_init(struct fuse_conn *fc)
+{
+	/* Just for sanity checks */
+	fc->kio.ctx = nullio_req_cachep;
+	pr_debug("nullio_conn_init\n");
+
+	/*This one is mandatary */
+	fuse_set_initialized(fc);
+	wake_up_all(&fc->blocked_waitq);
+
+	return 0;
+}
+
+static void nullio_conn_fini(struct fuse_conn *fc)
+{
+	BUG_ON(fc->kio.ctx != nullio_req_cachep);
+	pr_debug("nullio_conn_fini\n");
+
+}
+
+static void nullio_conn_abort(struct fuse_conn *fc)
+{
+	BUG_ON(fc->kio.ctx != nullio_req_cachep);
+	pr_debug("nullio_conn_abort\n");
+}
+
+/* Request hooks */
+static struct fuse_req *nullio_req_alloc(struct fuse_conn *fc, unsigned npages,
+					 gfp_t flags)
+{
+	struct nullio_req *r;
+	struct fuse_req *req;
+
+	req = fuse_generic_request_alloc(fc, nullio_req_cachep, npages, flags);
+	r = nullreq_from_fuse(req);
+	memset(r->payload, 0, payload_sz);
+	return req;
+}
+
+static int nullio_req_send(struct fuse_conn *fc, struct fuse_req *req, bool bg,
+			   bool locked)
+{
+	/* pass though all requests on uninitalized connection */
+	if (!fc->initialized)
+		return 1;
+
+	BUG_ON(fc->kio.ctx != nullio_req_cachep);
+	BUG_ON(req->cache != nullio_req_cachep);
+	switch (req->in.h.opcode) {
+	case FUSE_WRITE: {
+		struct fuse_write_in *in = &req->misc.write.in;
+		struct fuse_write_out *out = &req->misc.write.out;
+
+		if (!fake_write)
+			return 1;
+		/* Fake complete */
+		out->size = in->size;
+		break;
+	}
+	case FUSE_READ: {
+		if (!fake_read)
+			return 1;
+		break;
+	}
+	default:
+		/* fall back to generic fuse io-flow */
+		return 1;
+	}
+	/* Simulate immidiate completion path. */
+	__clear_bit(FR_BACKGROUND, &req->flags);
+	__clear_bit(FR_PENDING, &req->flags);
+	/* request_end below will do fuse_put_request() */
+	if (!bg)
+		atomic_inc(&req->count);
+
+	/* Finally complete */
+	req->out.h.error = 0;
+	request_end(fc, req);
+	return 0;
+}
+
+/* Inode scope hooks */
+static int nullio_file_open(struct fuse_conn *fc, struct file *file,
+			    struct inode *inode)
+{
+	BUG_ON(fc->kio.ctx != nullio_req_cachep);
+
+	if (S_ISREG(inode->i_mode)) {
+		struct fuse_inode *fi = get_fuse_inode(inode);
+
+		fi->private  = nullio_req_cachep;
+	}
+	return 0;
+}
+
+static void nullio_inode_release(struct fuse_inode *fi)
+{
+	if (!fi->private)
+		return;
+
+	BUG_ON(fi->private != nullio_req_cachep);
+}
+
+static struct fuse_kio_ops nullio_ops = {
+	.name		= "nullio",
+	.owner		= THIS_MODULE,
+	.probe		= nullio_probe,
+
+	.conn_init	= nullio_conn_init,
+	.conn_fini	= nullio_conn_fini,
+	.conn_abort	= nullio_conn_abort,
+	.req_alloc	= nullio_req_alloc,
+	.req_send	= nullio_req_send,
+	.file_open	= nullio_file_open,
+	.inode_release	= nullio_inode_release,
+};
+
+static int __init kio_nullio_mod_init(void)
+{
+	int err;
+
+	nullio_req_cachep = kmem_cache_create("nullio_fuse_request",
+					      sizeof(struct fuse_req) +
+					      payload_sz,
+					      0, 0, NULL);
+	if (!nullio_req_cachep)
+		return -ENOMEM;
+
+	err = -EINVAL;
+	if (fuse_register_kio(&nullio_ops))
+		goto free_cache;
+
+	return 0;
+
+free_cache:
+	kmem_cache_destroy(nullio_req_cachep);
+	return err;
+}
+
+static void __exit kio_nullio_mod_exit(void)
+{
+	fuse_unregister_kio(&nullio_ops);
+	kmem_cache_destroy(nullio_req_cachep);
+}
+
+module_init(kio_nullio_mod_init);
+module_exit(kio_nullio_mod_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Virtuozzo <devel at openvz.org>");


More information about the Devel mailing list