From patchwork Mon Dec 23 22:25:19 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13919435 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3905A18E35D for ; Mon, 23 Dec 2024 22:25:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734992720; cv=none; b=T/srY6J6F7iiQIL8fk8xGytSLuQ9kuJvXBXdsyNilUxBIqp4LZsvMi5lfcP+HMPtcFWpbHa9kyvpS/RSpzsmH5DnpTSoi5eIjI5yqTToP1X0hOAwVPgylo+emrFw79k1RvP1WdVvCcwcQwQHgJDNEyJJYNP1Rhxe7GgxnLiTPzk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734992720; c=relaxed/simple; bh=sHdcCzUSTJxIQxsLvKw3htxZcYbSzttyMF0khf7XcaM=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=ZUpRGbyiHegrnN/QYZTUG1LN18BSIY2XocVNAtfpYk3QhxMUD3GRw4ZfvJlJ5H2Inb9+HtL8UdcehTAPF2hr8TUPRMM3P87z12M/vM4IAiAd/plINmaIJA/jMvQHBQNKJOIgYbKaQi7bMIWUrKRh8SybcoyNcuzjas0yBqhSPwA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=fASLKN9z; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="fASLKN9z" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 0E51EC4CED3; Mon, 23 Dec 2024 22:25:20 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1734992720; bh=sHdcCzUSTJxIQxsLvKw3htxZcYbSzttyMF0khf7XcaM=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=fASLKN9zxMFMxk8wcz+kpZf2XUnPLK9LWqVbTgvZi5UX95fOp4qcgzM7mYN6ZKpWk 0WucYHBut73SPdpkClqtnq9lJ+qoCCeRG+zWCMBuLiqvR46hMcqQSnwRB4st/HLXjB cqxnFuMiLnzhIVjZTchsbtjiAOqUj3wpZjvvtoNja3kw0Hr/a5p34zxdyM1a+j7F/d nXS0w+rnB+7bJwAhBNNpeBeEUxP8prjUv0SxVqMQz5woIBcIdFUNWZLchrHklGL/qa 8bT5Zl4xIJnkFaNvpVCtGJCiGfrt6GzDH7aKFUEQVCn5lqxW9vvvYu4mQVBD6U7d7b UryAEg7NC0G7g== Date: Mon, 23 Dec 2024 14:25:19 -0800 Subject: [PATCH 1/7] libfrog: scrub quota file metapaths From: "Darrick J. Wong" To: djwong@kernel.org, aalbersh@kernel.org Cc: hch@lst.de, linux-xfs@vger.kernel.org Message-ID: <173498944983.2299261.5570475562041386399.stgit@frogsfrogsfrogs> In-Reply-To: <173498944956.2299261.16768993427453132101.stgit@frogsfrogsfrogs> References: <173498944956.2299261.16768993427453132101.stgit@frogsfrogsfrogs> Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Support scrubbing quota file metadir paths. Signed-off-by: "Darrick J. Wong" Reviewed-by: Christoph Hellwig --- libfrog/scrub.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/libfrog/scrub.c b/libfrog/scrub.c index d40364d35ce0b4..129f592e108ae1 100644 --- a/libfrog/scrub.c +++ b/libfrog/scrub.c @@ -187,6 +187,26 @@ const struct xfrog_scrub_descr xfrog_metapaths[XFS_SCRUB_METAPATH_NR] = { .descr = "rtgroup summary", .group = XFROG_SCRUB_GROUP_RTGROUP, }, + [XFS_SCRUB_METAPATH_QUOTADIR] = { + .name = "quotadir", + .descr = "quota file metadir", + .group = XFROG_SCRUB_GROUP_FS, + }, + [XFS_SCRUB_METAPATH_USRQUOTA] = { + .name = "usrquota", + .descr = "user quota file", + .group = XFROG_SCRUB_GROUP_FS, + }, + [XFS_SCRUB_METAPATH_GRPQUOTA] = { + .name = "grpquota", + .descr = "group quota file", + .group = XFROG_SCRUB_GROUP_FS, + }, + [XFS_SCRUB_METAPATH_PRJQUOTA] = { + .name = "prjquota", + .descr = "project quota file", + .group = XFROG_SCRUB_GROUP_FS, + }, }; /* Invoke the scrub ioctl. Returns zero or negative error code. */ From patchwork Mon Dec 23 22:25:35 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13919436 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 307EA192B86 for ; Mon, 23 Dec 2024 22:25:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734992736; cv=none; b=gIZbCaIF2nnLtZeaVkyDSmJSwMBUyafD8TcYR6Kyu6AV+V45p3hsVp6w8OfqJSZi1hAPmckJuZDcHefVhXgEFLu5c5Wjmn1BCx5DCi90SrWENAj/vL8dFu8VZ0NZTtXfNIveAzwThEWSrJ5031rZOdgC+w9LEwevd7svOXBVjho= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734992736; c=relaxed/simple; bh=zTmlcqHwfRxm2+48kwMJCKx22rsFj2lfzl5Mx72nWbA=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=E99n8AI3aOsBCaV6Pk7qEc9gJuFKI7yCmqmi3jZ2IvhCNJka3vqebF4iDhRR/thTuK0qmZU/WXpJboggMT8sV8W4557fOv98oxtSZJRl/cn/4/eUvTuD9lwwt5zescgWO9zbdXqCVx5NvNkF4FewT8h4agRUn6Bhe422zZyrQdM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=lj/S6kJ0; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="lj/S6kJ0" Received: by smtp.kernel.org (Postfix) with ESMTPSA id AA076C4CED3; Mon, 23 Dec 2024 22:25:35 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1734992735; bh=zTmlcqHwfRxm2+48kwMJCKx22rsFj2lfzl5Mx72nWbA=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=lj/S6kJ0uSnq3Z1Qvud4FkLTMX0R1S/7iUQAtn5TqNL8Nk3CSLjsKJRCcXBjpvTmR GqqRbUBPPzNwNJUfW89E75bnexNOXIyTs3iUBf0AN4BBbCoHzQ+nLGmjztalb+k9ZU V5j2gUVPlU9VoEnvZmnBmnlMMd/80CxjwN8ndCdld4aJNiHRz+dZNT0gYXf5MNHwMA Y+XKZThQlyzaqXbDG5o1sSybvwoZOvAsGjAN1ivRd0GjfQEj4i8BFCwuR5b1jel6mp mAw0jPf44w1lsz3NkIPIpd6BAPcX7Xd9HFMJuAyzgTbwHoQzwl4Q5/x3MXtMqOq2zH yzaS37EbaWsCw== Date: Mon, 23 Dec 2024 14:25:35 -0800 Subject: [PATCH 2/7] xfs_db: support metadir quotas From: "Darrick J. Wong" To: djwong@kernel.org, aalbersh@kernel.org Cc: hch@lst.de, linux-xfs@vger.kernel.org Message-ID: <173498944999.2299261.13893848897337655459.stgit@frogsfrogsfrogs> In-Reply-To: <173498944956.2299261.16768993427453132101.stgit@frogsfrogsfrogs> References: <173498944956.2299261.16768993427453132101.stgit@frogsfrogsfrogs> Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Support finding the quota files in the metadata directory. Signed-off-by: "Darrick J. Wong" Reviewed-by: Christoph Hellwig --- db/dquot.c | 59 ++++++++++++++++++++++++++++++++++------------ libxfs/libxfs_api_defs.h | 6 +++++ 2 files changed, 50 insertions(+), 15 deletions(-) diff --git a/db/dquot.c b/db/dquot.c index 338d064995155e..d2c76fd70bf1a6 100644 --- a/db/dquot.c +++ b/db/dquot.c @@ -81,6 +81,41 @@ dquot_help(void) { } +static xfs_ino_t +dqtype_to_inode( + struct xfs_mount *mp, + xfs_dqtype_t type) +{ + struct xfs_trans *tp; + struct xfs_inode *dp = NULL; + struct xfs_inode *ip; + xfs_ino_t ret = NULLFSINO; + int error; + + error = -libxfs_trans_alloc_empty(mp, &tp); + if (error) + return NULLFSINO; + + if (xfs_has_metadir(mp)) { + error = -libxfs_dqinode_load_parent(tp, &dp); + if (error) + goto out_cancel; + } + + error = -libxfs_dqinode_load(tp, dp, type, &ip); + if (error) + goto out_dp; + + ret = ip->i_ino; + libxfs_irele(ip); +out_dp: + if (dp) + libxfs_irele(dp); +out_cancel: + libxfs_trans_cancel(tp); + return ret; +} + static int dquot_f( int argc, @@ -88,8 +123,7 @@ dquot_f( { bmap_ext_t bm; int c; - int dogrp; - int doprj; + xfs_dqtype_t type = XFS_DQTYPE_USER; xfs_dqid_t id; xfs_ino_t ino; xfs_extnum_t nex; @@ -97,38 +131,33 @@ dquot_f( int perblock; xfs_fileoff_t qbno; int qoff; - char *s; + const char *s; - dogrp = doprj = optind = 0; + optind = 0; while ((c = getopt(argc, argv, "gpu")) != EOF) { switch (c) { case 'g': - dogrp = 1; - doprj = 0; + type = XFS_DQTYPE_GROUP; break; case 'p': - doprj = 1; - dogrp = 0; + type = XFS_DQTYPE_PROJ; break; case 'u': - dogrp = doprj = 0; + type = XFS_DQTYPE_USER; break; default: dbprintf(_("bad option for dquot command\n")); return 0; } } - s = doprj ? _("project") : dogrp ? _("group") : _("user"); + + s = libxfs_dqinode_path(type); if (optind != argc - 1) { dbprintf(_("dquot command requires one %s id argument\n"), s); return 0; } - ino = mp->m_sb.sb_uquotino; - if (doprj) - ino = mp->m_sb.sb_pquotino; - else if (dogrp) - ino = mp->m_sb.sb_gquotino; + ino = dqtype_to_inode(mp, type); if (ino == 0 || ino == NULLFSINO) { dbprintf(_("no %s quota inode present\n"), s); return 0; diff --git a/libxfs/libxfs_api_defs.h b/libxfs/libxfs_api_defs.h index a8416dfbb27f59..6b2dc7a30d2547 100644 --- a/libxfs/libxfs_api_defs.h +++ b/libxfs/libxfs_api_defs.h @@ -159,6 +159,12 @@ #define xfs_dir_replace libxfs_dir_replace #define xfs_dqblk_repair libxfs_dqblk_repair +#define xfs_dqinode_load libxfs_dqinode_load +#define xfs_dqinode_load_parent libxfs_dqinode_load_parent +#define xfs_dqinode_mkdir_parent libxfs_dqinode_mkdir_parent +#define xfs_dqinode_metadir_create libxfs_dqinode_metadir_create +#define xfs_dqinode_metadir_link libxfs_dqinode_metadir_link +#define xfs_dqinode_path libxfs_dqinode_path #define xfs_dquot_from_disk_ts libxfs_dquot_from_disk_ts #define xfs_dquot_verify libxfs_dquot_verify From patchwork Mon Dec 23 22:25:50 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13919437 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 792CD433D5 for ; Mon, 23 Dec 2024 22:25:51 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734992751; cv=none; b=S3pLgJcP+l+Q0cJore7nm1LWz+DNcv71oWUYhvuw1yi7mJqNEOG3ZXfqGriRVkWED/7TPwLd8pH/lCivsDEbUDH4DPOBOI71nwpDcZ/VwHRUgFrmzjFvpkcHpDUnDElb+UaMKuwAsT4AKL/lvRJotazN+shdztIpDiyzCGziBQk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734992751; c=relaxed/simple; bh=sjQLfn5OZFy7mqu3UlAKap1mHZRSXqb8xkEsqhbykQU=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=rU7Nh6LAbnbsUlgF28XHOVOO/zj+X/GtR7LcwyLqmxffKE5yyR63rfV5o4w4W/8xsZSMtmMWkgdhy47udYHYXUcLO8DGBJCvJASSwPebpmk4/GFBK8OKVqFmU2Sh7eiMaJFdaznIBsBfxoOYDRVVwaPSxCbuQKeyuirMW/xu/a0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=alyAS4Gz; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="alyAS4Gz" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 46129C4CED3; Mon, 23 Dec 2024 22:25:51 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1734992751; bh=sjQLfn5OZFy7mqu3UlAKap1mHZRSXqb8xkEsqhbykQU=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=alyAS4Gz/x2LMrYbdi0K55XdedDQcBE9Y8dxbtJVQDIISWVQgkNuu0u36AT5vi5NM FlLtaoL7gkX6ANDRivrUSD6tF/O1y0EJlVbbmFoOUdFyNEPldppmBCiRDBHSte1J4P Xtt+97Qm/jONixcFVDUBaHk2UAvrgAQGLbiL7lqGN5CwYZ+SfbRWdPw3Boc4Yhj3VJ ZmMP4DSW5HTKELdtLZpmrrUqTg7AIPy74H5+RPTvQcgfaZzcKALjy5FBMNUi03LPhM 8XA/lKTbsWdQPDcnoT/Lfjcpg8bCb01Gbt9xfHKhCgb0gyIb8IuRNJUTD+FPCyEgL7 0fyAiHoLQtgbg== Date: Mon, 23 Dec 2024 14:25:50 -0800 Subject: [PATCH 3/7] xfs_repair: refactor quota inumber handling From: "Darrick J. Wong" To: djwong@kernel.org, aalbersh@kernel.org Cc: hch@lst.de, linux-xfs@vger.kernel.org Message-ID: <173498945014.2299261.3904284923865882799.stgit@frogsfrogsfrogs> In-Reply-To: <173498944956.2299261.16768993427453132101.stgit@frogsfrogsfrogs> References: <173498944956.2299261.16768993427453132101.stgit@frogsfrogsfrogs> Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong In preparation for putting quota files in the metadata directory tree, refactor repair's quota inumber handling to use its own variables instead of the xfs_mount's. Signed-off-by: "Darrick J. Wong" Reviewed-by: Christoph Hellwig --- repair/dinode.c | 18 ++++---- repair/dir2.c | 12 +++--- repair/globals.c | 111 ++++++++++++++++++++++++++++++++++++++++++++++++--- repair/globals.h | 15 ++++--- repair/phase4.c | 96 ++++++++++++++++++-------------------------- repair/phase6.c | 12 +++--- repair/quotacheck.c | 47 +++++++++++++++------- repair/quotacheck.h | 2 + repair/versions.c | 9 +--- repair/xfs_repair.c | 12 ++++-- 10 files changed, 221 insertions(+), 113 deletions(-) diff --git a/repair/dinode.c b/repair/dinode.c index 2d341975e53993..9ab193bc5fe973 100644 --- a/repair/dinode.c +++ b/repair/dinode.c @@ -1662,29 +1662,29 @@ process_check_metadata_inodes( } return 0; } - if (lino == mp->m_sb.sb_uquotino) { + if (is_quota_inode(XFS_DQTYPE_USER, lino)) { if (*type != XR_INO_UQUOTA) { do_warn(_("user quota inode %" PRIu64 " has bad type 0x%x\n"), lino, dinode_fmt(dinoc)); - mp->m_sb.sb_uquotino = NULLFSINO; + clear_quota_inode(XFS_DQTYPE_USER); return 1; } return 0; } - if (lino == mp->m_sb.sb_gquotino) { + if (is_quota_inode(XFS_DQTYPE_GROUP, lino)) { if (*type != XR_INO_GQUOTA) { do_warn(_("group quota inode %" PRIu64 " has bad type 0x%x\n"), lino, dinode_fmt(dinoc)); - mp->m_sb.sb_gquotino = NULLFSINO; + clear_quota_inode(XFS_DQTYPE_GROUP); return 1; } return 0; } - if (lino == mp->m_sb.sb_pquotino) { + if (is_quota_inode(XFS_DQTYPE_PROJ, lino)) { if (*type != XR_INO_PQUOTA) { do_warn(_("project quota inode %" PRIu64 " has bad type 0x%x\n"), lino, dinode_fmt(dinoc)); - mp->m_sb.sb_pquotino = NULLFSINO; + clear_quota_inode(XFS_DQTYPE_PROJ); return 1; } return 0; @@ -2980,11 +2980,11 @@ _("bad (negative) size %" PRId64 " on inode %" PRIu64 "\n"), else if (lino == mp->m_sb.sb_rsumino || is_rtsummary_inode(lino)) type = XR_INO_RTSUM; - else if (lino == mp->m_sb.sb_uquotino) + else if (is_quota_inode(XFS_DQTYPE_USER, lino)) type = XR_INO_UQUOTA; - else if (lino == mp->m_sb.sb_gquotino) + else if (is_quota_inode(XFS_DQTYPE_GROUP, lino)) type = XR_INO_GQUOTA; - else if (lino == mp->m_sb.sb_pquotino) + else if (is_quota_inode(XFS_DQTYPE_PROJ, lino)) type = XR_INO_PQUOTA; else type = XR_INO_DATA; diff --git a/repair/dir2.c b/repair/dir2.c index ca747c90175e93..ed615662009957 100644 --- a/repair/dir2.c +++ b/repair/dir2.c @@ -265,13 +265,13 @@ process_sf_dir2( is_rtsummary_inode(lino)) { junkit = 1; junkreason = _("realtime summary"); - } else if (lino == mp->m_sb.sb_uquotino) { + } else if (is_quota_inode(XFS_DQTYPE_USER, lino)) { junkit = 1; junkreason = _("user quota"); - } else if (lino == mp->m_sb.sb_gquotino) { + } else if (is_quota_inode(XFS_DQTYPE_GROUP, lino)) { junkit = 1; junkreason = _("group quota"); - } else if (lino == mp->m_sb.sb_pquotino) { + } else if (is_quota_inode(XFS_DQTYPE_PROJ, lino)) { junkit = 1; junkreason = _("project quota"); } else if (lino == mp->m_sb.sb_metadirino) { @@ -746,11 +746,11 @@ process_dir2_data( } else if (ent_ino == mp->m_sb.sb_rsumino || is_rtsummary_inode(ent_ino)) { clearreason = _("realtime summary"); - } else if (ent_ino == mp->m_sb.sb_uquotino) { + } else if (is_quota_inode(XFS_DQTYPE_USER, ent_ino)) { clearreason = _("user quota"); - } else if (ent_ino == mp->m_sb.sb_gquotino) { + } else if (is_quota_inode(XFS_DQTYPE_GROUP, ent_ino)) { clearreason = _("group quota"); - } else if (ent_ino == mp->m_sb.sb_pquotino) { + } else if (is_quota_inode(XFS_DQTYPE_PROJ, ent_ino)) { clearreason = _("project quota"); } else if (ent_ino == mp->m_sb.sb_metadirino) { clearreason = _("metadata directory root"); diff --git a/repair/globals.c b/repair/globals.c index 30995f5298d5a1..99291d6afd61b9 100644 --- a/repair/globals.c +++ b/repair/globals.c @@ -73,12 +73,6 @@ int need_rbmino; int need_rsumino; int lost_quotas; -int have_uquotino; -int have_gquotino; -int have_pquotino; -int lost_uquotino; -int lost_gquotino; -int lost_pquotino; /* configuration vars -- fs geometry dependent */ @@ -119,3 +113,108 @@ int thread_count; /* If nonzero, simulate failure after this phase. */ int fail_after_phase; + +/* quota inode numbers */ +enum quotino_state { + QI_STATE_UNKNOWN, + QI_STATE_HAVE, + QI_STATE_LOST, +}; + +static xfs_ino_t quotinos[3] = { NULLFSINO, NULLFSINO, NULLFSINO }; +static enum quotino_state quotino_state[3]; + +static inline unsigned int quotino_off(xfs_dqtype_t type) +{ + switch (type) { + case XFS_DQTYPE_USER: + return 0; + case XFS_DQTYPE_GROUP: + return 1; + case XFS_DQTYPE_PROJ: + return 2; + } + + ASSERT(0); + return -1; +} + +void +set_quota_inode( + xfs_dqtype_t type, + xfs_ino_t ino) +{ + unsigned int off = quotino_off(type); + + quotinos[off] = ino; + quotino_state[off] = QI_STATE_HAVE; +} + +void +lose_quota_inode( + xfs_dqtype_t type) +{ + unsigned int off = quotino_off(type); + + quotinos[off] = NULLFSINO; + quotino_state[off] = QI_STATE_LOST; +} + +void +clear_quota_inode( + xfs_dqtype_t type) +{ + unsigned int off = quotino_off(type); + + quotinos[off] = NULLFSINO; + quotino_state[off] = QI_STATE_UNKNOWN; +} + +xfs_ino_t +get_quota_inode( + xfs_dqtype_t type) +{ + unsigned int off = quotino_off(type); + + return quotinos[off]; +} + +bool +is_quota_inode( + xfs_dqtype_t type, + xfs_ino_t ino) +{ + unsigned int off = quotino_off(type); + + return quotinos[off] == ino; +} + +bool +is_any_quota_inode( + xfs_ino_t ino) +{ + unsigned int i; + + for(i = 0; i < ARRAY_SIZE(quotinos); i++) + if (quotinos[i] == ino) + return true; + return false; +} + +bool +lost_quota_inode( + xfs_dqtype_t type) +{ + unsigned int off = quotino_off(type); + + return quotino_state[off] == QI_STATE_LOST; +} + +bool +has_quota_inode( + xfs_dqtype_t type) +{ + unsigned int off = quotino_off(type); + + return quotino_state[off] == QI_STATE_HAVE; +} diff --git a/repair/globals.h b/repair/globals.h index 7c2d9c56c8f8a7..b23a06af6cc81b 100644 --- a/repair/globals.h +++ b/repair/globals.h @@ -114,12 +114,6 @@ extern int need_rbmino; extern int need_rsumino; extern int lost_quotas; -extern int have_uquotino; -extern int have_gquotino; -extern int have_pquotino; -extern int lost_uquotino; -extern int lost_gquotino; -extern int lost_pquotino; /* configuration vars -- fs geometry dependent */ @@ -165,4 +159,13 @@ extern int fail_after_phase; extern struct libxfs_init x; +void set_quota_inode(xfs_dqtype_t type, xfs_ino_t); +void lose_quota_inode(xfs_dqtype_t type); +void clear_quota_inode(xfs_dqtype_t type); +xfs_ino_t get_quota_inode(xfs_dqtype_t type); +bool is_quota_inode(xfs_dqtype_t type, xfs_ino_t ino); +bool is_any_quota_inode(xfs_ino_t ino); +bool lost_quota_inode(xfs_dqtype_t type); +bool has_quota_inode(xfs_dqtype_t type); + #endif /* _XFS_REPAIR_GLOBAL_H */ diff --git a/repair/phase4.c b/repair/phase4.c index f43f8ecd84e25b..a4183c557a1891 100644 --- a/repair/phase4.c +++ b/repair/phase4.c @@ -23,6 +23,35 @@ bool collect_rmaps; +static inline void +quotino_check_one( + struct xfs_mount *mp, + xfs_dqtype_t type) +{ + struct ino_tree_node *irec; + xfs_ino_t ino; + + if (!has_quota_inode(type)) + return; + + ino = get_quota_inode(type); + if (!libxfs_verify_ino(mp, ino)) + goto bad; + + irec = find_inode_rec(mp, XFS_INO_TO_AGNO(mp, ino), + XFS_INO_TO_AGINO(mp, ino)); + if (!irec) + goto bad; + + if (is_inode_free(irec, ino - irec->ino_startnum)) + goto bad; + + return; + +bad: + lose_quota_inode(type); +} + /* * null out quota inode fields in sb if they point to non-existent inodes. * this isn't as redundant as it looks since it's possible that the sb field @@ -31,57 +60,12 @@ bool collect_rmaps; * be cleared by process_dinode(). */ static void -quotino_check(xfs_mount_t *mp) +quotino_check( + struct xfs_mount *mp) { - ino_tree_node_t *irec; - - if (mp->m_sb.sb_uquotino != NULLFSINO && mp->m_sb.sb_uquotino != 0) { - if (!libxfs_verify_ino(mp, mp->m_sb.sb_uquotino)) - irec = NULL; - else - irec = find_inode_rec(mp, - XFS_INO_TO_AGNO(mp, mp->m_sb.sb_uquotino), - XFS_INO_TO_AGINO(mp, mp->m_sb.sb_uquotino)); - - if (irec == NULL || is_inode_free(irec, - mp->m_sb.sb_uquotino - irec->ino_startnum)) { - mp->m_sb.sb_uquotino = NULLFSINO; - lost_uquotino = 1; - } else - lost_uquotino = 0; - } - - if (mp->m_sb.sb_gquotino != NULLFSINO && mp->m_sb.sb_gquotino != 0) { - if (!libxfs_verify_ino(mp, mp->m_sb.sb_gquotino)) - irec = NULL; - else - irec = find_inode_rec(mp, - XFS_INO_TO_AGNO(mp, mp->m_sb.sb_gquotino), - XFS_INO_TO_AGINO(mp, mp->m_sb.sb_gquotino)); - - if (irec == NULL || is_inode_free(irec, - mp->m_sb.sb_gquotino - irec->ino_startnum)) { - mp->m_sb.sb_gquotino = NULLFSINO; - lost_gquotino = 1; - } else - lost_gquotino = 0; - } - - if (mp->m_sb.sb_pquotino != NULLFSINO && mp->m_sb.sb_pquotino != 0) { - if (!libxfs_verify_ino(mp, mp->m_sb.sb_pquotino)) - irec = NULL; - else - irec = find_inode_rec(mp, - XFS_INO_TO_AGNO(mp, mp->m_sb.sb_pquotino), - XFS_INO_TO_AGINO(mp, mp->m_sb.sb_pquotino)); - - if (irec == NULL || is_inode_free(irec, - mp->m_sb.sb_pquotino - irec->ino_startnum)) { - mp->m_sb.sb_pquotino = NULLFSINO; - lost_pquotino = 1; - } else - lost_pquotino = 0; - } + quotino_check_one(mp, XFS_DQTYPE_USER); + quotino_check_one(mp, XFS_DQTYPE_GROUP); + quotino_check_one(mp, XFS_DQTYPE_PROJ); } static void @@ -107,14 +91,14 @@ quota_sb_check(xfs_mount_t *mp) */ if (fs_quotas && - (mp->m_sb.sb_uquotino == NULLFSINO || mp->m_sb.sb_uquotino == 0) && - (mp->m_sb.sb_gquotino == NULLFSINO || mp->m_sb.sb_gquotino == 0) && - (mp->m_sb.sb_pquotino == NULLFSINO || mp->m_sb.sb_pquotino == 0)) { + !has_quota_inode(XFS_DQTYPE_USER) && + !has_quota_inode(XFS_DQTYPE_GROUP) && + !has_quota_inode(XFS_DQTYPE_PROJ)) { lost_quotas = 1; fs_quotas = 0; - } else if (libxfs_verify_ino(mp, mp->m_sb.sb_uquotino) && - libxfs_verify_ino(mp, mp->m_sb.sb_gquotino) && - libxfs_verify_ino(mp, mp->m_sb.sb_pquotino)) { + } else if (libxfs_verify_ino(mp, get_quota_inode(XFS_DQTYPE_USER)) && + libxfs_verify_ino(mp, get_quota_inode(XFS_DQTYPE_GROUP)) && + libxfs_verify_ino(mp, get_quota_inode(XFS_DQTYPE_PROJ))) { fs_quotas = 1; } } diff --git a/repair/phase6.c b/repair/phase6.c index 59665f48684aa4..bd3b6e79bae095 100644 --- a/repair/phase6.c +++ b/repair/phase6.c @@ -3183,12 +3183,12 @@ mark_standalone_inodes(xfs_mount_t *mp) if (!fs_quotas) return; - if (mp->m_sb.sb_uquotino && mp->m_sb.sb_uquotino != NULLFSINO) - mark_inode(mp, mp->m_sb.sb_uquotino); - if (mp->m_sb.sb_gquotino && mp->m_sb.sb_gquotino != NULLFSINO) - mark_inode(mp, mp->m_sb.sb_gquotino); - if (mp->m_sb.sb_pquotino && mp->m_sb.sb_pquotino != NULLFSINO) - mark_inode(mp, mp->m_sb.sb_pquotino); + if (has_quota_inode(XFS_DQTYPE_USER)) + mark_inode(mp, get_quota_inode(XFS_DQTYPE_USER)); + if (has_quota_inode(XFS_DQTYPE_GROUP)) + mark_inode(mp, get_quota_inode(XFS_DQTYPE_GROUP)); + if (has_quota_inode(XFS_DQTYPE_PROJ)) + mark_inode(mp, get_quota_inode(XFS_DQTYPE_PROJ)); } static void diff --git a/repair/quotacheck.c b/repair/quotacheck.c index 11e2d64eb34791..c4baf70e41d6b1 100644 --- a/repair/quotacheck.c +++ b/repair/quotacheck.c @@ -203,9 +203,7 @@ quotacheck_adjust( return; /* Quota files are not included in quota counts. */ - if (ino == mp->m_sb.sb_uquotino || - ino == mp->m_sb.sb_gquotino || - ino == mp->m_sb.sb_pquotino) + if (is_any_quota_inode(ino)) return; error = -libxfs_iget(mp, NULL, ino, 0, &ip); @@ -415,20 +413,20 @@ quotacheck_verify( switch (type) { case XFS_DQTYPE_USER: - ino = mp->m_sb.sb_uquotino; dquots = user_dquots; metafile_type = XFS_METAFILE_USRQUOTA; break; case XFS_DQTYPE_GROUP: - ino = mp->m_sb.sb_gquotino; dquots = group_dquots; metafile_type = XFS_METAFILE_GRPQUOTA; break; case XFS_DQTYPE_PROJ: - ino = mp->m_sb.sb_pquotino; dquots = proj_dquots; metafile_type = XFS_METAFILE_PRJQUOTA; break; + default: + ASSERT(0); + return; } /* @@ -443,6 +441,7 @@ quotacheck_verify( if (error) do_error(_("could not alloc transaction to open quota file\n")); + ino = get_quota_inode(type); error = -libxfs_trans_metafile_iget(tp, ino, metafile_type, &ip); if (error) { do_warn( @@ -505,34 +504,28 @@ qc_has_quotafile( struct xfs_mount *mp, xfs_dqtype_t type) { - bool lost; xfs_ino_t ino; unsigned int qflag; switch (type) { case XFS_DQTYPE_USER: - lost = lost_uquotino; - ino = mp->m_sb.sb_uquotino; qflag = XFS_UQUOTA_CHKD; break; case XFS_DQTYPE_GROUP: - lost = lost_gquotino; - ino = mp->m_sb.sb_gquotino; qflag = XFS_GQUOTA_CHKD; break; case XFS_DQTYPE_PROJ: - lost = lost_pquotino; - ino = mp->m_sb.sb_pquotino; qflag = XFS_PQUOTA_CHKD; break; default: return false; } - if (lost) + if (lost_quota_inode(type)) return false; if (!(mp->m_sb.sb_qflags & qflag)) return false; + ino = get_quota_inode(type); if (ino == NULLFSINO || ino == 0) return false; return true; @@ -626,3 +619,29 @@ quotacheck_teardown(void) qc_purge(&group_dquots); qc_purge(&proj_dquots); } + +void +update_sb_quotinos( + struct xfs_mount *mp, + struct xfs_buf *sbp) +{ + bool dirty = false; + + if (mp->m_sb.sb_uquotino != get_quota_inode(XFS_DQTYPE_USER)) { + mp->m_sb.sb_uquotino = get_quota_inode(XFS_DQTYPE_USER); + dirty = true; + } + + if (mp->m_sb.sb_gquotino != get_quota_inode(XFS_DQTYPE_GROUP)) { + mp->m_sb.sb_gquotino = get_quota_inode(XFS_DQTYPE_GROUP); + dirty = true; + } + + if (mp->m_sb.sb_pquotino != get_quota_inode(XFS_DQTYPE_PROJ)) { + mp->m_sb.sb_pquotino = get_quota_inode(XFS_DQTYPE_PROJ); + dirty = true; + } + + if (dirty) + libxfs_sb_to_disk(sbp->b_addr, &mp->m_sb); +} diff --git a/repair/quotacheck.h b/repair/quotacheck.h index dcbf1623947b48..36f9f5a12f7f3e 100644 --- a/repair/quotacheck.h +++ b/repair/quotacheck.h @@ -13,4 +13,6 @@ uint16_t quotacheck_results(void); int quotacheck_setup(struct xfs_mount *mp); void quotacheck_teardown(void); +void update_sb_quotinos(struct xfs_mount *mp, struct xfs_buf *sbp); + #endif /* __XFS_REPAIR_QUOTACHECK_H__ */ diff --git a/repair/versions.c b/repair/versions.c index 7dc91b4597eece..689cc471176da0 100644 --- a/repair/versions.c +++ b/repair/versions.c @@ -104,9 +104,6 @@ parse_sb_version( fs_sb_feature_bits = 0; fs_ino_alignment = 0; fs_has_extflgbit = 1; - have_uquotino = 0; - have_gquotino = 0; - have_pquotino = 0; if (mp->m_sb.sb_versionnum & XFS_SB_VERSION_SHAREDBIT) { do_warn(_("Shared Version bit set. Not supported. Ever.\n")); @@ -166,13 +163,13 @@ _("WARNING: you have a V1 inode filesystem. It would be converted to a\n" fs_quotas = 1; if (mp->m_sb.sb_uquotino != 0 && mp->m_sb.sb_uquotino != NULLFSINO) - have_uquotino = 1; + set_quota_inode(XFS_DQTYPE_USER, mp->m_sb.sb_uquotino); if (mp->m_sb.sb_gquotino != 0 && mp->m_sb.sb_gquotino != NULLFSINO) - have_gquotino = 1; + set_quota_inode(XFS_DQTYPE_GROUP, mp->m_sb.sb_gquotino); if (mp->m_sb.sb_pquotino != 0 && mp->m_sb.sb_pquotino != NULLFSINO) - have_pquotino = 1; + set_quota_inode(XFS_DQTYPE_PROJ, mp->m_sb.sb_pquotino); } if (xfs_has_align(mp)) { diff --git a/repair/xfs_repair.c b/repair/xfs_repair.c index 2a8a72e7027591..363f8260bd575a 100644 --- a/repair/xfs_repair.c +++ b/repair/xfs_repair.c @@ -1404,7 +1404,9 @@ _("Inode allocation btrees are too corrupted, skipping phases 6 and 7\n")); free_rtgroup_inodes(); } - if (lost_quotas && !have_uquotino && !have_gquotino && !have_pquotino) { + if (lost_quotas && !has_quota_inode(XFS_DQTYPE_USER) && + !has_quota_inode(XFS_DQTYPE_GROUP) && + !has_quota_inode(XFS_DQTYPE_PROJ)) { if (!no_modify) { do_warn( _("Warning: no quota inodes were found. Quotas disabled.\n")); @@ -1421,7 +1423,7 @@ _("Warning: quota inodes were cleared. Quotas disabled.\n")); _("Warning: quota inodes would be cleared. Quotas would be disabled.\n")); } } else { - if (lost_uquotino) { + if (lost_quota_inode(XFS_DQTYPE_USER)) { if (!no_modify) { do_warn( _("Warning: user quota information was cleared.\n" @@ -1433,7 +1435,7 @@ _("Warning: user quota information would be cleared.\n" } } - if (lost_gquotino) { + if (lost_quota_inode(XFS_DQTYPE_GROUP)) { if (!no_modify) { do_warn( _("Warning: group quota information was cleared.\n" @@ -1445,7 +1447,7 @@ _("Warning: group quota information would be cleared.\n" } } - if (lost_pquotino) { + if (lost_quota_inode(XFS_DQTYPE_PROJ)) { if (!no_modify) { do_warn( _("Warning: project quota information was cleared.\n" @@ -1485,6 +1487,8 @@ _("Warning: project quota information would be cleared.\n" if (!sbp) do_error(_("couldn't get superblock\n")); + update_sb_quotinos(mp, sbp); + if ((mp->m_sb.sb_qflags & XFS_ALL_QUOTA_CHKD) != quotacheck_results()) { do_warn(_("Note - quota info will be regenerated on next " "quota mount.\n")); From patchwork Mon Dec 23 22:26:06 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13919438 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 78159433D5 for ; Mon, 23 Dec 2024 22:26:07 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734992767; cv=none; b=X2d6yn8sJb+ZWBhrg/TTkT6s3ZGD4upzKL18CW9VG8reQMXUO0Wpl1/ryqD/EGJAocCDWTuaxZ6dqizaDfFAst80A0n3VgC3u1eVNacu0hsJGpjRXiJRAY51hAQHZ4qSHPf9VAezbzJ8y/utpv13NHrkjzgh8Flp6zLQD8iDWQo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734992767; c=relaxed/simple; bh=UW4bsNqLFHmYt8byI5YLQPulvEg+oPiNlkqUYEY3+is=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=EKnyCntkKxYBw9hDbYKj79SFPhNtRtoEpAIA4CKsqjn9eSGMwDFd2xyIpChqKZuOnWnux/C1L+AechPk9T68as0UyQYF/ht+iPKkdLh9A4W9yurv3KwAX8B1xMlMP3LtL4RC+lcBO3n5a/w2TMNQ10KDIo5OJaC/QM5w3OqyW0M= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=T4x2uSL4; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="T4x2uSL4" Received: by smtp.kernel.org (Postfix) with ESMTPSA id DB372C4CED3; Mon, 23 Dec 2024 22:26:06 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1734992766; bh=UW4bsNqLFHmYt8byI5YLQPulvEg+oPiNlkqUYEY3+is=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=T4x2uSL4h6M7B+G5+i4z3JDk1BOZAnTGFDa4gxhg+zdfESutsf+aC/i1PFRjdZJ3m Kr7mnBAhmXCs5ryabAerBegfGcj5h+nBFZ66val4eC2uVY2KSo+1dsUlrVfhQ/p7l2 taQZj10+A6pu/r0H3vO1Mh9bekO/DOXzOVaoIjDuwGh2oa7MKZTqLI1VfVGPQVojz/ 4zymvkPba6kdR4xyMkQ2/PLWwIcYxfZnqSImIwB5HddO31JnmOKp2jcdDPEjaYIwDh zGxBiu/VzndAWpx4qN1kx23Zduz83flSbshAqWaw8hd8AYQjlONG3g3KDl7rjhBFg5 LQQU2vsuIbXoQ== Date: Mon, 23 Dec 2024 14:26:06 -0800 Subject: [PATCH 4/7] xfs_repair: hoist the secondary sb qflags handling From: "Darrick J. Wong" To: djwong@kernel.org, aalbersh@kernel.org Cc: hch@lst.de, linux-xfs@vger.kernel.org Message-ID: <173498945030.2299261.13963685796531975269.stgit@frogsfrogsfrogs> In-Reply-To: <173498944956.2299261.16768993427453132101.stgit@frogsfrogsfrogs> References: <173498944956.2299261.16768993427453132101.stgit@frogsfrogsfrogs> Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Hoist all the secondary superblock qflags and quota inode modification code into a separate function so that we can disable it in the next patch. Signed-off-by: "Darrick J. Wong" Reviewed-by: Christoph Hellwig --- repair/agheader.c | 157 +++++++++++++++++++++++++++++------------------------ 1 file changed, 85 insertions(+), 72 deletions(-) diff --git a/repair/agheader.c b/repair/agheader.c index fd279559aed973..4a530fd6b8fe96 100644 --- a/repair/agheader.c +++ b/repair/agheader.c @@ -319,6 +319,90 @@ check_v5_feature_mismatch( return XR_AG_SB_SEC; } +/* + * quota inodes and flags in secondary superblocks are never set by mkfs. + * However, they could be set in a secondary if a fs with quotas was growfs'ed + * since growfs copies the new primary into the secondaries. + * + * Also, the in-core inode flags now have different meaning to the on-disk + * flags, and so libxfs_sb_to_disk cannot directly write the + * sb_gquotino/sb_pquotino fields without specific sb_qflags being set. Hence + * we need to zero those fields directly in the sb buffer here. + */ +static int +secondary_sb_quota( + struct xfs_mount *mp, + struct xfs_buf *sbuf, + struct xfs_sb *sb, + xfs_agnumber_t i, + int do_bzero) +{ + struct xfs_dsb *dsb = sbuf->b_addr; + int rval = 0; + + if (sb->sb_inprogress == 1 && sb->sb_uquotino != NULLFSINO) { + if (!no_modify) + sb->sb_uquotino = 0; + if (!do_bzero) { + rval |= XR_AG_SB; + do_warn( + _("non-null user quota inode field in superblock %d\n"), + i); + + } else + rval |= XR_AG_SB_SEC; + } + + if (sb->sb_inprogress == 1 && sb->sb_gquotino != NULLFSINO) { + if (!no_modify) { + sb->sb_gquotino = 0; + dsb->sb_gquotino = 0; + } + if (!do_bzero) { + rval |= XR_AG_SB; + do_warn( + _("non-null group quota inode field in superblock %d\n"), + i); + + } else + rval |= XR_AG_SB_SEC; + } + + /* + * Note that sb_pquotino is not considered a valid sb field for pre-v5 + * superblocks. If it is anything other than 0 it is considered garbage + * data beyond the valid sb and explicitly zeroed above. + */ + if (xfs_has_pquotino(mp) && + sb->sb_inprogress == 1 && sb->sb_pquotino != NULLFSINO) { + if (!no_modify) { + sb->sb_pquotino = 0; + dsb->sb_pquotino = 0; + } + if (!do_bzero) { + rval |= XR_AG_SB; + do_warn( + _("non-null project quota inode field in superblock %d\n"), + i); + + } else + rval |= XR_AG_SB_SEC; + } + + if (sb->sb_inprogress == 1 && sb->sb_qflags) { + if (!no_modify) + sb->sb_qflags = 0; + if (!do_bzero) { + rval |= XR_AG_SB; + do_warn(_("non-null quota flags in superblock %d\n"), + i); + } else + rval |= XR_AG_SB_SEC; + } + + return rval; +} + /* * Possible fields that may have been set at mkfs time, * sb_inoalignmt, sb_unit, sb_width and sb_dirblklog. @@ -340,7 +424,6 @@ secondary_sb_whack( struct xfs_sb *sb, xfs_agnumber_t i) { - struct xfs_dsb *dsb = sbuf->b_addr; int do_bzero = 0; int size; char *ip; @@ -426,77 +509,7 @@ secondary_sb_whack( rval |= XR_AG_SB_SEC; } - /* - * quota inodes and flags in secondary superblocks are never set by - * mkfs. However, they could be set in a secondary if a fs with quotas - * was growfs'ed since growfs copies the new primary into the - * secondaries. - * - * Also, the in-core inode flags now have different meaning to the - * on-disk flags, and so libxfs_sb_to_disk cannot directly write the - * sb_gquotino/sb_pquotino fields without specific sb_qflags being set. - * Hence we need to zero those fields directly in the sb buffer here. - */ - - if (sb->sb_inprogress == 1 && sb->sb_uquotino != NULLFSINO) { - if (!no_modify) - sb->sb_uquotino = 0; - if (!do_bzero) { - rval |= XR_AG_SB; - do_warn( - _("non-null user quota inode field in superblock %d\n"), - i); - - } else - rval |= XR_AG_SB_SEC; - } - - if (sb->sb_inprogress == 1 && sb->sb_gquotino != NULLFSINO) { - if (!no_modify) { - sb->sb_gquotino = 0; - dsb->sb_gquotino = 0; - } - if (!do_bzero) { - rval |= XR_AG_SB; - do_warn( - _("non-null group quota inode field in superblock %d\n"), - i); - - } else - rval |= XR_AG_SB_SEC; - } - - /* - * Note that sb_pquotino is not considered a valid sb field for pre-v5 - * superblocks. If it is anything other than 0 it is considered garbage - * data beyond the valid sb and explicitly zeroed above. - */ - if (xfs_has_pquotino(mp) && - sb->sb_inprogress == 1 && sb->sb_pquotino != NULLFSINO) { - if (!no_modify) { - sb->sb_pquotino = 0; - dsb->sb_pquotino = 0; - } - if (!do_bzero) { - rval |= XR_AG_SB; - do_warn( - _("non-null project quota inode field in superblock %d\n"), - i); - - } else - rval |= XR_AG_SB_SEC; - } - - if (sb->sb_inprogress == 1 && sb->sb_qflags) { - if (!no_modify) - sb->sb_qflags = 0; - if (!do_bzero) { - rval |= XR_AG_SB; - do_warn(_("non-null quota flags in superblock %d\n"), - i); - } else - rval |= XR_AG_SB_SEC; - } + rval |= secondary_sb_quota(mp, sbuf, sb, i, do_bzero); /* * if the secondaries agree on a stripe unit/width or inode From patchwork Mon Dec 23 22:26:22 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13919439 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A238C433D5 for ; Mon, 23 Dec 2024 22:26:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734992782; cv=none; b=rLs4+TjttkXCnjz2zBISL87elGFPfE4nV9P4pM5+9xt1Oz6hKs7TrqJk1WujaHBYiRuoU2yUymxZdQKt4N9VsD5yGibZlF2EOkOlT0en8S1EqU1ZDvYTzLN6MguXkZ/5I+UmlYslTUCZxFK7Xa2XcJR3OkEpo+x4Kh7FqHQy6sY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734992782; c=relaxed/simple; bh=o0AHWiWI9gNrodvhORkZNV5nbp7vMBOmauLitZ1WO8I=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=tVCrV77q2NFSTElISD0fQrnq/+jZRXDwtQWAAn5zV4wBxDECO9hz9eC/ebmfTqyAyRhXNlt+YTiAJAqAH9U4SIx2HkXPC2h7yvtlrv1R5q9kRmcZGNg6mXdb6HufFA4OmMhOd+m1QoEy+RoYGILukMkA+htZohEfye4YdhR+SHA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=i9t2HdAK; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="i9t2HdAK" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 786E6C4CED3; Mon, 23 Dec 2024 22:26:22 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1734992782; bh=o0AHWiWI9gNrodvhORkZNV5nbp7vMBOmauLitZ1WO8I=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=i9t2HdAK/PVxibMBcg1wkMQlPZ1mDGUy0SxrrIP05nAs68i5N0wlklkbyD6BoCtoo qUTa65FmdgPhjJXDlnOsEfVNPtDbd81axFKvUIk8mqsV5k+zCj525v5JvnLvFJKNOG v0ZHs7aU+QKzNfinWRHjTpKHNx3diEBw+oPvdSfBiY/Dyqn8RGKlG1QzaX374HBjUc w54cK+DCb7+gkr94jM1Vg7i7bEk86fdRBWDfd6abvnj34Kh3/OGacHQgWn7TlWMwvb 52J2SSE71zHTHWbbwrI1MvlTwIlplKOYMcqUYlCNwknDXAxUHrtx5dmm2z7NQ8Hl2K E15hsw+BYfauQ== Date: Mon, 23 Dec 2024 14:26:22 -0800 Subject: [PATCH 5/7] xfs_repair: support quota inodes in the metadata directory From: "Darrick J. Wong" To: djwong@kernel.org, aalbersh@kernel.org Cc: hch@lst.de, linux-xfs@vger.kernel.org Message-ID: <173498945045.2299261.15698653151998552855.stgit@frogsfrogsfrogs> In-Reply-To: <173498944956.2299261.16768993427453132101.stgit@frogsfrogsfrogs> References: <173498944956.2299261.16768993427453132101.stgit@frogsfrogsfrogs> Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Handle quota inodes on metadir filesystems. This means that we have to discover whatever quota inodes exist by looking in /quotas instead of the superblock, and mend any broken metadir tree links might exist. Signed-off-by: "Darrick J. Wong" Reviewed-by: Christoph Hellwig --- repair/agheader.c | 3 + repair/phase2.c | 3 + repair/phase6.c | 116 +++++++++++++++++++++++++++++++++++++++++++++++++++ repair/quotacheck.c | 71 +++++++++++++++++++++++++++++++ repair/quotacheck.h | 1 repair/xfs_repair.c | 3 + 6 files changed, 194 insertions(+), 3 deletions(-) diff --git a/repair/agheader.c b/repair/agheader.c index 4a530fd6b8fe96..e6fca07c6cb4c9 100644 --- a/repair/agheader.c +++ b/repair/agheader.c @@ -509,7 +509,8 @@ secondary_sb_whack( rval |= XR_AG_SB_SEC; } - rval |= secondary_sb_quota(mp, sbuf, sb, i, do_bzero); + if (!xfs_has_metadir(mp)) + rval |= secondary_sb_quota(mp, sbuf, sb, i, do_bzero); /* * if the secondaries agree on a stripe unit/width or inode diff --git a/repair/phase2.c b/repair/phase2.c index 27c873fca76747..71576f5806e473 100644 --- a/repair/phase2.c +++ b/repair/phase2.c @@ -15,6 +15,7 @@ #include "progress.h" #include "scan.h" #include "rt.h" +#include "quotacheck.h" /* workaround craziness in the xlog routines */ int xlog_recover_do_trans(struct xlog *log, struct xlog_recover *t, int p) @@ -625,6 +626,8 @@ phase2( } discover_rtgroup_inodes(mp); + if (xfs_has_metadir(mp) && xfs_has_quota(mp)) + discover_quota_inodes(mp); /* * Upgrade the filesystem now that we've done a preliminary check of diff --git a/repair/phase6.c b/repair/phase6.c index bd3b6e79bae095..7d2e0554594265 100644 --- a/repair/phase6.c +++ b/repair/phase6.c @@ -20,6 +20,7 @@ #include "versions.h" #include "repair/pptr.h" #include "repair/rt.h" +#include "repair/quotacheck.h" static xfs_ino_t orphanage_ino; @@ -3180,7 +3181,7 @@ mark_standalone_inodes(xfs_mount_t *mp) mark_inode(mp, mp->m_sb.sb_rsumino); } - if (!fs_quotas) + if (!fs_quotas || xfs_has_metadir(mp)) return; if (has_quota_inode(XFS_DQTYPE_USER)) @@ -3402,6 +3403,116 @@ _(" - resetting contents of realtime bitmap and summary inodes\n")); } } +static bool +ensure_quota_file( + struct xfs_inode *dp, + xfs_dqtype_t type) +{ + struct xfs_mount *mp = dp->i_mount; + struct xfs_inode *ip; + const char *name = libxfs_dqinode_path(type); + int error; + + if (!has_quota_inode(type)) + return false; + + if (no_modify) { + if (lost_quota_inode(type)) + do_warn(_("would reset %s quota inode\n"), name); + return false; + } + + if (!lost_quota_inode(type)) { + /* + * The /quotas directory has been discarded, but we should + * be able to iget the quota files directly. + */ + error = -libxfs_metafile_iget(mp, get_quota_inode(type), + xfs_dqinode_metafile_type(type), &ip); + if (error) { + do_warn( +_("Could not open %s quota inode, error %d\n"), + name, error); + lose_quota_inode(type); + } + } + + if (lost_quota_inode(type)) { + /* + * The inode was bad or missing, state that we'll make a new + * one even though we always create a new one. + */ + do_warn(_("resetting %s quota inode\n"), name); + error = -libxfs_dqinode_metadir_create(dp, type, &ip); + if (error) { + do_warn( +_("Couldn't create %s quota inode, error %d\n"), + name, error); + goto bad; + } + } else { + struct xfs_trans *tp; + + /* Erase parent pointers before we create the new link */ + try_erase_parent_ptrs(ip); + + error = -libxfs_dqinode_metadir_link(dp, type, ip); + if (error) { + do_warn( +_("Couldn't link %s quota inode, error %d\n"), + name, error); + goto bad; + } + + /* + * Reset the link count to 1 because quota files are never + * hardlinked, but the link above probably bumped it. + */ + error = -libxfs_trans_alloc_inode(ip, &M_RES(mp)->tr_ichange, + 0, 0, false, &tp); + if (!error) { + set_nlink(VFS_I(ip), 1); + libxfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); + error = -libxfs_trans_commit(tp); + } + if (error) + do_error( +_("Couldn't reset link count on %s quota inode, error %d\n"), + name, error); + } + + /* Mark the inode in use. */ + mark_ino_inuse(mp, ip->i_ino, S_IFREG, dp->i_ino); + mark_ino_metadata(mp, ip->i_ino); + libxfs_irele(ip); + return true; +bad: + /* Zeroes qflags */ + quotacheck_skip(); + return false; +} + +static void +reset_quota_metadir_inodes( + struct xfs_mount *mp) +{ + struct xfs_inode *dp = NULL; + int error; + + error = -libxfs_dqinode_mkdir_parent(mp, &dp); + if (error) + do_error(_("failed to create quota metadir (%d)\n"), + error); + + mark_ino_inuse(mp, dp->i_ino, S_IFDIR, mp->m_metadirip->i_ino); + mark_ino_metadata(mp, dp->i_ino); + + ensure_quota_file(dp, XFS_DQTYPE_USER); + ensure_quota_file(dp, XFS_DQTYPE_GROUP); + ensure_quota_file(dp, XFS_DQTYPE_PROJ); + libxfs_irele(dp); +} + void phase6(xfs_mount_t *mp) { @@ -3455,6 +3566,9 @@ phase6(xfs_mount_t *mp) else reset_rt_sb_inodes(mp); + if (xfs_has_metadir(mp) && xfs_has_quota(mp) && !no_modify) + reset_quota_metadir_inodes(mp); + mark_standalone_inodes(mp); do_log(_(" - traversing filesystem ...\n")); diff --git a/repair/quotacheck.c b/repair/quotacheck.c index c4baf70e41d6b1..8c7339b267d8e6 100644 --- a/repair/quotacheck.c +++ b/repair/quotacheck.c @@ -645,3 +645,74 @@ update_sb_quotinos( if (dirty) libxfs_sb_to_disk(sbp->b_addr, &mp->m_sb); } + +static inline int +mark_quota_inode( + struct xfs_trans *tp, + struct xfs_inode *dp, + xfs_dqtype_t type) +{ + struct xfs_inode *ip; + int error; + + error = -libxfs_dqinode_load(tp, dp, type, &ip); + if (error == ENOENT) + return 0; + if (error) + goto out_corrupt; + + set_quota_inode(type, ip->i_ino); + libxfs_irele(ip); + return 0; + +out_corrupt: + lose_quota_inode(type); + return error; +} + +/* Mark the reachable quota metadata inodes prior to the inode scan. */ +void +discover_quota_inodes( + struct xfs_mount *mp) +{ + struct xfs_trans *tp; + struct xfs_inode *dp = NULL; + int error, err2; + + error = -libxfs_trans_alloc_empty(mp, &tp); + if (error) + goto out; + + error = -libxfs_dqinode_load_parent(tp, &dp); + if (error) + goto out_cancel; + + error = mark_quota_inode(tp, dp, XFS_DQTYPE_USER); + err2 = mark_quota_inode(tp, dp, XFS_DQTYPE_GROUP); + if (err2 && !error) + error = err2; + error = mark_quota_inode(tp, dp, XFS_DQTYPE_PROJ); + if (err2 && !error) + error = err2; + + libxfs_irele(dp); +out_cancel: + libxfs_trans_cancel(tp); +out: + if (error) { + switch (error) { + case EFSCORRUPTED: + do_warn( + _("corruption in metadata directory tree while discovering quota inodes\n")); + break; + case ENOENT: + /* Do nothing, we'll just clear qflags later. */ + break; + default: + do_warn( + _("couldn't discover quota inodes, err %d\n"), + error); + break; + } + } +} diff --git a/repair/quotacheck.h b/repair/quotacheck.h index 36f9f5a12f7f3e..24c9ffa418a3bf 100644 --- a/repair/quotacheck.h +++ b/repair/quotacheck.h @@ -14,5 +14,6 @@ int quotacheck_setup(struct xfs_mount *mp); void quotacheck_teardown(void); void update_sb_quotinos(struct xfs_mount *mp, struct xfs_buf *sbp); +void discover_quota_inodes(struct xfs_mount *mp); #endif /* __XFS_REPAIR_QUOTACHECK_H__ */ diff --git a/repair/xfs_repair.c b/repair/xfs_repair.c index 363f8260bd575a..9509f04685c870 100644 --- a/repair/xfs_repair.c +++ b/repair/xfs_repair.c @@ -1487,7 +1487,8 @@ _("Warning: project quota information would be cleared.\n" if (!sbp) do_error(_("couldn't get superblock\n")); - update_sb_quotinos(mp, sbp); + if (!xfs_has_metadir(mp)) + update_sb_quotinos(mp, sbp); if ((mp->m_sb.sb_qflags & XFS_ALL_QUOTA_CHKD) != quotacheck_results()) { do_warn(_("Note - quota info will be regenerated on next " From patchwork Mon Dec 23 22:26:37 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13919440 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9DD8D188596 for ; Mon, 23 Dec 2024 22:26:38 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734992798; cv=none; b=Swj89i4KMjNNarw1tjgolDt+1c5yvZjj6DiT8A9I1hR5WLn5PodxjleB13vRgBVOi6vs7fP5agrLgLARKSTpg9x6/lDd88T9P6e1IKgzDaSKT7BPsJQZOwo2xTmGAv+2gr30+zQ7kNiCtSf5abpvxTpiZaVnvm21eELU8bjVO/c= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734992798; c=relaxed/simple; bh=hGQtgBmomX1gzZ8fzZS5UVeKoRNPARCVZrZn4I92SjE=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=QyNLzbU/v/Hp6A9dRDMp0a5uLODWV/c9tOZRSF0LQqUH+PNC0iFEkucWOtuWx5ktOhw7LwtO3T7lFaPojMzCrItiIKqYZ6y6CI0rmJYq0ku18wnnpB0nMQ5A/M/UJtOjpqVAMtQIZWusJnKyFn6Pogvlb/wXJftH6fUjMeodUb8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=sxHQRAOa; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="sxHQRAOa" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 180F3C4CED3; Mon, 23 Dec 2024 22:26:38 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1734992798; bh=hGQtgBmomX1gzZ8fzZS5UVeKoRNPARCVZrZn4I92SjE=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=sxHQRAOatZkPW1hJ3e0Ec9H7rMaLYwDqTjzKMWDuewpOD0Vu0QvjkjDnpbJ+4xYey maEwcsFdl7Qzt1roVswmkkG8k36JfIYyFd2I/4udKdkr/5zQnOvcuVmLcu/rRRf/5h mkkKI69M2SVcBpYbDV6tC/jEIfJHRzy7T2gO5LS6b16P3JC8GBdczHwu80D78/QyL1 MNQJBLWwk2do6yH/uwHgdUxJORindo3jooZdaV+0KCFIQK3t0YTj6vI8f4SLO1EcSK byM0mAYG4wLdT7EPBRC1kXpUtm/UN23lVBQEpdVr3N+LWL/ouyQTlgzasy9ztoLtf/ nLmE1RWC1/4dA== Date: Mon, 23 Dec 2024 14:26:37 -0800 Subject: [PATCH 6/7] xfs_repair: try not to trash qflags on metadir filesystems From: "Darrick J. Wong" To: djwong@kernel.org, aalbersh@kernel.org Cc: hch@lst.de, linux-xfs@vger.kernel.org Message-ID: <173498945060.2299261.8688192402506588666.stgit@frogsfrogsfrogs> In-Reply-To: <173498944956.2299261.16768993427453132101.stgit@frogsfrogsfrogs> References: <173498944956.2299261.16768993427453132101.stgit@frogsfrogsfrogs> Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Try to preserve the accounting and enforcement quota flags when repairing filesystems. Signed-off-by: "Darrick J. Wong" Reviewed-by: Christoph Hellwig --- repair/agheader.c | 3 ++- repair/phase4.c | 20 ++++++++++++++++++++ repair/sb.c | 3 +++ 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/repair/agheader.c b/repair/agheader.c index e6fca07c6cb4c9..89a23a869a02e4 100644 --- a/repair/agheader.c +++ b/repair/agheader.c @@ -642,7 +642,8 @@ verify_set_agheader(xfs_mount_t *mp, struct xfs_buf *sbuf, xfs_sb_t *sb, sb->sb_fdblocks = 0; sb->sb_frextents = 0; - sb->sb_qflags = 0; + if (!xfs_has_metadir(mp)) + sb->sb_qflags = 0; } rval |= XR_AG_SB; diff --git a/repair/phase4.c b/repair/phase4.c index a4183c557a1891..728d9ed84cdc7a 100644 --- a/repair/phase4.c +++ b/repair/phase4.c @@ -71,6 +71,26 @@ quotino_check( static void quota_sb_check(xfs_mount_t *mp) { + if (xfs_has_metadir(mp)) { + /* + * Metadir filesystems try to preserve the quota accounting + * and enforcement flags so that users don't have to remember + * to supply quota mount options. Phase 1 discovered the + * QUOTABIT flag (fs_quotas) and phase 2 discovered the quota + * inodes from the metadir for us. + * + * If QUOTABIT wasn't set but we found quota inodes, signal + * phase 5 to add the feature bit for us. We do not ever + * downgrade the filesystem. + */ + if (!fs_quotas && + (has_quota_inode(XFS_DQTYPE_USER) || + has_quota_inode(XFS_DQTYPE_GROUP) || + has_quota_inode(XFS_DQTYPE_PROJ))) + fs_quotas = 1; + return; + } + /* * if the sb says we have quotas and we lost both, * signal a superblock downgrade. that will cause diff --git a/repair/sb.c b/repair/sb.c index d52ab2ffeaf28c..0e4827e046780b 100644 --- a/repair/sb.c +++ b/repair/sb.c @@ -233,6 +233,9 @@ find_secondary_sb(xfs_sb_t *rsb) if (!retval) retval = __find_secondary_sb(rsb, XFS_AG_MIN_BYTES, BSIZE); + if (retval && xfs_sb_version_hasmetadir(rsb)) + do_warn(_("quota accounting and enforcement flags lost\n")); + return retval; } From patchwork Mon Dec 23 22:26:53 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13919441 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 12BE21D63FF for ; Mon, 23 Dec 2024 22:26:53 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734992814; cv=none; b=E0AE2siA5nmuFjQsDZruW8sSXrGMHhHdN5XYkdlSr2zRHJNiG9Qr8NWoD062pZuPlC9+fIhXaKEDIOg2eYMpYWFYdYLmcFTpcOqEGKHSdGAGDaiG/3Pnsc9/9BVgG3bI2qR8oIT51T7ezLHy4lPAsDoUQXodNAGoMS5R18/wlqI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734992814; c=relaxed/simple; bh=L0qNjl5YR2SWIwh+sLldVLX1ZnV5wWeYv3f1gUpVT1g=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=VTBjrBWR+ww48OStl/V74rALJ5fL9Eu36geGWskhJchT39JcMzHS4JfsPlIqJ414IQRn0OmcGZI/5WOaI71l1+bewNYsKCNnKsj8g0H6rc+qmR+Cg7LS9Cy55WxsjxCmr2z4xxa7PGse5v8aIXJh7bu7xTt5i4cJqbo+KQdpKpI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=gKqycwCO; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="gKqycwCO" Received: by smtp.kernel.org (Postfix) with ESMTPSA id A9BD0C4CED3; Mon, 23 Dec 2024 22:26:53 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1734992813; bh=L0qNjl5YR2SWIwh+sLldVLX1ZnV5wWeYv3f1gUpVT1g=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=gKqycwCOIgk50Rt54rT8ALj1sSUJGGciACTI6GtaRWfmR7ceADxZ9w6qZ5wa6mEtI 9N4SLNGJxxtRB8NQhp06v2soorHeiMsHXL9u7aEaZb/CE1IYAz59juX7ENk6Tbs9ze n19R7Tcqs3Aaz5fjDTQ19K5PXXfJxwyJWfE7J9BKee6HI1lZj3jpo0ylu95NPE+vHU f3kp1TTKZVXH7ycRuaJ/t6MyCfdEhlF2nVSNjhgbfAv42dfav2GR+HoY0WuXwHgOre MFCPfjMcgZkRtAyOwWiSEwhfqUo8+zeyA6nF9aC6XF4Au/0oi/rHpwARsOJlcWfokQ SCn4rJYxbePSw== Date: Mon, 23 Dec 2024 14:26:53 -0800 Subject: [PATCH 7/7] mkfs: add quota flags when setting up filesystem From: "Darrick J. Wong" To: djwong@kernel.org, aalbersh@kernel.org Cc: hch@lst.de, linux-xfs@vger.kernel.org Message-ID: <173498945075.2299261.7418213392948446139.stgit@frogsfrogsfrogs> In-Reply-To: <173498944956.2299261.16768993427453132101.stgit@frogsfrogsfrogs> References: <173498944956.2299261.16768993427453132101.stgit@frogsfrogsfrogs> Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong If we're creating a metadir filesystem, the quota accounting and enforcement flags persist until the sysadmin changes them. Add a means to specify those qflags at format time. Signed-off-by: "Darrick J. Wong" Reviewed-by: Christoph Hellwig --- man/man8/mkfs.xfs.8.in | 48 ++++++++++++++++++++ mkfs/xfs_mkfs.c | 113 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 160 insertions(+), 1 deletion(-) diff --git a/man/man8/mkfs.xfs.8.in b/man/man8/mkfs.xfs.8.in index 0c0cf1dc151e4f..32361cf973fcf8 100644 --- a/man/man8/mkfs.xfs.8.in +++ b/man/man8/mkfs.xfs.8.in @@ -340,6 +340,54 @@ .SH OPTIONS See the .BI xfs_scrub (8) manual page for more information on this property. +.TP +.B uquota +If the metadata directory feature is enabled, the +.B \-m uquota +option will set up user quota accounting and enforcement at format time; +specifying the quota options in fstab is no longer unnecessary. +If metadata directories are not enabled, quotas must still be enabled via +fstab. +.TP +.B gquota +If the metadata directory feature is enabled, the +.B \-m gquota +option will set up group quota accounting and enforcement at format time; +specifying the quota options in fstab is no longer unnecessary. +If metadata directories are not enabled, quotas must still be enabled via +fstab. +.TP +.B pquota +If the metadata directory feature is enabled, the +.B \-m pquota +option will set up project quota accounting and enforcement at format time; +specifying the quota options in fstab is no longer unnecessary. +If metadata directories are not enabled, quotas must still be enabled via +fstab. +.TP +.B uqnoenforce +If the metadata directory feature is enabled, the +.B \-m uqnoenforce +option will set up user quota accounting at format time; specifying the quota +options in fstab is no longer unnecessary. +If metadata directories are not enabled, quotas must still be enabled via +fstab. +.TP +.B gqnoenforce +If the metadata directory feature is enabled, the +.B \-m gqnoenforce +option will set up group quota accounting at format time; specifying the quota +options in fstab is no longer unnecessary. +If metadata directories are not enabled, quotas must still be enabled via +fstab. +.TP +.B pqnoenforce +If the metadata directory feature is enabled, the +.B \-m pqnoenforce +option will set up project quota accounting at format time; specifying the +quota options in fstab is no longer unnecessary. +If metadata directories are not enabled, quotas must still be enabled via +fstab. .RE .PP .PD 0 diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c index cd94cfd0b93706..a15c19df03a86d 100644 --- a/mkfs/xfs_mkfs.c +++ b/mkfs/xfs_mkfs.c @@ -153,6 +153,12 @@ enum { M_BIGTIME, M_AUTOFSCK, M_METADIR, + M_UQUOTA, + M_GQUOTA, + M_PQUOTA, + M_UQNOENFORCE, + M_GQNOENFORCE, + M_PQNOENFORCE, M_MAX_OPTS, }; @@ -833,6 +839,12 @@ static struct opt_params mopts = { [M_BIGTIME] = "bigtime", [M_AUTOFSCK] = "autofsck", [M_METADIR] = "metadir", + [M_UQUOTA] = "uquota", + [M_GQUOTA] = "gquota", + [M_PQUOTA] = "pquota", + [M_UQNOENFORCE] = "uqnoenforce", + [M_GQNOENFORCE] = "gqnoenforce", + [M_PQNOENFORCE] = "pqnoenforce", [M_MAX_OPTS] = NULL, }, .subopt_params = { @@ -888,6 +900,48 @@ static struct opt_params mopts = { .maxval = 1, .defaultval = 1, }, + { .index = M_UQUOTA, + .conflicts = { { &mopts, M_UQNOENFORCE }, + { NULL, LAST_CONFLICT } }, + .minval = 0, + .maxval = 1, + .defaultval = 1, + }, + { .index = M_GQUOTA, + .conflicts = { { &mopts, M_GQNOENFORCE }, + { NULL, LAST_CONFLICT } }, + .minval = 0, + .maxval = 1, + .defaultval = 1, + }, + { .index = M_PQUOTA, + .conflicts = { { &mopts, M_GQNOENFORCE }, + { NULL, LAST_CONFLICT } }, + .minval = 0, + .maxval = 1, + .defaultval = 1, + }, + { .index = M_UQNOENFORCE, + .conflicts = { { &mopts, M_UQUOTA }, + { NULL, LAST_CONFLICT } }, + .minval = 0, + .maxval = 1, + .defaultval = 1, + }, + { .index = M_GQNOENFORCE, + .conflicts = { { &mopts, M_GQUOTA }, + { NULL, LAST_CONFLICT } }, + .minval = 0, + .maxval = 1, + .defaultval = 1, + }, + { .index = M_PQNOENFORCE, + .conflicts = { { &mopts, M_PQUOTA }, + { NULL, LAST_CONFLICT } }, + .minval = 0, + .maxval = 1, + .defaultval = 1, + }, }, }; @@ -945,6 +999,8 @@ struct sb_feat_args { bool nortalign; bool nrext64; bool exchrange; /* XFS_SB_FEAT_INCOMPAT_EXCHRANGE */ + + uint16_t qflags; }; struct cli_params { @@ -1083,6 +1139,8 @@ usage( void ) /* metadata */ [-m crc=0|1,finobt=0|1,uuid=xxx,rmapbt=0|1,reflink=0|1,\n\ inobtcount=0|1,bigtime=0|1,autofsck=xxx,\n\ metadir=0|1]\n\ +/* quota */ [-m uquota|uqnoenforce,gquota|gqnoenforce,\n\ + pquota|pqnoenforce]\n\ /* data subvol */ [-d agcount=n,agsize=n,file,name=xxx,size=num,\n\ (sunit=value,swidth=value|su=num,sw=num|noalign),\n\ sectsize=num,concurrency=num]\n\ @@ -1920,6 +1978,30 @@ meta_opts_parser( case M_METADIR: cli->sb_feat.metadir = getnum(value, opts, subopt); break; + case M_UQUOTA: + if (getnum(value, opts, subopt)) + cli->sb_feat.qflags |= XFS_UQUOTA_ACCT | XFS_UQUOTA_ENFD; + break; + case M_GQUOTA: + if (getnum(value, opts, subopt)) + cli->sb_feat.qflags |= XFS_GQUOTA_ACCT | XFS_GQUOTA_ENFD; + break; + case M_PQUOTA: + if (getnum(value, opts, subopt)) + cli->sb_feat.qflags |= XFS_PQUOTA_ACCT | XFS_PQUOTA_ENFD; + break; + case M_UQNOENFORCE: + if (getnum(value, opts, subopt)) + cli->sb_feat.qflags |= XFS_UQUOTA_ACCT; + break; + case M_GQNOENFORCE: + if (getnum(value, opts, subopt)) + cli->sb_feat.qflags |= XFS_GQUOTA_ACCT; + break; + case M_PQNOENFORCE: + if (getnum(value, opts, subopt)) + cli->sb_feat.qflags |= XFS_PQUOTA_ACCT; + break; default: return -EINVAL; } @@ -2516,6 +2598,12 @@ _("metadata directory not supported without CRC support\n")); usage(); } cli->sb_feat.metadir = false; + + if (cli->sb_feat.qflags) { + fprintf(stderr, +_("persistent quota flags not supported without CRC support\n")); + usage(); + } } if (!cli->sb_feat.finobt) { @@ -2561,6 +2649,26 @@ _("cowextsize not supported without reflink support\n")); cli->sb_feat.exchrange = true; } + if (cli->sb_feat.qflags && cli->xi->rt.name) { + fprintf(stderr, +_("persistent quota flags not supported with realtime volumes\n")); + usage(); + } + + /* + * Persistent quota flags requires metadir support because older + * kernels (or current kernels with old filesystems) will reset qflags + * in the absence of any quota mount options. + */ + if (cli->sb_feat.qflags && !cli->sb_feat.metadir) { + if (cli_opt_set(&mopts, M_METADIR)) { + fprintf(stderr, +_("persistent quota flags not supported without metadir support\n")); + usage(); + } + cli->sb_feat.metadir = true; + } + /* * Exchange-range will be needed for space reorganization on filesystems * with realtime rmap or realtime reflink enabled, and there is no good @@ -3811,6 +3919,9 @@ sb_set_features( if (fp->dirftype && !fp->crcs_enabled) sbp->sb_features2 |= XFS_SB_VERSION2_FTYPE; + if (fp->qflags) + sbp->sb_versionnum |= XFS_SB_VERSION_QUOTABIT; + /* update whether extended features are in use */ if (sbp->sb_features2 != 0) sbp->sb_versionnum |= XFS_SB_VERSION_MOREBITSBIT; @@ -4337,7 +4448,7 @@ finish_superblock_setup( (cfg->loginternal ? cfg->logblocks : 0); sbp->sb_frextents = 0; /* will do a free later */ sbp->sb_uquotino = sbp->sb_gquotino = sbp->sb_pquotino = 0; - sbp->sb_qflags = 0; + sbp->sb_qflags = cfg->sb_feat.qflags; sbp->sb_unit = cfg->dsunit; sbp->sb_width = cfg->dswidth; mp->m_features |= libxfs_sb_version_to_features(sbp);