diff options
Diffstat (limited to 'fs/fuse/inode.c')
-rw-r--r-- | fs/fuse/inode.c | 185 |
1 files changed, 101 insertions, 84 deletions
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 2e99f34b4435..459b73dd45e1 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | FUSE: Filesystem in Userspace | 2 | FUSE: Filesystem in Userspace |
3 | Copyright (C) 2001-2006 Miklos Szeredi <miklos@szeredi.hu> | 3 | Copyright (C) 2001-2008 Miklos Szeredi <miklos@szeredi.hu> |
4 | 4 | ||
5 | This program can be distributed under the terms of the GNU GPL. | 5 | This program can be distributed under the terms of the GNU GPL. |
6 | See the file COPYING. | 6 | See the file COPYING. |
@@ -37,10 +37,10 @@ struct fuse_mount_data { | |||
37 | unsigned rootmode; | 37 | unsigned rootmode; |
38 | unsigned user_id; | 38 | unsigned user_id; |
39 | unsigned group_id; | 39 | unsigned group_id; |
40 | unsigned fd_present : 1; | 40 | unsigned fd_present:1; |
41 | unsigned rootmode_present : 1; | 41 | unsigned rootmode_present:1; |
42 | unsigned user_id_present : 1; | 42 | unsigned user_id_present:1; |
43 | unsigned group_id_present : 1; | 43 | unsigned group_id_present:1; |
44 | unsigned flags; | 44 | unsigned flags; |
45 | unsigned max_read; | 45 | unsigned max_read; |
46 | unsigned blksize; | 46 | unsigned blksize; |
@@ -94,7 +94,7 @@ void fuse_send_forget(struct fuse_conn *fc, struct fuse_req *req, | |||
94 | req->in.numargs = 1; | 94 | req->in.numargs = 1; |
95 | req->in.args[0].size = sizeof(struct fuse_forget_in); | 95 | req->in.args[0].size = sizeof(struct fuse_forget_in); |
96 | req->in.args[0].value = inarg; | 96 | req->in.args[0].value = inarg; |
97 | request_send_noreply(fc, req); | 97 | fuse_request_send_noreply(fc, req); |
98 | } | 98 | } |
99 | 99 | ||
100 | static void fuse_clear_inode(struct inode *inode) | 100 | static void fuse_clear_inode(struct inode *inode) |
@@ -250,7 +250,7 @@ struct inode *fuse_iget(struct super_block *sb, u64 nodeid, | |||
250 | 250 | ||
251 | fi = get_fuse_inode(inode); | 251 | fi = get_fuse_inode(inode); |
252 | spin_lock(&fc->lock); | 252 | spin_lock(&fc->lock); |
253 | fi->nlookup ++; | 253 | fi->nlookup++; |
254 | spin_unlock(&fc->lock); | 254 | spin_unlock(&fc->lock); |
255 | fuse_change_attributes(inode, attr, attr_valid, attr_version); | 255 | fuse_change_attributes(inode, attr, attr_valid, attr_version); |
256 | 256 | ||
@@ -269,7 +269,7 @@ static void fuse_send_destroy(struct fuse_conn *fc) | |||
269 | fc->destroy_req = NULL; | 269 | fc->destroy_req = NULL; |
270 | req->in.h.opcode = FUSE_DESTROY; | 270 | req->in.h.opcode = FUSE_DESTROY; |
271 | req->force = 1; | 271 | req->force = 1; |
272 | request_send(fc, req); | 272 | fuse_request_send(fc, req); |
273 | fuse_put_request(fc, req); | 273 | fuse_put_request(fc, req); |
274 | } | 274 | } |
275 | } | 275 | } |
@@ -292,6 +292,7 @@ static void fuse_put_super(struct super_block *sb) | |||
292 | list_del(&fc->entry); | 292 | list_del(&fc->entry); |
293 | fuse_ctl_remove_conn(fc); | 293 | fuse_ctl_remove_conn(fc); |
294 | mutex_unlock(&fuse_mutex); | 294 | mutex_unlock(&fuse_mutex); |
295 | bdi_destroy(&fc->bdi); | ||
295 | fuse_conn_put(fc); | 296 | fuse_conn_put(fc); |
296 | } | 297 | } |
297 | 298 | ||
@@ -334,7 +335,7 @@ static int fuse_statfs(struct dentry *dentry, struct kstatfs *buf) | |||
334 | req->out.args[0].size = | 335 | req->out.args[0].size = |
335 | fc->minor < 4 ? FUSE_COMPAT_STATFS_SIZE : sizeof(outarg); | 336 | fc->minor < 4 ? FUSE_COMPAT_STATFS_SIZE : sizeof(outarg); |
336 | req->out.args[0].value = &outarg; | 337 | req->out.args[0].value = &outarg; |
337 | request_send(fc, req); | 338 | fuse_request_send(fc, req); |
338 | err = req->out.h.error; | 339 | err = req->out.h.error; |
339 | if (!err) | 340 | if (!err) |
340 | convert_fuse_statfs(buf, &outarg.st); | 341 | convert_fuse_statfs(buf, &outarg.st); |
@@ -462,68 +463,69 @@ static int fuse_show_options(struct seq_file *m, struct vfsmount *mnt) | |||
462 | return 0; | 463 | return 0; |
463 | } | 464 | } |
464 | 465 | ||
465 | static struct fuse_conn *new_conn(struct super_block *sb) | 466 | int fuse_conn_init(struct fuse_conn *fc, struct super_block *sb) |
466 | { | 467 | { |
467 | struct fuse_conn *fc; | ||
468 | int err; | 468 | int err; |
469 | 469 | ||
470 | fc = kzalloc(sizeof(*fc), GFP_KERNEL); | 470 | memset(fc, 0, sizeof(*fc)); |
471 | if (fc) { | 471 | spin_lock_init(&fc->lock); |
472 | spin_lock_init(&fc->lock); | 472 | mutex_init(&fc->inst_mutex); |
473 | mutex_init(&fc->inst_mutex); | 473 | atomic_set(&fc->count, 1); |
474 | atomic_set(&fc->count, 1); | 474 | init_waitqueue_head(&fc->waitq); |
475 | init_waitqueue_head(&fc->waitq); | 475 | init_waitqueue_head(&fc->blocked_waitq); |
476 | init_waitqueue_head(&fc->blocked_waitq); | 476 | init_waitqueue_head(&fc->reserved_req_waitq); |
477 | init_waitqueue_head(&fc->reserved_req_waitq); | 477 | INIT_LIST_HEAD(&fc->pending); |
478 | INIT_LIST_HEAD(&fc->pending); | 478 | INIT_LIST_HEAD(&fc->processing); |
479 | INIT_LIST_HEAD(&fc->processing); | 479 | INIT_LIST_HEAD(&fc->io); |
480 | INIT_LIST_HEAD(&fc->io); | 480 | INIT_LIST_HEAD(&fc->interrupts); |
481 | INIT_LIST_HEAD(&fc->interrupts); | 481 | INIT_LIST_HEAD(&fc->bg_queue); |
482 | INIT_LIST_HEAD(&fc->bg_queue); | 482 | INIT_LIST_HEAD(&fc->entry); |
483 | atomic_set(&fc->num_waiting, 0); | 483 | atomic_set(&fc->num_waiting, 0); |
484 | fc->bdi.ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE; | 484 | fc->bdi.ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE; |
485 | fc->bdi.unplug_io_fn = default_unplug_io_fn; | 485 | fc->bdi.unplug_io_fn = default_unplug_io_fn; |
486 | /* fuse does it's own writeback accounting */ | 486 | /* fuse does it's own writeback accounting */ |
487 | fc->bdi.capabilities = BDI_CAP_NO_ACCT_WB; | 487 | fc->bdi.capabilities = BDI_CAP_NO_ACCT_WB; |
488 | fc->dev = sb->s_dev; | 488 | fc->khctr = 0; |
489 | err = bdi_init(&fc->bdi); | 489 | fc->polled_files = RB_ROOT; |
490 | if (err) | 490 | fc->dev = sb->s_dev; |
491 | goto error_kfree; | 491 | err = bdi_init(&fc->bdi); |
492 | if (sb->s_bdev) { | 492 | if (err) |
493 | err = bdi_register(&fc->bdi, NULL, "%u:%u-fuseblk", | 493 | goto error_mutex_destroy; |
494 | MAJOR(fc->dev), MINOR(fc->dev)); | 494 | if (sb->s_bdev) { |
495 | } else { | 495 | err = bdi_register(&fc->bdi, NULL, "%u:%u-fuseblk", |
496 | err = bdi_register_dev(&fc->bdi, fc->dev); | 496 | MAJOR(fc->dev), MINOR(fc->dev)); |
497 | } | 497 | } else { |
498 | if (err) | 498 | err = bdi_register_dev(&fc->bdi, fc->dev); |
499 | goto error_bdi_destroy; | ||
500 | /* | ||
501 | * For a single fuse filesystem use max 1% of dirty + | ||
502 | * writeback threshold. | ||
503 | * | ||
504 | * This gives about 1M of write buffer for memory maps on a | ||
505 | * machine with 1G and 10% dirty_ratio, which should be more | ||
506 | * than enough. | ||
507 | * | ||
508 | * Privileged users can raise it by writing to | ||
509 | * | ||
510 | * /sys/class/bdi/<bdi>/max_ratio | ||
511 | */ | ||
512 | bdi_set_max_ratio(&fc->bdi, 1); | ||
513 | fc->reqctr = 0; | ||
514 | fc->blocked = 1; | ||
515 | fc->attr_version = 1; | ||
516 | get_random_bytes(&fc->scramble_key, sizeof(fc->scramble_key)); | ||
517 | } | 499 | } |
518 | return fc; | 500 | if (err) |
501 | goto error_bdi_destroy; | ||
502 | /* | ||
503 | * For a single fuse filesystem use max 1% of dirty + | ||
504 | * writeback threshold. | ||
505 | * | ||
506 | * This gives about 1M of write buffer for memory maps on a | ||
507 | * machine with 1G and 10% dirty_ratio, which should be more | ||
508 | * than enough. | ||
509 | * | ||
510 | * Privileged users can raise it by writing to | ||
511 | * | ||
512 | * /sys/class/bdi/<bdi>/max_ratio | ||
513 | */ | ||
514 | bdi_set_max_ratio(&fc->bdi, 1); | ||
515 | fc->reqctr = 0; | ||
516 | fc->blocked = 1; | ||
517 | fc->attr_version = 1; | ||
518 | get_random_bytes(&fc->scramble_key, sizeof(fc->scramble_key)); | ||
519 | 519 | ||
520 | error_bdi_destroy: | 520 | return 0; |
521 | |||
522 | error_bdi_destroy: | ||
521 | bdi_destroy(&fc->bdi); | 523 | bdi_destroy(&fc->bdi); |
522 | error_kfree: | 524 | error_mutex_destroy: |
523 | mutex_destroy(&fc->inst_mutex); | 525 | mutex_destroy(&fc->inst_mutex); |
524 | kfree(fc); | 526 | return err; |
525 | return NULL; | ||
526 | } | 527 | } |
528 | EXPORT_SYMBOL_GPL(fuse_conn_init); | ||
527 | 529 | ||
528 | void fuse_conn_put(struct fuse_conn *fc) | 530 | void fuse_conn_put(struct fuse_conn *fc) |
529 | { | 531 | { |
@@ -531,8 +533,7 @@ void fuse_conn_put(struct fuse_conn *fc) | |||
531 | if (fc->destroy_req) | 533 | if (fc->destroy_req) |
532 | fuse_request_free(fc->destroy_req); | 534 | fuse_request_free(fc->destroy_req); |
533 | mutex_destroy(&fc->inst_mutex); | 535 | mutex_destroy(&fc->inst_mutex); |
534 | bdi_destroy(&fc->bdi); | 536 | fc->release(fc); |
535 | kfree(fc); | ||
536 | } | 537 | } |
537 | } | 538 | } |
538 | 539 | ||
@@ -542,7 +543,7 @@ struct fuse_conn *fuse_conn_get(struct fuse_conn *fc) | |||
542 | return fc; | 543 | return fc; |
543 | } | 544 | } |
544 | 545 | ||
545 | static struct inode *get_root_inode(struct super_block *sb, unsigned mode) | 546 | static struct inode *fuse_get_root_inode(struct super_block *sb, unsigned mode) |
546 | { | 547 | { |
547 | struct fuse_attr attr; | 548 | struct fuse_attr attr; |
548 | memset(&attr, 0, sizeof(attr)); | 549 | memset(&attr, 0, sizeof(attr)); |
@@ -553,8 +554,7 @@ static struct inode *get_root_inode(struct super_block *sb, unsigned mode) | |||
553 | return fuse_iget(sb, 1, 0, &attr, 0, 0); | 554 | return fuse_iget(sb, 1, 0, &attr, 0, 0); |
554 | } | 555 | } |
555 | 556 | ||
556 | struct fuse_inode_handle | 557 | struct fuse_inode_handle { |
557 | { | ||
558 | u64 nodeid; | 558 | u64 nodeid; |
559 | u32 generation; | 559 | u32 generation; |
560 | }; | 560 | }; |
@@ -761,7 +761,6 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req) | |||
761 | fc->max_write = max_t(unsigned, 4096, fc->max_write); | 761 | fc->max_write = max_t(unsigned, 4096, fc->max_write); |
762 | fc->conn_init = 1; | 762 | fc->conn_init = 1; |
763 | } | 763 | } |
764 | fuse_put_request(fc, req); | ||
765 | fc->blocked = 0; | 764 | fc->blocked = 0; |
766 | wake_up_all(&fc->blocked_waitq); | 765 | wake_up_all(&fc->blocked_waitq); |
767 | } | 766 | } |
@@ -787,7 +786,12 @@ static void fuse_send_init(struct fuse_conn *fc, struct fuse_req *req) | |||
787 | req->out.args[0].size = sizeof(struct fuse_init_out); | 786 | req->out.args[0].size = sizeof(struct fuse_init_out); |
788 | req->out.args[0].value = &req->misc.init_out; | 787 | req->out.args[0].value = &req->misc.init_out; |
789 | req->end = process_init_reply; | 788 | req->end = process_init_reply; |
790 | request_send_background(fc, req); | 789 | fuse_request_send_background(fc, req); |
790 | } | ||
791 | |||
792 | static void fuse_free_conn(struct fuse_conn *fc) | ||
793 | { | ||
794 | kfree(fc); | ||
791 | } | 795 | } |
792 | 796 | ||
793 | static int fuse_fill_super(struct super_block *sb, void *data, int silent) | 797 | static int fuse_fill_super(struct super_block *sb, void *data, int silent) |
@@ -801,16 +805,18 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent) | |||
801 | int err; | 805 | int err; |
802 | int is_bdev = sb->s_bdev != NULL; | 806 | int is_bdev = sb->s_bdev != NULL; |
803 | 807 | ||
808 | err = -EINVAL; | ||
804 | if (sb->s_flags & MS_MANDLOCK) | 809 | if (sb->s_flags & MS_MANDLOCK) |
805 | return -EINVAL; | 810 | goto err; |
806 | 811 | ||
807 | if (!parse_fuse_opt((char *) data, &d, is_bdev)) | 812 | if (!parse_fuse_opt((char *) data, &d, is_bdev)) |
808 | return -EINVAL; | 813 | goto err; |
809 | 814 | ||
810 | if (is_bdev) { | 815 | if (is_bdev) { |
811 | #ifdef CONFIG_BLOCK | 816 | #ifdef CONFIG_BLOCK |
817 | err = -EINVAL; | ||
812 | if (!sb_set_blocksize(sb, d.blksize)) | 818 | if (!sb_set_blocksize(sb, d.blksize)) |
813 | return -EINVAL; | 819 | goto err; |
814 | #endif | 820 | #endif |
815 | } else { | 821 | } else { |
816 | sb->s_blocksize = PAGE_CACHE_SIZE; | 822 | sb->s_blocksize = PAGE_CACHE_SIZE; |
@@ -822,16 +828,25 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent) | |||
822 | sb->s_export_op = &fuse_export_operations; | 828 | sb->s_export_op = &fuse_export_operations; |
823 | 829 | ||
824 | file = fget(d.fd); | 830 | file = fget(d.fd); |
831 | err = -EINVAL; | ||
825 | if (!file) | 832 | if (!file) |
826 | return -EINVAL; | 833 | goto err; |
827 | 834 | ||
828 | if (file->f_op != &fuse_dev_operations) | 835 | if (file->f_op != &fuse_dev_operations) |
829 | return -EINVAL; | 836 | goto err_fput; |
830 | 837 | ||
831 | fc = new_conn(sb); | 838 | fc = kmalloc(sizeof(*fc), GFP_KERNEL); |
839 | err = -ENOMEM; | ||
832 | if (!fc) | 840 | if (!fc) |
833 | return -ENOMEM; | 841 | goto err_fput; |
834 | 842 | ||
843 | err = fuse_conn_init(fc, sb); | ||
844 | if (err) { | ||
845 | kfree(fc); | ||
846 | goto err_fput; | ||
847 | } | ||
848 | |||
849 | fc->release = fuse_free_conn; | ||
835 | fc->flags = d.flags; | 850 | fc->flags = d.flags; |
836 | fc->user_id = d.user_id; | 851 | fc->user_id = d.user_id; |
837 | fc->group_id = d.group_id; | 852 | fc->group_id = d.group_id; |
@@ -841,14 +856,14 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent) | |||
841 | sb->s_fs_info = fc; | 856 | sb->s_fs_info = fc; |
842 | 857 | ||
843 | err = -ENOMEM; | 858 | err = -ENOMEM; |
844 | root = get_root_inode(sb, d.rootmode); | 859 | root = fuse_get_root_inode(sb, d.rootmode); |
845 | if (!root) | 860 | if (!root) |
846 | goto err; | 861 | goto err_put_conn; |
847 | 862 | ||
848 | root_dentry = d_alloc_root(root); | 863 | root_dentry = d_alloc_root(root); |
849 | if (!root_dentry) { | 864 | if (!root_dentry) { |
850 | iput(root); | 865 | iput(root); |
851 | goto err; | 866 | goto err_put_conn; |
852 | } | 867 | } |
853 | 868 | ||
854 | init_req = fuse_request_alloc(); | 869 | init_req = fuse_request_alloc(); |
@@ -892,9 +907,11 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent) | |||
892 | fuse_request_free(init_req); | 907 | fuse_request_free(init_req); |
893 | err_put_root: | 908 | err_put_root: |
894 | dput(root_dentry); | 909 | dput(root_dentry); |
895 | err: | 910 | err_put_conn: |
896 | fput(file); | ||
897 | fuse_conn_put(fc); | 911 | fuse_conn_put(fc); |
912 | err_fput: | ||
913 | fput(file); | ||
914 | err: | ||
898 | return err; | 915 | return err; |
899 | } | 916 | } |
900 | 917 | ||
@@ -952,7 +969,7 @@ static inline void unregister_fuseblk(void) | |||
952 | 969 | ||
953 | static void fuse_inode_init_once(void *foo) | 970 | static void fuse_inode_init_once(void *foo) |
954 | { | 971 | { |
955 | struct inode * inode = foo; | 972 | struct inode *inode = foo; |
956 | 973 | ||
957 | inode_init_once(inode); | 974 | inode_init_once(inode); |
958 | } | 975 | } |
@@ -1031,7 +1048,7 @@ static int __init fuse_init(void) | |||
1031 | { | 1048 | { |
1032 | int res; | 1049 | int res; |
1033 | 1050 | ||
1034 | printk("fuse init (API version %i.%i)\n", | 1051 | printk(KERN_INFO "fuse init (API version %i.%i)\n", |
1035 | FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION); | 1052 | FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION); |
1036 | 1053 | ||
1037 | INIT_LIST_HEAD(&fuse_conn_list); | 1054 | INIT_LIST_HEAD(&fuse_conn_list); |