diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2011-02-23 00:44:32 +0100 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2011-03-11 21:39:27 +0100 |
commit | b064eca2cf6440bf9d5843b24cc4010624031694 (patch) | |
tree | f1024db40bf0afb7b764d6ee825d24cd715d1cc5 /fs/nfs | |
parent | NFSv4: Propagate the error NFS4ERR_BADOWNER to nfs4_do_setattr (diff) | |
download | linux-b064eca2cf6440bf9d5843b24cc4010624031694.tar.xz linux-b064eca2cf6440bf9d5843b24cc4010624031694.zip |
NFSv4: Send unmapped uid/gids to the server when using auth_sys
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>
Diffstat (limited to 'fs/nfs')
-rw-r--r-- | fs/nfs/client.c | 16 | ||||
-rw-r--r-- | fs/nfs/idmap.c | 24 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 15 |
3 files changed, 46 insertions, 9 deletions
diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 6dd50ac5b545..139be9647d80 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c @@ -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'"); diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c index e2d579d458f1..79664a1025af 100644 --- a/fs/nfs/idmap.c +++ b/fs/nfs/idmap.c @@ -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; diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 8f3ada04ea19..1d84e7088af9 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -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); |