aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Miklos Szeredi <miklos@szeredi.hu>2006-10-08 17:35:40 +0000
committerGravatar Miklos Szeredi <miklos@szeredi.hu>2006-10-08 17:35:40 +0000
commitb9ea32fc3bb3410c5f436c1f1f90558ff189bf23 (patch)
tree667f201f103569f79dcefcddc4ec699dc6418f04
parent7e7fa1fb9429adf2061670c97ce30a39685daadd (diff)
Add DESTROY message
-rw-r--r--ChangeLog9
-rw-r--r--kernel/fuse_i.h6
-rw-r--r--kernel/fuse_kernel.h1
-rw-r--r--kernel/inode.c22
-rw-r--r--lib/fuse_lowlevel.c22
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 <miklos@szeredi.hu>
* 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);