From: Greg Kroah-Hartman Date: Tue, 18 Feb 2025 08:29:35 +0000 (+0100) Subject: 6.12-stable patches X-Git-Tag: v6.12.15~1 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=749b38d738eb91659e7565447013ed0d58b74924;p=thirdparty%2Fkernel%2Fstable-queue.git 6.12-stable patches added patches: series xfs-don-t-lose-solo-dquot-update-transactions.patch --- diff --git a/queue-6.12/series b/queue-6.12/series new file mode 100644 index 0000000000..b6f089443a --- /dev/null +++ b/queue-6.12/series @@ -0,0 +1 @@ +xfs-don-t-lose-solo-dquot-update-transactions.patch diff --git a/queue-6.12/xfs-don-t-lose-solo-dquot-update-transactions.patch b/queue-6.12/xfs-don-t-lose-solo-dquot-update-transactions.patch new file mode 100644 index 0000000000..4ac903c3fb --- /dev/null +++ b/queue-6.12/xfs-don-t-lose-solo-dquot-update-transactions.patch @@ -0,0 +1,159 @@ +From 07137e925fa951646325762bda6bd2503dfe64c6 Mon Sep 17 00:00:00 2001 +From: "Darrick J. Wong" +Date: Mon, 2 Dec 2024 10:57:36 -0800 +Subject: xfs: don't lose solo dquot update transactions + +From: Darrick J. Wong + +commit 07137e925fa951646325762bda6bd2503dfe64c6 upstream. + +Quota counter updates are tracked via incore objects which hang off the +xfs_trans object. These changes are then turned into dirty log items in +xfs_trans_apply_dquot_deltas just prior to commiting the log items to +the CIL. + +However, updating the incore deltas do not cause XFS_TRANS_DIRTY to be +set on the transaction. In other words, a pure quota counter update +will be silently discarded if there are no other dirty log items +attached to the transaction. + +This is currently not the case anywhere in the filesystem because quota +updates always dirty at least one other metadata item, but a subsequent +bug fix will add dquot log item precommits, so we actually need a dirty +dquot log item prior to xfs_trans_run_precommits. Also let's not leave +a logic bomb. + +Cc: # v2.6.35 +Fixes: 0924378a689ccb ("xfs: split out iclog writing from xfs_trans_commit()") +Signed-off-by: "Darrick J. Wong" +Reviewed-by: Christoph Hellwig +Signed-off-by: Greg Kroah-Hartman +--- + fs/xfs/xfs_quota.h | 5 +++-- + fs/xfs/xfs_trans.c | 10 +++------- + fs/xfs/xfs_trans_dquot.c | 31 ++++++++++++++++++++++++++----- + 3 files changed, 32 insertions(+), 14 deletions(-) + +--- a/fs/xfs/xfs_quota.h ++++ b/fs/xfs/xfs_quota.h +@@ -96,7 +96,8 @@ extern void xfs_trans_free_dqinfo(struct + extern void xfs_trans_mod_dquot_byino(struct xfs_trans *, struct xfs_inode *, + uint, int64_t); + extern void xfs_trans_apply_dquot_deltas(struct xfs_trans *); +-extern void xfs_trans_unreserve_and_mod_dquots(struct xfs_trans *); ++void xfs_trans_unreserve_and_mod_dquots(struct xfs_trans *tp, ++ bool already_locked); + int xfs_trans_reserve_quota_nblks(struct xfs_trans *tp, struct xfs_inode *ip, + int64_t dblocks, int64_t rblocks, bool force); + extern int xfs_trans_reserve_quota_bydquots(struct xfs_trans *, +@@ -166,7 +167,7 @@ static inline void xfs_trans_mod_dquot_b + { + } + #define xfs_trans_apply_dquot_deltas(tp) +-#define xfs_trans_unreserve_and_mod_dquots(tp) ++#define xfs_trans_unreserve_and_mod_dquots(tp, a) + static inline int xfs_trans_reserve_quota_nblks(struct xfs_trans *tp, + struct xfs_inode *ip, int64_t dblocks, int64_t rblocks, + bool force) +--- a/fs/xfs/xfs_trans.c ++++ b/fs/xfs/xfs_trans.c +@@ -840,6 +840,7 @@ __xfs_trans_commit( + */ + if (tp->t_flags & XFS_TRANS_SB_DIRTY) + xfs_trans_apply_sb_deltas(tp); ++ xfs_trans_apply_dquot_deltas(tp); + + error = xfs_trans_run_precommits(tp); + if (error) +@@ -868,11 +869,6 @@ __xfs_trans_commit( + + ASSERT(tp->t_ticket != NULL); + +- /* +- * If we need to update the superblock, then do it now. +- */ +- xfs_trans_apply_dquot_deltas(tp); +- + xlog_cil_commit(log, tp, &commit_seq, regrant); + + xfs_trans_free(tp); +@@ -898,7 +894,7 @@ out_unreserve: + * the dqinfo portion to be. All that means is that we have some + * (non-persistent) quota reservations that need to be unreserved. + */ +- xfs_trans_unreserve_and_mod_dquots(tp); ++ xfs_trans_unreserve_and_mod_dquots(tp, true); + if (tp->t_ticket) { + if (regrant && !xlog_is_shutdown(log)) + xfs_log_ticket_regrant(log, tp->t_ticket); +@@ -992,7 +988,7 @@ xfs_trans_cancel( + } + #endif + xfs_trans_unreserve_and_mod_sb(tp); +- xfs_trans_unreserve_and_mod_dquots(tp); ++ xfs_trans_unreserve_and_mod_dquots(tp, false); + + if (tp->t_ticket) { + xfs_log_ticket_ungrant(log, tp->t_ticket); +--- a/fs/xfs/xfs_trans_dquot.c ++++ b/fs/xfs/xfs_trans_dquot.c +@@ -602,6 +602,24 @@ xfs_trans_apply_dquot_deltas( + ASSERT(dqp->q_blk.reserved >= dqp->q_blk.count); + ASSERT(dqp->q_ino.reserved >= dqp->q_ino.count); + ASSERT(dqp->q_rtb.reserved >= dqp->q_rtb.count); ++ ++ /* ++ * We've applied the count changes and given back ++ * whatever reservation we didn't use. Zero out the ++ * dqtrx fields. ++ */ ++ qtrx->qt_blk_res = 0; ++ qtrx->qt_bcount_delta = 0; ++ qtrx->qt_delbcnt_delta = 0; ++ ++ qtrx->qt_rtblk_res = 0; ++ qtrx->qt_rtblk_res_used = 0; ++ qtrx->qt_rtbcount_delta = 0; ++ qtrx->qt_delrtb_delta = 0; ++ ++ qtrx->qt_ino_res = 0; ++ qtrx->qt_ino_res_used = 0; ++ qtrx->qt_icount_delta = 0; + } + } + } +@@ -638,7 +656,8 @@ xfs_trans_unreserve_and_mod_dquots_hook( + */ + void + xfs_trans_unreserve_and_mod_dquots( +- struct xfs_trans *tp) ++ struct xfs_trans *tp, ++ bool already_locked) + { + int i, j; + struct xfs_dquot *dqp; +@@ -667,10 +686,12 @@ xfs_trans_unreserve_and_mod_dquots( + * about the number of blocks used field, or deltas. + * Also we don't bother to zero the fields. + */ +- locked = false; ++ locked = already_locked; + if (qtrx->qt_blk_res) { +- xfs_dqlock(dqp); +- locked = true; ++ if (!locked) { ++ xfs_dqlock(dqp); ++ locked = true; ++ } + dqp->q_blk.reserved -= + (xfs_qcnt_t)qtrx->qt_blk_res; + } +@@ -691,7 +712,7 @@ xfs_trans_unreserve_and_mod_dquots( + dqp->q_rtb.reserved -= + (xfs_qcnt_t)qtrx->qt_rtblk_res; + } +- if (locked) ++ if (locked && !already_locked) + xfs_dqunlock(dqp); + + }