From patchwork Tue Nov 5 22:39:00 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: 13863707 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 4A9B11CCB2D for ; Tue, 5 Nov 2024 22:39:01 +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=1730846341; cv=none; b=YFqq5+eyOQDsg6C6gw6mDz4Gep14Roo0GM0flyoCsWPhTiboKdBfqtKRCdSSgvN2ViP/iXZkS7GAdDwhjbjx1syyKgQU44GycTbl2ytGhXLUyu+/iED7yXj7ckfIPH/oBgD2Ym/LXNbGEYsNW+vD0LFcpsjExM6k+ZcjNGo48bg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1730846341; c=relaxed/simple; bh=Ghg8E08pjCYzdcD2fnG9nduoTiOPZud0RlUBIwmjog4=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=qOhGM738Uj1mopR0ZEkYN7ckuqAVBvXfsxkVJT1KwRE5+KzDsXVS4H1a9czb1+uyyKeCvcVg4Qr9v4g1cZ/5L4q/PBdsUKCw6wMNiasIQhPozTUZvIJjKO/Ma0586rxBYBJW+SGOVZCNY1dDgqc3enughsgu5zwjc+L/EaGtodM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=NXDPtxX+; 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="NXDPtxX+" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 2289AC4CECF; Tue, 5 Nov 2024 22:39:01 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1730846341; bh=Ghg8E08pjCYzdcD2fnG9nduoTiOPZud0RlUBIwmjog4=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=NXDPtxX+r1wXOFdXi5X5gO6JNMR46aQly2BRBLQiU3hJMicKXwQBA6qfdqNsh2vLp qCt+RJps/p/ut/FKmpNZXZQrJ1+k3IbpQpQZuHaQ71+NYdLWMSPkJMNLrUZ3oTD4TD waLgxX5PWYv3mjkVifeQZ5jDBknzhM/42BCqZE/P50EoGLRC2i4XKUz9hagE6e01ou VeSSeLsfffIY63/mSESPVsVNX3nwm7MNetlle64htSr8NbGwZO2CMozs9FJ4w94eoD M8AT3ghbIZdzz4H1sPIJ9WdpE9GOPvkCBCIvzzARGlo2F5qWUi4f49eEgGuGJBGDbO kFyruustUmfgQ== Date: Tue, 05 Nov 2024 14:39:00 -0800 Subject: [PATCH 1/4] xfs: refactor xfs_qm_destroy_quotainos From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <173084399144.1873039.16522849456439468829.stgit@frogsfrogsfrogs> In-Reply-To: <173084399117.1873039.18256038294248428421.stgit@frogsfrogsfrogs> References: <173084399117.1873039.18256038294248428421.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 Reuse this function instead of open-coding the logic. Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig --- fs/xfs/xfs_qm.c | 53 ++++++++++++++++++++--------------------------------- 1 file changed, 20 insertions(+), 33 deletions(-) diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c index 28b1420bac1dd2..b37e80fe7e86a6 100644 --- a/fs/xfs/xfs_qm.c +++ b/fs/xfs/xfs_qm.c @@ -40,7 +40,6 @@ STATIC int xfs_qm_init_quotainos(struct xfs_mount *mp); STATIC int xfs_qm_init_quotainfo(struct xfs_mount *mp); -STATIC void xfs_qm_destroy_quotainos(struct xfs_quotainfo *qi); STATIC void xfs_qm_dqfree_one(struct xfs_dquot *dqp); /* * We use the batch lookup interface to iterate over the dquots as it @@ -226,6 +225,24 @@ xfs_qm_unmount_rt( xfs_rtgroup_rele(rtg); } +STATIC void +xfs_qm_destroy_quotainos( + struct xfs_quotainfo *qi) +{ + if (qi->qi_uquotaip) { + xfs_irele(qi->qi_uquotaip); + qi->qi_uquotaip = NULL; /* paranoia */ + } + if (qi->qi_gquotaip) { + xfs_irele(qi->qi_gquotaip); + qi->qi_gquotaip = NULL; + } + if (qi->qi_pquotaip) { + xfs_irele(qi->qi_pquotaip); + qi->qi_pquotaip = NULL; + } +} + /* * Called from the vfsops layer. */ @@ -250,20 +267,8 @@ xfs_qm_unmount_quotas( /* * Release the quota inodes. */ - if (mp->m_quotainfo) { - if (mp->m_quotainfo->qi_uquotaip) { - xfs_irele(mp->m_quotainfo->qi_uquotaip); - mp->m_quotainfo->qi_uquotaip = NULL; - } - if (mp->m_quotainfo->qi_gquotaip) { - xfs_irele(mp->m_quotainfo->qi_gquotaip); - mp->m_quotainfo->qi_gquotaip = NULL; - } - if (mp->m_quotainfo->qi_pquotaip) { - xfs_irele(mp->m_quotainfo->qi_pquotaip); - mp->m_quotainfo->qi_pquotaip = NULL; - } - } + if (mp->m_quotainfo) + xfs_qm_destroy_quotainos(mp->m_quotainfo); } STATIC int @@ -1712,24 +1717,6 @@ xfs_qm_init_quotainos( return error; } -STATIC void -xfs_qm_destroy_quotainos( - struct xfs_quotainfo *qi) -{ - if (qi->qi_uquotaip) { - xfs_irele(qi->qi_uquotaip); - qi->qi_uquotaip = NULL; /* paranoia */ - } - if (qi->qi_gquotaip) { - xfs_irele(qi->qi_gquotaip); - qi->qi_gquotaip = NULL; - } - if (qi->qi_pquotaip) { - xfs_irele(qi->qi_pquotaip); - qi->qi_pquotaip = NULL; - } -} - STATIC void xfs_qm_dqfree_one( struct xfs_dquot *dqp) From patchwork Tue Nov 5 22:39:16 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: 13863708 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 EA7651CCB2D for ; Tue, 5 Nov 2024 22:39:16 +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=1730846357; cv=none; b=ZE8u0mW8xIN4weZ+PurXWwfghROMYypX7Gq6Yy0HT1Q4RlsReCD2BRq/Md2nDnm8owm8vJkHhAMgr5lFqHGiJNFzN4wX8bdweUNt0p7P9h2kp1m9mfL+V6Vyu3y5PNYtqYANvwi2vbdJzoeIhP5BrYa5TKSKmSr0gL4FFx9Ncs4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1730846357; c=relaxed/simple; bh=fv9YCJd3pfZdGHemSmALjKqFXFkGOMIaQjiJ3nPHsns=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=EbJkzL7zWhn5CefPMRQ6sADwG8SKJeYOKDjtEeGcdmfLnA+2XVUXrSX0TbvUKvZX/H67J5SzLmT1bTvYxncHp0kMtmrbvkbxKeqYut4jDWXeAF4jDDu9XZfyVV2mPjFNPB1+iEPnG6Pe3DTM0T5sAa30GopKzyVsVKkX8v6Ci2E= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=OH75L9te; 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="OH75L9te" Received: by smtp.kernel.org (Postfix) with ESMTPSA id C3CB2C4CED0; Tue, 5 Nov 2024 22:39:16 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1730846356; bh=fv9YCJd3pfZdGHemSmALjKqFXFkGOMIaQjiJ3nPHsns=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=OH75L9tebSAWDKqo/aix9S7gdmkkXxDWH+GMQW591GAV7sUEV6p4QjyqagaUNkcQa /xIX3pAXXNTlDZihERe1xZEntK2RJGpQ1W7jCCbdyk8KATsHsbIE5eLAhiH014M5xs s1yxDr/QEAQERyQQXYrcv5j3TWsFEhaVQ7ZF8OYRAelu5UT6GRY7RvlCP8CwmsYS8J CqntC3pYTLJpS5D9pkIluTFvmnLyWZc2agwb2NWLsQcNOl5pyKXEjGrdjzkBGtAYWP 0IHoFjsd27a/KTXWEDj3bJQd/cfsx0pqe0pZzRC1c8iyAAY6/DS9k76E9KiIYEI6Oq +wtaiLa7BzsmQ== Date: Tue, 05 Nov 2024 14:39:16 -0800 Subject: [PATCH 2/4] xfs: use metadir for quota inodes From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <173084399161.1873039.9685058342375775843.stgit@frogsfrogsfrogs> In-Reply-To: <173084399117.1873039.18256038294248428421.stgit@frogsfrogsfrogs> References: <173084399117.1873039.18256038294248428421.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 Store the quota inodes in the /quota metadata directory if metadir is enabled. This enables us to stop using the sb_[ugp]uotino fields in the superblock. From this point on, all metadata files will be children of the metadata directory tree root. Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig --- fs/xfs/libxfs/xfs_dquot_buf.c | 190 +++++++++++++++++++++++++++++++++++++++ fs/xfs/libxfs/xfs_quota_defs.h | 43 +++++++++ fs/xfs/libxfs/xfs_sb.c | 1 fs/xfs/xfs_qm.c | 197 +++++++++++++++++++++++++++++++++++----- 4 files changed, 407 insertions(+), 24 deletions(-) diff --git a/fs/xfs/libxfs/xfs_dquot_buf.c b/fs/xfs/libxfs/xfs_dquot_buf.c index 15a362e2f5ea70..dceef2abd4e2a3 100644 --- a/fs/xfs/libxfs/xfs_dquot_buf.c +++ b/fs/xfs/libxfs/xfs_dquot_buf.c @@ -16,6 +16,9 @@ #include "xfs_trans.h" #include "xfs_qm.h" #include "xfs_error.h" +#include "xfs_health.h" +#include "xfs_metadir.h" +#include "xfs_metafile.h" int xfs_calc_dquots_per_chunk( @@ -323,3 +326,190 @@ xfs_dquot_to_disk_ts( return cpu_to_be32(t); } + +inline unsigned int +xfs_dqinode_sick_mask(xfs_dqtype_t type) +{ + switch (type) { + case XFS_DQTYPE_USER: + return XFS_SICK_FS_UQUOTA; + case XFS_DQTYPE_GROUP: + return XFS_SICK_FS_GQUOTA; + case XFS_DQTYPE_PROJ: + return XFS_SICK_FS_PQUOTA; + } + + ASSERT(0); + return 0; +} + +/* + * Load the inode for a given type of quota, assuming that the sb fields have + * been sorted out. This is not true when switching quota types on a V4 + * filesystem, so do not use this function for that. If metadir is enabled, + * @dp must be the /quota metadir. + * + * Returns -ENOENT if the quota inode field is NULLFSINO; 0 and an inode on + * success; or a negative errno. + */ +int +xfs_dqinode_load( + struct xfs_trans *tp, + struct xfs_inode *dp, + xfs_dqtype_t type, + struct xfs_inode **ipp) +{ + struct xfs_mount *mp = tp->t_mountp; + struct xfs_inode *ip; + enum xfs_metafile_type metafile_type = xfs_dqinode_metafile_type(type); + int error; + + if (!xfs_has_metadir(mp)) { + xfs_ino_t ino; + + switch (type) { + case XFS_DQTYPE_USER: + ino = mp->m_sb.sb_uquotino; + break; + case XFS_DQTYPE_GROUP: + ino = mp->m_sb.sb_gquotino; + break; + case XFS_DQTYPE_PROJ: + ino = mp->m_sb.sb_pquotino; + break; + default: + ASSERT(0); + return -EFSCORRUPTED; + } + + /* Should have set 0 to NULLFSINO when loading superblock */ + if (ino == NULLFSINO) + return -ENOENT; + + error = xfs_trans_metafile_iget(tp, ino, metafile_type, &ip); + } else { + error = xfs_metadir_load(tp, dp, xfs_dqinode_path(type), + metafile_type, &ip); + if (error == -ENOENT) + return error; + } + if (error) { + if (xfs_metadata_is_sick(error)) + xfs_fs_mark_sick(mp, xfs_dqinode_sick_mask(type)); + return error; + } + + if (XFS_IS_CORRUPT(mp, ip->i_df.if_format != XFS_DINODE_FMT_EXTENTS && + ip->i_df.if_format != XFS_DINODE_FMT_BTREE)) { + xfs_irele(ip); + xfs_fs_mark_sick(mp, xfs_dqinode_sick_mask(type)); + return -EFSCORRUPTED; + } + + if (XFS_IS_CORRUPT(mp, ip->i_projid != 0)) { + xfs_irele(ip); + xfs_fs_mark_sick(mp, xfs_dqinode_sick_mask(type)); + return -EFSCORRUPTED; + } + + *ipp = ip; + return 0; +} + +/* Create a metadata directory quota inode. */ +int +xfs_dqinode_metadir_create( + struct xfs_inode *dp, + xfs_dqtype_t type, + struct xfs_inode **ipp) +{ + struct xfs_metadir_update upd = { + .dp = dp, + .metafile_type = xfs_dqinode_metafile_type(type), + .path = xfs_dqinode_path(type), + }; + int error; + + error = xfs_metadir_start_create(&upd); + if (error) + return error; + + error = xfs_metadir_create(&upd, S_IFREG); + if (error) + return error; + + xfs_trans_log_inode(upd.tp, upd.ip, XFS_ILOG_CORE); + + error = xfs_metadir_commit(&upd); + if (error) + return error; + + xfs_finish_inode_setup(upd.ip); + *ipp = upd.ip; + return 0; +} + +#ifndef __KERNEL__ +/* Link a metadata directory quota inode. */ +int +xfs_dqinode_metadir_link( + struct xfs_inode *dp, + xfs_dqtype_t type, + struct xfs_inode *ip) +{ + struct xfs_metadir_update upd = { + .dp = dp, + .metafile_type = xfs_dqinode_metafile_type(type), + .path = xfs_dqinode_path(type), + .ip = ip, + }; + int error; + + error = xfs_metadir_start_link(&upd); + if (error) + return error; + + error = xfs_metadir_link(&upd); + if (error) + return error; + + xfs_trans_log_inode(upd.tp, upd.ip, XFS_ILOG_CORE); + + return xfs_metadir_commit(&upd); +} +#endif /* __KERNEL__ */ + +/* Create the parent directory for all quota inodes and load it. */ +int +xfs_dqinode_mkdir_parent( + struct xfs_mount *mp, + struct xfs_inode **dpp) +{ + if (!mp->m_metadirip) { + xfs_fs_mark_sick(mp, XFS_SICK_FS_METADIR); + return -EFSCORRUPTED; + } + + return xfs_metadir_mkdir(mp->m_metadirip, "quota", dpp); +} + +/* + * Load the parent directory of all quota inodes. Pass the inode to the caller + * because quota functions (e.g. QUOTARM) can be called on the quota files even + * if quotas are not enabled. + */ +int +xfs_dqinode_load_parent( + struct xfs_trans *tp, + struct xfs_inode **dpp) +{ + struct xfs_mount *mp = tp->t_mountp; + + if (!mp->m_metadirip) { + xfs_fs_mark_sick(mp, XFS_SICK_FS_METADIR); + return -EFSCORRUPTED; + } + + return xfs_metadir_load(tp, mp->m_metadirip, "quota", XFS_METAFILE_DIR, + dpp); +} diff --git a/fs/xfs/libxfs/xfs_quota_defs.h b/fs/xfs/libxfs/xfs_quota_defs.h index fb05f44f6c754a..763d941a8420c5 100644 --- a/fs/xfs/libxfs/xfs_quota_defs.h +++ b/fs/xfs/libxfs/xfs_quota_defs.h @@ -143,4 +143,47 @@ time64_t xfs_dquot_from_disk_ts(struct xfs_disk_dquot *ddq, __be32 dtimer); __be32 xfs_dquot_to_disk_ts(struct xfs_dquot *ddq, time64_t timer); +static inline const char * +xfs_dqinode_path(xfs_dqtype_t type) +{ + switch (type) { + case XFS_DQTYPE_USER: + return "user"; + case XFS_DQTYPE_GROUP: + return "group"; + case XFS_DQTYPE_PROJ: + return "project"; + } + + ASSERT(0); + return NULL; +} + +static inline enum xfs_metafile_type +xfs_dqinode_metafile_type(xfs_dqtype_t type) +{ + switch (type) { + case XFS_DQTYPE_USER: + return XFS_METAFILE_USRQUOTA; + case XFS_DQTYPE_GROUP: + return XFS_METAFILE_GRPQUOTA; + case XFS_DQTYPE_PROJ: + return XFS_METAFILE_PRJQUOTA; + } + + ASSERT(0); + return XFS_METAFILE_UNKNOWN; +} + +unsigned int xfs_dqinode_sick_mask(xfs_dqtype_t type); + +int xfs_dqinode_load(struct xfs_trans *tp, struct xfs_inode *dp, + xfs_dqtype_t type, struct xfs_inode **ipp); +int xfs_dqinode_metadir_create(struct xfs_inode *dp, xfs_dqtype_t type, + struct xfs_inode **ipp); +int xfs_dqinode_metadir_link(struct xfs_inode *dp, xfs_dqtype_t type, + struct xfs_inode *ip); +int xfs_dqinode_mkdir_parent(struct xfs_mount *mp, struct xfs_inode **dpp); +int xfs_dqinode_load_parent(struct xfs_trans *tp, struct xfs_inode **dpp); + #endif /* __XFS_QUOTA_H__ */ diff --git a/fs/xfs/libxfs/xfs_sb.c b/fs/xfs/libxfs/xfs_sb.c index 6a31f48a2c5424..30c7c5238437bc 100644 --- a/fs/xfs/libxfs/xfs_sb.c +++ b/fs/xfs/libxfs/xfs_sb.c @@ -844,6 +844,7 @@ xfs_sb_quota_to_disk( if (xfs_sb_is_v5(from) && (from->sb_features_incompat & XFS_SB_FEAT_INCOMPAT_METADIR)) { + to->sb_qflags = cpu_to_be16(from->sb_qflags); to->sb_uquotino = cpu_to_be64(0); to->sb_gquotino = cpu_to_be64(0); to->sb_pquotino = cpu_to_be64(0); diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c index b37e80fe7e86a6..d9d09195eabb0d 100644 --- a/fs/xfs/xfs_qm.c +++ b/fs/xfs/xfs_qm.c @@ -645,6 +645,157 @@ xfs_qm_init_timelimits( xfs_qm_dqdestroy(dqp); } +static int +xfs_qm_load_metadir_qinos( + struct xfs_mount *mp, + struct xfs_quotainfo *qi, + struct xfs_inode **dpp) +{ + struct xfs_trans *tp; + int error; + + error = xfs_trans_alloc_empty(mp, &tp); + if (error) + return error; + + error = xfs_dqinode_load_parent(tp, dpp); + if (error == -ENOENT) { + /* no quota dir directory, but we'll create one later */ + error = 0; + goto out_trans; + } + if (error) + goto out_trans; + + if (XFS_IS_UQUOTA_ON(mp)) { + error = xfs_dqinode_load(tp, *dpp, XFS_DQTYPE_USER, + &qi->qi_uquotaip); + if (error && error != -ENOENT) + goto out_trans; + } + + if (XFS_IS_GQUOTA_ON(mp)) { + error = xfs_dqinode_load(tp, *dpp, XFS_DQTYPE_GROUP, + &qi->qi_gquotaip); + if (error && error != -ENOENT) + goto out_trans; + } + + if (XFS_IS_PQUOTA_ON(mp)) { + error = xfs_dqinode_load(tp, *dpp, XFS_DQTYPE_PROJ, + &qi->qi_pquotaip); + if (error && error != -ENOENT) + goto out_trans; + } + + error = 0; +out_trans: + xfs_trans_cancel(tp); + return error; +} + +/* Create quota inodes in the metadata directory tree. */ +STATIC int +xfs_qm_create_metadir_qinos( + struct xfs_mount *mp, + struct xfs_quotainfo *qi, + struct xfs_inode **dpp) +{ + int error; + + if (!*dpp) { + error = xfs_dqinode_mkdir_parent(mp, dpp); + if (error && error != -EEXIST) + return error; + } + + if (XFS_IS_UQUOTA_ON(mp) && !qi->qi_uquotaip) { + error = xfs_dqinode_metadir_create(*dpp, XFS_DQTYPE_USER, + &qi->qi_uquotaip); + if (error) + return error; + } + + if (XFS_IS_GQUOTA_ON(mp) && !qi->qi_gquotaip) { + error = xfs_dqinode_metadir_create(*dpp, XFS_DQTYPE_GROUP, + &qi->qi_gquotaip); + if (error) + return error; + } + + if (XFS_IS_PQUOTA_ON(mp) && !qi->qi_pquotaip) { + error = xfs_dqinode_metadir_create(*dpp, XFS_DQTYPE_PROJ, + &qi->qi_pquotaip); + if (error) + return error; + } + + return 0; +} + +/* + * Add QUOTABIT to sb_versionnum and initialize qflags in preparation for + * creating quota files on a metadir filesystem. + */ +STATIC int +xfs_qm_prep_metadir_sb( + struct xfs_mount *mp) +{ + struct xfs_trans *tp; + int error; + + error = xfs_trans_alloc(mp, &M_RES(mp)->tr_sb, 0, 0, 0, &tp); + if (error) + return error; + + spin_lock(&mp->m_sb_lock); + + xfs_add_quota(mp); + + /* qflags will get updated fully _after_ quotacheck */ + mp->m_sb.sb_qflags = mp->m_qflags & XFS_ALL_QUOTA_ACCT; + + spin_unlock(&mp->m_sb_lock); + xfs_log_sb(tp); + + return xfs_trans_commit(tp); +} + +/* + * Load existing quota inodes or create them. Since this is a V5 filesystem, + * we don't have to deal with the grp/prjquota switcheroo thing from V4. + */ +STATIC int +xfs_qm_init_metadir_qinos( + struct xfs_mount *mp) +{ + struct xfs_quotainfo *qi = mp->m_quotainfo; + struct xfs_inode *dp = NULL; + int error; + + if (!xfs_has_quota(mp)) { + error = xfs_qm_prep_metadir_sb(mp); + if (error) + return error; + } + + error = xfs_qm_load_metadir_qinos(mp, qi, &dp); + if (error) + goto out_err; + + error = xfs_qm_create_metadir_qinos(mp, qi, &dp); + if (error) + goto out_err; + + xfs_irele(dp); + return 0; +out_err: + xfs_qm_destroy_quotainos(mp->m_quotainfo); + if (dp) + xfs_irele(dp); + return error; +} + /* * This initializes all the quota information that's kept in the * mount structure @@ -669,7 +820,10 @@ xfs_qm_init_quotainfo( * See if quotainodes are setup, and if not, allocate them, * and change the superblock accordingly. */ - error = xfs_qm_init_quotainos(mp); + if (xfs_has_metadir(mp)) + error = xfs_qm_init_metadir_qinos(mp); + else + error = xfs_qm_init_quotainos(mp); if (error) goto out_free_lru; @@ -1581,7 +1735,7 @@ xfs_qm_mount_quotas( } if (error) { - xfs_warn(mp, "Failed to initialize disk quotas."); + xfs_warn(mp, "Failed to initialize disk quotas, err %d.", error); return; } } @@ -1600,31 +1754,26 @@ xfs_qm_qino_load( xfs_dqtype_t type, struct xfs_inode **ipp) { - xfs_ino_t ino = NULLFSINO; - enum xfs_metafile_type metafile_type = XFS_METAFILE_UNKNOWN; + struct xfs_trans *tp; + struct xfs_inode *dp = NULL; + int error; - switch (type) { - case XFS_DQTYPE_USER: - ino = mp->m_sb.sb_uquotino; - metafile_type = XFS_METAFILE_USRQUOTA; - break; - case XFS_DQTYPE_GROUP: - ino = mp->m_sb.sb_gquotino; - metafile_type = XFS_METAFILE_GRPQUOTA; - break; - case XFS_DQTYPE_PROJ: - ino = mp->m_sb.sb_pquotino; - metafile_type = XFS_METAFILE_PRJQUOTA; - break; - default: - ASSERT(0); - return -EFSCORRUPTED; + error = xfs_trans_alloc_empty(mp, &tp); + if (error) + return error; + + if (xfs_has_metadir(mp)) { + error = xfs_dqinode_load_parent(tp, &dp); + if (error) + goto out_cancel; } - if (ino == NULLFSINO) - return -ENOENT; - - return xfs_metafile_iget(mp, ino, metafile_type, ipp); + error = xfs_dqinode_load(tp, dp, type, ipp); + if (dp) + xfs_irele(dp); +out_cancel: + xfs_trans_cancel(tp); + return error; } /* From patchwork Tue Nov 5 22:39:31 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: 13863709 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 83B471CCB2D for ; Tue, 5 Nov 2024 22:39:32 +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=1730846372; cv=none; b=guPUG5sIO/vr5mge+bhIqmhB+yvJmQf/vNubT++BDJDphWSObNmz5i4NH/6GVX2qrrqj/ar15VhjuWbE2wJGg1qBwCRP7lcAG2NwbUqMt2/AryBgZoyQgKooLdrbtHYSF9JKyX23Ocj74LHwfbP1prIZ9auQZK70R8vQBBepaVk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1730846372; c=relaxed/simple; bh=7GfUwpdzc0U4wBIhJ3wcU6Chv/e1f+4uJQpDUZpPib8=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=Wj/7WvJ46VZJvIouyFXaNycrXEJnrq2NpZ2SAhlyhYJN6cDKv4oz+tDUWuTmhlD2I7gxfDI1JIHIvoSEFLDHbBLoQ6/soJvCW90fOwPIwz5GE1glRDoROHZgvGBqcLeuK/KGK4cQVRoLHrSqdy3aVJ0QPNZ+Ks/BW6kLcKNnZpg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=UFJuGBlO; 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="UFJuGBlO" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 6158AC4CECF; Tue, 5 Nov 2024 22:39:32 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1730846372; bh=7GfUwpdzc0U4wBIhJ3wcU6Chv/e1f+4uJQpDUZpPib8=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=UFJuGBlObWf8hjwbm+CsskfYETykA+xFosRKj8yuS3OHDfYfgywTCRHXe73r98qKM mwmuGtSzs9SIKn0CRDBIYLU4jnf0/bJaeBCzXDDvGmgpaBmpqqND6w3ei7xGdgv/AP Sm7XVy5r2Mx4irm16uLsLY/Rc0gv9lXiLuwrtmS8YTrUPkzFRc67Ih1npXnMtYaifL h68AR7uABhD6bsgl1jYtpWqhJwp0/yuAg2lZ5u3qFD/k2HNXJany1PmtfcDHmkBqhG MJyjo89fynbjvtlHylQMIjDm97rSL+xsnUE4NFMcHUKessz6baKWWB20BZFoJbGVWE kbff5NEIOO8Pg== Date: Tue, 05 Nov 2024 14:39:31 -0800 Subject: [PATCH 3/4] xfs: scrub quota file metapaths From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <173084399178.1873039.14519977840767252944.stgit@frogsfrogsfrogs> In-Reply-To: <173084399117.1873039.18256038294248428421.stgit@frogsfrogsfrogs> References: <173084399117.1873039.18256038294248428421.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 Enable online fsck for quota file metadata directory paths. Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig --- fs/xfs/libxfs/xfs_fs.h | 6 +++- fs/xfs/scrub/metapath.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 1 deletion(-) diff --git a/fs/xfs/libxfs/xfs_fs.h b/fs/xfs/libxfs/xfs_fs.h index 96f7d3c95fb4bc..41ce4d3d650ec7 100644 --- a/fs/xfs/libxfs/xfs_fs.h +++ b/fs/xfs/libxfs/xfs_fs.h @@ -825,9 +825,13 @@ struct xfs_scrub_vec_head { #define XFS_SCRUB_METAPATH_RTDIR (1) /* rtrgroups metadir */ #define XFS_SCRUB_METAPATH_RTBITMAP (2) /* per-rtg bitmap */ #define XFS_SCRUB_METAPATH_RTSUMMARY (3) /* per-rtg summary */ +#define XFS_SCRUB_METAPATH_QUOTADIR (4) /* quota metadir */ +#define XFS_SCRUB_METAPATH_USRQUOTA (5) /* user quota */ +#define XFS_SCRUB_METAPATH_GRPQUOTA (6) /* group quota */ +#define XFS_SCRUB_METAPATH_PRJQUOTA (7) /* project quota */ /* Number of metapath sm_ino values */ -#define XFS_SCRUB_METAPATH_NR (4) +#define XFS_SCRUB_METAPATH_NR (8) /* * ioctl limits diff --git a/fs/xfs/scrub/metapath.c b/fs/xfs/scrub/metapath.c index b8e427fd7fa73e..b78db651346518 100644 --- a/fs/xfs/scrub/metapath.c +++ b/fs/xfs/scrub/metapath.c @@ -165,6 +165,74 @@ xchk_setup_metapath_rtginode( # define xchk_setup_metapath_rtginode(...) (-ENOENT) #endif /* CONFIG_XFS_RT */ +#ifdef CONFIG_XFS_QUOTA +/* Scan the /quota directory itself. */ +static int +xchk_setup_metapath_quotadir( + struct xfs_scrub *sc) +{ + struct xfs_trans *tp; + struct xfs_inode *dp = NULL; + int error; + + error = xfs_trans_alloc_empty(sc->mp, &tp); + if (error) + return error; + + error = xfs_dqinode_load_parent(tp, &dp); + xfs_trans_cancel(tp); + if (error) + return error; + + error = xchk_setup_metapath_scan(sc, sc->mp->m_metadirip, + kasprintf(GFP_KERNEL, "quota"), dp); + xfs_irele(dp); + return error; +} + +/* Scan a quota inode under the /quota directory. */ +static int +xchk_setup_metapath_dqinode( + struct xfs_scrub *sc, + xfs_dqtype_t type) +{ + struct xfs_trans *tp = NULL; + struct xfs_inode *dp = NULL; + struct xfs_inode *ip = NULL; + const char *path; + int error; + + error = xfs_trans_alloc_empty(sc->mp, &tp); + if (error) + return error; + + error = xfs_dqinode_load_parent(tp, &dp); + if (error) + goto out_cancel; + + error = xfs_dqinode_load(tp, dp, type, &ip); + if (error) + goto out_dp; + + xfs_trans_cancel(tp); + tp = NULL; + + path = kasprintf(GFP_KERNEL, "%s", xfs_dqinode_path(type)); + error = xchk_setup_metapath_scan(sc, dp, path, ip); + + xfs_irele(ip); +out_dp: + xfs_irele(dp); +out_cancel: + if (tp) + xfs_trans_cancel(tp); + return error; +} +#else +# define xchk_setup_metapath_quotadir(...) (-ENOENT) +# define xchk_setup_metapath_dqinode(...) (-ENOENT) +#endif /* CONFIG_XFS_QUOTA */ + int xchk_setup_metapath( struct xfs_scrub *sc) @@ -186,6 +254,14 @@ xchk_setup_metapath( return xchk_setup_metapath_rtginode(sc, XFS_RTGI_BITMAP); case XFS_SCRUB_METAPATH_RTSUMMARY: return xchk_setup_metapath_rtginode(sc, XFS_RTGI_SUMMARY); + case XFS_SCRUB_METAPATH_QUOTADIR: + return xchk_setup_metapath_quotadir(sc); + case XFS_SCRUB_METAPATH_USRQUOTA: + return xchk_setup_metapath_dqinode(sc, XFS_DQTYPE_USER); + case XFS_SCRUB_METAPATH_GRPQUOTA: + return xchk_setup_metapath_dqinode(sc, XFS_DQTYPE_GROUP); + case XFS_SCRUB_METAPATH_PRJQUOTA: + return xchk_setup_metapath_dqinode(sc, XFS_DQTYPE_PROJ); default: return -ENOENT; } From patchwork Tue Nov 5 22:39:47 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: 13863710 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 74F2F1CCB2D for ; Tue, 5 Nov 2024 22:39:48 +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=1730846388; cv=none; b=pzAl+sxmMnhBS+e5O9wrytQKqxzVInFPqJhhmH5DZHY6MsnNCzUGuqFx7cORt3rLLnnsoU4lmi7CJpFCj2O+2dBMccg6AkQvce+sMWhfkaD3XyZXbsj/qpj42GSpyPuAx1lltT8lKQbqz4EV4xneEf8qeYZFqHK99UnGsRRduiU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1730846388; c=relaxed/simple; bh=bbiLO93OQ6Ycr7d6ryR+a319ZV0mTkU2JidIL6rKeTk=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=LgEGEnhrJqTpA3hggyQw+JDYPLdPVcbam1tOsDCnDFwArfpr8AqIQdIYK2bgbXBJf64Nr4RG0OBX9ihevB/VZYTchUtZVN/kQURqbcs/7KzsPPVGtKPPvLoL14vk8uNFmDgfq5uAatTB0INykc0ZUkN+Myd7TDNHcZI3QhDhaQk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=K3karwBd; 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="K3karwBd" Received: by smtp.kernel.org (Postfix) with ESMTPSA id F0BA7C4CECF; Tue, 5 Nov 2024 22:39:47 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1730846388; bh=bbiLO93OQ6Ycr7d6ryR+a319ZV0mTkU2JidIL6rKeTk=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=K3karwBdZ1bleCQ2wp10UUImU7uNxCUFSAPvPRVxE8HOnEU9lMxXtEmhERCJcX2aL uUXzORNOTZW03IQ4K236Fqgh6ZU6XbwwNZRl9kAZi5eg0hgne61I1mq8keT5JdmWPk XeZda5Ur26u895LuVV8+XxAUmxvh6g8cznG7gbBOudci+USW0my8ci5rRN7/Wlr4eK onlZfExp26IoS1KjyT/CKr55x09NlB2HSbtnQXQepVDG7nm7iC4v+sscPfiV9FGejN /b3331HMF+GR1c9vB+Jl9q6DipHcrmafe21SPudLVK714RcCGVcnYCcScI47YPS2Uc 6yrjh+/EiFUBg== Date: Tue, 05 Nov 2024 14:39:47 -0800 Subject: [PATCH 4/4] xfs: persist quota flags with metadir From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <173084399195.1873039.3463059991538428309.stgit@frogsfrogsfrogs> In-Reply-To: <173084399117.1873039.18256038294248428421.stgit@frogsfrogsfrogs> References: <173084399117.1873039.18256038294248428421.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 It's annoying that one has to keep reminding XFS about what quota options it should mount with, since the quota flags recording the previous state are sitting right there in the primary superblock. Even more strangely, there exists a noquota option to disable quotas completely, so it's odder still that providing no options is the same as noquota. Starting with metadir, let's change the behavior so that if the user does not specify any quota-related mount options at all, the ondisk quota flags will be used to bring up quota. In other words, the filesystem will mount in the same state and with the same functionality as it had during the last mount. Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig --- fs/xfs/xfs_mount.c | 15 +++++++++++++++ fs/xfs/xfs_mount.h | 21 +++++++++++++++++++-- fs/xfs/xfs_qm_bhv.c | 18 ++++++++++++++++++ fs/xfs/xfs_quota.h | 2 ++ fs/xfs/xfs_super.c | 25 ++++++++++++++++++++++++- 5 files changed, 78 insertions(+), 3 deletions(-) diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c index dba1f6fc688166..5918f433dba754 100644 --- a/fs/xfs/xfs_mount.c +++ b/fs/xfs/xfs_mount.c @@ -852,6 +852,13 @@ xfs_mountfs( if (error) goto out_fail_wait; + /* + * If we're resuming quota status, pick up the preliminary qflags from + * the ondisk superblock so that we know if we should recover dquots. + */ + if (xfs_is_resuming_quotaon(mp)) + xfs_qm_resume_quotaon(mp); + /* * Log's mount-time initialization. The first part of recovery can place * some items on the AIL, to be handled when recovery is finished or @@ -865,6 +872,14 @@ xfs_mountfs( goto out_inodegc_shrinker; } + /* + * If we're resuming quota status and recovered the log, re-sample the + * qflags from the ondisk superblock now that we've recovered it, just + * in case someone shut down enforcement just before a crash. + */ + if (xfs_clear_resuming_quotaon(mp) && xlog_recovery_needed(mp->m_log)) + xfs_qm_resume_quotaon(mp); + /* * If logged xattrs are still enabled after log recovery finishes, then * they'll be available until unmount. Otherwise, turn them off. diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h index ee1c3eb53d9f2b..db9dade7d22a19 100644 --- a/fs/xfs/xfs_mount.h +++ b/fs/xfs/xfs_mount.h @@ -499,6 +499,8 @@ __XFS_HAS_FEAT(nouuid, NOUUID) #define XFS_OPSTATE_WARNED_PPTR 16 /* Kernel has logged a warning about metadata dirs being used on this fs. */ #define XFS_OPSTATE_WARNED_METADIR 17 +/* Filesystem should use qflags to determine quotaon status */ +#define XFS_OPSTATE_RESUMING_QUOTAON 18 #define __XFS_IS_OPSTATE(name, NAME) \ static inline bool xfs_is_ ## name (struct xfs_mount *mp) \ @@ -523,9 +525,24 @@ __XFS_IS_OPSTATE(inodegc_enabled, INODEGC_ENABLED) __XFS_IS_OPSTATE(blockgc_enabled, BLOCKGC_ENABLED) #ifdef CONFIG_XFS_QUOTA __XFS_IS_OPSTATE(quotacheck_running, QUOTACHECK_RUNNING) +__XFS_IS_OPSTATE(resuming_quotaon, RESUMING_QUOTAON) #else -# define xfs_is_quotacheck_running(mp) (false) -#endif +static inline bool xfs_is_quotacheck_running(struct xfs_mount *mp) +{ + return false; +} +static inline bool xfs_is_resuming_quotaon(struct xfs_mount *mp) +{ + return false; +} +static inline void xfs_set_resuming_quotaon(struct xfs_mount *m) +{ +} +static inline bool xfs_clear_resuming_quotaon(struct xfs_mount *mp) +{ + return false; +} +#endif /* CONFIG_XFS_QUOTA */ __XFS_IS_OPSTATE(done_with_log_incompat, UNSET_LOG_INCOMPAT) __XFS_IS_OPSTATE(using_logged_xattrs, USE_LARP) diff --git a/fs/xfs/xfs_qm_bhv.c b/fs/xfs/xfs_qm_bhv.c index a11436579877d5..79a96558f739e3 100644 --- a/fs/xfs/xfs_qm_bhv.c +++ b/fs/xfs/xfs_qm_bhv.c @@ -135,3 +135,21 @@ xfs_qm_newmount( return 0; } + +/* + * If the sysadmin didn't provide any quota mount options, restore the quota + * accounting and enforcement state from the ondisk superblock. Only do this + * for metadir filesystems because this is a behavior change. + */ +void +xfs_qm_resume_quotaon( + struct xfs_mount *mp) +{ + if (!xfs_has_metadir(mp)) + return; + if (xfs_has_norecovery(mp)) + return; + + mp->m_qflags = mp->m_sb.sb_qflags & (XFS_ALL_QUOTA_ACCT | + XFS_ALL_QUOTA_ENFD); +} diff --git a/fs/xfs/xfs_quota.h b/fs/xfs/xfs_quota.h index 645761997bf2d9..2d36d967380e7c 100644 --- a/fs/xfs/xfs_quota.h +++ b/fs/xfs/xfs_quota.h @@ -125,6 +125,7 @@ extern void xfs_qm_dqdetach(struct xfs_inode *); extern void xfs_qm_dqrele(struct xfs_dquot *); extern void xfs_qm_statvfs(struct xfs_inode *, struct kstatfs *); extern int xfs_qm_newmount(struct xfs_mount *, uint *, uint *); +void xfs_qm_resume_quotaon(struct xfs_mount *mp); extern void xfs_qm_mount_quotas(struct xfs_mount *); extern void xfs_qm_unmount(struct xfs_mount *); extern void xfs_qm_unmount_quotas(struct xfs_mount *); @@ -202,6 +203,7 @@ xfs_trans_reserve_quota_icreate(struct xfs_trans *tp, struct xfs_dquot *udqp, #define xfs_qm_dqrele(d) do { (d) = (d); } while(0) #define xfs_qm_statvfs(ip, s) do { } while(0) #define xfs_qm_newmount(mp, a, b) (0) +#define xfs_qm_resume_quotaon(mp) ((void)0) #define xfs_qm_mount_quotas(mp) #define xfs_qm_unmount(mp) #define xfs_qm_unmount_quotas(mp) diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c index 3afeab6844680a..20fde2442768c4 100644 --- a/fs/xfs/xfs_super.c +++ b/fs/xfs/xfs_super.c @@ -67,6 +67,9 @@ enum xfs_dax_mode { XFS_DAX_NEVER = 2, }; +/* Were quota mount options provided? Must use the upper 16 bits of qflags. */ +#define XFS_QFLAGS_MNTOPTS (1U << 31) + static void xfs_mount_set_dax_mode( struct xfs_mount *mp, @@ -1264,6 +1267,8 @@ xfs_fs_parse_param( int size = 0; int opt; + BUILD_BUG_ON(XFS_QFLAGS_MNTOPTS & XFS_MOUNT_QUOTA_ALL); + opt = fs_parse(fc, xfs_fs_parameters, param, &result); if (opt < 0) return opt; @@ -1341,32 +1346,39 @@ xfs_fs_parse_param( case Opt_noquota: parsing_mp->m_qflags &= ~XFS_ALL_QUOTA_ACCT; parsing_mp->m_qflags &= ~XFS_ALL_QUOTA_ENFD; + parsing_mp->m_qflags |= XFS_QFLAGS_MNTOPTS; return 0; case Opt_quota: case Opt_uquota: case Opt_usrquota: parsing_mp->m_qflags |= (XFS_UQUOTA_ACCT | XFS_UQUOTA_ENFD); + parsing_mp->m_qflags |= XFS_QFLAGS_MNTOPTS; return 0; case Opt_qnoenforce: case Opt_uqnoenforce: parsing_mp->m_qflags |= XFS_UQUOTA_ACCT; parsing_mp->m_qflags &= ~XFS_UQUOTA_ENFD; + parsing_mp->m_qflags |= XFS_QFLAGS_MNTOPTS; return 0; case Opt_pquota: case Opt_prjquota: parsing_mp->m_qflags |= (XFS_PQUOTA_ACCT | XFS_PQUOTA_ENFD); + parsing_mp->m_qflags |= XFS_QFLAGS_MNTOPTS; return 0; case Opt_pqnoenforce: parsing_mp->m_qflags |= XFS_PQUOTA_ACCT; parsing_mp->m_qflags &= ~XFS_PQUOTA_ENFD; + parsing_mp->m_qflags |= XFS_QFLAGS_MNTOPTS; return 0; case Opt_gquota: case Opt_grpquota: parsing_mp->m_qflags |= (XFS_GQUOTA_ACCT | XFS_GQUOTA_ENFD); + parsing_mp->m_qflags |= XFS_QFLAGS_MNTOPTS; return 0; case Opt_gqnoenforce: parsing_mp->m_qflags |= XFS_GQUOTA_ACCT; parsing_mp->m_qflags &= ~XFS_GQUOTA_ENFD; + parsing_mp->m_qflags |= XFS_QFLAGS_MNTOPTS; return 0; case Opt_discard: parsing_mp->m_features |= XFS_FEAT_DISCARD; @@ -1433,7 +1445,8 @@ xfs_fs_validate_params( return -EINVAL; } - if (!IS_ENABLED(CONFIG_XFS_QUOTA) && mp->m_qflags != 0) { + if (!IS_ENABLED(CONFIG_XFS_QUOTA) && + (mp->m_qflags & ~XFS_QFLAGS_MNTOPTS)) { xfs_warn(mp, "quota support not available in this kernel."); return -EINVAL; } @@ -1768,6 +1781,14 @@ xfs_fs_fill_super( if (xfs_has_parent(mp)) xfs_warn_experimental(mp, XFS_EXPERIMENTAL_PPTR); + /* + * If no quota mount options were provided, maybe we'll try to pick + * up the quota accounting and enforcement flags from the ondisk sb. + */ + if (!(mp->m_qflags & XFS_QFLAGS_MNTOPTS)) + xfs_set_resuming_quotaon(mp); + mp->m_qflags &= ~XFS_QFLAGS_MNTOPTS; + error = xfs_mountfs(mp); if (error) goto out_filestream_unmount; @@ -1954,6 +1975,8 @@ xfs_fs_reconfigure( int flags = fc->sb_flags; int error; + new_mp->m_qflags &= ~XFS_QFLAGS_MNTOPTS; + /* version 5 superblocks always support version counters. */ if (xfs_has_crc(mp)) fc->sb_flags |= SB_I_VERSION;