This is a note to let you know that I've just added the patch titled NFSv4: Fix races between nfs_remove_bad_delegation() and delegation return to the 3.17-stable tree which can be found at: http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary The filename of the patch is: nfsv4-fix-races-between-nfs_remove_bad_delegation-and-delegation-return.patch and it can be found in the queue-3.17 subdirectory. If you, or anyone else, feels it should not be added to the stable tree, please let <stable@xxxxxxxxxxxxxxx> know about it. >From 869f9dfa4d6d57b79e0afc3af14772c2a023eeb1 Mon Sep 17 00:00:00 2001 From: Trond Myklebust <trond.myklebust@xxxxxxxxxxxxxxx> Date: Mon, 10 Nov 2014 18:43:56 -0500 Subject: NFSv4: Fix races between nfs_remove_bad_delegation() and delegation return From: Trond Myklebust <trond.myklebust@xxxxxxxxxxxxxxx> commit 869f9dfa4d6d57b79e0afc3af14772c2a023eeb1 upstream. Any attempt to call nfs_remove_bad_delegation() while a delegation is being returned is currently a no-op. This means that we can end up looping forever in nfs_end_delegation_return() if something causes the delegation to be revoked. This patch adds a mechanism whereby the state recovery code can communicate to the delegation return code that the delegation is no longer valid and that it should not be used when reclaiming state. It also changes the return value for nfs4_handle_delegation_recall_error() to ensure that nfs_end_delegation_return() does not reattempt the lock reclaim before state recovery is done. http://lkml.kernel.org/r/CAN-5tyHwG=Cn2Q9KsHWadewjpTTy_K26ee+UnSvHvG4192p-Xw@xxxxxxxxxxxxxx Signed-off-by: Trond Myklebust <trond.myklebust@xxxxxxxxxxxxxxx> Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx> --- fs/nfs/delegation.c | 23 +++++++++++++++++++++-- fs/nfs/delegation.h | 1 + fs/nfs/nfs4proc.c | 2 +- 3 files changed, 23 insertions(+), 3 deletions(-) --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c @@ -195,7 +195,11 @@ static int nfs_do_return_delegation(stru { int res = 0; - res = nfs4_proc_delegreturn(inode, delegation->cred, &delegation->stateid, issync); + if (!test_bit(NFS_DELEGATION_REVOKED, &delegation->flags)) + res = nfs4_proc_delegreturn(inode, + delegation->cred, + &delegation->stateid, + issync); nfs_free_delegation(delegation); return res; } @@ -382,11 +386,13 @@ static int nfs_end_delegation_return(str { struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; struct nfs_inode *nfsi = NFS_I(inode); - int err; + int err = 0; if (delegation == NULL) return 0; do { + if (test_bit(NFS_DELEGATION_REVOKED, &delegation->flags)) + break; err = nfs_delegation_claim_opens(inode, &delegation->stateid); if (!issync || err != -EAGAIN) break; @@ -607,10 +613,23 @@ static void nfs_client_mark_return_unuse rcu_read_unlock(); } +static void nfs_revoke_delegation(struct inode *inode) +{ + struct nfs_delegation *delegation; + rcu_read_lock(); + delegation = rcu_dereference(NFS_I(inode)->delegation); + if (delegation != NULL) { + set_bit(NFS_DELEGATION_REVOKED, &delegation->flags); + nfs_mark_return_delegation(NFS_SERVER(inode), delegation); + } + rcu_read_unlock(); +} + void nfs_remove_bad_delegation(struct inode *inode) { struct nfs_delegation *delegation; + nfs_revoke_delegation(inode); delegation = nfs_inode_detach_delegation(inode); if (delegation) { nfs_inode_find_state_and_recover(inode, &delegation->stateid); --- a/fs/nfs/delegation.h +++ b/fs/nfs/delegation.h @@ -31,6 +31,7 @@ enum { NFS_DELEGATION_RETURN_IF_CLOSED, NFS_DELEGATION_REFERENCED, NFS_DELEGATION_RETURNING, + NFS_DELEGATION_REVOKED, }; int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -1642,7 +1642,7 @@ static int nfs4_handle_delegation_recall nfs_inode_find_state_and_recover(state->inode, stateid); nfs4_schedule_stateid_recovery(server, state); - return 0; + return -EAGAIN; case -NFS4ERR_DELAY: case -NFS4ERR_GRACE: set_bit(NFS_DELEGATED_STATE, &state->flags); Patches currently in stable-queue which might be from trond.myklebust@xxxxxxxxxxxxxxx are queue-3.17/sunrpc-fix-sleeping-under-rcu_read_lock-in-gss_stringify_acceptor.patch queue-3.17/nfsv4-ensure-that-we-remove-nfsv4.0-delegations-when-state-has-expired.patch queue-3.17/nfsv4.1-nfs41_clear_delegation_stateid-shouldn-t-trust-nfs_delegated_state.patch queue-3.17/nfsv4-fix-races-between-nfs_remove_bad_delegation-and-delegation-return.patch queue-3.17/nfs-fix-use-of-uninitialized-variable-in-nfs_getattr.patch queue-3.17/nfs-fix-pnfs-direct-write-memory-leak.patch queue-3.17/nfs-don-t-try-to-reclaim-delegation-open-state-if-recovery-failed.patch queue-3.17/nfsv4-ensure-that-we-call-free_stateid-when-nfsv4.x-stateids-are-revoked.patch -- To unsubscribe from this list: send the line "unsubscribe stable" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html