From b9ea32fc3bb3410c5f436c1f1f90558ff189bf23 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Sun, 8 Oct 2006 17:35:40 +0000 Subject: [PATCH] Add DESTROY message --- ChangeLog | 9 +++++++++ kernel/fuse_i.h | 6 ++++++ kernel/fuse_kernel.h | 1 + kernel/inode.c | 22 ++++++++++++++++++++++ lib/fuse_lowlevel.c | 22 ++++++++++++++++++++-- 5 files changed, 58 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index c034ccf..bdd4c5f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -19,6 +19,15 @@ * Minor clean up of udev rules + * Add a synchronous DESTROY message to kernel interface. This is + invoked from umount, when the final instance of the filesystem is + released. It is only sent for filesystems mounted with the + 'blkdev' option for security reasons. + + * If the DESTROY message is received, call the filesystem's + ->destroy() method. In this case it's not called from session + destruction as it would be otherwise. + 2006-10-01 Miklos Szeredi * Released 2.6.0-rc2 diff --git a/kernel/fuse_i.h b/kernel/fuse_i.h index 0841e44..9be2de1 100644 --- a/kernel/fuse_i.h +++ b/kernel/fuse_i.h @@ -357,6 +357,9 @@ struct fuse_conn { reply, before any other request, and never cleared */ unsigned conn_error : 1; + /** Connection successful. Only set in INIT */ + unsigned conn_init : 1; + /** Do readpages asynchronously? Only set in INIT */ unsigned async_read : 1; @@ -427,6 +430,9 @@ struct fuse_conn { /** Key for lock owner ID scrambling */ u32 scramble_key[4]; + + /** Reserved request for the DESTROY message */ + struct fuse_req *destroy_req; }; static inline struct fuse_conn *get_fuse_conn_super(struct super_block *sb) diff --git a/kernel/fuse_kernel.h b/kernel/fuse_kernel.h index 94154b1..00026a6 100644 --- a/kernel/fuse_kernel.h +++ b/kernel/fuse_kernel.h @@ -168,6 +168,7 @@ enum fuse_opcode { FUSE_CREATE = 35, FUSE_INTERRUPT = 36, FUSE_BMAP = 37, + FUSE_DESTROY = 38, }; /* The read buffer is required to be at least 8k, but may be much larger */ diff --git a/kernel/inode.c b/kernel/inode.c index 7800892..be72f80 100644 --- a/kernel/inode.c +++ b/kernel/inode.c @@ -226,10 +226,23 @@ static void fuse_umount_begin(struct super_block *sb) } #endif +static void fuse_send_destroy(struct fuse_conn *fc) +{ + struct fuse_req *req = fc->destroy_req; + if (req && fc->conn_init) { + fc->destroy_req = NULL; + req->in.h.opcode = FUSE_DESTROY; + req->force = 1; + request_send(fc, req); + fuse_put_request(fc, req); + } +} + static void fuse_put_super(struct super_block *sb) { struct fuse_conn *fc = get_fuse_conn_super(sb); + fuse_send_destroy(fc); spin_lock(&fc->lock); fc->connected = 0; fc->blocked = 0; @@ -447,6 +460,8 @@ static struct fuse_conn *new_conn(void) void fuse_conn_put(struct fuse_conn *fc) { if (atomic_dec_and_test(&fc->count)) { + if (fc->destroy_req) + fuse_request_free(fc->destroy_req); mutex_destroy(&fc->inst_mutex); kfree(fc); } @@ -565,6 +580,7 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req) fc->bdi.ra_pages = min(fc->bdi.ra_pages, ra_pages); fc->minor = arg->minor; fc->max_write = arg->minor < 5 ? 4096 : arg->max_write; + fc->conn_init = 1; } fuse_put_request(fc, req); fc->blocked = 0; @@ -665,6 +681,12 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent) if (!init_req) goto err_put_root; + if (is_bdev) { + fc->destroy_req = fuse_request_alloc(); + if (!fc->destroy_req) + goto err_put_root; + } + mutex_lock(&fuse_mutex); err = -EINVAL; if (file->private_data) diff --git a/lib/fuse_lowlevel.c b/lib/fuse_lowlevel.c index f7de2c7..05d99e1 100644 --- a/lib/fuse_lowlevel.c +++ b/lib/fuse_lowlevel.c @@ -57,6 +57,7 @@ struct fuse_ll { struct fuse_req list; struct fuse_req interrupts; pthread_mutex_t lock; + int got_destroy; }; static void convert_stat(const struct stat *stbuf, struct fuse_attr *attr) @@ -995,6 +996,20 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) send_reply_ok(req, &outarg, arg->minor < 5 ? 8 : sizeof(outarg)); } +static void do_destroy(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) +{ + struct fuse_ll *f = req->f; + + (void) nodeid; + (void) inarg; + + f->got_destroy = 1; + if (f->op.destroy) + f->op.destroy(f->userdata); + + send_reply_ok(req, NULL, 0); +} + void *fuse_req_userdata(fuse_req_t req) { return req->f->userdata; @@ -1066,6 +1081,7 @@ static struct { [FUSE_CREATE] = { do_create, "CREATE" }, [FUSE_INTERRUPT] = { do_interrupt, "INTERRUPT" }, [FUSE_BMAP] = { do_bmap, "BMAP" }, + [FUSE_DESTROY] = { do_destroy, "DESTROY" }, }; #define FUSE_MAXOP (sizeof(fuse_ll_ops) / sizeof(fuse_ll_ops[0])) @@ -1200,8 +1216,10 @@ static void fuse_ll_destroy(void *data) { struct fuse_ll *f = (struct fuse_ll *) data; - if (f->op.destroy) - f->op.destroy(f->userdata); + if (f->got_init && !f->got_destroy) { + if (f->op.destroy) + f->op.destroy(f->userdata); + } pthread_mutex_destroy(&f->lock); free(f); -- 2.30.2