diff options
author | Miklos Szeredi <miklos@szeredi.hu> | 2006-12-06 23:35:52 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.osdl.org> | 2006-12-07 11:39:32 -0500 |
commit | 0ec7ca41f6f0f74a394a7d686bc0ee8afef84887 (patch) | |
tree | bb4aac390be07d04b484fddc325598f05b498db0 /fs/fuse/inode.c | |
parent | b2d2272fae1e1df26ec8f93a6d5baea891dcce37 (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>
Diffstat (limited to 'fs/fuse/inode.c')
-rw-r--r-- | fs/fuse/inode.c | 22 |
1 files changed, 22 insertions, 0 deletions
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) | |||
206 | fuse_abort_conn(get_fuse_conn_super(vfsmnt->mnt_sb)); | 206 | fuse_abort_conn(get_fuse_conn_super(vfsmnt->mnt_sb)); |
207 | } | 207 | } |
208 | 208 | ||
209 | static void fuse_send_destroy(struct fuse_conn *fc) | ||
210 | { | ||
211 | struct fuse_req *req = fc->destroy_req; | ||
212 | if (req && fc->conn_init) { | ||
213 | fc->destroy_req = NULL; | ||
214 | req->in.h.opcode = FUSE_DESTROY; | ||
215 | req->force = 1; | ||
216 | request_send(fc, req); | ||
217 | fuse_put_request(fc, req); | ||
218 | } | ||
219 | } | ||
220 | |||
209 | static void fuse_put_super(struct super_block *sb) | 221 | static void fuse_put_super(struct super_block *sb) |
210 | { | 222 | { |
211 | struct fuse_conn *fc = get_fuse_conn_super(sb); | 223 | struct fuse_conn *fc = get_fuse_conn_super(sb); |
212 | 224 | ||
225 | fuse_send_destroy(fc); | ||
213 | spin_lock(&fc->lock); | 226 | spin_lock(&fc->lock); |
214 | fc->connected = 0; | 227 | fc->connected = 0; |
215 | fc->blocked = 0; | 228 | fc->blocked = 0; |
@@ -410,6 +423,8 @@ static struct fuse_conn *new_conn(void) | |||
410 | void fuse_conn_put(struct fuse_conn *fc) | 423 | void fuse_conn_put(struct fuse_conn *fc) |
411 | { | 424 | { |
412 | if (atomic_dec_and_test(&fc->count)) { | 425 | if (atomic_dec_and_test(&fc->count)) { |
426 | if (fc->destroy_req) | ||
427 | fuse_request_free(fc->destroy_req); | ||
413 | mutex_destroy(&fc->inst_mutex); | 428 | mutex_destroy(&fc->inst_mutex); |
414 | kfree(fc); | 429 | kfree(fc); |
415 | } | 430 | } |
@@ -466,6 +481,7 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req) | |||
466 | fc->bdi.ra_pages = min(fc->bdi.ra_pages, ra_pages); | 481 | fc->bdi.ra_pages = min(fc->bdi.ra_pages, ra_pages); |
467 | fc->minor = arg->minor; | 482 | fc->minor = arg->minor; |
468 | fc->max_write = arg->minor < 5 ? 4096 : arg->max_write; | 483 | fc->max_write = arg->minor < 5 ? 4096 : arg->max_write; |
484 | fc->conn_init = 1; | ||
469 | } | 485 | } |
470 | fuse_put_request(fc, req); | 486 | fuse_put_request(fc, req); |
471 | fc->blocked = 0; | 487 | fc->blocked = 0; |
@@ -563,6 +579,12 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent) | |||
563 | if (!init_req) | 579 | if (!init_req) |
564 | goto err_put_root; | 580 | goto err_put_root; |
565 | 581 | ||
582 | if (is_bdev) { | ||
583 | fc->destroy_req = fuse_request_alloc(); | ||
584 | if (!fc->destroy_req) | ||
585 | goto err_put_root; | ||
586 | } | ||
587 | |||
566 | mutex_lock(&fuse_mutex); | 588 | mutex_lock(&fuse_mutex); |
567 | err = -EINVAL; | 589 | err = -EINVAL; |
568 | if (file->private_data) | 590 | if (file->private_data) |