From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.remote-ip=100.103.45.18 ARC-Seal: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; cv=none; t=1794590882; b=ApBplG+wFJdlbePQi2LNdtE+jExrHlOzSmKmOm75ticj4L2bpeJzwVUvj6Sg6AujFcD4 54LdkkebGG2cLve0pM5HpiIRsK8nhvptVSfF3kfui/cc4jaXUy9lAVoJ0ZOcYOZQLfuNl +VAU9ymBXEUR5p3mVlVoq3KdKuXw1UBju4yuJoTq+lQaURrEH3MMDPfy08wOcK37Qi7ew U/KogpyD1WPxaUIGY/qO0HhuUSR2mgLl5Mo+M5BQuSpc4Dmb/E+kGmblN3kv8I4SyePuU 7wvtTncPqzXbsYqZDGS46Z2SHGRPGmwt4jQNLrwU1OpsCkb1sxKtvkNo2z/1q5muRJQ== ARC-Message-Signature: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1794590882; h=Received:DKIM-Signature:From:To:Cc:Subject:Date:Message-ID:X-Mailer: In-Reply-To:References:User-Agent:X-stable:X-Patchwork-Hint: MIME-Version:Content-Transfer-Encoding; bh=dt/o4TW1CzqAO/kcfOG8B9jaV8KEBCZNCuZOIavX7bc=; b=ybNx1i3xRB4Njzs1c56v4y/V7Yq3ol9b0D1hgFEpr5WthVR+yocu+2RdpzJrbiwShv0O 8MVAQB1RiZpV3E7/559TQVwCkhM+xmnDDDcljEsQjiLw2A98WBi4KyZiFsj9MPSHH3rtZ nL0I7Uyvhlw27cMmMN540HY14xGF7qroIzpXrlw1HTC1i7I4Kfs5GSda3zO0stkNPTFd8 iLbSdwGaEPFXduvSsrxXFygA7rNCKbL3+Fp0Cn5l+zSv8F3A3q0qut5nxzHATnoiG1Kcn eviR+YW18EsjTPpnicGW8OhTHKyrlGpvQTgs9s8eutpan+kVhDE4SjMpC310Z909JlQ== ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass header.d=linuxfoundation.org header.i=@linuxfoundation.org header.a=rsa-sha256 header.s=korg header.b=CEqBYVIO; arc=none smtp.remote-ip=100.103.45.18 Received: from smtp.kernel.org (quasi.space.kernel.org [100.103.45.18]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (prime256v1)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C16EE606D869; Fri, 13 Nov 2026 17:28:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linuxfoundation.org header.i=@linuxfoundation.org header.a=rsa-sha256 header.s=korg header.b=CEqBYVIO Received: by smtp.kernel.org (Postfix) with ESMTPSA id 6D7121F000C4; Fri, 13 Nov 2026 17:28:02 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linuxfoundation.org; s=korg; t=1794590882; bh=dt/o4TW1CzqAO/kcfOG8B9jaV8KEBCZNCuZOIavX7bc=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=CEqBYVIOeP6B+gUOzoJaQ3Bsq3EjFJ39yoNlzT1p8qZdEdlzZ/9G/qvMFbB6FoMAv PZqA+7b2qmYc+j9oHvHh2WibiTdhY+S4xzMxF6TD8bGUOOzVhjN8qBCIf1w7cNTkju ZhlyJzSbTs8CKMniPNE3wLLGS1r/7io1lEIeQGMU= From: Greg Kroah-Hartman To: stable@vger.kernel.org Cc: Greg Kroah-Hartman , patches@lists.linux.dev, "Darrick J. Wong" , Christoph Hellwig , Carlos Maiolino , Sasha Levin Subject: [PATCH 6.12 077/670] xfs: reattach dquots after changing inode ids Date: Fri, 13 Nov 2026 10:44:01 -0500 Message-ID: <20261113153814.188356377@linuxfoundation.org> X-Mailer: git-send-email 2.56.0 In-Reply-To: <20261113153811.177190860@linuxfoundation.org> References: <20261113153811.177190860@linuxfoundation.org> User-Agent: quilt/0.69 X-stable: review X-Patchwork-Hint: ignore X-Mailing-List: stable@vger.kernel.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Transfer-Encoding: 8bit 6.12-stable review patch. If anyone has any objections, please let me know. ------------------ From: Darrick J. Wong [ 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 Assisted-by: LOLLM # finding obvious bugs Reviewed-by: Christoph Hellwig Signed-off-by: Carlos Maiolino [ sashal: adapted quota attachment for missing metadata-directory support and xfs_qm_dqget_inode() returning locked dquots ] Signed-off-by: Sasha Levin --- 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