Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'nfs-for-3.9-4' of git://git.linux-nfs.org/projects/trondmy/linux-nfs

Pull NFS client bugfixes from Trond Myklebust:
- fix for memory corruption issues in nfs4[01]_walk_client_list (stable)
- fix for an Oopsable bug in rpc_clone_client (stable)
- another state manager deadlock in the NFSv4 open code
- memory leaks in nfs4_discover_server_trunking and rpc_new_client

* tag 'nfs-for-3.9-4' of git://git.linux-nfs.org/projects/trondmy/linux-nfs:
NFSv4: Fix another potential state manager deadlock
SUNRPC: Fix a potential memory leak in rpc_new_client
NFSv4/4.1: Fix bugs in nfs4[01]_walk_client_list
NFSv4: Fix a memory leak in nfs4_discover_server_trunking
SUNRPC: Remove extra xprt_put()

+39 -25
+28 -16
fs/nfs/nfs4client.c
··· 300 300 struct rpc_cred *cred) 301 301 { 302 302 struct nfs_net *nn = net_generic(new->cl_net, nfs_net_id); 303 - struct nfs_client *pos, *n, *prev = NULL; 303 + struct nfs_client *pos, *prev = NULL; 304 304 struct nfs4_setclientid_res clid = { 305 305 .clientid = new->cl_clientid, 306 306 .confirm = new->cl_confirm, ··· 308 308 int status = -NFS4ERR_STALE_CLIENTID; 309 309 310 310 spin_lock(&nn->nfs_client_lock); 311 - list_for_each_entry_safe(pos, n, &nn->nfs_client_list, cl_share_link) { 311 + list_for_each_entry(pos, &nn->nfs_client_list, cl_share_link) { 312 312 /* If "pos" isn't marked ready, we can't trust the 313 313 * remaining fields in "pos" */ 314 - if (pos->cl_cons_state < NFS_CS_READY) 314 + if (pos->cl_cons_state > NFS_CS_READY) { 315 + atomic_inc(&pos->cl_count); 316 + spin_unlock(&nn->nfs_client_lock); 317 + 318 + if (prev) 319 + nfs_put_client(prev); 320 + prev = pos; 321 + 322 + status = nfs_wait_client_init_complete(pos); 323 + spin_lock(&nn->nfs_client_lock); 324 + if (status < 0) 325 + continue; 326 + } 327 + if (pos->cl_cons_state != NFS_CS_READY) 315 328 continue; 316 329 317 330 if (pos->rpc_ops != new->rpc_ops) ··· 436 423 struct rpc_cred *cred) 437 424 { 438 425 struct nfs_net *nn = net_generic(new->cl_net, nfs_net_id); 439 - struct nfs_client *pos, *n, *prev = NULL; 426 + struct nfs_client *pos, *prev = NULL; 440 427 int status = -NFS4ERR_STALE_CLIENTID; 441 428 442 429 spin_lock(&nn->nfs_client_lock); 443 - list_for_each_entry_safe(pos, n, &nn->nfs_client_list, cl_share_link) { 430 + list_for_each_entry(pos, &nn->nfs_client_list, cl_share_link) { 444 431 /* If "pos" isn't marked ready, we can't trust the 445 432 * remaining fields in "pos", especially the client 446 433 * ID and serverowner fields. Wait for CREATE_SESSION 447 434 * to finish. */ 448 - if (pos->cl_cons_state < NFS_CS_READY) { 435 + if (pos->cl_cons_state > NFS_CS_READY) { 449 436 atomic_inc(&pos->cl_count); 450 437 spin_unlock(&nn->nfs_client_lock); 451 438 ··· 453 440 nfs_put_client(prev); 454 441 prev = pos; 455 442 456 - nfs4_schedule_lease_recovery(pos); 457 443 status = nfs_wait_client_init_complete(pos); 458 - if (status < 0) { 459 - nfs_put_client(pos); 460 - spin_lock(&nn->nfs_client_lock); 461 - continue; 444 + if (status == 0) { 445 + nfs4_schedule_lease_recovery(pos); 446 + status = nfs4_wait_clnt_recover(pos); 462 447 } 463 - status = pos->cl_cons_state; 464 448 spin_lock(&nn->nfs_client_lock); 465 449 if (status < 0) 466 450 continue; 467 451 } 452 + if (pos->cl_cons_state != NFS_CS_READY) 453 + continue; 468 454 469 455 if (pos->rpc_ops != new->rpc_ops) 470 456 continue; ··· 481 469 continue; 482 470 483 471 atomic_inc(&pos->cl_count); 484 - spin_unlock(&nn->nfs_client_lock); 472 + *result = pos; 485 473 dprintk("NFS: <-- %s using nfs_client = %p ({%d})\n", 486 474 __func__, pos, atomic_read(&pos->cl_count)); 487 - 488 - *result = pos; 489 - return 0; 475 + break; 490 476 } 491 477 492 478 /* No matching nfs_client found. */ 493 479 spin_unlock(&nn->nfs_client_lock); 494 480 dprintk("NFS: <-- %s status = %d\n", __func__, status); 481 + if (prev) 482 + nfs_put_client(prev); 495 483 return status; 496 484 } 497 485 #endif /* CONFIG_NFS_V4_1 */
+1
fs/nfs/nfs4proc.c
··· 1046 1046 /* Save the delegation */ 1047 1047 nfs4_stateid_copy(&stateid, &delegation->stateid); 1048 1048 rcu_read_unlock(); 1049 + nfs_release_seqid(opendata->o_arg.seqid); 1049 1050 ret = nfs_may_open(state->inode, state->owner->so_cred, open_mode); 1050 1051 if (ret != 0) 1051 1052 goto out;
+7 -1
fs/nfs/nfs4state.c
··· 1886 1886 status = PTR_ERR(clnt); 1887 1887 break; 1888 1888 } 1889 - clp->cl_rpcclient = clnt; 1889 + /* Note: this is safe because we haven't yet marked the 1890 + * client as ready, so we are the only user of 1891 + * clp->cl_rpcclient 1892 + */ 1893 + clnt = xchg(&clp->cl_rpcclient, clnt); 1894 + rpc_shutdown_client(clnt); 1895 + clnt = clp->cl_rpcclient; 1890 1896 goto again; 1891 1897 1892 1898 case -NFS4ERR_MINOR_VERS_MISMATCH:
+3 -8
net/sunrpc/clnt.c
··· 304 304 err = rpciod_up(); 305 305 if (err) 306 306 goto out_no_rpciod; 307 - err = -EINVAL; 308 - if (!xprt) 309 - goto out_no_xprt; 310 307 308 + err = -EINVAL; 311 309 if (args->version >= program->nrvers) 312 310 goto out_err; 313 311 version = program->version[args->version]; ··· 380 382 out_no_stats: 381 383 kfree(clnt); 382 384 out_err: 383 - xprt_put(xprt); 384 - out_no_xprt: 385 385 rpciod_down(); 386 386 out_no_rpciod: 387 + xprt_put(xprt); 387 388 return ERR_PTR(err); 388 389 } 389 390 ··· 509 512 new = rpc_new_client(args, xprt); 510 513 if (IS_ERR(new)) { 511 514 err = PTR_ERR(new); 512 - goto out_put; 515 + goto out_err; 513 516 } 514 517 515 518 atomic_inc(&clnt->cl_count); ··· 522 525 new->cl_chatty = clnt->cl_chatty; 523 526 return new; 524 527 525 - out_put: 526 - xprt_put(xprt); 527 528 out_err: 528 529 dprintk("RPC: %s: returned error %d\n", __func__, err); 529 530 return ERR_PTR(err);