Skip to content

Commit 1ba0439

Browse files
Trond Myklebustamschuma-ntap
authored andcommitted
NFSv4: Fix a potential state reclaim deadlock
If the server reboots while we are engaged in a delegation return, and there is a pNFS layout with return-on-close set, then the current code can end up deadlocking in pnfs_roc() when nfs_inode_set_delegation() tries to return the old delegation. Now that delegreturn actually uses its own copy of the stateid, it should be safe to just always update the delegation stateid in place. Fixes: 078000d ("pNFS: We want return-on-close to complete when evicting the inode") Signed-off-by: Trond Myklebust <[email protected]> Signed-off-by: Anna Schumaker <[email protected]>
1 parent cf0d7e7 commit 1ba0439

File tree

1 file changed

+17
-19
lines changed

1 file changed

+17
-19
lines changed

fs/nfs/delegation.c

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -228,8 +228,7 @@ static int nfs_delegation_claim_opens(struct inode *inode,
228228
*
229229
*/
230230
void nfs_inode_reclaim_delegation(struct inode *inode, const struct cred *cred,
231-
fmode_t type,
232-
const nfs4_stateid *stateid,
231+
fmode_t type, const nfs4_stateid *stateid,
233232
unsigned long pagemod_limit)
234233
{
235234
struct nfs_delegation *delegation;
@@ -239,25 +238,24 @@ void nfs_inode_reclaim_delegation(struct inode *inode, const struct cred *cred,
239238
delegation = rcu_dereference(NFS_I(inode)->delegation);
240239
if (delegation != NULL) {
241240
spin_lock(&delegation->lock);
242-
if (nfs4_is_valid_delegation(delegation, 0)) {
243-
nfs4_stateid_copy(&delegation->stateid, stateid);
244-
delegation->type = type;
245-
delegation->pagemod_limit = pagemod_limit;
246-
oldcred = delegation->cred;
247-
delegation->cred = get_cred(cred);
248-
clear_bit(NFS_DELEGATION_NEED_RECLAIM,
249-
&delegation->flags);
250-
spin_unlock(&delegation->lock);
251-
rcu_read_unlock();
252-
put_cred(oldcred);
253-
trace_nfs4_reclaim_delegation(inode, type);
254-
return;
255-
}
256-
/* We appear to have raced with a delegation return. */
241+
nfs4_stateid_copy(&delegation->stateid, stateid);
242+
delegation->type = type;
243+
delegation->pagemod_limit = pagemod_limit;
244+
oldcred = delegation->cred;
245+
delegation->cred = get_cred(cred);
246+
clear_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags);
247+
if (test_and_clear_bit(NFS_DELEGATION_REVOKED,
248+
&delegation->flags))
249+
atomic_long_inc(&nfs_active_delegations);
257250
spin_unlock(&delegation->lock);
251+
rcu_read_unlock();
252+
put_cred(oldcred);
253+
trace_nfs4_reclaim_delegation(inode, type);
254+
} else {
255+
rcu_read_unlock();
256+
nfs_inode_set_delegation(inode, cred, type, stateid,
257+
pagemod_limit);
258258
}
259-
rcu_read_unlock();
260-
nfs_inode_set_delegation(inode, cred, type, stateid, pagemod_limit);
261259
}
262260

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

0 commit comments

Comments
 (0)