summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiklos Szeredi <mszeredi@suse.cz>2011-05-19 15:26:37 +0200
committerMiklos Szeredi <mszeredi@suse.cz>2011-05-19 15:26:37 +0200
commitd915a6b4a84ae6e82f3756df9ca695395e5aacfe (patch)
tree9755b85c71fc7392b6253ba4715fc6fe3a08390b
parent9c526a7a54b90608463380deffe94e1c9d17db15 (diff)
downloadfuse-d915a6b4a84ae6e82f3756df9ca695395e5aacfe.tar.gz
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
-rw-r--r--ChangeLog6
-rw-r--r--include/fuse_kernel.h16
-rw-r--r--lib/fuse_loop_mt.c10
-rw-r--r--lib/fuse_lowlevel.c61
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 <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
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 = &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,