* FAILED: patch "[PATCH] xfs: reattach dquots after changing inode ids" failed to apply to 6.12-stable tree
@ 2026-11-04 17:51 gregkh
2026-11-05 16:24 ` [PATCH 6.12.y] xfs: reattach dquots after changing inode ids Sasha Levin
0 siblings, 1 reply; 2+ messages in thread
From: gregkh @ 2026-11-04 17:51 UTC (permalink / raw)
To: djwong, cem, hch; +Cc: stable
The patch below does not apply to the 6.12-stable tree.
If someone wants it applied there, or to any other stable or longterm
tree, then please email the backport, including the original git commit
id to <stable@vger.kernel.org>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.12.y
git checkout FETCH_HEAD
git cherry-pick -x 2f528e4a8f89daa6d0cc64b044f6f94c018fe9ae
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<stable@vger.kernel.org>' --in-reply-to '2026110407-plot-stainable-802b@gregkh' --subject-prefix 'PATCH 6.12.y' 'HEAD^..'
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 2f528e4a8f89daa6d0cc64b044f6f94c018fe9ae Mon Sep 17 00:00:00 2001
From: "Darrick J. Wong" <djwong@kernel.org>
Date: Mon, 12 Oct 2026 08:21:22 -0700
Subject: [PATCH] xfs: reattach dquots after changing inode ids
LOLLM noticed that xrep_inode_ids can change the user, group, or project
id of any given file. When this happens, we need to detach any existing
incore dquot and attach the correct ones.
Cc: stable@vger.kernel.org # v6.8
Fixes: 2d295fe65776d1 ("xfs: repair inode records")
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>
diff --git a/fs/xfs/scrub/inode_repair.c b/fs/xfs/scrub/inode_repair.c
index e1a7a2729b47..c81dfb0485e2 100644
--- a/fs/xfs/scrub/inode_repair.c
+++ b/fs/xfs/scrub/inode_repair.c
@@ -41,6 +41,8 @@
#include "xfs_rtgroup.h"
#include "xfs_rtrmap_btree.h"
#include "xfs_rtrefcount_btree.h"
+#include "xfs_dquot_item.h"
+#include "xfs_dquot.h"
#include "scrub/xfs_scrub.h"
#include "scrub/scrub.h"
#include "scrub/common.h"
@@ -1757,6 +1759,20 @@ xrep_inode_ids(
trace_xrep_inode_ids(sc);
+ /*
+ * We changed one of the file IDs, so we must detach the dquots to
+ * prevent further changes from being accounted to them, and try to
+ * attach the dquot for the new id to absorb any other block usage
+ * changes. We can't do that right now because the existing dquots
+ * might be attached to the scrub transaction and we're in the middle
+ * of fixing the inode, so we'll switch the incore dquot pointers
+ * later.
+ *
+ * Schedule a quotacheck so the accounting discrepancies will get fixed
+ * eventually. We'll have to repeat this later when we do the actual
+ * switch.
+ */
+
if (!uid_valid(VFS_I(sc->ip)->i_uid)) {
i_uid_write(VFS_I(sc->ip), 0);
dirty = true;
@@ -2066,6 +2082,113 @@ xrep_inode_unlinked(
return 0;
}
+#ifdef CONFIG_XFS_QUOTA
+static inline bool
+xrep_inode_need_reset_dquots(
+ struct xfs_scrub *sc)
+{
+ struct xfs_mount *mp = sc->mp;
+ struct xfs_inode *ip = sc->ip;
+
+ if (!XFS_IS_QUOTA_ON(mp))
+ return false;
+ if (xfs_is_quota_inode(&mp->m_sb, I_INO(ip)))
+ return false;
+ if (xfs_is_metadir_inode(ip))
+ return false;
+
+ if (XFS_IS_UQUOTA_ON(sc->mp) &&
+ (!ip->i_udquot || ip->i_udquot->q_id != i_uid_read(VFS_I(ip))))
+ return true;
+ if (XFS_IS_GQUOTA_ON(sc->mp) &&
+ (!ip->i_gdquot || ip->i_gdquot->q_id != i_gid_read(VFS_I(ip))))
+ return true;
+ if (XFS_IS_PQUOTA_ON(sc->mp) &&
+ (!ip->i_pdquot || ip->i_pdquot->q_id != ip->i_projid))
+ return true;
+
+ return false;
+}
+
+/* Switch dquot, return dqtype if we need quotacheck */
+static xfs_dqtype_t
+xrep_inode_switch_dquot(
+ struct xfs_scrub *sc,
+ xfs_dqtype_t type,
+ struct xfs_dquot **dqp)
+{
+ xfs_dqtype_t ret = 0;
+ xfs_dqid_t id = xfs_qm_id_for_quotatype(sc->ip, type);
+
+ if (*dqp != NULL && (*dqp)->q_id != id) {
+ xfs_qm_dqrele(*dqp);
+ *dqp = NULL;
+ }
+
+ if (!*dqp) {
+ xfs_qm_dqget_inode(sc->ip, type, true, dqp);
+ ret = type;
+ }
+ return ret;
+}
+
+static int
+xrep_inode_reset_dquots(
+ struct xfs_scrub *sc)
+{
+ xfs_dqtype_t need = 0;
+ int error;
+
+ /*
+ * If we changed the file IDs, then we need to drop the transaction so
+ * that we can detach the dquots and attach new ones.
+ *
+ * Commit the scrub transaction so that there are no dangling
+ * references to any dquots that might get detached, and retain the
+ * ILOCK, as required by the dqattach code.
+ *
+ * Note that dqattach can cycle the ILOCK when creating a new dquot, so
+ * this must be the very last thing that the repair function does.
+ */
+ error = xrep_trans_commit(sc);
+ if (error)
+ return error;
+
+ if (XFS_IS_UQUOTA_ON(sc->mp))
+ need |= xrep_inode_switch_dquot(sc, XFS_DQTYPE_USER,
+ &sc->ip->i_udquot);
+ if (XFS_IS_GQUOTA_ON(sc->mp))
+ need |= xrep_inode_switch_dquot(sc, XFS_DQTYPE_GROUP,
+ &sc->ip->i_gdquot);
+ if (XFS_IS_PQUOTA_ON(sc->mp))
+ need |= xrep_inode_switch_dquot(sc, XFS_DQTYPE_PROJ,
+ &sc->ip->i_pdquot);
+
+ xchk_iunlock(sc, XFS_ILOCK_EXCL);
+
+ /*
+ * Now that we've updated the dquots, force quotacheck once again.
+ * In theory we could be racing against a concurrent quotacheck.
+ * Note that we can't hold the ILOCK when allocating a transaction.
+ */
+ error = xchk_trans_alloc(sc, 0);
+ if (error)
+ return error;
+
+ if (need & XFS_DQTYPE_USER)
+ xrep_force_quotacheck(sc, XFS_DQTYPE_USER);
+ if (need & XFS_DQTYPE_GROUP)
+ xrep_force_quotacheck(sc, XFS_DQTYPE_GROUP);
+ if (need & XFS_DQTYPE_PROJ)
+ xrep_force_quotacheck(sc, XFS_DQTYPE_PROJ);
+
+ return 0;
+}
+#else
+# define xrep_inode_need_reset_dquots(sc) (false)
+# define xrep_inode_reset_dquots(sc) (0)
+#endif
+
/* Repair an inode's fields. */
int
xrep_inode(
@@ -2120,5 +2243,13 @@ xrep_inode(
if (error)
return error;
- return xrep_defer_finish(sc);
+ error = xrep_defer_finish(sc);
+ if (error)
+ return error;
+
+ /* Must come last */
+ if (xrep_inode_need_reset_dquots(sc))
+ return xrep_inode_reset_dquots(sc);
+
+ return 0;
}
^ permalink raw reply related [flat|nested] 2+ messages in thread
* [PATCH 6.12.y] xfs: reattach dquots after changing inode ids
2026-11-04 17:51 FAILED: patch "[PATCH] xfs: reattach dquots after changing inode ids" failed to apply to 6.12-stable tree gregkh
@ 2026-11-05 16:24 ` Sasha Levin
0 siblings, 0 replies; 2+ messages in thread
From: Sasha Levin @ 2026-11-05 16:24 UTC (permalink / raw)
To: stable; +Cc: Darrick J. Wong, Christoph Hellwig, Carlos Maiolino, Sasha Levin
From: "Darrick J. Wong" <djwong@kernel.org>
[ Upstream commit 2f528e4a8f89daa6d0cc64b044f6f94c018fe9ae ]
LOLLM noticed that xrep_inode_ids can change the user, group, or project
id of any given file. When this happens, we need to detach any existing
incore dquot and attach the correct ones.
Cc: stable@vger.kernel.org # v6.8
Fixes: 2d295fe65776d1 ("xfs: repair inode records")
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>
[ sashal: adapted quota attachment for missing metadata-directory support and xfs_qm_dqget_inode() returning locked dquots ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/xfs/scrub/inode_repair.c | 132 +++++++++++++++++++++++++++++++++++-
1 file changed, 131 insertions(+), 1 deletion(-)
diff --git a/fs/xfs/scrub/inode_repair.c b/fs/xfs/scrub/inode_repair.c
index 6be4551bffbd3..fa84a2efee431 100644
--- a/fs/xfs/scrub/inode_repair.c
+++ b/fs/xfs/scrub/inode_repair.c
@@ -38,6 +38,8 @@
#include "xfs_log_priv.h"
#include "xfs_health.h"
#include "xfs_symlink_remote.h"
+#include "xfs_dquot_item.h"
+#include "xfs_dquot.h"
#include "scrub/xfs_scrub.h"
#include "scrub/scrub.h"
#include "scrub/common.h"
@@ -1570,6 +1572,20 @@ xrep_inode_ids(
trace_xrep_inode_ids(sc);
+ /*
+ * We changed one of the file IDs, so we must detach the dquots to
+ * prevent further changes from being accounted to them, and try to
+ * attach the dquot for the new id to absorb any other block usage
+ * changes. We can't do that right now because the existing dquots
+ * might be attached to the scrub transaction and we're in the middle
+ * of fixing the inode, so we'll switch the incore dquot pointers
+ * later.
+ *
+ * Schedule a quotacheck so the accounting discrepancies will get fixed
+ * eventually. We'll have to repeat this later when we do the actual
+ * switch.
+ */
+
if (!uid_valid(VFS_I(sc->ip)->i_uid)) {
i_uid_write(VFS_I(sc->ip), 0);
dirty = true;
@@ -1876,6 +1892,112 @@ xrep_inode_unlinked(
return 0;
}
+#ifdef CONFIG_XFS_QUOTA
+static inline bool
+xrep_inode_need_reset_dquots(
+ struct xfs_scrub *sc)
+{
+ struct xfs_mount *mp = sc->mp;
+ struct xfs_inode *ip = sc->ip;
+
+ if (!XFS_IS_QUOTA_ON(mp))
+ return false;
+ if (xfs_is_quota_inode(&mp->m_sb, I_INO(ip)))
+ return false;
+
+ if (XFS_IS_UQUOTA_ON(sc->mp) &&
+ (!ip->i_udquot || ip->i_udquot->q_id != i_uid_read(VFS_I(ip))))
+ return true;
+ if (XFS_IS_GQUOTA_ON(sc->mp) &&
+ (!ip->i_gdquot || ip->i_gdquot->q_id != i_gid_read(VFS_I(ip))))
+ return true;
+ if (XFS_IS_PQUOTA_ON(sc->mp) &&
+ (!ip->i_pdquot || ip->i_pdquot->q_id != ip->i_projid))
+ return true;
+
+ return false;
+}
+
+/* Switch dquot, return dqtype if we need quotacheck */
+static xfs_dqtype_t
+xrep_inode_switch_dquot(
+ struct xfs_scrub *sc,
+ xfs_dqtype_t type,
+ struct xfs_dquot **dqp)
+{
+ xfs_dqtype_t ret = 0;
+ xfs_dqid_t id = xfs_qm_id_for_quotatype(sc->ip, type);
+
+ if (*dqp != NULL && (*dqp)->q_id != id) {
+ xfs_qm_dqrele(*dqp);
+ *dqp = NULL;
+ }
+
+ if (!*dqp) {
+ if (!xfs_qm_dqget_inode(sc->ip, type, true, dqp))
+ xfs_dqunlock(*dqp);
+ ret = type;
+ }
+ return ret;
+}
+
+static int
+xrep_inode_reset_dquots(
+ struct xfs_scrub *sc)
+{
+ xfs_dqtype_t need = 0;
+ int error;
+
+ /*
+ * If we changed the file IDs, then we need to drop the transaction so
+ * that we can detach the dquots and attach new ones.
+ *
+ * Commit the scrub transaction so that there are no dangling
+ * references to any dquots that might get detached, and retain the
+ * ILOCK, as required by the dqattach code.
+ *
+ * Note that dqattach can cycle the ILOCK when creating a new dquot, so
+ * this must be the very last thing that the repair function does.
+ */
+ error = xrep_trans_commit(sc);
+ if (error)
+ return error;
+
+ if (XFS_IS_UQUOTA_ON(sc->mp))
+ need |= xrep_inode_switch_dquot(sc, XFS_DQTYPE_USER,
+ &sc->ip->i_udquot);
+ if (XFS_IS_GQUOTA_ON(sc->mp))
+ need |= xrep_inode_switch_dquot(sc, XFS_DQTYPE_GROUP,
+ &sc->ip->i_gdquot);
+ if (XFS_IS_PQUOTA_ON(sc->mp))
+ need |= xrep_inode_switch_dquot(sc, XFS_DQTYPE_PROJ,
+ &sc->ip->i_pdquot);
+
+ xchk_iunlock(sc, XFS_ILOCK_EXCL);
+
+ /*
+ * Now that we've updated the dquots, force quotacheck once again.
+ * In theory we could be racing against a concurrent quotacheck.
+ * Note that we can't hold the ILOCK when allocating a transaction.
+ */
+ error = xchk_trans_alloc(sc, 0);
+ if (error)
+ return error;
+
+ if (need & XFS_DQTYPE_USER)
+ xrep_force_quotacheck(sc, XFS_DQTYPE_USER);
+ if (need & XFS_DQTYPE_GROUP)
+ xrep_force_quotacheck(sc, XFS_DQTYPE_GROUP);
+ if (need & XFS_DQTYPE_PROJ)
+ xrep_force_quotacheck(sc, XFS_DQTYPE_PROJ);
+
+ return 0;
+}
+#else
+# define xrep_inode_need_reset_dquots(sc) (false)
+# define xrep_inode_reset_dquots(sc) (0)
+#endif
+
/* Repair an inode's fields. */
int
xrep_inode(
@@ -1930,5 +2052,13 @@ xrep_inode(
if (error)
return error;
- return xrep_defer_finish(sc);
+ error = xrep_defer_finish(sc);
+ if (error)
+ return error;
+
+ /* Must come last */
+ if (xrep_inode_need_reset_dquots(sc))
+ return xrep_inode_reset_dquots(sc);
+
+ return 0;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-11-05 16:24 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-04 17:51 FAILED: patch "[PATCH] xfs: reattach dquots after changing inode ids" failed to apply to 6.12-stable tree gregkh
2026-11-05 16:24 ` [PATCH 6.12.y] xfs: reattach dquots after changing inode ids Sasha Levin
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.