summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiklos Szeredi <miklos@szeredi.hu>2006-12-06 20:35:52 -0800
committerLinus Torvalds <torvalds@woody.osdl.org>2006-12-07 08:39:32 -0800
commit0ec7ca41f6f0f74a394a7d686bc0ee8afef84887 (patch)
treebb4aac390be07d04b484fddc325598f05b498db0
parentb2d2272fae1e1df26ec8f93a6d5baea891dcce37 (diff)
[PATCH] fuse: add DESTROY operation
Add a DESTROY operation for block device based filesystems. With the help of this operation, such a filesystem can flush dirty data to the device synchronously before the umount returns. This is needed in situations where the filesystem is assumed to be clean immediately after unmount (e.g. ejecting removable media). Signed-off-by: Miklos Szeredi <miklos@szeredi.hu> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--fs/fuse/fuse_i.h6
-rw-r--r--fs/fuse/inode.c22
-rw-r--r--include/linux/fuse.h1
3 files changed, 29 insertions, 0 deletions
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index 58d482d9f6bb..b98b20de7405 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -298,6 +298,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;
@@ -368,6 +371,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/fs/fuse/inode.c b/fs/fuse/inode.c
index 1baaaeb2e850..437d61c65268 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -206,10 +206,23 @@ static void fuse_umount_begin(struct vfsmount *vfsmnt, int flags)
fuse_abort_conn(get_fuse_conn_super(vfsmnt->mnt_sb));
}
+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;
@@ -410,6 +423,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);
}
@@ -466,6 +481,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;
@@ -563,6 +579,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/include/linux/fuse.h b/include/linux/fuse.h
index 162a754f4db7..534744efe30d 100644
--- a/include/linux/fuse.h
+++ b/include/linux/fuse.h
@@ -133,6 +133,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 */