diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-12-16 13:12:53 -0800 | 
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-12-16 13:12:53 -0800 | 
| commit | d025fbf1a2cd1d60f39579d331a9accf84c5ec5b (patch) | |
| tree | 0314bc504eb0f5cc1ea4dd611eb55eb2cc88b98e /fs | |
| parent | f6f3732162b5ae3c771b9285a5a32d72b8586920 (diff) | |
| parent | 90d91b0cd371193d9dbfa9beacab8ab9a4cb75e0 (diff) | |
| download | linux-d025fbf1a2cd1d60f39579d331a9accf84c5ec5b.tar.bz2 | |
Merge tag 'nfs-for-4.15-3' of git://git.linux-nfs.org/projects/anna/linux-nfs
Pull NFS client fixes from Anna Schumaker:
 "This has two stable bugfixes, one to fix a BUG_ON() when
  nfs_commit_inode() is called with no outstanding commit requests and
  another to fix a race in the SUNRPC receive codepath.
  Additionally, there are also fixes for an NFS client deadlock and an
  xprtrdma performance regression.
  Summary:
  Stable bugfixes:
   - NFS: Avoid a BUG_ON() in nfs_commit_inode() by not waiting for a
     commit in the case that there were no commit requests.
   - SUNRPC: Fix a race in the receive code path
  Other fixes:
   - NFS: Fix a deadlock in nfs client initialization
   - xprtrdma: Fix a performance regression for small IOs"
* tag 'nfs-for-4.15-3' of git://git.linux-nfs.org/projects/anna/linux-nfs:
  SUNRPC: Fix a race in the receive code path
  nfs: don't wait on commit in nfs_commit_inode() if there were no commit requests
  xprtrdma: Spread reply processing over more CPUs
  nfs: fix a deadlock in nfs client initialization
Diffstat (limited to 'fs')
| -rw-r--r-- | fs/nfs/client.c | 11 | ||||
| -rw-r--r-- | fs/nfs/nfs4client.c | 17 | ||||
| -rw-r--r-- | fs/nfs/write.c | 2 | 
3 files changed, 26 insertions, 4 deletions
| diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 0ac2fb1c6b63..b9129e2befea 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c @@ -291,12 +291,23 @@ static struct nfs_client *nfs_match_client(const struct nfs_client_initdata *dat  	const struct sockaddr *sap = data->addr;  	struct nfs_net *nn = net_generic(data->net, nfs_net_id); +again:  	list_for_each_entry(clp, &nn->nfs_client_list, cl_share_link) {  	        const struct sockaddr *clap = (struct sockaddr *)&clp->cl_addr;  		/* Don't match clients that failed to initialise properly */  		if (clp->cl_cons_state < 0)  			continue; +		/* If a client is still initializing then we need to wait */ +		if (clp->cl_cons_state > NFS_CS_READY) { +			refcount_inc(&clp->cl_count); +			spin_unlock(&nn->nfs_client_lock); +			nfs_wait_client_init_complete(clp); +			nfs_put_client(clp); +			spin_lock(&nn->nfs_client_lock); +			goto again; +		} +  		/* Different NFS versions cannot share the same nfs_client */  		if (clp->rpc_ops != data->nfs_mod->rpc_ops)  			continue; diff --git a/fs/nfs/nfs4client.c b/fs/nfs/nfs4client.c index 12bbab0becb4..65a7e5da508c 100644 --- a/fs/nfs/nfs4client.c +++ b/fs/nfs/nfs4client.c @@ -404,15 +404,19 @@ struct nfs_client *nfs4_init_client(struct nfs_client *clp,  	if (error < 0)  		goto error; -	if (!nfs4_has_session(clp)) -		nfs_mark_client_ready(clp, NFS_CS_READY); -  	error = nfs4_discover_server_trunking(clp, &old);  	if (error < 0)  		goto error; -	if (clp != old) +	if (clp != old) {  		clp->cl_preserve_clid = true; +		/* +		 * Mark the client as having failed initialization so other +		 * processes walking the nfs_client_list in nfs_match_client() +		 * won't try to use it. +		 */ +		nfs_mark_client_ready(clp, -EPERM); +	}  	nfs_put_client(clp);  	clear_bit(NFS_CS_TSM_POSSIBLE, &clp->cl_flags);  	return old; @@ -539,6 +543,9 @@ int nfs40_walk_client_list(struct nfs_client *new,  	spin_lock(&nn->nfs_client_lock);  	list_for_each_entry(pos, &nn->nfs_client_list, cl_share_link) { +		if (pos == new) +			goto found; +  		status = nfs4_match_client(pos, new, &prev, nn);  		if (status < 0)  			goto out_unlock; @@ -559,6 +566,7 @@ int nfs40_walk_client_list(struct nfs_client *new,  		 * way that a SETCLIENTID_CONFIRM to pos can succeed is  		 * if new and pos point to the same server:  		 */ +found:  		refcount_inc(&pos->cl_count);  		spin_unlock(&nn->nfs_client_lock); @@ -572,6 +580,7 @@ int nfs40_walk_client_list(struct nfs_client *new,  		case 0:  			nfs4_swap_callback_idents(pos, new);  			pos->cl_confirm = new->cl_confirm; +			nfs_mark_client_ready(pos, NFS_CS_READY);  			prev = NULL;  			*result = pos; diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 5b5f464f6f2a..4a379d7918f2 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -1890,6 +1890,8 @@ int nfs_commit_inode(struct inode *inode, int how)  	if (res)  		error = nfs_generic_commit_list(inode, &head, how, &cinfo);  	nfs_commit_end(cinfo.mds); +	if (res == 0) +		return res;  	if (error < 0)  		goto out_error;  	if (!may_wait) |