NFSv4: Send unmapped uid/gids to the server when using auth_sys
authorTrond Myklebust <Trond.Myklebust@netapp.com>
Tue, 22 Feb 2011 23:44:32 +0000 (15:44 -0800)
committerTrond Myklebust <Trond.Myklebust@netapp.com>
Fri, 11 Mar 2011 20:39:27 +0000 (15:39 -0500)
The new behaviour is enabled using the new module parameter
'nfs4_disable_idmapping'.

Note that if the server rejects an unmapped uid or gid, then
the client will automatically switch back to using the idmapper.

Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Documentation/kernel-parameters.txt
fs/nfs/client.c
fs/nfs/idmap.c
fs/nfs/nfs4proc.c
include/linux/nfs_fs_sb.h

index f4a04c0..14dcf1b 100644 (file)
@@ -1580,6 +1580,14 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        of returning the full 64-bit number.
                        The default is to return 64-bit inode numbers.
 
+       nfs.nfs4_disable_idmapping=
+                       [NFSv4] When set, this option disables the NFSv4
+                       idmapper on the client, but only if the mount
+                       is using the 'sec=sys' security flavour. This may
+                       make migration from legacy NFSv2/v3 systems easier
+                       provided that the server has the appropriate support.
+                       The default is to always enable NFSv4 idmapping.
+
        nmi_debug=      [KNL,AVR32,SH] Specify one or more actions to take
                        when a NMI is triggered.
                        Format: [state][,regs][,debounce][,die]
index 6dd50ac..139be96 100644 (file)
@@ -82,6 +82,11 @@ retry:
 #endif /* CONFIG_NFS_V4 */
 
 /*
+ * Turn off NFSv4 uid/gid mapping when using AUTH_SYS
+ */
+static int nfs4_disable_idmapping = 0;
+
+/*
  * RPC cruft for NFS
  */
 static struct rpc_version *nfs_version[5] = {
@@ -1567,6 +1572,13 @@ static int nfs4_init_server(struct nfs_server *server,
        if (error < 0)
                goto error;
 
+       /*
+        * Don't use NFS uid/gid mapping if we're using AUTH_SYS or lower
+        * authentication.
+        */
+       if (nfs4_disable_idmapping && data->auth_flavors[0] == RPC_AUTH_UNIX)
+               server->caps |= NFS_CAP_UIDGID_NOMAP;
+
        if (data->rsize)
                server->rsize = nfs_block_size(data->rsize, NULL);
        if (data->wsize)
@@ -1984,3 +1996,7 @@ void nfs_fs_proc_exit(void)
 }
 
 #endif /* CONFIG_PROC_FS */
+
+module_param(nfs4_disable_idmapping, bool, 0644);
+MODULE_PARM_DESC(nfs4_disable_idmapping,
+               "Turn off NFSv4 idmapping when using 'sec=sys'");
index e2d579d..79664a1 100644 (file)
@@ -61,6 +61,9 @@ static int nfs_map_numeric_to_string(__u32 id, char *buf, size_t buflen)
 
 #include <linux/slab.h>
 #include <linux/cred.h>
+#include <linux/sunrpc/sched.h>
+#include <linux/nfs4.h>
+#include <linux/nfs_fs_sb.h>
 #include <linux/nfs_idmap.h>
 #include <linux/keyctl.h>
 #include <linux/key-type.h>
@@ -257,17 +260,20 @@ int nfs_map_group_to_gid(const struct nfs_server *server, const char *name, size
 
 int nfs_map_uid_to_name(const struct nfs_server *server, __u32 uid, char *buf, size_t buflen)
 {
-       int ret;
-       ret = nfs_idmap_lookup_name(uid, "user", buf, buflen);
+       int ret = -EINVAL;
+
+       if (!(server->caps & NFS_CAP_UIDGID_NOMAP))
+               ret = nfs_idmap_lookup_name(uid, "user", buf, buflen);
        if (ret < 0)
                ret = nfs_map_numeric_to_string(uid, buf, buflen);
        return ret;
 }
 int nfs_map_gid_to_group(const struct nfs_server *server, __u32 gid, char *buf, size_t buflen)
 {
-       int ret;
+       int ret = -EINVAL;
 
-       ret = nfs_idmap_lookup_name(gid, "group", buf, buflen);
+       if (!(server->caps & NFS_CAP_UIDGID_NOMAP))
+               ret = nfs_idmap_lookup_name(gid, "group", buf, buflen);
        if (ret < 0)
                ret = nfs_map_numeric_to_string(gid, buf, buflen);
        return ret;
@@ -750,9 +756,10 @@ int nfs_map_group_to_gid(const struct nfs_server *server, const char *name, size
 int nfs_map_uid_to_name(const struct nfs_server *server, __u32 uid, char *buf, size_t buflen)
 {
        struct idmap *idmap = server->nfs_client->cl_idmap;
-       int ret;
+       int ret = -EINVAL;
 
-       ret = nfs_idmap_name(idmap, &idmap->idmap_user_hash, uid, buf);
+       if (!(server->caps & NFS_CAP_UIDGID_NOMAP))
+               ret = nfs_idmap_name(idmap, &idmap->idmap_user_hash, uid, buf);
        if (ret < 0)
                ret = nfs_map_numeric_to_string(uid, buf, buflen);
        return ret;
@@ -760,9 +767,10 @@ int nfs_map_uid_to_name(const struct nfs_server *server, __u32 uid, char *buf, s
 int nfs_map_gid_to_group(const struct nfs_server *server, __u32 uid, char *buf, size_t buflen)
 {
        struct idmap *idmap = server->nfs_client->cl_idmap;
-       int ret;
+       int ret = -EINVAL;
 
-       ret = nfs_idmap_name(idmap, &idmap->idmap_group_hash, uid, buf);
+       if (!(server->caps & NFS_CAP_UIDGID_NOMAP))
+               ret = nfs_idmap_name(idmap, &idmap->idmap_group_hash, uid, buf);
        if (ret < 0)
                ret = nfs_map_numeric_to_string(uid, buf, buflen);
        return ret;
index 8f3ada0..1d84e70 100644 (file)
@@ -244,7 +244,7 @@ static int nfs4_delay(struct rpc_clnt *clnt, long *timeout)
 /* This is the error handling routine for processes that are allowed
  * to sleep.
  */
-static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception)
+static int nfs4_handle_exception(struct nfs_server *server, int errorcode, struct nfs4_exception *exception)
 {
        struct nfs_client *clp = server->nfs_client;
        struct nfs4_state *state = exception->state;
@@ -296,6 +296,19 @@ static int nfs4_handle_exception(const struct nfs_server *server, int errorcode,
                                break;
                case -NFS4ERR_OLD_STATEID:
                        exception->retry = 1;
+                       break;
+               case -NFS4ERR_BADOWNER:
+                       /* The following works around a Linux server bug! */
+               case -NFS4ERR_BADNAME:
+                       if (server->caps & NFS_CAP_UIDGID_NOMAP) {
+                               server->caps &= ~NFS_CAP_UIDGID_NOMAP;
+                               exception->retry = 1;
+                               printk(KERN_WARNING "NFS: v4 server %s "
+                                               "does not accept raw "
+                                               "uid/gids. "
+                                               "Reenabling the idmapper.\n",
+                                               server->nfs_client->cl_hostname);
+                       }
        }
        /* We failed to handle the error */
        return nfs4_map_errors(ret);
index 0cbf109..216cea5 100644 (file)
@@ -177,6 +177,7 @@ struct nfs_server {
 #define NFS_CAP_CTIME          (1U << 12)
 #define NFS_CAP_MTIME          (1U << 13)
 #define NFS_CAP_POSIX_LOCK     (1U << 14)
+#define NFS_CAP_UIDGID_NOMAP   (1U << 15)
 
 
 /* maximum number of slots to use */