From d915a6b4a84ae6e82f3756df9ca695395e5aacfe Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Thu, 19 May 2011 15:26:37 +0200 Subject: [PATCH] Allow batching of forget requests This allows forget requests to be processed faster and doesn't require a modification to fuse filesystems. Reported by Terje Malmedal --- ChangeLog | 6 +++++ include/fuse_kernel.h | 16 +++++++++++- lib/fuse_loop_mt.c | 10 ++++--- lib/fuse_lowlevel.c | 61 ++++++++++++++++++++++++++++++++++++------- 4 files changed, 80 insertions(+), 13 deletions(-) diff --git a/ChangeLog b/ChangeLog index f836222..ef22dd1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -46,6 +46,12 @@ * Highlevel lib: use dynamically resized hash table for looking up by name and node ID. +2010-12-07 Miklos Szeredi + + * Allow batching of forget requests. This allows forget requests + to be processed faster and doesn't require a modification to fuse + filesystems. Reported by Terje Malmedal + 2010-11-10 Miklos Szeredi * Add new write_buf() method to the highlevel API. Similarly to diff --git a/include/fuse_kernel.h b/include/fuse_kernel.h index c7c99a5..7e7ca17 100644 --- a/include/fuse_kernel.h +++ b/include/fuse_kernel.h @@ -67,6 +67,9 @@ * 7.15 * - add store notify * - add retrieve notify + * + * 7.16 + * - add BATCH_FORGET request */ #ifndef _LINUX_FUSE_H @@ -103,7 +106,7 @@ #define FUSE_KERNEL_VERSION 7 /** Minor version number of this interface */ -#define FUSE_KERNEL_MINOR_VERSION 15 +#define FUSE_KERNEL_MINOR_VERSION 16 /** The node ID of the root inode */ #define FUSE_ROOT_ID 1 @@ -287,6 +290,7 @@ enum fuse_opcode { FUSE_IOCTL = 39, FUSE_POLL = 40, FUSE_NOTIFY_REPLY = 41, + FUSE_BATCH_FORGET = 42, /* CUSE specific operations */ CUSE_INIT = 4096, @@ -321,6 +325,16 @@ struct fuse_forget_in { __u64 nlookup; }; +struct fuse_forget_one { + __u64 nodeid; + __u64 nlookup; +}; + +struct fuse_batch_forget_in { + __u32 count; + __u32 dummy; +}; + struct fuse_getattr_in { __u32 getattr_flags; __u32 dummy; diff --git a/lib/fuse_loop_mt.c b/lib/fuse_loop_mt.c index 694f98c..ab5fd11 100644 --- a/lib/fuse_loop_mt.c +++ b/lib/fuse_loop_mt.c @@ -99,9 +99,13 @@ static void *fuse_do_work(void *data) * This disgusting hack is needed so that zillions of threads * are not created on a burst of FORGET messages */ - if (!(fbuf.flags & FUSE_BUF_IS_FD) && - ((struct fuse_in_header *) fbuf.mem)->opcode == FUSE_FORGET) - isforget = 1; + if (!(fbuf.flags & FUSE_BUF_IS_FD)) { + struct fuse_in_header *in = fbuf.mem; + + if (in->opcode == FUSE_FORGET || + in->opcode == FUSE_BATCH_FORGET) + isforget = 1; + } if (!isforget) mt->numavail--; diff --git a/lib/fuse_lowlevel.c b/lib/fuse_lowlevel.c index 55bce2b..4643a8a 100644 --- a/lib/fuse_lowlevel.c +++ b/lib/fuse_lowlevel.c @@ -137,6 +137,24 @@ void fuse_free_req(fuse_req_t req) destroy_req(req); } +static struct fuse_req *fuse_ll_alloc_req(struct fuse_ll *f) +{ + struct fuse_req *req; + + req = (struct fuse_req *) calloc(1, sizeof(struct fuse_req)); + if (req == NULL) { + fprintf(stderr, "fuse: failed to allocate request\n"); + } else { + req->f = f; + req->ctr = 1; + list_init_req(req); + fuse_mutex_init(&req->lock); + } + + return req; +} + + static int fuse_send_msg(struct fuse_ll *f, struct fuse_chan *ch, struct iovec *iov, int count) { @@ -284,7 +302,8 @@ int fuse_reply_err(fuse_req_t req, int err) void fuse_reply_none(fuse_req_t req) { - fuse_chan_send(req->ch, NULL, 0); + if (req->ch) + fuse_chan_send(req->ch, NULL, 0); fuse_free_req(req); } @@ -878,6 +897,35 @@ static void do_forget(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) fuse_reply_none(req); } +static void do_batch_forget(fuse_req_t req, fuse_ino_t nodeid, + const void *inarg) +{ + struct fuse_batch_forget_in *arg = (void *) inarg; + struct fuse_forget_one *param = (void *) PARAM(arg); + unsigned int i; + + (void) nodeid; + + if (req->f->op.forget) { + for (i = 0; i < arg->count; i++) { + struct fuse_forget_one *forget = ¶m[i]; + struct fuse_req *dummy_req; + + dummy_req = fuse_ll_alloc_req(req->f); + if (dummy_req == NULL) + break; + + dummy_req->unique = req->unique; + dummy_req->ctx = req->ctx; + dummy_req->ch = NULL; + + req->f->op.forget(dummy_req, forget->nodeid, + forget->nlookup); + } + } + fuse_reply_none(req); +} + static void do_getattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { struct fuse_file_info *fip = NULL; @@ -2035,6 +2083,7 @@ static struct { [FUSE_POLL] = { do_poll, "POLL" }, [FUSE_DESTROY] = { do_destroy, "DESTROY" }, [FUSE_NOTIFY_REPLY] = { (void *) 1, "NOTIFY_REPLY" }, + [FUSE_BATCH_FORGET] = { do_batch_forget, "BATCH_FORGET" }, [CUSE_INIT] = { cuse_lowlevel_init, "CUSE_INIT" }, }; @@ -2098,21 +2147,15 @@ static void fuse_ll_process_buf(void *data, const struct fuse_buf *buf, in = buf->mem; } - req = (struct fuse_req *) calloc(1, sizeof(struct fuse_req)); - if (req == NULL) { - fprintf(stderr, "fuse: failed to allocate request\n"); + req = fuse_ll_alloc_req(f); + if (req == NULL) goto clear_pipe; - } - req->f = f; req->unique = in->unique; req->ctx.uid = in->uid; req->ctx.gid = in->gid; req->ctx.pid = in->pid; req->ch = ch; - req->ctr = 1; - list_init_req(req); - fuse_mutex_init(&req->lock); if (f->debug) fprintf(stderr, -- 2.30.2