]> nv-tegra.nvidia Code Review - linux-3.10.git/blobdiff - fs/nfsd/nfsctl.c
Merge branch 'for-3.3' of git://linux-nfs.org/~bfields/linux
[linux-3.10.git] / fs / nfsd / nfsctl.c
index b1c5be85bea535e298ba81fd40210a5139b31c8c..748eda93ce590d1ad1e4f7892f29e25f8ad8856a 100644 (file)
@@ -8,27 +8,23 @@
 #include <linux/namei.h>
 #include <linux/ctype.h>
 
-#include <linux/nfsd_idmap.h>
 #include <linux/sunrpc/svcsock.h>
-#include <linux/nfsd/syscall.h>
 #include <linux/lockd/lockd.h>
 #include <linux/sunrpc/clnt.h>
+#include <linux/sunrpc/gss_api.h>
+#include <linux/sunrpc/gss_krb5_enctypes.h>
+#include <linux/module.h>
 
+#include "idmap.h"
 #include "nfsd.h"
 #include "cache.h"
+#include "fault_inject.h"
 
 /*
- *     We have a single directory with 9 nodes in it.
+ *     We have a single directory with several nodes in it.
  */
 enum {
        NFSD_Root = 1,
-       NFSD_Svc,
-       NFSD_Add,
-       NFSD_Del,
-       NFSD_Export,
-       NFSD_Unexport,
-       NFSD_Getfd,
-       NFSD_Getfs,
        NFSD_List,
        NFSD_Export_features,
        NFSD_Fh,
@@ -40,6 +36,7 @@ enum {
        NFSD_Versions,
        NFSD_Ports,
        NFSD_MaxBlkSize,
+       NFSD_SupportedEnctypes,
        /*
         * The below MUST come last.  Otherwise we leave a hole in nfsd_files[]
         * with !CONFIG_NFSD_V4 and simple_fill_super() goes oops
@@ -54,13 +51,6 @@ enum {
 /*
  * write() for these nodes.
  */
-static ssize_t write_svc(struct file *file, char *buf, size_t size);
-static ssize_t write_add(struct file *file, char *buf, size_t size);
-static ssize_t write_del(struct file *file, char *buf, size_t size);
-static ssize_t write_export(struct file *file, char *buf, size_t size);
-static ssize_t write_unexport(struct file *file, char *buf, size_t size);
-static ssize_t write_getfd(struct file *file, char *buf, size_t size);
-static ssize_t write_getfs(struct file *file, char *buf, size_t size);
 static ssize_t write_filehandle(struct file *file, char *buf, size_t size);
 static ssize_t write_unlock_ip(struct file *file, char *buf, size_t size);
 static ssize_t write_unlock_fs(struct file *file, char *buf, size_t size);
@@ -76,13 +66,6 @@ static ssize_t write_recoverydir(struct file *file, char *buf, size_t size);
 #endif
 
 static ssize_t (*write_op[])(struct file *, char *, size_t) = {
-       [NFSD_Svc] = write_svc,
-       [NFSD_Add] = write_add,
-       [NFSD_Del] = write_del,
-       [NFSD_Export] = write_export,
-       [NFSD_Unexport] = write_unexport,
-       [NFSD_Getfd] = write_getfd,
-       [NFSD_Getfs] = write_getfs,
        [NFSD_Fh] = write_filehandle,
        [NFSD_FO_UnlockIP] = write_unlock_ip,
        [NFSD_FO_UnlockFS] = write_unlock_fs,
@@ -137,6 +120,7 @@ static const struct file_operations transaction_ops = {
        .write          = nfsctl_transaction_write,
        .read           = nfsctl_transaction_read,
        .release        = simple_transaction_release,
+       .llseek         = default_llseek,
 };
 
 static int exports_open(struct inode *inode, struct file *file)
@@ -170,6 +154,26 @@ static struct file_operations export_features_operations = {
        .release        = single_release,
 };
 
+#if defined(CONFIG_SUNRPC_GSS) || defined(CONFIG_SUNRPC_GSS_MODULE)
+static int supported_enctypes_show(struct seq_file *m, void *v)
+{
+       seq_printf(m, KRB5_SUPPORTED_ENCTYPES);
+       return 0;
+}
+
+static int supported_enctypes_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, supported_enctypes_show, NULL);
+}
+
+static struct file_operations supported_enctypes_ops = {
+       .open           = supported_enctypes_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+#endif /* CONFIG_SUNRPC_GSS or CONFIG_SUNRPC_GSS_MODULE */
+
 extern int nfsd_pool_stats_open(struct inode *inode, struct file *file);
 extern int nfsd_pool_stats_release(struct inode *inode, struct file *file);
 
@@ -186,301 +190,6 @@ static const struct file_operations pool_stats_operations = {
  * payload - write methods
  */
 
-/**
- * write_svc - Start kernel's NFSD server
- *
- * Deprecated.  /proc/fs/nfsd/threads is preferred.
- * Function remains to support old versions of nfs-utils.
- *
- * Input:
- *                     buf:    struct nfsctl_svc
- *                             svc_port:       port number of this
- *                                             server's listener
- *                             svc_nthreads:   number of threads to start
- *                     size:   size in bytes of passed in nfsctl_svc
- * Output:
- *     On success:     returns zero
- *     On error:       return code is negative errno value
- */
-static ssize_t write_svc(struct file *file, char *buf, size_t size)
-{
-       struct nfsctl_svc *data;
-       int err;
-       if (size < sizeof(*data))
-               return -EINVAL;
-       data = (struct nfsctl_svc*) buf;
-       err = nfsd_svc(data->svc_port, data->svc_nthreads);
-       if (err < 0)
-               return err;
-       return 0;
-}
-
-/**
- * write_add - Add or modify client entry in auth unix cache
- *
- * Deprecated.  /proc/net/rpc/auth.unix.ip is preferred.
- * Function remains to support old versions of nfs-utils.
- *
- * Input:
- *                     buf:    struct nfsctl_client
- *                             cl_ident:       '\0'-terminated C string
- *                                             containing domain name
- *                                             of client
- *                             cl_naddr:       no. of items in cl_addrlist
- *                             cl_addrlist:    array of client addresses
- *                             cl_fhkeytype:   ignored
- *                             cl_fhkeylen:    ignored
- *                             cl_fhkey:       ignored
- *                     size:   size in bytes of passed in nfsctl_client
- * Output:
- *     On success:     returns zero
- *     On error:       return code is negative errno value
- *
- * Note: Only AF_INET client addresses are passed in, since
- * nfsctl_client.cl_addrlist contains only in_addr fields for addresses.
- */
-static ssize_t write_add(struct file *file, char *buf, size_t size)
-{
-       struct nfsctl_client *data;
-       if (size < sizeof(*data))
-               return -EINVAL;
-       data = (struct nfsctl_client *)buf;
-       return exp_addclient(data);
-}
-
-/**
- * write_del - Remove client from auth unix cache
- *
- * Deprecated.  /proc/net/rpc/auth.unix.ip is preferred.
- * Function remains to support old versions of nfs-utils.
- *
- * Input:
- *                     buf:    struct nfsctl_client
- *                             cl_ident:       '\0'-terminated C string
- *                                             containing domain name
- *                                             of client
- *                             cl_naddr:       ignored
- *                             cl_addrlist:    ignored
- *                             cl_fhkeytype:   ignored
- *                             cl_fhkeylen:    ignored
- *                             cl_fhkey:       ignored
- *                     size:   size in bytes of passed in nfsctl_client
- * Output:
- *     On success:     returns zero
- *     On error:       return code is negative errno value
- *
- * Note: Only AF_INET client addresses are passed in, since
- * nfsctl_client.cl_addrlist contains only in_addr fields for addresses.
- */
-static ssize_t write_del(struct file *file, char *buf, size_t size)
-{
-       struct nfsctl_client *data;
-       if (size < sizeof(*data))
-               return -EINVAL;
-       data = (struct nfsctl_client *)buf;
-       return exp_delclient(data);
-}
-
-/**
- * write_export - Export part or all of a local file system
- *
- * Deprecated.  /proc/net/rpc/{nfsd.export,nfsd.fh} are preferred.
- * Function remains to support old versions of nfs-utils.
- *
- * Input:
- *                     buf:    struct nfsctl_export
- *                             ex_client:      '\0'-terminated C string
- *                                             containing domain name
- *                                             of client allowed to access
- *                                             this export
- *                             ex_path:        '\0'-terminated C string
- *                                             containing pathname of
- *                                             directory in local file system
- *                             ex_dev:         fsid to use for this export
- *                             ex_ino:         ignored
- *                             ex_flags:       export flags for this export
- *                             ex_anon_uid:    UID to use for anonymous
- *                                             requests
- *                             ex_anon_gid:    GID to use for anonymous
- *                                             requests
- *                     size:   size in bytes of passed in nfsctl_export
- * Output:
- *     On success:     returns zero
- *     On error:       return code is negative errno value
- */
-static ssize_t write_export(struct file *file, char *buf, size_t size)
-{
-       struct nfsctl_export *data;
-       if (size < sizeof(*data))
-               return -EINVAL;
-       data = (struct nfsctl_export*)buf;
-       return exp_export(data);
-}
-
-/**
- * write_unexport - Unexport a previously exported file system
- *
- * Deprecated.  /proc/net/rpc/{nfsd.export,nfsd.fh} are preferred.
- * Function remains to support old versions of nfs-utils.
- *
- * Input:
- *                     buf:    struct nfsctl_export
- *                             ex_client:      '\0'-terminated C string
- *                                             containing domain name
- *                                             of client no longer allowed
- *                                             to access this export
- *                             ex_path:        '\0'-terminated C string
- *                                             containing pathname of
- *                                             directory in local file system
- *                             ex_dev:         ignored
- *                             ex_ino:         ignored
- *                             ex_flags:       ignored
- *                             ex_anon_uid:    ignored
- *                             ex_anon_gid:    ignored
- *                     size:   size in bytes of passed in nfsctl_export
- * Output:
- *     On success:     returns zero
- *     On error:       return code is negative errno value
- */
-static ssize_t write_unexport(struct file *file, char *buf, size_t size)
-{
-       struct nfsctl_export *data;
-
-       if (size < sizeof(*data))
-               return -EINVAL;
-       data = (struct nfsctl_export*)buf;
-       return exp_unexport(data);
-}
-
-/**
- * write_getfs - Get a variable-length NFS file handle by path
- *
- * Deprecated.  /proc/fs/nfsd/filehandle is preferred.
- * Function remains to support old versions of nfs-utils.
- *
- * Input:
- *                     buf:    struct nfsctl_fsparm
- *                             gd_addr:        socket address of client
- *                             gd_path:        '\0'-terminated C string
- *                                             containing pathname of
- *                                             directory in local file system
- *                             gd_maxlen:      maximum size of returned file
- *                                             handle
- *                     size:   size in bytes of passed in nfsctl_fsparm
- * Output:
- *     On success:     passed-in buffer filled with a knfsd_fh structure
- *                     (a variable-length raw NFS file handle);
- *                     return code is the size in bytes of the file handle
- *     On error:       return code is negative errno value
- *
- * Note: Only AF_INET client addresses are passed in, since gd_addr
- * is the same size as a struct sockaddr_in.
- */
-static ssize_t write_getfs(struct file *file, char *buf, size_t size)
-{
-       struct nfsctl_fsparm *data;
-       struct sockaddr_in *sin;
-       struct auth_domain *clp;
-       int err = 0;
-       struct knfsd_fh *res;
-       struct in6_addr in6;
-
-       if (size < sizeof(*data))
-               return -EINVAL;
-       data = (struct nfsctl_fsparm*)buf;
-       err = -EPROTONOSUPPORT;
-       if (data->gd_addr.sa_family != AF_INET)
-               goto out;
-       sin = (struct sockaddr_in *)&data->gd_addr;
-       if (data->gd_maxlen > NFS3_FHSIZE)
-               data->gd_maxlen = NFS3_FHSIZE;
-
-       res = (struct knfsd_fh*)buf;
-
-       exp_readlock();
-
-       ipv6_addr_set_v4mapped(sin->sin_addr.s_addr, &in6);
-
-       clp = auth_unix_lookup(&in6);
-       if (!clp)
-               err = -EPERM;
-       else {
-               err = exp_rootfh(clp, data->gd_path, res, data->gd_maxlen);
-               auth_domain_put(clp);
-       }
-       exp_readunlock();
-       if (err == 0)
-               err = res->fh_size + offsetof(struct knfsd_fh, fh_base);
- out:
-       return err;
-}
-
-/**
- * write_getfd - Get a fixed-length NFS file handle by path (used by mountd)
- *
- * Deprecated.  /proc/fs/nfsd/filehandle is preferred.
- * Function remains to support old versions of nfs-utils.
- *
- * Input:
- *                     buf:    struct nfsctl_fdparm
- *                             gd_addr:        socket address of client
- *                             gd_path:        '\0'-terminated C string
- *                                             containing pathname of
- *                                             directory in local file system
- *                             gd_version:     fdparm structure version
- *                     size:   size in bytes of passed in nfsctl_fdparm
- * Output:
- *     On success:     passed-in buffer filled with nfsctl_res
- *                     (a fixed-length raw NFS file handle);
- *                     return code is the size in bytes of the file handle
- *     On error:       return code is negative errno value
- *
- * Note: Only AF_INET client addresses are passed in, since gd_addr
- * is the same size as a struct sockaddr_in.
- */
-static ssize_t write_getfd(struct file *file, char *buf, size_t size)
-{
-       struct nfsctl_fdparm *data;
-       struct sockaddr_in *sin;
-       struct auth_domain *clp;
-       int err = 0;
-       struct knfsd_fh fh;
-       char *res;
-       struct in6_addr in6;
-
-       if (size < sizeof(*data))
-               return -EINVAL;
-       data = (struct nfsctl_fdparm*)buf;
-       err = -EPROTONOSUPPORT;
-       if (data->gd_addr.sa_family != AF_INET)
-               goto out;
-       err = -EINVAL;
-       if (data->gd_version < 2 || data->gd_version > NFSSVC_MAXVERS)
-               goto out;
-
-       res = buf;
-       sin = (struct sockaddr_in *)&data->gd_addr;
-       exp_readlock();
-
-       ipv6_addr_set_v4mapped(sin->sin_addr.s_addr, &in6);
-
-       clp = auth_unix_lookup(&in6);
-       if (!clp)
-               err = -EPERM;
-       else {
-               err = exp_rootfh(clp, data->gd_path, &fh, NFS_FHSIZE);
-               auth_domain_put(clp);
-       }
-       exp_readunlock();
-
-       if (err == 0) {
-               memset(res,0, NFS_FHSIZE);
-               memcpy(res, &fh.fh_base, fh.fh_size);
-               err = NFS_FHSIZE;
-       }
- out:
-       return err;
-}
 
 /**
  * write_unlock_ip - Release all locks used by a client
@@ -564,7 +273,7 @@ static ssize_t write_unlock_fs(struct file *file, char *buf, size_t size)
         * 2.  Is that directory a mount point, or
         * 3.  Is that directory the root of an exported file system?
         */
-       error = nlmsvc_unlock_all_by_sb(path.mnt->mnt_sb);
+       error = nlmsvc_unlock_all_by_sb(path.dentry->d_sb);
 
        path_put(&path);
        return error;
@@ -999,12 +708,12 @@ static ssize_t __write_ports_addxprt(char *buf)
        if (err != 0)
                return err;
 
-       err = svc_create_xprt(nfsd_serv, transport,
+       err = svc_create_xprt(nfsd_serv, transport, &init_net,
                                PF_INET, port, SVC_SOCK_ANONYMOUS);
        if (err < 0)
                goto out_err;
 
-       err = svc_create_xprt(nfsd_serv, transport,
+       err = svc_create_xprt(nfsd_serv, transport, &init_net,
                                PF_INET6, port, SVC_SOCK_ANONYMOUS);
        if (err < 0 && err != -EAFNOSUPPORT)
                goto out_close;
@@ -1190,7 +899,7 @@ static ssize_t write_maxblksize(struct file *file, char *buf, size_t size)
                        bsize = NFSSVC_MAXBLKSIZE;
                bsize &= ~(1024-1);
                mutex_lock(&nfsd_mutex);
-               if (nfsd_serv && nfsd_serv->sv_nrthreads) {
+               if (nfsd_serv) {
                        mutex_unlock(&nfsd_mutex);
                        return -EBUSY;
                }
@@ -1306,6 +1015,8 @@ static ssize_t __write_recoverydir(struct file *file, char *buf, size_t size)
                        return -EINVAL;
 
                status = nfs4_reset_recoverydir(recdir);
+               if (status)
+                       return status;
        }
 
        return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%s\n",
@@ -1353,13 +1064,6 @@ static ssize_t write_recoverydir(struct file *file, char *buf, size_t size)
 static int nfsd_fill_super(struct super_block * sb, void * data, int silent)
 {
        static struct tree_descr nfsd_files[] = {
-               [NFSD_Svc] = {".svc", &transaction_ops, S_IWUSR},
-               [NFSD_Add] = {".add", &transaction_ops, S_IWUSR},
-               [NFSD_Del] = {".del", &transaction_ops, S_IWUSR},
-               [NFSD_Export] = {".export", &transaction_ops, S_IWUSR},
-               [NFSD_Unexport] = {".unexport", &transaction_ops, S_IWUSR},
-               [NFSD_Getfd] = {".getfd", &transaction_ops, S_IWUSR|S_IRUSR},
-               [NFSD_Getfs] = {".getfs", &transaction_ops, S_IWUSR|S_IRUSR},
                [NFSD_List] = {"exports", &exports_operations, S_IRUGO},
                [NFSD_Export_features] = {"export_features",
                                        &export_features_operations, S_IRUGO},
@@ -1374,6 +1078,9 @@ 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},
+#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 */
 #ifdef CONFIG_NFSD_V4
                [NFSD_Leasetime] = {"nfsv4leasetime", &transaction_ops, S_IWUSR|S_IRUSR},
                [NFSD_Gracetime] = {"nfsv4gracetime", &transaction_ops, S_IWUSR|S_IRUSR},
@@ -1384,16 +1091,16 @@ static int nfsd_fill_super(struct super_block * sb, void * data, int silent)
        return simple_fill_super(sb, 0x6e667364, nfsd_files);
 }
 
-static int nfsd_get_sb(struct file_system_type *fs_type,
-       int flags, const char *dev_name, void *data, struct vfsmount *mnt)
+static struct dentry *nfsd_mount(struct file_system_type *fs_type,
+       int flags, const char *dev_name, void *data)
 {
-       return get_sb_single(fs_type, flags, data, nfsd_fill_super, mnt);
+       return mount_single(fs_type, flags, data, nfsd_fill_super);
 }
 
 static struct file_system_type nfsd_fs_type = {
        .owner          = THIS_MODULE,
        .name           = "nfsd",
-       .get_sb         = nfsd_get_sb,
+       .mount          = nfsd_mount,
        .kill_sb        = kill_litter_super,
 };
 
@@ -1422,9 +1129,13 @@ static int __init init_nfsd(void)
        int retval;
        printk(KERN_INFO "Installing knfsd (copyright (C) 1996 okir@monad.swb.de).\n");
 
-       retval = nfs4_state_init(); /* nfs4 locking state */
+       retval = nfsd4_init_slabs();
        if (retval)
                return retval;
+       nfs4_state_init();
+       retval = nfsd_fault_inject_init(); /* nfsd fault injection controls */
+       if (retval)
+               goto out_free_slabs;
        nfsd_stat_init();       /* Statistics */
        retval = nfsd_reply_cache_init();
        if (retval)
@@ -1455,6 +1166,8 @@ out_free_cache:
        nfsd_reply_cache_shutdown();
 out_free_stat:
        nfsd_stat_shutdown();
+       nfsd_fault_inject_cleanup();
+out_free_slabs:
        nfsd4_free_slabs();
        return retval;
 }
@@ -1469,6 +1182,7 @@ static void __exit exit_nfsd(void)
        nfsd_lockd_shutdown();
        nfsd_idmap_shutdown();
        nfsd4_free_slabs();
+       nfsd_fault_inject_cleanup();
        unregister_filesystem(&nfsd_fs_type);
 }