diff options
Diffstat (limited to 'fs/fuse/inode.c')
-rw-r--r-- | fs/fuse/inode.c | 90 |
1 files changed, 60 insertions, 30 deletions
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 4df34da2284a..79b615873838 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c | |||
@@ -59,7 +59,11 @@ static struct inode *fuse_alloc_inode(struct super_block *sb) | |||
59 | fi->nodeid = 0; | 59 | fi->nodeid = 0; |
60 | fi->nlookup = 0; | 60 | fi->nlookup = 0; |
61 | fi->attr_version = 0; | 61 | fi->attr_version = 0; |
62 | fi->writectr = 0; | ||
62 | INIT_LIST_HEAD(&fi->write_files); | 63 | INIT_LIST_HEAD(&fi->write_files); |
64 | INIT_LIST_HEAD(&fi->queued_writes); | ||
65 | INIT_LIST_HEAD(&fi->writepages); | ||
66 | init_waitqueue_head(&fi->page_waitq); | ||
63 | fi->forget_req = fuse_request_alloc(); | 67 | fi->forget_req = fuse_request_alloc(); |
64 | if (!fi->forget_req) { | 68 | if (!fi->forget_req) { |
65 | kmem_cache_free(fuse_inode_cachep, inode); | 69 | kmem_cache_free(fuse_inode_cachep, inode); |
@@ -73,13 +77,14 @@ static void fuse_destroy_inode(struct inode *inode) | |||
73 | { | 77 | { |
74 | struct fuse_inode *fi = get_fuse_inode(inode); | 78 | struct fuse_inode *fi = get_fuse_inode(inode); |
75 | BUG_ON(!list_empty(&fi->write_files)); | 79 | BUG_ON(!list_empty(&fi->write_files)); |
80 | BUG_ON(!list_empty(&fi->queued_writes)); | ||
76 | if (fi->forget_req) | 81 | if (fi->forget_req) |
77 | fuse_request_free(fi->forget_req); | 82 | fuse_request_free(fi->forget_req); |
78 | kmem_cache_free(fuse_inode_cachep, inode); | 83 | kmem_cache_free(fuse_inode_cachep, inode); |
79 | } | 84 | } |
80 | 85 | ||
81 | void fuse_send_forget(struct fuse_conn *fc, struct fuse_req *req, | 86 | void fuse_send_forget(struct fuse_conn *fc, struct fuse_req *req, |
82 | unsigned long nodeid, u64 nlookup) | 87 | u64 nodeid, u64 nlookup) |
83 | { | 88 | { |
84 | struct fuse_forget_in *inarg = &req->misc.forget_in; | 89 | struct fuse_forget_in *inarg = &req->misc.forget_in; |
85 | inarg->nlookup = nlookup; | 90 | inarg->nlookup = nlookup; |
@@ -109,7 +114,7 @@ static int fuse_remount_fs(struct super_block *sb, int *flags, char *data) | |||
109 | return 0; | 114 | return 0; |
110 | } | 115 | } |
111 | 116 | ||
112 | static void fuse_truncate(struct address_space *mapping, loff_t offset) | 117 | void fuse_truncate(struct address_space *mapping, loff_t offset) |
113 | { | 118 | { |
114 | /* See vmtruncate() */ | 119 | /* See vmtruncate() */ |
115 | unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1); | 120 | unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1); |
@@ -117,19 +122,12 @@ static void fuse_truncate(struct address_space *mapping, loff_t offset) | |||
117 | unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1); | 122 | unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1); |
118 | } | 123 | } |
119 | 124 | ||
120 | 125 | void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr, | |
121 | void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr, | 126 | u64 attr_valid) |
122 | u64 attr_valid, u64 attr_version) | ||
123 | { | 127 | { |
124 | struct fuse_conn *fc = get_fuse_conn(inode); | 128 | struct fuse_conn *fc = get_fuse_conn(inode); |
125 | struct fuse_inode *fi = get_fuse_inode(inode); | 129 | struct fuse_inode *fi = get_fuse_inode(inode); |
126 | loff_t oldsize; | ||
127 | 130 | ||
128 | spin_lock(&fc->lock); | ||
129 | if (attr_version != 0 && fi->attr_version > attr_version) { | ||
130 | spin_unlock(&fc->lock); | ||
131 | return; | ||
132 | } | ||
133 | fi->attr_version = ++fc->attr_version; | 131 | fi->attr_version = ++fc->attr_version; |
134 | fi->i_time = attr_valid; | 132 | fi->i_time = attr_valid; |
135 | 133 | ||
@@ -159,6 +157,22 @@ void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr, | |||
159 | fi->orig_i_mode = inode->i_mode; | 157 | fi->orig_i_mode = inode->i_mode; |
160 | if (!(fc->flags & FUSE_DEFAULT_PERMISSIONS)) | 158 | if (!(fc->flags & FUSE_DEFAULT_PERMISSIONS)) |
161 | inode->i_mode &= ~S_ISVTX; | 159 | inode->i_mode &= ~S_ISVTX; |
160 | } | ||
161 | |||
162 | void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr, | ||
163 | u64 attr_valid, u64 attr_version) | ||
164 | { | ||
165 | struct fuse_conn *fc = get_fuse_conn(inode); | ||
166 | struct fuse_inode *fi = get_fuse_inode(inode); | ||
167 | loff_t oldsize; | ||
168 | |||
169 | spin_lock(&fc->lock); | ||
170 | if (attr_version != 0 && fi->attr_version > attr_version) { | ||
171 | spin_unlock(&fc->lock); | ||
172 | return; | ||
173 | } | ||
174 | |||
175 | fuse_change_attributes_common(inode, attr, attr_valid); | ||
162 | 176 | ||
163 | oldsize = inode->i_size; | 177 | oldsize = inode->i_size; |
164 | i_size_write(inode, attr->size); | 178 | i_size_write(inode, attr->size); |
@@ -193,7 +207,7 @@ static void fuse_init_inode(struct inode *inode, struct fuse_attr *attr) | |||
193 | 207 | ||
194 | static int fuse_inode_eq(struct inode *inode, void *_nodeidp) | 208 | static int fuse_inode_eq(struct inode *inode, void *_nodeidp) |
195 | { | 209 | { |
196 | unsigned long nodeid = *(unsigned long *) _nodeidp; | 210 | u64 nodeid = *(u64 *) _nodeidp; |
197 | if (get_node_id(inode) == nodeid) | 211 | if (get_node_id(inode) == nodeid) |
198 | return 1; | 212 | return 1; |
199 | else | 213 | else |
@@ -202,12 +216,12 @@ static int fuse_inode_eq(struct inode *inode, void *_nodeidp) | |||
202 | 216 | ||
203 | static int fuse_inode_set(struct inode *inode, void *_nodeidp) | 217 | static int fuse_inode_set(struct inode *inode, void *_nodeidp) |
204 | { | 218 | { |
205 | unsigned long nodeid = *(unsigned long *) _nodeidp; | 219 | u64 nodeid = *(u64 *) _nodeidp; |
206 | get_fuse_inode(inode)->nodeid = nodeid; | 220 | get_fuse_inode(inode)->nodeid = nodeid; |
207 | return 0; | 221 | return 0; |
208 | } | 222 | } |
209 | 223 | ||
210 | struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid, | 224 | struct inode *fuse_iget(struct super_block *sb, u64 nodeid, |
211 | int generation, struct fuse_attr *attr, | 225 | int generation, struct fuse_attr *attr, |
212 | u64 attr_valid, u64 attr_version) | 226 | u64 attr_valid, u64 attr_version) |
213 | { | 227 | { |
@@ -447,7 +461,7 @@ static int fuse_show_options(struct seq_file *m, struct vfsmount *mnt) | |||
447 | return 0; | 461 | return 0; |
448 | } | 462 | } |
449 | 463 | ||
450 | static struct fuse_conn *new_conn(void) | 464 | static struct fuse_conn *new_conn(struct super_block *sb) |
451 | { | 465 | { |
452 | struct fuse_conn *fc; | 466 | struct fuse_conn *fc; |
453 | int err; | 467 | int err; |
@@ -468,19 +482,41 @@ static struct fuse_conn *new_conn(void) | |||
468 | atomic_set(&fc->num_waiting, 0); | 482 | atomic_set(&fc->num_waiting, 0); |
469 | fc->bdi.ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE; | 483 | fc->bdi.ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE; |
470 | fc->bdi.unplug_io_fn = default_unplug_io_fn; | 484 | fc->bdi.unplug_io_fn = default_unplug_io_fn; |
485 | /* fuse does it's own writeback accounting */ | ||
486 | fc->bdi.capabilities = BDI_CAP_NO_ACCT_WB; | ||
487 | fc->dev = sb->s_dev; | ||
471 | err = bdi_init(&fc->bdi); | 488 | err = bdi_init(&fc->bdi); |
472 | if (err) { | 489 | if (err) |
473 | kfree(fc); | 490 | goto error_kfree; |
474 | fc = NULL; | 491 | err = bdi_register_dev(&fc->bdi, fc->dev); |
475 | goto out; | 492 | if (err) |
476 | } | 493 | goto error_bdi_destroy; |
494 | /* | ||
495 | * For a single fuse filesystem use max 1% of dirty + | ||
496 | * writeback threshold. | ||
497 | * | ||
498 | * This gives about 1M of write buffer for memory maps on a | ||
499 | * machine with 1G and 10% dirty_ratio, which should be more | ||
500 | * than enough. | ||
501 | * | ||
502 | * Privileged users can raise it by writing to | ||
503 | * | ||
504 | * /sys/class/bdi/<bdi>/max_ratio | ||
505 | */ | ||
506 | bdi_set_max_ratio(&fc->bdi, 1); | ||
477 | fc->reqctr = 0; | 507 | fc->reqctr = 0; |
478 | fc->blocked = 1; | 508 | fc->blocked = 1; |
479 | fc->attr_version = 1; | 509 | fc->attr_version = 1; |
480 | get_random_bytes(&fc->scramble_key, sizeof(fc->scramble_key)); | 510 | get_random_bytes(&fc->scramble_key, sizeof(fc->scramble_key)); |
481 | } | 511 | } |
482 | out: | ||
483 | return fc; | 512 | return fc; |
513 | |||
514 | error_bdi_destroy: | ||
515 | bdi_destroy(&fc->bdi); | ||
516 | error_kfree: | ||
517 | mutex_destroy(&fc->inst_mutex); | ||
518 | kfree(fc); | ||
519 | return NULL; | ||
484 | } | 520 | } |
485 | 521 | ||
486 | void fuse_conn_put(struct fuse_conn *fc) | 522 | void fuse_conn_put(struct fuse_conn *fc) |
@@ -548,6 +584,7 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req) | |||
548 | fc->bdi.ra_pages = min(fc->bdi.ra_pages, ra_pages); | 584 | fc->bdi.ra_pages = min(fc->bdi.ra_pages, ra_pages); |
549 | fc->minor = arg->minor; | 585 | fc->minor = arg->minor; |
550 | fc->max_write = arg->minor < 5 ? 4096 : arg->max_write; | 586 | fc->max_write = arg->minor < 5 ? 4096 : arg->max_write; |
587 | fc->max_write = min_t(unsigned, 4096, fc->max_write); | ||
551 | fc->conn_init = 1; | 588 | fc->conn_init = 1; |
552 | } | 589 | } |
553 | fuse_put_request(fc, req); | 590 | fuse_put_request(fc, req); |
@@ -578,12 +615,6 @@ static void fuse_send_init(struct fuse_conn *fc, struct fuse_req *req) | |||
578 | request_send_background(fc, req); | 615 | request_send_background(fc, req); |
579 | } | 616 | } |
580 | 617 | ||
581 | static u64 conn_id(void) | ||
582 | { | ||
583 | static u64 ctr = 1; | ||
584 | return ctr++; | ||
585 | } | ||
586 | |||
587 | static int fuse_fill_super(struct super_block *sb, void *data, int silent) | 618 | static int fuse_fill_super(struct super_block *sb, void *data, int silent) |
588 | { | 619 | { |
589 | struct fuse_conn *fc; | 620 | struct fuse_conn *fc; |
@@ -621,14 +652,14 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent) | |||
621 | if (file->f_op != &fuse_dev_operations) | 652 | if (file->f_op != &fuse_dev_operations) |
622 | return -EINVAL; | 653 | return -EINVAL; |
623 | 654 | ||
624 | fc = new_conn(); | 655 | fc = new_conn(sb); |
625 | if (!fc) | 656 | if (!fc) |
626 | return -ENOMEM; | 657 | return -ENOMEM; |
627 | 658 | ||
628 | fc->flags = d.flags; | 659 | fc->flags = d.flags; |
629 | fc->user_id = d.user_id; | 660 | fc->user_id = d.user_id; |
630 | fc->group_id = d.group_id; | 661 | fc->group_id = d.group_id; |
631 | fc->max_read = d.max_read; | 662 | fc->max_read = min_t(unsigned, 4096, d.max_read); |
632 | 663 | ||
633 | /* Used by get_root_inode() */ | 664 | /* Used by get_root_inode() */ |
634 | sb->s_fs_info = fc; | 665 | sb->s_fs_info = fc; |
@@ -659,7 +690,6 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent) | |||
659 | if (file->private_data) | 690 | if (file->private_data) |
660 | goto err_unlock; | 691 | goto err_unlock; |
661 | 692 | ||
662 | fc->id = conn_id(); | ||
663 | err = fuse_ctl_add_conn(fc); | 693 | err = fuse_ctl_add_conn(fc); |
664 | if (err) | 694 | if (err) |
665 | goto err_unlock; | 695 | goto err_unlock; |