Add DESTROY message
authorMiklos Szeredi <miklos@szeredi.hu>
Sun, 8 Oct 2006 17:35:40 +0000 (17:35 +0000)
committerMiklos Szeredi <miklos@szeredi.hu>
Sun, 8 Oct 2006 17:35:40 +0000 (17:35 +0000)
ChangeLog
kernel/fuse_i.h
kernel/fuse_kernel.h
kernel/inode.c
lib/fuse_lowlevel.c

index c034ccf4461d90089c9cb6636da802c6d4a58425..bdd4c5fd5a3caa676d4e927bee2c27698f63a721 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
 
        * 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
index 0841e449b20ea6c819aa26bff1c2c97ddab484cf..9be2de164e6d4074008507bcd060275f3dbf8a52 100644 (file)
@@ -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)
index 94154b12ac006b35043de25c0db316c9d1b807e9..00026a61072c27d719c7bca1276c54a5afe68bf1 100644 (file)
@@ -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 */
index 7800892061bd8d333a73a6fdc3b271ace8ea0aa8..be72f809a4ef19df9cbb08aea2ac54826c87f850 100644 (file)
@@ -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)
index f7de2c7ad380e26ce7e2d8f8dbb79dd8e262b3af..05d99e13728132a942f28e80749595addd4ee487 100644 (file)
@@ -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);