From: Trond Myklebust 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 #include #include +#include #include #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 */ _