diff options
Diffstat (limited to 'fs/fuse/inode.c')
-rw-r--r-- | fs/fuse/inode.c | 91 |
1 files changed, 81 insertions, 10 deletions
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index e5dbecd87b0f..1a822ce2b24b 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/seq_file.h> | 14 | #include <linux/seq_file.h> |
15 | #include <linux/init.h> | 15 | #include <linux/init.h> |
16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
17 | #include <linux/moduleparam.h> | ||
17 | #include <linux/parser.h> | 18 | #include <linux/parser.h> |
18 | #include <linux/statfs.h> | 19 | #include <linux/statfs.h> |
19 | #include <linux/random.h> | 20 | #include <linux/random.h> |
@@ -28,10 +29,34 @@ static struct kmem_cache *fuse_inode_cachep; | |||
28 | struct list_head fuse_conn_list; | 29 | struct list_head fuse_conn_list; |
29 | DEFINE_MUTEX(fuse_mutex); | 30 | DEFINE_MUTEX(fuse_mutex); |
30 | 31 | ||
32 | static int set_global_limit(const char *val, struct kernel_param *kp); | ||
33 | |||
34 | unsigned max_user_bgreq; | ||
35 | module_param_call(max_user_bgreq, set_global_limit, param_get_uint, | ||
36 | &max_user_bgreq, 0644); | ||
37 | __MODULE_PARM_TYPE(max_user_bgreq, "uint"); | ||
38 | MODULE_PARM_DESC(max_user_bgreq, | ||
39 | "Global limit for the maximum number of backgrounded requests an " | ||
40 | "unprivileged user can set"); | ||
41 | |||
42 | unsigned max_user_congthresh; | ||
43 | module_param_call(max_user_congthresh, set_global_limit, param_get_uint, | ||
44 | &max_user_congthresh, 0644); | ||
45 | __MODULE_PARM_TYPE(max_user_congthresh, "uint"); | ||
46 | MODULE_PARM_DESC(max_user_congthresh, | ||
47 | "Global limit for the maximum congestion threshold an " | ||
48 | "unprivileged user can set"); | ||
49 | |||
31 | #define FUSE_SUPER_MAGIC 0x65735546 | 50 | #define FUSE_SUPER_MAGIC 0x65735546 |
32 | 51 | ||
33 | #define FUSE_DEFAULT_BLKSIZE 512 | 52 | #define FUSE_DEFAULT_BLKSIZE 512 |
34 | 53 | ||
54 | /** Maximum number of outstanding background requests */ | ||
55 | #define FUSE_DEFAULT_MAX_BACKGROUND 12 | ||
56 | |||
57 | /** Congestion starts at 75% of maximum */ | ||
58 | #define FUSE_DEFAULT_CONGESTION_THRESHOLD (FUSE_DEFAULT_MAX_BACKGROUND * 3 / 4) | ||
59 | |||
35 | struct fuse_mount_data { | 60 | struct fuse_mount_data { |
36 | int fd; | 61 | int fd; |
37 | unsigned rootmode; | 62 | unsigned rootmode; |
@@ -115,14 +140,6 @@ static int fuse_remount_fs(struct super_block *sb, int *flags, char *data) | |||
115 | return 0; | 140 | return 0; |
116 | } | 141 | } |
117 | 142 | ||
118 | void fuse_truncate(struct address_space *mapping, loff_t offset) | ||
119 | { | ||
120 | /* See vmtruncate() */ | ||
121 | unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1); | ||
122 | truncate_inode_pages(mapping, offset); | ||
123 | unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1); | ||
124 | } | ||
125 | |||
126 | void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr, | 143 | void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr, |
127 | u64 attr_valid) | 144 | u64 attr_valid) |
128 | { | 145 | { |
@@ -180,8 +197,7 @@ void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr, | |||
180 | spin_unlock(&fc->lock); | 197 | spin_unlock(&fc->lock); |
181 | 198 | ||
182 | if (S_ISREG(inode->i_mode) && oldsize != attr->size) { | 199 | if (S_ISREG(inode->i_mode) && oldsize != attr->size) { |
183 | if (attr->size < oldsize) | 200 | truncate_pagecache(inode, oldsize, attr->size); |
184 | fuse_truncate(inode->i_mapping, attr->size); | ||
185 | invalidate_inode_pages2(inode->i_mapping); | 201 | invalidate_inode_pages2(inode->i_mapping); |
186 | } | 202 | } |
187 | } | 203 | } |
@@ -517,6 +533,8 @@ void fuse_conn_init(struct fuse_conn *fc) | |||
517 | INIT_LIST_HEAD(&fc->bg_queue); | 533 | INIT_LIST_HEAD(&fc->bg_queue); |
518 | INIT_LIST_HEAD(&fc->entry); | 534 | INIT_LIST_HEAD(&fc->entry); |
519 | atomic_set(&fc->num_waiting, 0); | 535 | atomic_set(&fc->num_waiting, 0); |
536 | fc->max_background = FUSE_DEFAULT_MAX_BACKGROUND; | ||
537 | fc->congestion_threshold = FUSE_DEFAULT_CONGESTION_THRESHOLD; | ||
520 | fc->khctr = 0; | 538 | fc->khctr = 0; |
521 | fc->polled_files = RB_ROOT; | 539 | fc->polled_files = RB_ROOT; |
522 | fc->reqctr = 0; | 540 | fc->reqctr = 0; |
@@ -727,6 +745,54 @@ static const struct super_operations fuse_super_operations = { | |||
727 | .show_options = fuse_show_options, | 745 | .show_options = fuse_show_options, |
728 | }; | 746 | }; |
729 | 747 | ||
748 | static void sanitize_global_limit(unsigned *limit) | ||
749 | { | ||
750 | if (*limit == 0) | ||
751 | *limit = ((num_physpages << PAGE_SHIFT) >> 13) / | ||
752 | sizeof(struct fuse_req); | ||
753 | |||
754 | if (*limit >= 1 << 16) | ||
755 | *limit = (1 << 16) - 1; | ||
756 | } | ||
757 | |||
758 | static int set_global_limit(const char *val, struct kernel_param *kp) | ||
759 | { | ||
760 | int rv; | ||
761 | |||
762 | rv = param_set_uint(val, kp); | ||
763 | if (rv) | ||
764 | return rv; | ||
765 | |||
766 | sanitize_global_limit((unsigned *)kp->arg); | ||
767 | |||
768 | return 0; | ||
769 | } | ||
770 | |||
771 | static void process_init_limits(struct fuse_conn *fc, struct fuse_init_out *arg) | ||
772 | { | ||
773 | int cap_sys_admin = capable(CAP_SYS_ADMIN); | ||
774 | |||
775 | if (arg->minor < 13) | ||
776 | return; | ||
777 | |||
778 | sanitize_global_limit(&max_user_bgreq); | ||
779 | sanitize_global_limit(&max_user_congthresh); | ||
780 | |||
781 | if (arg->max_background) { | ||
782 | fc->max_background = arg->max_background; | ||
783 | |||
784 | if (!cap_sys_admin && fc->max_background > max_user_bgreq) | ||
785 | fc->max_background = max_user_bgreq; | ||
786 | } | ||
787 | if (arg->congestion_threshold) { | ||
788 | fc->congestion_threshold = arg->congestion_threshold; | ||
789 | |||
790 | if (!cap_sys_admin && | ||
791 | fc->congestion_threshold > max_user_congthresh) | ||
792 | fc->congestion_threshold = max_user_congthresh; | ||
793 | } | ||
794 | } | ||
795 | |||
730 | static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req) | 796 | static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req) |
731 | { | 797 | { |
732 | struct fuse_init_out *arg = &req->misc.init_out; | 798 | struct fuse_init_out *arg = &req->misc.init_out; |
@@ -736,6 +802,8 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req) | |||
736 | else { | 802 | else { |
737 | unsigned long ra_pages; | 803 | unsigned long ra_pages; |
738 | 804 | ||
805 | process_init_limits(fc, arg); | ||
806 | |||
739 | if (arg->minor >= 6) { | 807 | if (arg->minor >= 6) { |
740 | ra_pages = arg->max_readahead / PAGE_CACHE_SIZE; | 808 | ra_pages = arg->max_readahead / PAGE_CACHE_SIZE; |
741 | if (arg->flags & FUSE_ASYNC_READ) | 809 | if (arg->flags & FUSE_ASYNC_READ) |
@@ -1150,6 +1218,9 @@ static int __init fuse_init(void) | |||
1150 | if (res) | 1218 | if (res) |
1151 | goto err_sysfs_cleanup; | 1219 | goto err_sysfs_cleanup; |
1152 | 1220 | ||
1221 | sanitize_global_limit(&max_user_bgreq); | ||
1222 | sanitize_global_limit(&max_user_congthresh); | ||
1223 | |||
1153 | return 0; | 1224 | return 0; |
1154 | 1225 | ||
1155 | err_sysfs_cleanup: | 1226 | err_sysfs_cleanup: |