Commit 1f37cd43 authored by Trond Myklebust's avatar Trond Myklebust

NFSv4: Fix a bug which was causing Oopses if the client was

mounting more than one partition from the same server.
parent c04e88db
...@@ -88,23 +88,27 @@ static struct rpc_pipe_ops idmap_upcall_ops = { ...@@ -88,23 +88,27 @@ static struct rpc_pipe_ops idmap_upcall_ops = {
.destroy_msg = idmap_pipe_destroy_msg, .destroy_msg = idmap_pipe_destroy_msg,
}; };
void * void
nfs_idmap_new(struct nfs_server *server) nfs_idmap_new(struct nfs4_client *clp)
{ {
struct idmap *idmap; struct idmap *idmap;
if (clp->cl_idmap != NULL)
return;
if ((idmap = kmalloc(sizeof(*idmap), GFP_KERNEL)) == NULL) if ((idmap = kmalloc(sizeof(*idmap), GFP_KERNEL)) == NULL)
return (NULL); return;
memset(idmap, 0, sizeof(*idmap)); memset(idmap, 0, sizeof(*idmap));
snprintf(idmap->idmap_path, sizeof(idmap->idmap_path), snprintf(idmap->idmap_path, sizeof(idmap->idmap_path),
"%s/idmap", server->client->cl_pathname); "%s/idmap", clp->cl_rpcclient->cl_pathname);
idmap->idmap_dentry = rpc_mkpipe(idmap->idmap_path, idmap->idmap_dentry = rpc_mkpipe(idmap->idmap_path,
idmap, &idmap_upcall_ops, 0); idmap, &idmap_upcall_ops, 0);
if (IS_ERR(idmap->idmap_dentry)) if (IS_ERR(idmap->idmap_dentry)) {
goto err_free; kfree(idmap);
return;
}
init_MUTEX(&idmap->idmap_lock); init_MUTEX(&idmap->idmap_lock);
init_MUTEX(&idmap->idmap_im_lock); init_MUTEX(&idmap->idmap_im_lock);
...@@ -112,22 +116,18 @@ nfs_idmap_new(struct nfs_server *server) ...@@ -112,22 +116,18 @@ nfs_idmap_new(struct nfs_server *server)
idmap->idmap_user_hash.h_type = IDMAP_TYPE_USER; idmap->idmap_user_hash.h_type = IDMAP_TYPE_USER;
idmap->idmap_group_hash.h_type = IDMAP_TYPE_GROUP; idmap->idmap_group_hash.h_type = IDMAP_TYPE_GROUP;
return (idmap); clp->cl_idmap = idmap;
err_free:
kfree(idmap);
return (NULL);
} }
void void
nfs_idmap_delete(struct nfs_server *server) nfs_idmap_delete(struct nfs4_client *clp)
{ {
struct idmap *idmap = server->idmap; struct idmap *idmap = clp->cl_idmap;
if (!idmap) if (!idmap)
return; return;
rpc_unlink(idmap->idmap_path); rpc_unlink(idmap->idmap_path);
server->idmap = NULL; clp->cl_idmap = NULL;
kfree(idmap); kfree(idmap);
} }
...@@ -468,29 +468,29 @@ static unsigned int fnvhash32(const void *buf, size_t buflen) ...@@ -468,29 +468,29 @@ static unsigned int fnvhash32(const void *buf, size_t buflen)
return (hash); return (hash);
} }
int nfs_map_name_to_uid(struct nfs_server *server, const char *name, size_t namelen, __u32 *uid) int nfs_map_name_to_uid(struct nfs4_client *clp, const char *name, size_t namelen, __u32 *uid)
{ {
struct idmap *idmap = server->idmap; struct idmap *idmap = clp->cl_idmap;
return nfs_idmap_id(idmap, &idmap->idmap_user_hash, name, namelen, uid); return nfs_idmap_id(idmap, &idmap->idmap_user_hash, name, namelen, uid);
} }
int nfs_map_group_to_gid(struct nfs_server *server, const char *name, size_t namelen, __u32 *uid) int nfs_map_group_to_gid(struct nfs4_client *clp, const char *name, size_t namelen, __u32 *uid)
{ {
struct idmap *idmap = server->idmap; struct idmap *idmap = clp->cl_idmap;
return nfs_idmap_id(idmap, &idmap->idmap_group_hash, name, namelen, uid); return nfs_idmap_id(idmap, &idmap->idmap_group_hash, name, namelen, uid);
} }
int nfs_map_uid_to_name(struct nfs_server *server, __u32 uid, char *buf) int nfs_map_uid_to_name(struct nfs4_client *clp, __u32 uid, char *buf)
{ {
struct idmap *idmap = server->idmap; struct idmap *idmap = clp->cl_idmap;
return nfs_idmap_name(idmap, &idmap->idmap_user_hash, uid, buf); return nfs_idmap_name(idmap, &idmap->idmap_user_hash, uid, buf);
} }
int nfs_map_gid_to_group(struct nfs_server *server, __u32 uid, char *buf) int nfs_map_gid_to_group(struct nfs4_client *clp, __u32 uid, char *buf)
{ {
struct idmap *idmap = server->idmap; struct idmap *idmap = clp->cl_idmap;
return nfs_idmap_name(idmap, &idmap->idmap_group_hash, uid, buf); return nfs_idmap_name(idmap, &idmap->idmap_group_hash, uid, buf);
} }
......
...@@ -158,11 +158,6 @@ nfs_put_super(struct super_block *sb) ...@@ -158,11 +158,6 @@ nfs_put_super(struct super_block *sb)
{ {
struct nfs_server *server = NFS_SB(sb); struct nfs_server *server = NFS_SB(sb);
#ifdef CONFIG_NFS_V4
if (server->idmap != NULL)
nfs_idmap_delete(server);
#endif /* CONFIG_NFS_V4 */
nfs4_renewd_prepare_shutdown(server); nfs4_renewd_prepare_shutdown(server);
if (server->client != NULL) if (server->client != NULL)
...@@ -1494,6 +1489,7 @@ static int nfs4_fill_super(struct super_block *sb, struct nfs4_mount_data *data, ...@@ -1494,6 +1489,7 @@ static int nfs4_fill_super(struct super_block *sb, struct nfs4_mount_data *data,
clp->cl_rpcclient = clnt; clp->cl_rpcclient = clnt;
clp->cl_cred = rpcauth_lookupcred(clnt->cl_auth, 0); clp->cl_cred = rpcauth_lookupcred(clnt->cl_auth, 0);
memcpy(clp->cl_ipaddr, server->ip_addr, sizeof(clp->cl_ipaddr)); memcpy(clp->cl_ipaddr, server->ip_addr, sizeof(clp->cl_ipaddr));
nfs_idmap_new(clp);
} }
if (list_empty(&clp->cl_superblocks)) if (list_empty(&clp->cl_superblocks))
clear_bit(NFS4CLNT_OK, &clp->cl_state); clear_bit(NFS4CLNT_OK, &clp->cl_state);
...@@ -1507,6 +1503,10 @@ static int nfs4_fill_super(struct super_block *sb, struct nfs4_mount_data *data, ...@@ -1507,6 +1503,10 @@ static int nfs4_fill_super(struct super_block *sb, struct nfs4_mount_data *data,
printk(KERN_WARNING "NFS: cannot create RPC client.\n"); printk(KERN_WARNING "NFS: cannot create RPC client.\n");
goto out_remove_list; goto out_remove_list;
} }
if (server->nfs4_state->cl_idmap == NULL) {
printk(KERN_WARNING "NFS: failed to create idmapper.\n");
goto out_shutdown;
}
clnt->cl_intr = (server->flags & NFS4_MOUNT_INTR) ? 1 : 0; clnt->cl_intr = (server->flags & NFS4_MOUNT_INTR) ? 1 : 0;
clnt->cl_softrtry = (server->flags & NFS4_MOUNT_SOFT) ? 1 : 0; clnt->cl_softrtry = (server->flags & NFS4_MOUNT_SOFT) ? 1 : 0;
...@@ -1525,16 +1525,11 @@ static int nfs4_fill_super(struct super_block *sb, struct nfs4_mount_data *data, ...@@ -1525,16 +1525,11 @@ static int nfs4_fill_super(struct super_block *sb, struct nfs4_mount_data *data,
goto out_shutdown; goto out_shutdown;
} }
if ((server->idmap = nfs_idmap_new(server)) == NULL)
printk(KERN_WARNING "NFS: couldn't start IDmap\n");
sb->s_op = &nfs4_sops; sb->s_op = &nfs4_sops;
err = nfs_sb_init(sb, authflavour); err = nfs_sb_init(sb, authflavour);
if (err == 0) if (err == 0)
return 0; return 0;
rpciod_down(); rpciod_down();
if (server->idmap != NULL)
nfs_idmap_delete(server);
out_shutdown: out_shutdown:
rpc_shutdown_client(server->client); rpc_shutdown_client(server->client);
out_remove_list: out_remove_list:
......
...@@ -41,6 +41,7 @@ ...@@ -41,6 +41,7 @@
#include <linux/config.h> #include <linux/config.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/nfs_fs.h> #include <linux/nfs_fs.h>
#include <linux/nfs_idmap.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
#define OPENOWNER_POOL_SIZE 8 #define OPENOWNER_POOL_SIZE 8
...@@ -124,6 +125,7 @@ nfs4_free_client(struct nfs4_client *clp) ...@@ -124,6 +125,7 @@ nfs4_free_client(struct nfs4_client *clp)
BUG_ON(!list_empty(&clp->cl_state_owners)); BUG_ON(!list_empty(&clp->cl_state_owners));
if (clp->cl_cred) if (clp->cl_cred)
put_rpccred(clp->cl_cred); put_rpccred(clp->cl_cred);
nfs_idmap_delete(clp);
if (clp->cl_rpcclient) if (clp->cl_rpcclient)
rpc_shutdown_client(clp->cl_rpcclient); rpc_shutdown_client(clp->cl_rpcclient);
kfree(clp); kfree(clp);
......
...@@ -328,7 +328,7 @@ encode_attrs(struct xdr_stream *xdr, struct iattr *iap, ...@@ -328,7 +328,7 @@ encode_attrs(struct xdr_stream *xdr, struct iattr *iap,
if (iap->ia_valid & ATTR_MODE) if (iap->ia_valid & ATTR_MODE)
len += 4; len += 4;
if (iap->ia_valid & ATTR_UID) { if (iap->ia_valid & ATTR_UID) {
owner_namelen = nfs_map_uid_to_name(server, iap->ia_uid, owner_name); owner_namelen = nfs_map_uid_to_name(server->nfs4_state, iap->ia_uid, owner_name);
if (owner_namelen < 0) { if (owner_namelen < 0) {
printk(KERN_WARNING "nfs: couldn't resolve uid %d to string\n", printk(KERN_WARNING "nfs: couldn't resolve uid %d to string\n",
iap->ia_uid); iap->ia_uid);
...@@ -340,7 +340,7 @@ encode_attrs(struct xdr_stream *xdr, struct iattr *iap, ...@@ -340,7 +340,7 @@ encode_attrs(struct xdr_stream *xdr, struct iattr *iap,
len += 4 + (XDR_QUADLEN(owner_namelen) << 2); len += 4 + (XDR_QUADLEN(owner_namelen) << 2);
} }
if (iap->ia_valid & ATTR_GID) { if (iap->ia_valid & ATTR_GID) {
owner_grouplen = nfs_map_gid_to_group(server, iap->ia_gid, owner_group); owner_grouplen = nfs_map_gid_to_group(server->nfs4_state, iap->ia_gid, owner_group);
if (owner_grouplen < 0) { if (owner_grouplen < 0) {
printk(KERN_WARNING "nfs4: couldn't resolve gid %d to string\n", printk(KERN_WARNING "nfs4: couldn't resolve gid %d to string\n",
iap->ia_gid); iap->ia_gid);
...@@ -1677,7 +1677,7 @@ decode_getattr(struct xdr_stream *xdr, struct nfs4_getattr *getattr, ...@@ -1677,7 +1677,7 @@ decode_getattr(struct xdr_stream *xdr, struct nfs4_getattr *getattr,
} }
READ_BUF(dummy32); READ_BUF(dummy32);
len += (XDR_QUADLEN(dummy32) << 2); len += (XDR_QUADLEN(dummy32) << 2);
if ((status = nfs_map_name_to_uid(server, (char *)p, dummy32, if ((status = nfs_map_name_to_uid(server->nfs4_state, (char *)p, dummy32,
&nfp->uid)) < 0) { &nfp->uid)) < 0) {
dprintk("read_attrs: name-to-uid mapping failed!\n"); dprintk("read_attrs: name-to-uid mapping failed!\n");
nfp->uid = -2; nfp->uid = -2;
...@@ -1694,7 +1694,7 @@ decode_getattr(struct xdr_stream *xdr, struct nfs4_getattr *getattr, ...@@ -1694,7 +1694,7 @@ decode_getattr(struct xdr_stream *xdr, struct nfs4_getattr *getattr,
} }
READ_BUF(dummy32); READ_BUF(dummy32);
len += (XDR_QUADLEN(dummy32) << 2); len += (XDR_QUADLEN(dummy32) << 2);
if ((status = nfs_map_group_to_gid(server, (char *)p, dummy32, if ((status = nfs_map_group_to_gid(server->nfs4_state, (char *)p, dummy32,
&nfp->gid)) < 0) { &nfp->gid)) < 0) {
dprintk("read_attrs: group-to-gid mapping failed!\n"); dprintk("read_attrs: group-to-gid mapping failed!\n");
nfp->gid = -2; nfp->gid = -2;
......
...@@ -438,6 +438,8 @@ extern void * nfs_root_data(void); ...@@ -438,6 +438,8 @@ extern void * nfs_root_data(void);
#ifdef CONFIG_NFS_V4 #ifdef CONFIG_NFS_V4
struct idmap;
/* /*
* In a seqid-mutating op, this macro controls which error return * In a seqid-mutating op, this macro controls which error return
* values trigger incrementation of the seqid. * values trigger incrementation of the seqid.
...@@ -506,6 +508,9 @@ struct nfs4_client { ...@@ -506,6 +508,9 @@ struct nfs4_client {
wait_queue_head_t cl_waitq; wait_queue_head_t cl_waitq;
struct rpc_wait_queue cl_rpcwaitq; struct rpc_wait_queue cl_rpcwaitq;
/* idmapper */
struct idmap * cl_idmap;
/* Our own IP address, as a null-terminated string. /* Our own IP address, as a null-terminated string.
* This is used to generate the clientid, and the callback address. * This is used to generate the clientid, and the callback address.
*/ */
......
...@@ -38,7 +38,6 @@ struct nfs_server { ...@@ -38,7 +38,6 @@ struct nfs_server {
struct list_head nfs4_siblings; /* List of other nfs_server structs struct list_head nfs4_siblings; /* List of other nfs_server structs
* that share the same clientid * that share the same clientid
*/ */
void *idmap;
#endif #endif
}; };
......
...@@ -60,13 +60,13 @@ struct idmap_msg { ...@@ -60,13 +60,13 @@ struct idmap_msg {
}; };
#ifdef __KERNEL__ #ifdef __KERNEL__
void *nfs_idmap_new(struct nfs_server *); void nfs_idmap_new(struct nfs4_client *);
void nfs_idmap_delete(struct nfs_server *); void nfs_idmap_delete(struct nfs4_client *);
int nfs_map_name_to_uid(struct nfs_server *, const char *, size_t, __u32 *); int nfs_map_name_to_uid(struct nfs4_client *, const char *, size_t, __u32 *);
int nfs_map_group_to_gid(struct nfs_server *, const char *, size_t, __u32 *); int nfs_map_group_to_gid(struct nfs4_client *, const char *, size_t, __u32 *);
int nfs_map_uid_to_name(struct nfs_server *, __u32, char *); int nfs_map_uid_to_name(struct nfs4_client *, __u32, char *);
int nfs_map_gid_to_group(struct nfs_server *, __u32, char *); int nfs_map_gid_to_group(struct nfs4_client *, __u32, char *);
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
#endif /* NFS_IDMAP_H */ #endif /* NFS_IDMAP_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment