From: Trond Myklebust <trond.myklebust@fys.uio.no>

NFSv4: Fix a bug which was causing Oopses if the client was mounting more
than one partition from the same server.


---

 fs/nfs/idmap.c            |   44 ++++++++++++++++++++++----------------------
 fs/nfs/inode.c            |   15 +++++----------
 fs/nfs/nfs4state.c        |    2 ++
 fs/nfs/nfs4xdr.c          |    8 ++++----
 include/linux/nfs_fs.h    |    5 +++++
 include/linux/nfs_fs_sb.h |    1 -
 include/linux/nfs_idmap.h |   12 ++++++------
 7 files changed, 44 insertions(+), 43 deletions(-)

diff -puN fs/nfs/idmap.c~nfs-29-fix_idmap3 fs/nfs/idmap.c
--- 25/fs/nfs/idmap.c~nfs-29-fix_idmap3	2004-01-14 02:10:04.000000000 -0800
+++ 25-akpm/fs/nfs/idmap.c	2004-01-14 02:10:04.000000000 -0800
@@ -88,23 +88,27 @@ static struct rpc_pipe_ops idmap_upcall_
         .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
 	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);
 }
diff -puN fs/nfs/inode.c~nfs-29-fix_idmap3 fs/nfs/inode.c
--- 25/fs/nfs/inode.c~nfs-29-fix_idmap3	2004-01-14 02:10:04.000000000 -0800
+++ 25-akpm/fs/nfs/inode.c	2004-01-14 02:10:04.000000000 -0800
@@ -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_
 		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_
 		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_
 		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:
diff -puN fs/nfs/nfs4state.c~nfs-29-fix_idmap3 fs/nfs/nfs4state.c
--- 25/fs/nfs/nfs4state.c~nfs-29-fix_idmap3	2004-01-14 02:10:04.000000000 -0800
+++ 25-akpm/fs/nfs/nfs4state.c	2004-01-14 02:10:04.000000000 -0800
@@ -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);
diff -puN fs/nfs/nfs4xdr.c~nfs-29-fix_idmap3 fs/nfs/nfs4xdr.c
--- 25/fs/nfs/nfs4xdr.c~nfs-29-fix_idmap3	2004-01-14 02:10:04.000000000 -0800
+++ 25-akpm/fs/nfs/nfs4xdr.c	2004-01-14 02:10:04.000000000 -0800
@@ -328,7 +328,7 @@ encode_attrs(struct xdr_stream *xdr, str
 	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, str
 		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, s
 		}
 		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, s
 		}
 		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;
diff -puN include/linux/nfs_fs.h~nfs-29-fix_idmap3 include/linux/nfs_fs.h
--- 25/include/linux/nfs_fs.h~nfs-29-fix_idmap3	2004-01-14 02:10:04.000000000 -0800
+++ 25-akpm/include/linux/nfs_fs.h	2004-01-14 02:10:04.000000000 -0800
@@ -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.
 	 */
diff -puN include/linux/nfs_fs_sb.h~nfs-29-fix_idmap3 include/linux/nfs_fs_sb.h
--- 25/include/linux/nfs_fs_sb.h~nfs-29-fix_idmap3	2004-01-14 02:10:04.000000000 -0800
+++ 25-akpm/include/linux/nfs_fs_sb.h	2004-01-14 02:10:04.000000000 -0800
@@ -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
 };
 
diff -puN include/linux/nfs_idmap.h~nfs-29-fix_idmap3 include/linux/nfs_idmap.h
--- 25/include/linux/nfs_idmap.h~nfs-29-fix_idmap3	2004-01-14 02:10:04.000000000 -0800
+++ 25-akpm/include/linux/nfs_idmap.h	2004-01-14 02:10:04.000000000 -0800
@@ -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 */

_