nfsd: add a new /proc/fs/nfsd/max_connections file
authorJeff Layton <jlayton@primarydata.com>
Wed, 2 Jul 2014 20:11:22 +0000 (16:11 -0400)
committerJ. Bruce Fields <bfields@redhat.com>
Tue, 8 Jul 2014 21:14:32 +0000 (17:14 -0400)
Currently, the maximum number of connections that nfsd will allow
is based on the number of threads spawned. While this is fine for a
default, there really isn't a clear relationship between the two.

The number of threads corresponds to the number of concurrent requests
that we want to allow the server to process at any given time. The
connection limit corresponds to the maximum number of clients that we
want to allow the server to handle. These are two entirely different
quantities.

Break the dependency on increasing threads in order to allow for more
connections, by adding a new per-net parameter that can be set to a
non-zero value. The default is still to base it on the number of threads,
so there should be no behavior change for anyone who doesn't use it.

Cc: Trond Myklebust <trond.myklebust@primarydata.com>
Signed-off-by: Jeff Layton <jlayton@primarydata.com>
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
fs/nfsd/netns.h
fs/nfsd/nfsctl.c
fs/nfsd/nfssvc.c

index d32b3aa6600da986ab964ec2c30a4493c24eb5cb..113e1aa9b0e81c596798be0a73e0f881e3e2f5e1 100644 (file)
@@ -102,6 +102,12 @@ struct nfsd_net {
         */
        struct timeval nfssvc_boot;
 
+       /*
+        * Max number of connections this nfsd container will allow. Defaults
+        * to '0' which is means that it bases this on the number of threads.
+        */
+       unsigned int max_connections;
+
        struct svc_serv *nfsd_serv;
 };
 
index 6a6f65cc8b348dbfefefa2697c000d0f2117f880..4e042105fb6e3dc81595649bdfeff51d2d16a65c 100644 (file)
@@ -39,6 +39,7 @@ enum {
        NFSD_Versions,
        NFSD_Ports,
        NFSD_MaxBlkSize,
+       NFSD_MaxConnections,
        NFSD_SupportedEnctypes,
        /*
         * The below MUST come last.  Otherwise we leave a hole in nfsd_files[]
@@ -62,6 +63,7 @@ static ssize_t write_pool_threads(struct file *file, char *buf, size_t size);
 static ssize_t write_versions(struct file *file, char *buf, size_t size);
 static ssize_t write_ports(struct file *file, char *buf, size_t size);
 static ssize_t write_maxblksize(struct file *file, char *buf, size_t size);
+static ssize_t write_maxconn(struct file *file, char *buf, size_t size);
 #ifdef CONFIG_NFSD_V4
 static ssize_t write_leasetime(struct file *file, char *buf, size_t size);
 static ssize_t write_gracetime(struct file *file, char *buf, size_t size);
@@ -77,6 +79,7 @@ static ssize_t (*write_op[])(struct file *, char *, size_t) = {
        [NFSD_Versions] = write_versions,
        [NFSD_Ports] = write_ports,
        [NFSD_MaxBlkSize] = write_maxblksize,
+       [NFSD_MaxConnections] = write_maxconn,
 #ifdef CONFIG_NFSD_V4
        [NFSD_Leasetime] = write_leasetime,
        [NFSD_Gracetime] = write_gracetime,
@@ -886,6 +889,44 @@ static ssize_t write_maxblksize(struct file *file, char *buf, size_t size)
                                                        nfsd_max_blksize);
 }
 
+/**
+ * write_maxconn - Set or report the current max number of connections
+ *
+ * Input:
+ *                     buf:            ignored
+ *                     size:           zero
+ * OR
+ *
+ * Input:
+ *                     buf:            C string containing an unsigned
+ *                                     integer value representing the new
+ *                                     number of max connections
+ *                     size:           non-zero length of C string in @buf
+ * Output:
+ *     On success:     passed-in buffer filled with '\n'-terminated C string
+ *                     containing numeric value of max_connections setting
+ *                     for this net namespace;
+ *                     return code is the size in bytes of the string
+ *     On error:       return code is zero or a negative errno value
+ */
+static ssize_t write_maxconn(struct file *file, char *buf, size_t size)
+{
+       char *mesg = buf;
+       struct net *net = file->f_dentry->d_sb->s_fs_info;
+       struct nfsd_net *nn = net_generic(net, nfsd_net_id);
+       unsigned int maxconn = nn->max_connections;
+
+       if (size > 0) {
+               int rv = get_uint(&mesg, &maxconn);
+
+               if (rv)
+                       return rv;
+               nn->max_connections = maxconn;
+       }
+
+       return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%u\n", maxconn);
+}
+
 #ifdef CONFIG_NFSD_V4
 static ssize_t __nfsd4_write_time(struct file *file, char *buf, size_t size,
                                  time_t *time, struct nfsd_net *nn)
@@ -1061,6 +1102,7 @@ static int nfsd_fill_super(struct super_block * sb, void * data, int silent)
                [NFSD_Versions] = {"versions", &transaction_ops, S_IWUSR|S_IRUSR},
                [NFSD_Ports] = {"portlist", &transaction_ops, S_IWUSR|S_IRUGO},
                [NFSD_MaxBlkSize] = {"max_block_size", &transaction_ops, S_IWUSR|S_IRUGO},
+               [NFSD_MaxConnections] = {"max_connections", &transaction_ops, S_IWUSR|S_IRUGO},
 #if defined(CONFIG_SUNRPC_GSS) || defined(CONFIG_SUNRPC_GSS_MODULE)
                [NFSD_SupportedEnctypes] = {"supported_krb5_enctypes", &supported_enctypes_ops, S_IRUGO},
 #endif /* CONFIG_SUNRPC_GSS or CONFIG_SUNRPC_GSS_MODULE */
index 209474174fe43442d513c229e8ad7b8bb3f43cf9..5d026dca00caebdc6f150fc4aa90095974ffad80 100644 (file)
@@ -405,6 +405,7 @@ int nfsd_create_serv(struct net *net)
        if (nn->nfsd_serv == NULL)
                return -ENOMEM;
 
+       nn->nfsd_serv->sv_maxconn = nn->max_connections;
        error = svc_bind(nn->nfsd_serv, net);
        if (error < 0) {
                svc_destroy(nn->nfsd_serv);
@@ -563,6 +564,7 @@ nfsd(void *vrqstp)
        struct svc_rqst *rqstp = (struct svc_rqst *) vrqstp;
        struct svc_xprt *perm_sock = list_entry(rqstp->rq_server->sv_permsocks.next, typeof(struct svc_xprt), xpt_list);
        struct net *net = perm_sock->xpt_net;
+       struct nfsd_net *nn = net_generic(net, nfsd_net_id);
        int err;
 
        /* Lock module and set up kernel thread */
@@ -596,6 +598,9 @@ nfsd(void *vrqstp)
         * The main request loop
         */
        for (;;) {
+               /* Update sv_maxconn if it has changed */
+               rqstp->rq_server->sv_maxconn = nn->max_connections;
+
                /*
                 * Find a socket with data available and call its
                 * recvfrom routine.