]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
6.12-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 18 Feb 2025 08:29:35 +0000 (09:29 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 18 Feb 2025 08:29:35 +0000 (09:29 +0100)
added patches:
series
xfs-don-t-lose-solo-dquot-update-transactions.patch

queue-6.12/series [new file with mode: 0644]
queue-6.12/xfs-don-t-lose-solo-dquot-update-transactions.patch [new file with mode: 0644]

diff --git a/queue-6.12/series b/queue-6.12/series
new file mode 100644 (file)
index 0000000..b6f0894
--- /dev/null
@@ -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 (file)
index 0000000..4ac903c
--- /dev/null
@@ -0,0 +1,159 @@
+From 07137e925fa951646325762bda6bd2503dfe64c6 Mon Sep 17 00:00:00 2001
+From: "Darrick J. Wong" <djwong@kernel.org>
+Date: Mon, 2 Dec 2024 10:57:36 -0800
+Subject: xfs: don't lose solo dquot update transactions
+
+From: Darrick J. Wong <djwong@kernel.org>
+
+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: <stable@vger.kernel.org> # v2.6.35
+Fixes: 0924378a689ccb ("xfs: split out iclog writing from xfs_trans_commit()")
+Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
+Reviewed-by: Christoph Hellwig <hch@lst.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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);
+               }