mirror of
https://github.com/torvalds/linux.git
synced 2024-11-01 04:53:36 +01:00
nfsd-6.12 fixes:
- Fix a couple of use-after-free bugs -----BEGIN PGP SIGNATURE----- iQIyBAABCAAdFiEEKLLlsBKG3yQ88j7+M2qzM29mf5cFAmcbp9YACgkQM2qzM29m f5dzAg/4lCFRbsebia7qktW88ZDBbAoZyKolk2DHfjZXCuq5DHb/5I/Hk1rGyTYs VaJmCU59ZdpyBFSdQhOYKf2xvgNPvJG02U8il5KWtMAY5cStXFjeU0FSDoC5O4Dl 9IoaVbtAWGMCjxWJ1WEGpU82JoM7moSVB4G718LlxF+4cUS7idq5se0uK31WQvft DmJsOfmnch1Y/7+RRcDwbBu0HwP2ZQHS8zMYMQ2JGXPDZJFenTibezVb36YyzyZn WQfvaW6MmdiVL9omZxvURL9WuBKA2L+Ly/92PyHaflcAXSngcpfu28IIQbzp/m7K JT/3ad32lB7F3LrDP5I4gwVh8oGLYiI5r7RBWo0e98LPvAR/89gBVdZHhjasstCh nAL7Kk6P/jQdbM/KR9T+yS7xTVScI5Wp4Xcitz2mlHgU4br67GO9gpo1e/tqXenm Gasapkg5qCduz+ksj2vwpeFXKQi+qwJgfVGKMxELoV8qTazyr09Dfgouqe045ztl /0khkOrLkw0bYLDNJKhj/XG0ZEV5V10c/0PEnivC2BHVQioBIDRQAaH2S2G/8vQH MdWayGhNlTV0g4DdtMVPxf5uN+uQmfMsj5BIe17NIUYxiJnw0CSM/bzHUcJ15+DH nTblaek6sa5BFpZ2fed8by4il4/tme3NOJEeHnSqe/3QKyZgOQ== =1YOr -----END PGP SIGNATURE----- Merge tag 'nfsd-6.12-2' of git://git.kernel.org/pub/scm/linux/kernel/git/cel/linux Pull nfsd fixes from Chuck Lever: - Fix a couple of use-after-free bugs * tag 'nfsd-6.12-2' of git://git.kernel.org/pub/scm/linux/kernel/git/cel/linux: nfsd: cancel nfsd_shrinker_work using sync mode in nfs4_state_shutdown_net nfsd: fix race between laundromat and free_stateid
This commit is contained in:
commit
f647053312
2 changed files with 43 additions and 9 deletions
|
@ -1359,21 +1359,47 @@ static void destroy_delegation(struct nfs4_delegation *dp)
|
|||
destroy_unhashed_deleg(dp);
|
||||
}
|
||||
|
||||
/**
|
||||
* revoke_delegation - perform nfs4 delegation structure cleanup
|
||||
* @dp: pointer to the delegation
|
||||
*
|
||||
* This function assumes that it's called either from the administrative
|
||||
* interface (nfsd4_revoke_states()) that's revoking a specific delegation
|
||||
* 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.
|
||||
*
|
||||
* 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
|
||||
* we can proceed to removing it from recalled list. However, if @dp state
|
||||
* isn't marked SC_STATUS_FREED, it means we need place it on the cl_revoked
|
||||
* list and wait for the FREE_STATEID to arrive from the client. At the same
|
||||
* time, we need to mark it as SC_STATUS_FREEABLE to indicate to the
|
||||
* nfsd4_free_stateid() function that this stateid has already been added
|
||||
* to the cl_revoked list and that nfsd4_free_stateid() is now responsible
|
||||
* for removing it from the list. Inspection of where the delegation state
|
||||
* in the revocation process is protected by the clp->cl_lock.
|
||||
*/
|
||||
static void revoke_delegation(struct nfs4_delegation *dp)
|
||||
{
|
||||
struct nfs4_client *clp = dp->dl_stid.sc_client;
|
||||
|
||||
WARN_ON(!list_empty(&dp->dl_recall_lru));
|
||||
WARN_ON_ONCE(!(dp->dl_stid.sc_status &
|
||||
(SC_STATUS_REVOKED | SC_STATUS_ADMIN_REVOKED)));
|
||||
|
||||
trace_nfsd_stid_revoke(&dp->dl_stid);
|
||||
|
||||
if (dp->dl_stid.sc_status &
|
||||
(SC_STATUS_REVOKED | SC_STATUS_ADMIN_REVOKED)) {
|
||||
spin_lock(&clp->cl_lock);
|
||||
refcount_inc(&dp->dl_stid.sc_count);
|
||||
list_add(&dp->dl_recall_lru, &clp->cl_revoked);
|
||||
spin_unlock(&clp->cl_lock);
|
||||
spin_lock(&clp->cl_lock);
|
||||
if (dp->dl_stid.sc_status & SC_STATUS_FREED) {
|
||||
list_del_init(&dp->dl_recall_lru);
|
||||
goto out;
|
||||
}
|
||||
list_add(&dp->dl_recall_lru, &clp->cl_revoked);
|
||||
dp->dl_stid.sc_status |= SC_STATUS_FREEABLE;
|
||||
out:
|
||||
spin_unlock(&clp->cl_lock);
|
||||
destroy_unhashed_deleg(dp);
|
||||
}
|
||||
|
||||
|
@ -1780,6 +1806,7 @@ void nfsd4_revoke_states(struct net *net, struct super_block *sb)
|
|||
mutex_unlock(&stp->st_mutex);
|
||||
break;
|
||||
case SC_TYPE_DELEG:
|
||||
refcount_inc(&stid->sc_count);
|
||||
dp = delegstateid(stid);
|
||||
spin_lock(&state_lock);
|
||||
if (!unhash_delegation_locked(
|
||||
|
@ -6545,6 +6572,7 @@ nfs4_laundromat(struct nfsd_net *nn)
|
|||
dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru);
|
||||
if (!state_expired(<, dp->dl_time))
|
||||
break;
|
||||
refcount_inc(&dp->dl_stid.sc_count);
|
||||
unhash_delegation_locked(dp, SC_STATUS_REVOKED);
|
||||
list_add(&dp->dl_recall_lru, &reaplist);
|
||||
}
|
||||
|
@ -7157,7 +7185,9 @@ nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
|||
s->sc_status |= SC_STATUS_CLOSED;
|
||||
spin_unlock(&s->sc_lock);
|
||||
dp = delegstateid(s);
|
||||
list_del_init(&dp->dl_recall_lru);
|
||||
if (s->sc_status & SC_STATUS_FREEABLE)
|
||||
list_del_init(&dp->dl_recall_lru);
|
||||
s->sc_status |= SC_STATUS_FREED;
|
||||
spin_unlock(&cl->cl_lock);
|
||||
nfs4_put_stid(s);
|
||||
ret = nfs_ok;
|
||||
|
@ -7487,7 +7517,9 @@ nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
|||
if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0)))
|
||||
return status;
|
||||
|
||||
status = nfsd4_lookup_stateid(cstate, stateid, SC_TYPE_DELEG, 0, &s, nn);
|
||||
status = nfsd4_lookup_stateid(cstate, stateid, SC_TYPE_DELEG,
|
||||
SC_STATUS_REVOKED | SC_STATUS_FREEABLE,
|
||||
&s, nn);
|
||||
if (status)
|
||||
goto out;
|
||||
dp = delegstateid(s);
|
||||
|
@ -8684,7 +8716,7 @@ nfs4_state_shutdown_net(struct net *net)
|
|||
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
|
||||
|
||||
shrinker_free(nn->nfsd_client_shrinker);
|
||||
cancel_work(&nn->nfsd_shrinker_work);
|
||||
cancel_work_sync(&nn->nfsd_shrinker_work);
|
||||
cancel_delayed_work_sync(&nn->laundromat_work);
|
||||
locks_end_grace(&nn->nfsd4_manager);
|
||||
|
||||
|
|
|
@ -114,6 +114,8 @@ struct nfs4_stid {
|
|||
/* For a deleg stateid kept around only to process free_stateid's: */
|
||||
#define SC_STATUS_REVOKED BIT(1)
|
||||
#define SC_STATUS_ADMIN_REVOKED BIT(2)
|
||||
#define SC_STATUS_FREEABLE BIT(3)
|
||||
#define SC_STATUS_FREED BIT(4)
|
||||
unsigned short sc_status;
|
||||
|
||||
struct list_head sc_cp_list;
|
||||
|
|
Loading…
Reference in a new issue