Skip to content

Commit 8c75593

Browse files
trondmyamschuma-ntap
authored andcommitted
NFSv4: Ensure the delegation is pinned in nfs_do_return_delegation()
The call to nfs_do_return_delegation() needs to be taken without any RCU locks. Add a refcount to make sure the delegation remains pinned in memory until we're done. Fixes: ee05f45 ("NFSv4: Fix races between open and delegreturn") Signed-off-by: Trond Myklebust <[email protected]> Signed-off-by: Anna Schumaker <[email protected]>
1 parent cd1b659 commit 8c75593

File tree

2 files changed

+27
-7
lines changed

2 files changed

+27
-7
lines changed

fs/nfs/delegation.c

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,22 @@ static void nfs_mark_delegation_revoked(struct nfs_delegation *delegation)
4747
}
4848
}
4949

50+
static struct nfs_delegation *nfs_get_delegation(struct nfs_delegation *delegation)
51+
{
52+
refcount_inc(&delegation->refcount);
53+
return delegation;
54+
}
55+
56+
static void nfs_put_delegation(struct nfs_delegation *delegation)
57+
{
58+
if (refcount_dec_and_test(&delegation->refcount))
59+
__nfs_free_delegation(delegation);
60+
}
61+
5062
static void nfs_free_delegation(struct nfs_delegation *delegation)
5163
{
5264
nfs_mark_delegation_revoked(delegation);
53-
__nfs_free_delegation(delegation);
65+
nfs_put_delegation(delegation);
5466
}
5567

5668
/**
@@ -275,8 +287,10 @@ nfs_start_delegation_return_locked(struct nfs_inode *nfsi)
275287
if (delegation == NULL)
276288
goto out;
277289
spin_lock(&delegation->lock);
278-
if (!test_and_set_bit(NFS_DELEGATION_RETURNING, &delegation->flags))
279-
ret = delegation;
290+
if (!test_and_set_bit(NFS_DELEGATION_RETURNING, &delegation->flags)) {
291+
/* Refcount matched in nfs_end_delegation_return() */
292+
ret = nfs_get_delegation(delegation);
293+
}
280294
spin_unlock(&delegation->lock);
281295
if (ret)
282296
nfs_clear_verifier_delegated(&nfsi->vfs_inode);
@@ -397,6 +411,7 @@ int nfs_inode_set_delegation(struct inode *inode, const struct cred *cred,
397411
if (delegation == NULL)
398412
return -ENOMEM;
399413
nfs4_stateid_copy(&delegation->stateid, stateid);
414+
refcount_set(&delegation->refcount, 1);
400415
delegation->type = type;
401416
delegation->pagemod_limit = pagemod_limit;
402417
delegation->change_attr = inode_peek_iversion_raw(inode);
@@ -496,6 +511,8 @@ static int nfs_end_delegation_return(struct inode *inode, struct nfs_delegation
496511

497512
err = nfs_do_return_delegation(inode, delegation, issync);
498513
out:
514+
/* Refcount matched in nfs_start_delegation_return_locked() */
515+
nfs_put_delegation(delegation);
499516
return err;
500517
}
501518

@@ -690,7 +707,8 @@ void nfs4_inode_return_delegation_on_close(struct inode *inode)
690707
list_empty(&NFS_I(inode)->open_files) &&
691708
!test_and_set_bit(NFS_DELEGATION_RETURNING, &delegation->flags)) {
692709
clear_bit(NFS_DELEGATION_RETURN_IF_CLOSED, &delegation->flags);
693-
ret = delegation;
710+
/* Refcount matched in nfs_end_delegation_return() */
711+
ret = nfs_get_delegation(delegation);
694712
}
695713
spin_unlock(&delegation->lock);
696714
if (ret)
@@ -1094,10 +1112,11 @@ void nfs_delegation_reap_unclaimed(struct nfs_client *clp)
10941112
delegation = nfs_start_delegation_return_locked(NFS_I(inode));
10951113
rcu_read_unlock();
10961114
if (delegation != NULL) {
1097-
delegation = nfs_detach_delegation(NFS_I(inode),
1098-
delegation, server);
1099-
if (delegation != NULL)
1115+
if (nfs_detach_delegation(NFS_I(inode), delegation,
1116+
server) != NULL)
11001117
nfs_free_delegation(delegation);
1118+
/* Match nfs_start_delegation_return_locked */
1119+
nfs_put_delegation(delegation);
11011120
}
11021121
iput(inode);
11031122
nfs_sb_deactive(server->super);

fs/nfs/delegation.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ struct nfs_delegation {
2222
unsigned long pagemod_limit;
2323
__u64 change_attr;
2424
unsigned long flags;
25+
refcount_t refcount;
2526
spinlock_t lock;
2627
struct rcu_head rcu;
2728
};

0 commit comments

Comments
 (0)