]> Pileus Git - ~andy/linux/commitdiff
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi...
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 18 Sep 2009 16:23:03 +0000 (09:23 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 18 Sep 2009 16:23:03 +0000 (09:23 -0700)
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse:
  fuse: add fusectl interface to max_background
  fuse: limit user-specified values of max background requests
  fuse: use drop_nlink() instead of direct nlink manipulation
  fuse: document protocol version negotiation
  fuse: make the number of max background requests and congestion threshold tunable

1  2 
fs/fuse/dev.c
fs/fuse/inode.c

diff --combined fs/fuse/dev.c
index 6484eb75acd6f318c04238a51763b7cf2c9599ea,b152761c1bf60fbb33e8683df48abbdfdae8fe07..51d9e33d634f4fb40f28fc00276123e1dc8f13c0
@@@ -250,7 -250,7 +250,7 @@@ static void queue_request(struct fuse_c
  
  static void flush_bg_queue(struct fuse_conn *fc)
  {
-       while (fc->active_background < FUSE_MAX_BACKGROUND &&
+       while (fc->active_background < fc->max_background &&
               !list_empty(&fc->bg_queue)) {
                struct fuse_req *req;
  
@@@ -280,14 -280,14 +280,14 @@@ __releases(&fc->lock
        list_del(&req->intr_entry);
        req->state = FUSE_REQ_FINISHED;
        if (req->background) {
-               if (fc->num_background == FUSE_MAX_BACKGROUND) {
+               if (fc->num_background == fc->max_background) {
                        fc->blocked = 0;
                        wake_up_all(&fc->blocked_waitq);
                }
-               if (fc->num_background == FUSE_CONGESTION_THRESHOLD &&
+               if (fc->num_background == fc->congestion_threshold &&
                    fc->connected && fc->bdi_initialized) {
 -                      clear_bdi_congested(&fc->bdi, READ);
 -                      clear_bdi_congested(&fc->bdi, WRITE);
 +                      clear_bdi_congested(&fc->bdi, BLK_RW_SYNC);
 +                      clear_bdi_congested(&fc->bdi, BLK_RW_ASYNC);
                }
                fc->num_background--;
                fc->active_background--;
@@@ -410,12 -410,12 +410,12 @@@ static void fuse_request_send_nowait_lo
  {
        req->background = 1;
        fc->num_background++;
-       if (fc->num_background == FUSE_MAX_BACKGROUND)
+       if (fc->num_background == fc->max_background)
                fc->blocked = 1;
-       if (fc->num_background == FUSE_CONGESTION_THRESHOLD &&
+       if (fc->num_background == fc->congestion_threshold &&
            fc->bdi_initialized) {
 -              set_bdi_congested(&fc->bdi, READ);
 -              set_bdi_congested(&fc->bdi, WRITE);
 +              set_bdi_congested(&fc->bdi, BLK_RW_SYNC);
 +              set_bdi_congested(&fc->bdi, BLK_RW_ASYNC);
        }
        list_add_tail(&req->list, &fc->bg_queue);
        flush_bg_queue(fc);
diff --combined fs/fuse/inode.c
index e5dbecd87b0f49c748aa4465c3a22447e29fc540,8f9aca8d4ad598e724e463ffff6816dae5f301e0..6da947daabda1894f55a5079226ade24b30d72e0
@@@ -14,6 -14,7 +14,7 @@@
  #include <linux/seq_file.h>
  #include <linux/init.h>
  #include <linux/module.h>
+ #include <linux/moduleparam.h>
  #include <linux/parser.h>
  #include <linux/statfs.h>
  #include <linux/random.h>
@@@ -28,10 -29,34 +29,34 @@@ static struct kmem_cache *fuse_inode_ca
  struct list_head fuse_conn_list;
  DEFINE_MUTEX(fuse_mutex);
  
+ static int set_global_limit(const char *val, struct kernel_param *kp);
+ unsigned max_user_bgreq;
+ module_param_call(max_user_bgreq, set_global_limit, param_get_uint,
+                 &max_user_bgreq, 0644);
+ __MODULE_PARM_TYPE(max_user_bgreq, "uint");
+ MODULE_PARM_DESC(max_user_bgreq,
+  "Global limit for the maximum number of backgrounded requests an "
+  "unprivileged user can set");
+ unsigned max_user_congthresh;
+ module_param_call(max_user_congthresh, set_global_limit, param_get_uint,
+                 &max_user_congthresh, 0644);
+ __MODULE_PARM_TYPE(max_user_congthresh, "uint");
+ MODULE_PARM_DESC(max_user_congthresh,
+  "Global limit for the maximum congestion threshold an "
+  "unprivileged user can set");
  #define FUSE_SUPER_MAGIC 0x65735546
  
  #define FUSE_DEFAULT_BLKSIZE 512
  
+ /** Maximum number of outstanding background requests */
+ #define FUSE_DEFAULT_MAX_BACKGROUND 12
+ /** Congestion starts at 75% of maximum */
+ #define FUSE_DEFAULT_CONGESTION_THRESHOLD (FUSE_DEFAULT_MAX_BACKGROUND * 3 / 4)
  struct fuse_mount_data {
        int fd;
        unsigned rootmode;
@@@ -517,6 -542,8 +542,8 @@@ void fuse_conn_init(struct fuse_conn *f
        INIT_LIST_HEAD(&fc->bg_queue);
        INIT_LIST_HEAD(&fc->entry);
        atomic_set(&fc->num_waiting, 0);
+       fc->max_background = FUSE_DEFAULT_MAX_BACKGROUND;
+       fc->congestion_threshold = FUSE_DEFAULT_CONGESTION_THRESHOLD;
        fc->khctr = 0;
        fc->polled_files = RB_ROOT;
        fc->reqctr = 0;
@@@ -727,6 -754,54 +754,54 @@@ static const struct super_operations fu
        .show_options   = fuse_show_options,
  };
  
+ static void sanitize_global_limit(unsigned *limit)
+ {
+       if (*limit == 0)
+               *limit = ((num_physpages << PAGE_SHIFT) >> 13) /
+                        sizeof(struct fuse_req);
+       if (*limit >= 1 << 16)
+               *limit = (1 << 16) - 1;
+ }
+ static int set_global_limit(const char *val, struct kernel_param *kp)
+ {
+       int rv;
+       rv = param_set_uint(val, kp);
+       if (rv)
+               return rv;
+       sanitize_global_limit((unsigned *)kp->arg);
+       return 0;
+ }
+ static void process_init_limits(struct fuse_conn *fc, struct fuse_init_out *arg)
+ {
+       int cap_sys_admin = capable(CAP_SYS_ADMIN);
+       if (arg->minor < 13)
+               return;
+       sanitize_global_limit(&max_user_bgreq);
+       sanitize_global_limit(&max_user_congthresh);
+       if (arg->max_background) {
+               fc->max_background = arg->max_background;
+               if (!cap_sys_admin && fc->max_background > max_user_bgreq)
+                       fc->max_background = max_user_bgreq;
+       }
+       if (arg->congestion_threshold) {
+               fc->congestion_threshold = arg->congestion_threshold;
+               if (!cap_sys_admin &&
+                   fc->congestion_threshold > max_user_congthresh)
+                       fc->congestion_threshold = max_user_congthresh;
+       }
+ }
  static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req)
  {
        struct fuse_init_out *arg = &req->misc.init_out;
        else {
                unsigned long ra_pages;
  
+               process_init_limits(fc, arg);
                if (arg->minor >= 6) {
                        ra_pages = arg->max_readahead / PAGE_CACHE_SIZE;
                        if (arg->flags & FUSE_ASYNC_READ)
@@@ -801,7 -878,6 +878,7 @@@ static int fuse_bdi_init(struct fuse_co
  {
        int err;
  
 +      fc->bdi.name = "fuse";
        fc->bdi.ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE;
        fc->bdi.unplug_io_fn = default_unplug_io_fn;
        /* fuse does it's own writeback accounting */
@@@ -894,8 -970,6 +971,8 @@@ static int fuse_fill_super(struct super
        if (err)
                goto err_put_conn;
  
 +      sb->s_bdi = &fc->bdi;
 +
        /* Handle umasking inside the fuse code */
        if (sb->s_flags & MS_POSIXACL)
                fc->dont_mask = 1;
@@@ -1150,6 -1224,9 +1227,9 @@@ static int __init fuse_init(void
        if (res)
                goto err_sysfs_cleanup;
  
+       sanitize_global_limit(&max_user_bgreq);
+       sanitize_global_limit(&max_user_congthresh);
        return 0;
  
   err_sysfs_cleanup: