From: Trond Myklebust NFSv4/RPCSEC_GSS: Make Frank's server->client_sys feature use RPC cloning in order to avoid duplicating sockets etc. Make NFSv4 share a single socket for all communication to the same server. --- fs/nfs/inode.c | 67 ++++++++++++++++++++++++++++++++++++++----------- fs/nfs/nfs4proc.c | 6 ---- fs/nfs/nfs4state.c | 4 ++ include/linux/nfs_fs.h | 15 +++++----- 4 files changed, 65 insertions(+), 27 deletions(-) diff -puN fs/nfs/inode.c~nfs-17-rpc_clone2 fs/nfs/inode.c --- 25/fs/nfs/inode.c~nfs-17-rpc_clone2 2004-01-14 02:09:43.000000000 -0800 +++ 25-akpm/fs/nfs/inode.c 2004-01-14 02:09:43.000000000 -0800 @@ -493,10 +493,17 @@ nfs_fill_super(struct super_block *sb, s server->client = nfs_create_client(server, data); if (server->client == NULL) goto out_fail; - data->pseudoflavor = RPC_AUTH_UNIX; /* RFC 2623, sec 2.3.2 */ - server->client_sys = nfs_create_client(server, data); - if (server->client_sys == NULL) - goto out_shutdown; + /* RFC 2623, sec 2.3.2 */ + if (authflavor != RPC_AUTH_UNIX) { + server->client_sys = rpc_clone_client(server->client); + if (server->client_sys == NULL) + goto out_shutdown; + if (!rpcauth_create(RPC_AUTH_UNIX, server->client_sys)) + goto out_shutdown; + } else { + atomic_inc(&server->client->cl_count); + server->client_sys = server->client; + } /* Fire up rpciod if not yet running */ if (rpciod_up() != 0) { @@ -1349,6 +1356,7 @@ static struct file_system_type nfs_fs_ty static int nfs4_fill_super(struct super_block *sb, struct nfs4_mount_data *data, int silent) { struct nfs_server *server; + struct nfs4_client *clp = NULL; struct rpc_xprt *xprt = NULL; struct rpc_clnt *clnt = NULL; struct rpc_timeout timeparms; @@ -1398,13 +1406,13 @@ static int nfs4_fill_super(struct super_ return -EINVAL; } - /* Now create transport and client */ - xprt = xprt_create_proto(proto, &server->addr, &timeparms); - if (xprt == NULL) { - printk(KERN_WARNING "NFS: cannot create RPC transport.\n"); + clp = nfs4_get_client(&server->addr.sin_addr); + if (!clp) { + printk(KERN_WARNING "NFS: failed to create NFS4 client.\n"); goto out_fail; } + /* Now create transport and client */ authflavour = RPC_AUTH_UNIX; if (data->auth_flavourlen != 0) { if (data->auth_flavourlen > 1) @@ -1414,34 +1422,61 @@ static int nfs4_fill_super(struct super_ goto out_fail; } } - clnt = rpc_create_client(xprt, server->hostname, &nfs_program, - server->rpc_ops->version, authflavour); + + down_write(&clp->cl_sem); + if (clp->cl_rpcclient == NULL) { + xprt = xprt_create_proto(proto, &server->addr, &timeparms); + if (xprt == NULL) { + up_write(&clp->cl_sem); + printk(KERN_WARNING "NFS: cannot create RPC transport.\n"); + goto out_fail; + } + clnt = rpc_create_client(xprt, server->hostname, &nfs_program, + server->rpc_ops->version, authflavour); + if (clnt == NULL) { + up_write(&clp->cl_sem); + printk(KERN_WARNING "NFS: cannot create RPC client.\n"); + xprt_destroy(xprt); + goto out_fail; + } + clnt->cl_chatty = 1; + clp->cl_rpcclient = clnt; + clp->cl_cred = rpcauth_lookupcred(clnt->cl_auth, 0); + memcpy(clp->cl_ipaddr, server->ip_addr, sizeof(clp->cl_ipaddr)); + } + clnt = rpc_clone_client(clp->cl_rpcclient); + server->nfs4_state = clp; + up_write(&clp->cl_sem); + if (clnt == NULL) { printk(KERN_WARNING "NFS: cannot create RPC client.\n"); - xprt_destroy(xprt); goto out_fail; } clnt->cl_intr = (server->flags & NFS4_MOUNT_INTR) ? 1 : 0; clnt->cl_softrtry = (server->flags & NFS4_MOUNT_SOFT) ? 1 : 0; - clnt->cl_chatty = 1; server->client = clnt; + if (clnt->cl_auth->au_flavor != authflavour) { + if (rpcauth_create(authflavour, clnt) == NULL) { + printk(KERN_WARNING "NFS: couldn't create credcache!\n"); + goto out_shutdown; + } + } + /* Fire up rpciod if not yet running */ if (rpciod_up() != 0) { printk(KERN_WARNING "NFS: couldn't start rpciod!\n"); goto out_shutdown; } - if (create_nfsv4_state(server, data)) - goto out_shutdown; - if ((server->idmap = nfs_idmap_new(server)) == NULL) printk(KERN_WARNING "NFS: couldn't start IDmap\n"); err = nfs_sb_init(sb, authflavour); if (err == 0) return 0; + clp = NULL; rpciod_down(); destroy_nfsv4_state(server); if (server->idmap != NULL) @@ -1449,6 +1484,8 @@ static int nfs4_fill_super(struct super_ out_shutdown: rpc_shutdown_client(server->client); out_fail: + if (clp) + nfs4_put_client(clp); return err; } diff -puN fs/nfs/nfs4proc.c~nfs-17-rpc_clone2 fs/nfs/nfs4proc.c --- 25/fs/nfs/nfs4proc.c~nfs-17-rpc_clone2 2004-01-14 02:09:43.000000000 -0800 +++ 25-akpm/fs/nfs/nfs4proc.c 2004-01-14 02:09:45.000000000 -0800 @@ -762,9 +762,7 @@ nfs4_proc_get_root(struct nfs_server *se struct qstr q; int status; - clp = server->nfs4_state = nfs4_get_client(&server->addr.sin_addr); - if (!clp) - return -ENOMEM; + clp = server->nfs4_state; down_write(&clp->cl_sem); /* Has the clientid already been initialized? */ @@ -850,8 +848,6 @@ no_setclientid: return status; out_unlock: up_write(&clp->cl_sem); - nfs4_put_client(clp); - server->nfs4_state = NULL; return status; } diff -puN fs/nfs/nfs4state.c~nfs-17-rpc_clone2 fs/nfs/nfs4state.c --- 25/fs/nfs/nfs4state.c~nfs-17-rpc_clone2 2004-01-14 02:09:43.000000000 -0800 +++ 25-akpm/fs/nfs/nfs4state.c 2004-01-14 02:09:43.000000000 -0800 @@ -93,6 +93,10 @@ nfs4_free_client(struct nfs4_client *clp kfree(sp); } BUG_ON(!list_empty(&clp->cl_state_owners)); + if (clp->cl_cred) + put_rpccred(clp->cl_cred); + if (clp->cl_rpcclient) + rpc_shutdown_client(clp->cl_rpcclient); kfree(clp); } diff -puN include/linux/nfs_fs.h~nfs-17-rpc_clone2 include/linux/nfs_fs.h --- 25/include/linux/nfs_fs.h~nfs-17-rpc_clone2 2004-01-14 02:09:43.000000000 -0800 +++ 25-akpm/include/linux/nfs_fs.h 2004-01-14 02:09:45.000000000 -0800 @@ -489,6 +489,14 @@ struct nfs4_client { int cl_nunused; spinlock_t cl_lock; atomic_t cl_count; + + struct rpc_clnt * cl_rpcclient; + struct rpc_cred * cl_cred; + + /* Our own IP address, as a null-terminated string. + * This is used to generate the clientid, and the callback address. + */ + char cl_ipaddr[16]; }; /* @@ -558,13 +566,6 @@ extern void nfs4_increment_seqid(u32 sta struct nfs4_mount_data; -static inline int -create_nfsv4_state(struct nfs_server *server, struct nfs4_mount_data *data) -{ - server->nfs4_state = NULL; - return 0; -} - static inline void destroy_nfsv4_state(struct nfs_server *server) { _