diff options
Diffstat (limited to 'fs/fuse/inode.c')
-rw-r--r-- | fs/fuse/inode.c | 80 |
1 files changed, 80 insertions, 0 deletions
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index e5dbecd87b0f..6da947daabda 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; |
@@ -517,6 +542,8 @@ void fuse_conn_init(struct fuse_conn *fc) | |||
517 | INIT_LIST_HEAD(&fc->bg_queue); | 542 | INIT_LIST_HEAD(&fc->bg_queue); |
518 | INIT_LIST_HEAD(&fc->entry); | 543 | INIT_LIST_HEAD(&fc->entry); |
519 | atomic_set(&fc->num_waiting, 0); | 544 | atomic_set(&fc->num_waiting, 0); |
545 | fc->max_background = FUSE_DEFAULT_MAX_BACKGROUND; | ||
546 | fc->congestion_threshold = FUSE_DEFAULT_CONGESTION_THRESHOLD; | ||
520 | fc->khctr = 0; | 547 | fc->khctr = 0; |
521 | fc->polled_files = RB_ROOT; | 548 | fc->polled_files = RB_ROOT; |
522 | fc->reqctr = 0; | 549 | fc->reqctr = 0; |
@@ -727,6 +754,54 @@ static const struct super_operations fuse_super_operations = { | |||
727 | .show_options = fuse_show_options, | 754 | .show_options = fuse_show_options, |
728 | }; | 755 | }; |
729 | 756 | ||
757 | static void sanitize_global_limit(unsigned *limit) | ||
758 | { | ||
759 | if (*limit == 0) | ||
760 | *limit = ((num_physpages << PAGE_SHIFT) >> 13) / | ||
761 | sizeof(struct fuse_req); | ||
762 | |||
763 | if (*limit >= 1 << 16) | ||
764 | *limit = (1 << 16) - 1; | ||
765 | } | ||
766 | |||
767 | static int set_global_limit(const char *val, struct kernel_param *kp) | ||
768 | { | ||
769 | int rv; | ||
770 | |||
771 | rv = param_set_uint(val, kp); | ||
772 | if (rv) | ||
773 | return rv; | ||
774 | |||
775 | sanitize_global_limit((unsigned *)kp->arg); | ||
776 | |||
777 | return 0; | ||
778 | } | ||
779 | |||
780 | static void process_init_limits(struct fuse_conn *fc, struct fuse_init_out *arg) | ||
781 | { | ||
782 | int cap_sys_admin = capable(CAP_SYS_ADMIN); | ||
783 | |||
784 | if (arg->minor < 13) | ||
785 | return; | ||
786 | |||
787 | sanitize_global_limit(&max_user_bgreq); | ||
788 | sanitize_global_limit(&max_user_congthresh); | ||
789 | |||
790 | if (arg->max_background) { | ||
791 | fc->max_background = arg->max_background; | ||
792 | |||
793 | if (!cap_sys_admin && fc->max_background > max_user_bgreq) | ||
794 | fc->max_background = max_user_bgreq; | ||
795 | } | ||
796 | if (arg->congestion_threshold) { | ||
797 | fc->congestion_threshold = arg->congestion_threshold; | ||
798 | |||
799 | if (!cap_sys_admin && | ||
800 | fc->congestion_threshold > max_user_congthresh) | ||
801 | fc->congestion_threshold = max_user_congthresh; | ||
802 | } | ||
803 | } | ||
804 | |||
730 | static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req) | 805 | static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req) |
731 | { | 806 | { |
732 | struct fuse_init_out *arg = &req->misc.init_out; | 807 | struct fuse_init_out *arg = &req->misc.init_out; |
@@ -736,6 +811,8 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req) | |||
736 | else { | 811 | else { |
737 | unsigned long ra_pages; | 812 | unsigned long ra_pages; |
738 | 813 | ||
814 | process_init_limits(fc, arg); | ||
815 | |||
739 | if (arg->minor >= 6) { | 816 | if (arg->minor >= 6) { |
740 | ra_pages = arg->max_readahead / PAGE_CACHE_SIZE; | 817 | ra_pages = arg->max_readahead / PAGE_CACHE_SIZE; |
741 | if (arg->flags & FUSE_ASYNC_READ) | 818 | if (arg->flags & FUSE_ASYNC_READ) |
@@ -1150,6 +1227,9 @@ static int __init fuse_init(void) | |||
1150 | if (res) | 1227 | if (res) |
1151 | goto err_sysfs_cleanup; | 1228 | goto err_sysfs_cleanup; |
1152 | 1229 | ||
1230 | sanitize_global_limit(&max_user_bgreq); | ||
1231 | sanitize_global_limit(&max_user_congthresh); | ||
1232 | |||
1153 | return 0; | 1233 | return 0; |
1154 | 1234 | ||
1155 | err_sysfs_cleanup: | 1235 | err_sysfs_cleanup: |