mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
xfs: fix missing xfs_qm_adjust_dqlimits call in quotacheck repair
LOLLM noticed that everywhere else in the kernel, a call to
xfs_qm_adjust_dqlimits precedes every call to xfs_qm_adjust_dqtimers.
In particular, mount-time quotacheck does this, but online quotacheck
does not.
Looking at xfs_qm_adjust_dqlimits, that function is in charge of
conveying default limits to a dquot if that dquot's limits have been
zeroed. That's quite possible in a repair, so we actually need to do
that.
However, there's a pre-existing pattern in the kernel -- for non-root
dquots, first we call xfs_qm_adjust_dqlimits to set the dquot's limits
to the defaults if they are zero, and then xfs_qm_adjust_dqtimers to
start grace periods if the dquot's usage is above the softlimit. The
grace period decision cannot be made correctly if we forget to import
the default limits.
Therefore, let's combine both into a single xfs_qm_adjust_dqenforcement
helper that takes care of both pieces, which fixes quotacheck and makes
it hard to repeat this mistake.
Cc: stable@vger.kernel.org # v6.9
Fixes: 96ed2ae4a9 ("xfs: repair dquots based on live quotacheck results")
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Assisted-by: LOLLM # finding obvious bugs
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
This commit is contained in:
parent
23f91a5142
commit
da483b8a9c
|
|
@ -248,10 +248,7 @@ xrep_quota_item(
|
|||
|
||||
dq->q_flags |= XFS_DQFLAG_DIRTY;
|
||||
xfs_trans_dqjoin(sc->tp, dq);
|
||||
if (dq->q_id) {
|
||||
xfs_qm_adjust_dqlimits(dq);
|
||||
xfs_qm_adjust_dqtimers(dq);
|
||||
}
|
||||
xfs_qm_adjust_dqenforcement(dq);
|
||||
xfs_trans_log_dquot(sc->tp, dq);
|
||||
return xfs_trans_roll(&sc->tp);
|
||||
|
||||
|
|
|
|||
|
|
@ -110,8 +110,7 @@ xqcheck_commit_dquot(
|
|||
|
||||
/* Commit the dirty dquot to disk. */
|
||||
dq->q_flags |= XFS_DQFLAG_DIRTY;
|
||||
if (dq->q_id)
|
||||
xfs_qm_adjust_dqtimers(dq);
|
||||
xfs_qm_adjust_dqenforcement(dq);
|
||||
xfs_trans_log_dquot(xqc->sc->tp, dq);
|
||||
return xrep_trans_commit(xqc->sc);
|
||||
|
||||
|
|
|
|||
|
|
@ -115,18 +115,15 @@ xfs_qm_dqdestroy(
|
|||
* We overwrite the dquot limits only if they are zero and this
|
||||
* is not the root dquot.
|
||||
*/
|
||||
void
|
||||
static void
|
||||
xfs_qm_adjust_dqlimits(
|
||||
struct xfs_dquot *dq)
|
||||
{
|
||||
struct xfs_mount *mp = dq->q_mount;
|
||||
struct xfs_quotainfo *q = mp->m_quotainfo;
|
||||
struct xfs_def_quota *defq;
|
||||
struct xfs_def_quota *defq = xfs_get_defquota(q, xfs_dquot_type(dq));
|
||||
int prealloc = 0;
|
||||
|
||||
ASSERT(dq->q_id);
|
||||
defq = xfs_get_defquota(q, xfs_dquot_type(dq));
|
||||
|
||||
if (!dq->q_blk.softlimit) {
|
||||
dq->q_blk.softlimit = defq->blk.soft;
|
||||
prealloc = 1;
|
||||
|
|
@ -223,6 +220,19 @@ xfs_qm_adjust_dqtimers(
|
|||
xfs_qm_adjust_res_timer(dq->q_mount, &dq->q_rtb, &defq->rtb);
|
||||
}
|
||||
|
||||
/* Adjust enforcement limits and timers after a change in usage. */
|
||||
void
|
||||
xfs_qm_adjust_dqenforcement(
|
||||
struct xfs_dquot *dq)
|
||||
{
|
||||
if (dq->q_id == 0)
|
||||
return;
|
||||
|
||||
xfs_qm_adjust_dqlimits(dq);
|
||||
xfs_qm_adjust_dqtimers(dq);
|
||||
dq->q_flags |= XFS_DQFLAG_DIRTY;
|
||||
}
|
||||
|
||||
/*
|
||||
* initialize a buffer full of dquots and log the whole thing
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -205,7 +205,7 @@ void xfs_qm_dqdestroy(struct xfs_dquot *dqp);
|
|||
int xfs_qm_dqflush(struct xfs_dquot *dqp, struct xfs_buf *bp);
|
||||
void xfs_qm_dqunpin_wait(struct xfs_dquot *dqp);
|
||||
void xfs_qm_adjust_dqtimers(struct xfs_dquot *d);
|
||||
void xfs_qm_adjust_dqlimits(struct xfs_dquot *d);
|
||||
void xfs_qm_adjust_dqenforcement(struct xfs_dquot *d);
|
||||
xfs_dqid_t xfs_qm_id_for_quotatype(struct xfs_inode *ip,
|
||||
xfs_dqtype_t type);
|
||||
int xfs_qm_dqget(struct xfs_mount *mp, xfs_dqid_t id,
|
||||
|
|
|
|||
|
|
@ -1294,11 +1294,7 @@ xfs_qm_quotacheck_dqadjust(
|
|||
*
|
||||
* There are no timers for the default values set in the root dquot.
|
||||
*/
|
||||
if (dqp->q_id) {
|
||||
xfs_qm_adjust_dqlimits(dqp);
|
||||
xfs_qm_adjust_dqtimers(dqp);
|
||||
}
|
||||
|
||||
xfs_qm_adjust_dqenforcement(dqp);
|
||||
dqp->q_flags |= XFS_DQFLAG_DIRTY;
|
||||
out_unlock:
|
||||
mutex_unlock(&dqp->q_qlock);
|
||||
|
|
|
|||
|
|
@ -566,11 +566,7 @@ xfs_trans_apply_dquot_deltas(
|
|||
* Get any default limits in use.
|
||||
* Start/reset the timer(s) if needed.
|
||||
*/
|
||||
if (dqp->q_id) {
|
||||
xfs_qm_adjust_dqlimits(dqp);
|
||||
xfs_qm_adjust_dqtimers(dqp);
|
||||
}
|
||||
|
||||
xfs_qm_adjust_dqenforcement(dqp);
|
||||
dqp->q_flags |= XFS_DQFLAG_DIRTY;
|
||||
/*
|
||||
* add this to the list of items to get logged
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user