diff options
-rw-r--r-- | fs/fuse/fuse_i.h | 6 | ||||
-rw-r--r-- | fs/fuse/inode.c | 22 | ||||
-rw-r--r-- | include/linux/fuse.h | 1 |
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 { | |||
298 | reply, before any other request, and never cleared */ | 298 | reply, before any other request, and never cleared */ |
299 | unsigned conn_error : 1; | 299 | unsigned conn_error : 1; |
300 | 300 | ||
301 | /** Connection successful. Only set in INIT */ | ||
302 | unsigned conn_init : 1; | ||
303 | |||
301 | /** Do readpages asynchronously? Only set in INIT */ | 304 | /** Do readpages asynchronously? Only set in INIT */ |
302 | unsigned async_read : 1; | 305 | unsigned async_read : 1; |
303 | 306 | ||
@@ -368,6 +371,9 @@ struct fuse_conn { | |||
368 | 371 | ||
369 | /** Key for lock owner ID scrambling */ | 372 | /** Key for lock owner ID scrambling */ |
370 | u32 scramble_key[4]; | 373 | u32 scramble_key[4]; |
374 | |||
375 | /** Reserved request for the DESTROY message */ | ||
376 | struct fuse_req *destroy_req; | ||
371 | }; | 377 | }; |
372 | 378 | ||
373 | static inline struct fuse_conn *get_fuse_conn_super(struct super_block *sb) | 379 | 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) | |||
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) |
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 { | |||
133 | FUSE_CREATE = 35, | 133 | FUSE_CREATE = 35, |
134 | FUSE_INTERRUPT = 36, | 134 | FUSE_INTERRUPT = 36, |
135 | FUSE_BMAP = 37, | 135 | FUSE_BMAP = 37, |
136 | FUSE_DESTROY = 38, | ||
136 | }; | 137 | }; |
137 | 138 | ||
138 | /* The read buffer is required to be at least 8k, but may be much larger */ | 139 | /* The read buffer is required to be at least 8k, but may be much larger */ |