mirror of
https://github.com/torvalds/linux.git
synced 2026-07-28 10:09:10 +02:00
NFSD: Fix delegation reference leak in nfsd4_revoke_states
When revoking delegation state, nfsd4_revoke_states() takes an extra
reference on the stid before calling unhash_delegation_locked(). If
unhash_delegation_locked() returns false (the delegation was already
unhashed by a concurrent path), dp is set to NULL and
revoke_delegation() is skipped, but the extra reference is never
released. Each occurrence permanently pins the stid in memory. The
leaked reference also prevents nfs4_put_stid() from decrementing
cl_admin_revoked, leaving the counter permanently inflated.
Drop the extra reference in the failure path.
Fixes: 8dd91e8d31 ("nfsd: fix race between laundromat and free_stateid")
Reviewed-by: Jeff Layton <jlayton@kernel.org>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
This commit is contained in:
parent
e7f558158e
commit
625981c8f3
|
|
@ -1376,7 +1376,8 @@ static void destroy_delegation(struct nfs4_delegation *dp)
|
|||
* stateid or it's called from a laundromat thread (nfsd4_landromat()) that
|
||||
* determined that this specific state has expired and needs to be revoked
|
||||
* (both mark state with the appropriate stid sc_status mode). It is also
|
||||
* assumed that a reference was taken on the @dp state.
|
||||
* assumed that a reference was taken on the @dp state. This function
|
||||
* consumes that reference.
|
||||
*
|
||||
* If this function finds that the @dp state is SC_STATUS_FREED it means
|
||||
* that a FREE_STATEID operation for this stateid has been processed and
|
||||
|
|
@ -1839,6 +1840,10 @@ void nfsd4_revoke_states(struct nfsd_net *nn, struct super_block *sb)
|
|||
mutex_unlock(&stp->st_mutex);
|
||||
break;
|
||||
case SC_TYPE_DELEG:
|
||||
/* Extra reference guards against concurrent
|
||||
* FREE_STATEID; revoke_delegation() consumes
|
||||
* it, otherwise release it directly.
|
||||
*/
|
||||
refcount_inc(&stid->sc_count);
|
||||
dp = delegstateid(stid);
|
||||
spin_lock(&nn->deleg_lock);
|
||||
|
|
@ -1848,6 +1853,8 @@ void nfsd4_revoke_states(struct nfsd_net *nn, struct super_block *sb)
|
|||
spin_unlock(&nn->deleg_lock);
|
||||
if (dp)
|
||||
revoke_delegation(dp);
|
||||
else
|
||||
nfs4_put_stid(stid);
|
||||
break;
|
||||
case SC_TYPE_LAYOUT:
|
||||
ls = layoutstateid(stid);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user