NFSD: Refactor transport addition out of __write_ports()
[safe/jmp/linux-2.6] / fs / nfsd / nfsctl.c
index 3d93b20..748532b 100644 (file)
@@ -60,6 +60,7 @@ enum {
        NFSD_FO_UnlockFS,
        NFSD_Threads,
        NFSD_Pool_Threads,
+       NFSD_Pool_Stats,
        NFSD_Versions,
        NFSD_Ports,
        NFSD_MaxBlkSize,
@@ -172,6 +173,16 @@ static const struct file_operations exports_operations = {
        .owner          = THIS_MODULE,
 };
 
+extern int nfsd_pool_stats_open(struct inode *inode, struct file *file);
+
+static struct file_operations pool_stats_operations = {
+       .open           = nfsd_pool_stats_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = seq_release,
+       .owner          = THIS_MODULE,
+};
+
 /*----------------------------------------------------------------------------*/
 /*
  * payload - write methods
@@ -781,8 +792,9 @@ out_free:
 static ssize_t __write_versions(struct file *file, char *buf, size_t size)
 {
        char *mesg = buf;
-       char *vers, sign;
+       char *vers, *minorp, sign;
        int len, num;
+       unsigned minor;
        ssize_t tlen = 0;
        char *sep;
 
@@ -803,9 +815,20 @@ static ssize_t __write_versions(struct file *file, char *buf, size_t size)
                do {
                        sign = *vers;
                        if (sign == '+' || sign == '-')
-                               num = simple_strtol((vers+1), NULL, 0);
+                               num = simple_strtol((vers+1), &minorp, 0);
                        else
-                               num = simple_strtol(vers, NULL, 0);
+                               num = simple_strtol(vers, &minorp, 0);
+                       if (*minorp == '.') {
+                               if (num < 4)
+                                       return -EINVAL;
+                               minor = simple_strtoul(minorp+1, NULL, 0);
+                               if (minor == 0)
+                                       return -EINVAL;
+                               if (nfsd_minorversion(minor, sign == '-' ?
+                                                    NFSD_CLEAR : NFSD_SET) < 0)
+                                       return -EINVAL;
+                               goto next;
+                       }
                        switch(num) {
                        case 2:
                        case 3:
@@ -815,6 +838,7 @@ static ssize_t __write_versions(struct file *file, char *buf, size_t size)
                        default:
                                return -EINVAL;
                        }
+               next:
                        vers += len + 1;
                        tlen += len;
                } while ((len = qword_get(&mesg, vers, size)) > 0);
@@ -833,6 +857,13 @@ static ssize_t __write_versions(struct file *file, char *buf, size_t size)
                                       num);
                        sep = " ";
                }
+       if (nfsd_vers(4, NFSD_AVAIL))
+               for (minor = 1; minor <= NFSD_SUPPORTED_MINOR_VERSION; minor++)
+                       len += sprintf(buf+len, " %c4.%u",
+                                       (nfsd_vers(4, NFSD_TEST) &&
+                                        nfsd_minorversion(minor, NFSD_TEST)) ?
+                                               '+' : '-',
+                                       minor);
        len += sprintf(buf+len, "\n");
        return len;
 }
@@ -879,6 +910,61 @@ static ssize_t write_versions(struct file *file, char *buf, size_t size)
        return rv;
 }
 
+/*
+ * A transport listener is added by writing it's transport name and
+ * a port number.
+ */
+static ssize_t __write_ports_addxprt(char *buf)
+{
+       char transport[16];
+       int port, err;
+
+       if (sscanf(buf, "%15s %4u", transport, &port) != 2)
+               return -EINVAL;
+
+       if (port < 1 || port > USHORT_MAX)
+               return -EINVAL;
+
+       err = nfsd_create_serv();
+       if (err != 0)
+               return err;
+
+       err = svc_create_xprt(nfsd_serv, transport,
+                               PF_INET, port, SVC_SOCK_ANONYMOUS);
+       if (err < 0) {
+               /* Give a reasonable perror msg for bad transport string */
+               if (err == -ENOENT)
+                       err = -EPROTONOSUPPORT;
+               return err;
+       }
+       return 0;
+}
+
+/*
+ * A transport listener is removed by writing a "-", it's transport
+ * name, and it's port number.
+ */
+static ssize_t __write_ports_delxprt(char *buf)
+{
+       struct svc_xprt *xprt;
+       char transport[16];
+       int port;
+
+       if (sscanf(&buf[1], "%15s %4u", transport, &port) != 2)
+               return -EINVAL;
+
+       if (port < 1 || port > USHORT_MAX || nfsd_serv == NULL)
+               return -EINVAL;
+
+       xprt = svc_find_xprt(nfsd_serv, transport, AF_UNSPEC, port);
+       if (xprt == NULL)
+               return -ENOTCONN;
+
+       svc_close_xprt(xprt);
+       svc_xprt_put(xprt);
+       return 0;
+}
+
 static ssize_t __write_ports(struct file *file, char *buf, size_t size)
 {
        if (size == 0) {
@@ -930,51 +1016,13 @@ static ssize_t __write_ports(struct file *file, char *buf, size_t size)
                kfree(toclose);
                return len;
        }
-       /*
-        * Add a transport listener by writing it's transport name
-        */
-       if (isalpha(buf[0])) {
-               int err;
-               char transport[16];
-               int port;
-               if (sscanf(buf, "%15s %4d", transport, &port) == 2) {
-                       err = nfsd_create_serv();
-                       if (!err) {
-                               err = svc_create_xprt(nfsd_serv,
-                                                     transport, port,
-                                                     SVC_SOCK_ANONYMOUS);
-                               if (err == -ENOENT)
-                                       /* Give a reasonable perror msg for
-                                        * bad transport string */
-                                       err = -EPROTONOSUPPORT;
-                       }
-                       return err < 0 ? err : 0;
-               }
-       }
-       /*
-        * Remove a transport by writing it's transport name and port number
-        */
-       if (buf[0] == '-' && isalpha(buf[1])) {
-               struct svc_xprt *xprt;
-               int err = -EINVAL;
-               char transport[16];
-               int port;
-               if (sscanf(&buf[1], "%15s %4d", transport, &port) == 2) {
-                       if (port == 0)
-                               return -EINVAL;
-                       if (nfsd_serv) {
-                               xprt = svc_find_xprt(nfsd_serv, transport,
-                                                    AF_UNSPEC, port);
-                               if (xprt) {
-                                       svc_close_xprt(xprt);
-                                       svc_xprt_put(xprt);
-                                       err = 0;
-                               } else
-                                       err = -ENOTCONN;
-                       }
-                       return err < 0 ? err : 0;
-               }
-       }
+
+       if (isalpha(buf[0]))
+               return __write_ports_addxprt(buf);
+
+       if (buf[0] == '-' && isalpha(buf[1]))
+               return __write_ports_delxprt(buf);
+
        return -EINVAL;
 }
 
@@ -1246,6 +1294,7 @@ static int nfsd_fill_super(struct super_block * sb, void * data, int silent)
                [NFSD_Fh] = {"filehandle", &transaction_ops, S_IWUSR|S_IRUSR},
                [NFSD_Threads] = {"threads", &transaction_ops, S_IWUSR|S_IRUSR},
                [NFSD_Pool_Threads] = {"pool_threads", &transaction_ops, S_IWUSR|S_IRUSR},
+               [NFSD_Pool_Stats] = {"pool_stats", &pool_stats_operations, S_IRUGO},
                [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},