Allow batching of forget requests
authorMiklos Szeredi <mszeredi@suse.cz>
Thu, 19 May 2011 13:26:37 +0000 (15:26 +0200)
committerMiklos Szeredi <mszeredi@suse.cz>
Thu, 19 May 2011 13:26:37 +0000 (15:26 +0200)
This allows forget requests to be processed faster and doesn't require
a modification to fuse filesystems.  Reported by Terje Malmedal

ChangeLog
include/fuse_kernel.h
lib/fuse_loop_mt.c
lib/fuse_lowlevel.c

index f836222e96df2a784dfd24b9eb2ec2445d99813f..ef22dd134b9e76a5e71cfa4295d5c280e2b77d41 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
        * Highlevel lib: use dynamically resized hash table for looking up
        by name and node ID.
 
+2010-12-07  Miklos Szeredi <miklos@szeredi.hu>
+
+       * 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 <miklos@szeredi.hu>
 
        * Add new write_buf() method to the highlevel API.  Similarly to
index c7c99a5e0838611148ac88d4e714bfd9e89e1748..7e7ca1745eeb0561909f4351162558a73bb5f85c 100644 (file)
@@ -67,6 +67,9 @@
  * 7.15
  *  - add store notify
  *  - add retrieve notify
+ *
+ * 7.16
+ *  - add BATCH_FORGET request
  */
 
 #ifndef _LINUX_FUSE_H
 #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;
index 694f98cd56033a018f574bde7d452289edf92467..ab5fd11369626ca8cb2eb8444568026098f63cee 100644 (file)
@@ -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--;
index 55bce2bd603e7adf91cf620ca810242f914b580a..4643a8a408d42188b089a78a079883b54f004664 100644 (file)
@@ -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 = &param[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,