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 = {
.destroy_msg = idmap_pipe_destroy_msg,
};
void *
nfs_idmap_new(struct nfs_server *server)
void
nfs_idmap_new(struct nfs4_client *clp)
{
struct idmap *idmap;
if (clp->cl_idmap != NULL)
return;
if ((idmap = kmalloc(sizeof(*idmap), GFP_KERNEL)) == NULL)
return (NULL);
return;
memset(idmap, 0, sizeof(*idmap));
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_upcall_ops, 0);
if (IS_ERR(idmap->idmap_dentry))
goto err_free;
if (IS_ERR(idmap->idmap_dentry)) {
kfree(idmap);
return;
}
init_MUTEX(&idmap->idmap_lock);
init_MUTEX(&idmap->idmap_im_lock);
......@@ -112,22 +116,18 @@ nfs_idmap_new(struct nfs_server *server)
idmap->idmap_user_hash.h_type = IDMAP_TYPE_USER;
idmap->idmap_group_hash.h_type = IDMAP_TYPE_GROUP;
return (idmap);
err_free:
kfree(idmap);
return (NULL);
clp->cl_idmap = idmap;
}
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)
return;
rpc_unlink(idmap->idmap_path);
server->idmap = NULL;
clp->cl_idmap = NULL;
kfree(idmap);
}
......@@ -468,29 +468,29 @@ static unsigned int fnvhash32(const void *buf, size_t buflen)
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);
}
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);
}
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);
}
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);
}
......
......@@ -158,11 +158,6 @@ nfs_put_super(struct super_block *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);
if (server->client != NULL)
......@@ -1494,6 +1489,7 @@ static int nfs4_fill_super(struct super_block *sb, struct nfs4_mount_data *data,
clp->cl_rpcclient = clnt;
clp->cl_cred = rpcauth_lookupcred(clnt->cl_auth, 0);
memcpy(clp->cl_ipaddr, server->ip_addr, sizeof(clp->cl_ipaddr));
nfs_idmap_new(clp);
}
if (list_empty(&clp->cl_superblocks))
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,
printk(KERN_WARNING "NFS: cannot create RPC client.\n");
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_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,
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;
err = nfs_sb_init(sb, authflavour);
if (err == 0)
return 0;
rpciod_down();
if (server->idmap != NULL)
nfs_idmap_delete(server);
out_shutdown:
rpc_shutdown_client(server->client);
out_remove_list:
......
......@@ -41,6 +41,7 @@
#include <linux/config.h>
#include <linux/slab.h>
#include <linux/nfs_fs.h>
#include <linux/nfs_idmap.h>
#include <linux/workqueue.h>
#define OPENOWNER_POOL_SIZE 8
......@@ -124,6 +125,7 @@ nfs4_free_client(struct nfs4_client *clp)
BUG_ON(!list_empty(&clp->cl_state_owners));
if (clp->cl_cred)
put_rpccred(clp->cl_cred);
nfs_idmap_delete(clp);
if (clp->cl_rpcclient)
rpc_shutdown_client(clp->cl_rpcclient);
kfree(clp);
......
......@@ -328,7 +328,7 @@ encode_attrs(struct xdr_stream *xdr, struct iattr *iap,
if (iap->ia_valid & ATTR_MODE)
len += 4;
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) {
printk(KERN_WARNING "nfs: couldn't resolve uid %d to string\n",
iap->ia_uid);
......@@ -340,7 +340,7 @@ encode_attrs(struct xdr_stream *xdr, struct iattr *iap,
len += 4 + (XDR_QUADLEN(owner_namelen) << 2);
}
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) {
printk(KERN_WARNING "nfs4: couldn't resolve gid %d to string\n",
iap->ia_gid);
......@@ -1677,7 +1677,7 @@ decode_getattr(struct xdr_stream *xdr, struct nfs4_getattr *getattr,
}
READ_BUF(dummy32);
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) {
dprintk("read_attrs: name-to-uid mapping failed!\n");
nfp->uid = -2;
......@@ -1694,7 +1694,7 @@ decode_getattr(struct xdr_stream *xdr, struct nfs4_getattr *getattr,
}
READ_BUF(dummy32);
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) {
dprintk("read_attrs: group-to-gid mapping failed!\n");
nfp->gid = -2;
......
......@@ -438,6 +438,8 @@ extern void * nfs_root_data(void);
#ifdef CONFIG_NFS_V4
struct idmap;
/*
* In a seqid-mutating op, this macro controls which error return
* values trigger incrementation of the seqid.
......@@ -506,6 +508,9 @@ struct nfs4_client {
wait_queue_head_t cl_waitq;
struct rpc_wait_queue cl_rpcwaitq;
/* idmapper */
struct idmap * cl_idmap;
/* Our own IP address, as a null-terminated string.
* This is used to generate the clientid, and the callback address.
*/
......
......@@ -38,7 +38,6 @@ struct nfs_server {
struct list_head nfs4_siblings; /* List of other nfs_server structs
* that share the same clientid
*/
void *idmap;
#endif
};
......
......@@ -60,13 +60,13 @@ struct idmap_msg {
};
#ifdef __KERNEL__
void *nfs_idmap_new(struct nfs_server *);
void nfs_idmap_delete(struct nfs_server *);
void nfs_idmap_new(struct nfs4_client *);
void nfs_idmap_delete(struct nfs4_client *);
int nfs_map_name_to_uid(struct nfs_server *, const char *, size_t, __u32 *);
int nfs_map_group_to_gid(struct nfs_server *, const char *, size_t, __u32 *);
int nfs_map_uid_to_name(struct nfs_server *, __u32, char *);
int nfs_map_gid_to_group(struct nfs_server *, __u32, char *);
int nfs_map_name_to_uid(struct nfs4_client *, 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 nfs4_client *, __u32, char *);
int nfs_map_gid_to_group(struct nfs4_client *, __u32, char *);
#endif /* __KERNEL__ */
#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