Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8f649c37 authored by Trond Myklebust's avatar Trond Myklebust
Browse files

NFSv4: Fix the locking in nfs_inode_reclaim_delegation()



Ensure that we correctly rcu-dereference the delegation itself, and that we
protect against removal while we're changing the contents.

Signed-off-by: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
Signed-off-by: default avatarPaul E. McKenney <paulmck@linux.vnet.ibm.com>
parent be1066bb
Loading
Loading
Loading
Loading
+28 −14
Original line number Diff line number Diff line
@@ -129,21 +129,35 @@ static int nfs_delegation_claim_opens(struct inode *inode, const nfs4_stateid *s
 */
void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res)
{
	struct nfs_delegation *delegation = NFS_I(inode)->delegation;
	struct rpc_cred *oldcred;
	struct nfs_delegation *delegation;
	struct rpc_cred *oldcred = NULL;

	if (delegation == NULL)
		return;
	rcu_read_lock();
	delegation = rcu_dereference(NFS_I(inode)->delegation);
	if (delegation != NULL) {
		spin_lock(&delegation->lock);
		if (delegation->inode != NULL) {
			memcpy(delegation->stateid.data, res->delegation.data,
			       sizeof(delegation->stateid.data));
			delegation->type = res->delegation_type;
			delegation->maxsize = res->maxsize;
			oldcred = delegation->cred;
			delegation->cred = get_rpccred(cred);
	clear_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags);
			clear_bit(NFS_DELEGATION_NEED_RECLAIM,
				  &delegation->flags);
			NFS_I(inode)->delegation_state = delegation->type;
	smp_wmb();
			spin_unlock(&delegation->lock);
			put_rpccred(oldcred);
			rcu_read_unlock();
		} else {
			/* We appear to have raced with a delegation return. */
			spin_unlock(&delegation->lock);
			rcu_read_unlock();
			nfs_inode_set_delegation(inode, cred, res);
		}
	} else {
		rcu_read_unlock();
	}
}

static int nfs_do_return_delegation(struct inode *inode, struct nfs_delegation *delegation, int issync)