NFS: Fix an Oops in the pNFS files and flexfiles connection setup to the DS
Chris Worley reports:
RIP: 0010:[<ffffffffa0245f80>] [<ffffffffa0245f80>] rpc_new_client+0x2a0/0x2e0 [sunrpc]
RSP: 0018:ffff880158f6f548 EFLAGS: 00010246
RAX: 0000000000000000 RBX: ffff880234f8bc00 RCX: 000000000000ea60
RDX: 0000000000074cc0 RSI: 000000000000ea60 RDI: ffff880234f8bcf0
RBP: ffff880158f6f588 R08: 000000000001ac80 R09: ffff880237003300
R10: ffff880201171000 R11: ffffea0000d75200 R12: ffffffffa03afc60
R13: ffff880230c18800 R14: 0000000000000000 R15: ffff880158f6f680
FS: 00007f0e32673740(0000) GS:ffff88023fc40000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b
CR2: 0000000000000008 CR3: 0000000234886000 CR4: 00000000001406e0
Stack:
ffffffffa047a680 0000000000000000 ffff880158f6f598 ffff880158f6f680
ffff880158f6f680 ffff880234d11d00 ffff88023357f800 ffff880158f6f7d0
ffff880158f6f5b8 ffffffffa024660a ffff880158f6f5b8 ffffffffa02492ec
Call Trace:
[<ffffffffa024660a>] rpc_create_xprt+0x1a/0xb0 [sunrpc]
[<ffffffffa02492ec>] ? xprt_create_transport+0x13c/0x240 [sunrpc]
[<ffffffffa0246766>] rpc_create+0xc6/0x1a0 [sunrpc]
[<ffffffffa038e695>] nfs_create_rpc_client+0xf5/0x140 [nfs]
[<ffffffffa038f31a>] nfs_init_client+0x3a/0xd0 [nfs]
[<ffffffffa038f22f>] nfs_get_client+0x25f/0x310 [nfs]
[<ffffffffa025cef8>] ? rpc_ntop+0xe8/0x100 [sunrpc]
[<ffffffffa047512c>] nfs3_set_ds_client+0xcc/0x100 [nfsv3]
[<ffffffffa041fa10>] nfs4_pnfs_ds_connect+0x120/0x400 [nfsv4]
[<ffffffffa03d41c7>] nfs4_ff_layout_prepare_ds+0xe7/0x330 [nfs_layout_flexfiles]
[<ffffffffa03d1b1b>] ff_layout_pg_init_write+0xcb/0x280 [nfs_layout_flexfiles]
[<ffffffffa03a14dc>] __nfs_pageio_add_request+0x12c/0x490 [nfs]
[<ffffffffa03a1fa2>] nfs_pageio_add_request+0xc2/0x2a0 [nfs]
[<ffffffffa03a0365>] ? nfs_pageio_init+0x75/0x120 [nfs]
[<ffffffffa03a5b50>] nfs_do_writepage+0x120/0x270 [nfs]
[<ffffffffa03a5d31>] nfs_writepage_locked+0x61/0xc0 [nfs]
[<ffffffff813d4115>] ? __percpu_counter_add+0x55/0x70
[<ffffffffa03a6a9f>] nfs_wb_single_page+0xef/0x1c0 [nfs]
[<ffffffff811ca4a3>] ? __dec_zone_page_state+0x33/0x40
[<ffffffffa0395b21>] nfs_launder_page+0x41/0x90 [nfs]
[<ffffffff811baba0>] invalidate_inode_pages2_range+0x340/0x3a0
[<ffffffff811bac17>] invalidate_inode_pages2+0x17/0x20
[<ffffffffa039960e>] nfs_release+0x9e/0xb0 [nfs]
[<ffffffffa0399570>] ? nfs_open+0x60/0x60 [nfs]
[<ffffffffa0394dad>] nfs_file_release+0x3d/0x60 [nfs]
[<ffffffff81226e6c>] __fput+0xdc/0x1e0
[<ffffffff81226fbe>] ____fput+0xe/0x10
[<ffffffff810bf2e4>] task_work_run+0xc4/0xe0
[<ffffffff810a4188>] do_exit+0x2e8/0xb30
[<ffffffff8102471c>] ? do_audit_syscall_entry+0x6c/0x70
[<ffffffff811464e6>] ? __audit_syscall_exit+0x1e6/0x280
[<ffffffff810a4a5f>] do_group_exit+0x3f/0xa0
[<ffffffff810a4ad4>] SyS_exit_group+0x14/0x20
[<ffffffff8179b76e>] system_call_fastpath+0x12/0x71
Which seems to be due to a call to utsname() when in a task exit context
in order to determine the hostname to set in rpc_new_client().
In reality, what we want here is not the hostname of the current task, but
the hostname that was used to set up the metadata server.
Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index 0c96528..4849d0f 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -367,8 +367,6 @@
*/
struct nfs_client *
nfs_get_client(const struct nfs_client_initdata *cl_init,
- const struct rpc_timeout *timeparms,
- const char *ip_addr,
rpc_authflavor_t authflavour)
{
struct nfs_client *clp, *new = NULL;
@@ -399,7 +397,7 @@
&nn->nfs_client_list);
spin_unlock(&nn->nfs_client_lock);
new->cl_flags = cl_init->init_flags;
- return rpc_ops->init_client(new, timeparms, ip_addr);
+ return rpc_ops->init_client(new, cl_init);
}
spin_unlock(&nn->nfs_client_lock);
@@ -470,7 +468,7 @@
* Create an RPC client handle
*/
int nfs_create_rpc_client(struct nfs_client *clp,
- const struct rpc_timeout *timeparms,
+ const struct nfs_client_initdata *cl_init,
rpc_authflavor_t flavor)
{
struct rpc_clnt *clnt = NULL;
@@ -479,8 +477,9 @@
.protocol = clp->cl_proto,
.address = (struct sockaddr *)&clp->cl_addr,
.addrsize = clp->cl_addrlen,
- .timeout = timeparms,
+ .timeout = cl_init->timeparms,
.servername = clp->cl_hostname,
+ .nodename = cl_init->nodename,
.program = &nfs_program,
.version = clp->rpc_ops->version,
.authflavor = flavor,
@@ -591,14 +590,12 @@
* nfs_init_client - Initialise an NFS2 or NFS3 client
*
* @clp: nfs_client to initialise
- * @timeparms: timeout parameters for underlying RPC transport
- * @ip_addr: IP presentation address (not used)
+ * @cl_init: Initialisation parameters
*
* Returns pointer to an NFS client, or an ERR_PTR value.
*/
struct nfs_client *nfs_init_client(struct nfs_client *clp,
- const struct rpc_timeout *timeparms,
- const char *ip_addr)
+ const struct nfs_client_initdata *cl_init)
{
int error;
@@ -612,7 +609,7 @@
* Create a client RPC handle for doing FSSTAT with UNIX auth only
* - RFC 2623, sec 2.3.2
*/
- error = nfs_create_rpc_client(clp, timeparms, RPC_AUTH_UNIX);
+ error = nfs_create_rpc_client(clp, cl_init, RPC_AUTH_UNIX);
if (error < 0)
goto error;
nfs_mark_client_ready(clp, NFS_CS_READY);
@@ -633,6 +630,7 @@
const struct nfs_parsed_mount_data *data,
struct nfs_subversion *nfs_mod)
{
+ struct rpc_timeout timeparms;
struct nfs_client_initdata cl_init = {
.hostname = data->nfs_server.hostname,
.addr = (const struct sockaddr *)&data->nfs_server.address,
@@ -640,8 +638,8 @@
.nfs_mod = nfs_mod,
.proto = data->nfs_server.protocol,
.net = data->net,
+ .timeparms = &timeparms,
};
- struct rpc_timeout timeparms;
struct nfs_client *clp;
int error;
@@ -653,7 +651,7 @@
set_bit(NFS_CS_NORESVPORT, &cl_init.init_flags);
/* Allocate or find a client reference we can use */
- clp = nfs_get_client(&cl_init, &timeparms, NULL, RPC_AUTH_UNIX);
+ clp = nfs_get_client(&cl_init, RPC_AUTH_UNIX);
if (IS_ERR(clp)) {
dprintk("<-- nfs_init_server() = error %ld\n", PTR_ERR(clp));
return PTR_ERR(clp);