arm64: dts: rockchip: rk3399-box-rev1: increase drive strength for sd/sdio pin
[firefly-linux-kernel-4.4.55.git] / fs / nfsd / nfsctl.c
index f34d9de802abc7bfea33c14388020abcfcd007dc..9690cb4dd5887b020ffc897ba93888f302db3a56 100644 (file)
@@ -21,6 +21,7 @@
 #include "cache.h"
 #include "state.h"
 #include "netns.h"
+#include "pnfs.h"
 
 /*
  *     We have a single directory with several nodes in it.
@@ -39,6 +40,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[]
@@ -48,6 +50,7 @@ enum {
        NFSD_Leasetime,
        NFSD_Gracetime,
        NFSD_RecoveryDir,
+       NFSD_V4EndGrace,
 #endif
 };
 
@@ -62,10 +65,12 @@ 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);
 static ssize_t write_recoverydir(struct file *file, char *buf, size_t size);
+static ssize_t write_v4_end_grace(struct file *file, char *buf, size_t size);
 #endif
 
 static ssize_t (*write_op[])(struct file *, char *, size_t) = {
@@ -77,10 +82,12 @@ 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,
        [NFSD_RecoveryDir] = write_recoverydir,
+       [NFSD_V4EndGrace] = write_v4_end_grace,
 #endif
 };
 
@@ -225,6 +232,10 @@ static struct file_operations reply_cache_stats_operations = {
  * payload - write methods
  */
 
+static inline struct net *netns(struct file *file)
+{
+       return file_inode(file)->i_sb->s_fs_info;
+}
 
 /**
  * write_unlock_ip - Release all locks used by a client
@@ -246,7 +257,7 @@ static ssize_t write_unlock_ip(struct file *file, char *buf, size_t size)
        struct sockaddr *sap = (struct sockaddr *)&address;
        size_t salen = sizeof(address);
        char *fo_path;
-       struct net *net = file->f_dentry->d_sb->s_fs_info;
+       struct net *net = netns(file);
 
        /* sanity check */
        if (size == 0)
@@ -344,7 +355,6 @@ static ssize_t write_filehandle(struct file *file, char *buf, size_t size)
        int len;
        struct auth_domain *dom;
        struct knfsd_fh fh;
-       struct net *net = file->f_dentry->d_sb->s_fs_info;
 
        if (size == 0)
                return -EINVAL;
@@ -369,8 +379,7 @@ static ssize_t write_filehandle(struct file *file, char *buf, size_t size)
 
        if (maxsize < NFS_FHSIZE)
                return -EINVAL;
-       if (maxsize > NFS3_FHSIZE)
-               maxsize = NFS3_FHSIZE;
+       maxsize = min(maxsize, NFS3_FHSIZE);
 
        if (qword_get(&mesg, mesg, size)>0)
                return -EINVAL;
@@ -380,7 +389,7 @@ static ssize_t write_filehandle(struct file *file, char *buf, size_t size)
        if (!dom)
                return -ENOMEM;
 
-       len = exp_rootfh(net, dom, path, &fh,  maxsize);
+       len = exp_rootfh(netns(file), dom, path, &fh,  maxsize);
        auth_domain_put(dom);
        if (len)
                return len;
@@ -424,7 +433,7 @@ static ssize_t write_threads(struct file *file, char *buf, size_t size)
 {
        char *mesg = buf;
        int rv;
-       struct net *net = file->f_dentry->d_sb->s_fs_info;
+       struct net *net = netns(file);
 
        if (size > 0) {
                int newthreads;
@@ -475,7 +484,7 @@ static ssize_t write_pool_threads(struct file *file, char *buf, size_t size)
        int len;
        int npools;
        int *nthreads;
-       struct net *net = file->f_dentry->d_sb->s_fs_info;
+       struct net *net = netns(file);
 
        mutex_lock(&nfsd_mutex);
        npools = nfsd_nrpools(net);
@@ -538,8 +547,7 @@ static ssize_t __write_versions(struct file *file, char *buf, size_t size)
        unsigned minor;
        ssize_t tlen = 0;
        char *sep;
-       struct net *net = file->f_dentry->d_sb->s_fs_info;
-       struct nfsd_net *nn = net_generic(net, nfsd_net_id);
+       struct nfsd_net *nn = net_generic(netns(file), nfsd_net_id);
 
        if (size>0) {
                if (nn->nfsd_serv)
@@ -601,7 +609,7 @@ static ssize_t __write_versions(struct file *file, char *buf, size_t size)
                                       num);
                        sep = " ";
 
-                       if (len > remaining)
+                       if (len >= remaining)
                                break;
                        remaining -= len;
                        buf += len;
@@ -616,7 +624,7 @@ static ssize_t __write_versions(struct file *file, char *buf, size_t size)
                                                '+' : '-',
                                        minor);
 
-                       if (len > remaining)
+                       if (len >= remaining)
                                break;
                        remaining -= len;
                        buf += len;
@@ -624,7 +632,7 @@ static ssize_t __write_versions(struct file *file, char *buf, size_t size)
                }
 
        len = snprintf(buf, remaining, "\n");
-       if (len > remaining)
+       if (len >= remaining)
                return -EINVAL;
        return tlen + len;
 }
@@ -825,10 +833,9 @@ static ssize_t __write_ports(struct file *file, char *buf, size_t size,
 static ssize_t write_ports(struct file *file, char *buf, size_t size)
 {
        ssize_t rv;
-       struct net *net = file->f_dentry->d_sb->s_fs_info;
 
        mutex_lock(&nfsd_mutex);
-       rv = __write_ports(file, buf, size, net);
+       rv = __write_ports(file, buf, size, netns(file));
        mutex_unlock(&nfsd_mutex);
        return rv;
 }
@@ -860,8 +867,7 @@ int nfsd_max_blksize;
 static ssize_t write_maxblksize(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);
+       struct nfsd_net *nn = net_generic(netns(file), nfsd_net_id);
 
        if (size > 0) {
                int bsize;
@@ -871,10 +877,8 @@ static ssize_t write_maxblksize(struct file *file, char *buf, size_t size)
                /* force bsize into allowed range and
                 * required alignment.
                 */
-               if (bsize < 1024)
-                       bsize = 1024;
-               if (bsize > NFSSVC_MAXBLKSIZE)
-                       bsize = NFSSVC_MAXBLKSIZE;
+               bsize = max_t(int, bsize, 1024);
+               bsize = min_t(int, bsize, NFSSVC_MAXBLKSIZE);
                bsize &= ~(1024-1);
                mutex_lock(&nfsd_mutex);
                if (nn->nfsd_serv) {
@@ -889,6 +893,43 @@ 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 nfsd_net *nn = net_generic(netns(file), 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)
@@ -956,8 +997,7 @@ static ssize_t nfsd4_write_time(struct file *file, char *buf, size_t size,
  */
 static ssize_t write_leasetime(struct file *file, char *buf, size_t size)
 {
-       struct net *net = file->f_dentry->d_sb->s_fs_info;
-       struct nfsd_net *nn = net_generic(net, nfsd_net_id);
+       struct nfsd_net *nn = net_generic(netns(file), nfsd_net_id);
        return nfsd4_write_time(file, buf, size, &nn->nfsd4_lease, nn);
 }
 
@@ -973,8 +1013,7 @@ 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)
 {
-       struct net *net = file->f_dentry->d_sb->s_fs_info;
-       struct nfsd_net *nn = net_generic(net, nfsd_net_id);
+       struct nfsd_net *nn = net_generic(netns(file), nfsd_net_id);
        return nfsd4_write_time(file, buf, size, &nn->nfsd4_grace, nn);
 }
 
@@ -1030,8 +1069,7 @@ static ssize_t __write_recoverydir(struct file *file, char *buf, size_t size,
 static ssize_t write_recoverydir(struct file *file, char *buf, size_t size)
 {
        ssize_t rv;
-       struct net *net = file->f_dentry->d_sb->s_fs_info;
-       struct nfsd_net *nn = net_generic(net, nfsd_net_id);
+       struct nfsd_net *nn = net_generic(netns(file), nfsd_net_id);
 
        mutex_lock(&nfsd_mutex);
        rv = __write_recoverydir(file, buf, size, nn);
@@ -1039,6 +1077,46 @@ static ssize_t write_recoverydir(struct file *file, char *buf, size_t size)
        return rv;
 }
 
+/**
+ * write_v4_end_grace - release grace period for nfsd's v4.x lock manager
+ *
+ * Input:
+ *                     buf:            ignored
+ *                     size:           zero
+ * OR
+ *
+ * Input:
+ *                     buf:            any value
+ *                     size:           non-zero length of C string in @buf
+ * Output:
+ *                     passed-in buffer filled with "Y" or "N" with a newline
+ *                     and NULL-terminated C string. This indicates whether
+ *                     the grace period has ended in the current net
+ *                     namespace. Return code is the size in bytes of the
+ *                     string. Writing a string that starts with 'Y', 'y', or
+ *                     '1' to the file will end the grace period for nfsd's v4
+ *                     lock manager.
+ */
+static ssize_t write_v4_end_grace(struct file *file, char *buf, size_t size)
+{
+       struct nfsd_net *nn = net_generic(netns(file), nfsd_net_id);
+
+       if (size > 0) {
+               switch(buf[0]) {
+               case 'Y':
+               case 'y':
+               case '1':
+                       nfsd4_end_grace(nn);
+                       break;
+               default:
+                       return -EINVAL;
+               }
+       }
+
+       return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%c\n",
+                        nn->grace_ended ? 'Y' : 'N');
+}
+
 #endif
 
 /*----------------------------------------------------------------------------*/
@@ -1064,6 +1142,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 */
@@ -1071,6 +1150,7 @@ static int nfsd_fill_super(struct super_block * sb, void * data, int silent)
                [NFSD_Leasetime] = {"nfsv4leasetime", &transaction_ops, S_IWUSR|S_IRUSR},
                [NFSD_Gracetime] = {"nfsv4gracetime", &transaction_ops, S_IWUSR|S_IRUSR},
                [NFSD_RecoveryDir] = {"nfsv4recoverydir", &transaction_ops, S_IWUSR|S_IRUSR},
+               [NFSD_V4EndGrace] = {"v4_end_grace", &transaction_ops, S_IWUSR|S_IRUGO},
 #endif
                /* last one */ {""}
        };
@@ -1170,19 +1250,21 @@ static int __init init_nfsd(void)
        int retval;
        printk(KERN_INFO "Installing knfsd (copyright (C) 1996 okir@monad.swb.de).\n");
 
-       retval = register_cld_notifier();
-       if (retval)
-               return retval;
        retval = register_pernet_subsys(&nfsd_net_ops);
        if (retval < 0)
-               goto out_unregister_notifier;
-       retval = nfsd4_init_slabs();
+               return retval;
+       retval = register_cld_notifier();
        if (retval)
                goto out_unregister_pernet;
-       nfs4_state_init();
-       retval = nfsd_fault_inject_init(); /* nfsd fault injection controls */
+       retval = nfsd4_init_slabs();
+       if (retval)
+               goto out_unregister_notifier;
+       retval = nfsd4_init_pnfs();
        if (retval)
                goto out_free_slabs;
+       retval = nfsd_fault_inject_init(); /* nfsd fault injection controls */
+       if (retval)
+               goto out_exit_pnfs;
        nfsd_stat_init();       /* Statistics */
        retval = nfsd_reply_cache_init();
        if (retval)
@@ -1204,12 +1286,14 @@ out_free_lockd:
 out_free_stat:
        nfsd_stat_shutdown();
        nfsd_fault_inject_cleanup();
+out_exit_pnfs:
+       nfsd4_exit_pnfs();
 out_free_slabs:
        nfsd4_free_slabs();
-out_unregister_pernet:
-       unregister_pernet_subsys(&nfsd_net_ops);
 out_unregister_notifier:
        unregister_cld_notifier();
+out_unregister_pernet:
+       unregister_pernet_subsys(&nfsd_net_ops);
        return retval;
 }
 
@@ -1221,10 +1305,11 @@ static void __exit exit_nfsd(void)
        nfsd_stat_shutdown();
        nfsd_lockd_shutdown();
        nfsd4_free_slabs();
+       nfsd4_exit_pnfs();
        nfsd_fault_inject_cleanup();
        unregister_filesystem(&nfsd_fs_type);
-       unregister_pernet_subsys(&nfsd_net_ops);
        unregister_cld_notifier();
+       unregister_pernet_subsys(&nfsd_net_ops);
 }
 
 MODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>");