From patchwork Sun Dec 31 23:29:50 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13508118 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 012BBC2D4 for ; Sun, 31 Dec 2023 23:29:51 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="DySp13Fd" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 647AAC433C8; Sun, 31 Dec 2023 23:29:51 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704065391; bh=QuFqgqzER0t8/R+FFaFWpG4KBpl2YcqoW/je87ttp28=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=DySp13Fd8OZYFdQgg8fl40zLJNT+IPAqLGq2IgnzNu9aKDv9ykOPp6BmRzctbTHbP jW0jSAiM6ryP6MzWudyd3e3hxuh8IM9zXWLtrgsfTZtpfVzLFzQDvjIrxok6iUUXK3 zjJvdWb6qkIPpSx4OBQsEM5WZilUP3/H1G7mAPkrJtlQSth4zXhWP8rD01TO8ge5DM aIqt/fyg4hbfJpcXLP1eCv9YwgXGebrsjZhXPTCyC1dltal8WBtjZtH+r40VQeqdY7 xaPFanDdoTguZ4WR4ayBTw26+AQGt00OA/S9qTM/1PvIWHpdQvupIjZNH68sqIS/uT T3OBs14j+tOLA== Date: Sun, 31 Dec 2023 15:29:50 -0800 Subject: [PATCH 01/58] xfs: don't use the incore struct xfs_sb for offsets into struct xfs_dsb From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <170405009961.1809361.5479999483125335705.stgit@frogsfrogsfrogs> In-Reply-To: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> References: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Currently, the XFS_SB_CRC_OFF macro uses the incore superblock struct (xfs_sb) to compute the address of sb_crc within the ondisk superblock struct (xfs_dsb). This is a landmine if we ever change the layout of the incore superblock (as we're about to do), so redefine the macro to use xfs_dsb to compute the layout of xfs_dsb. Signed-off-by: Darrick J. Wong --- db/sb.c | 4 ++-- libxfs/xfs_format.h | 9 ++++----- libxfs/xfs_ondisk.h | 1 + mdrestore/xfs_mdrestore.c | 6 ++---- repair/agheader.c | 12 ++++++------ 5 files changed, 15 insertions(+), 17 deletions(-) diff --git a/db/sb.c b/db/sb.c index 9a5d665dfbd..e738065b5be 100644 --- a/db/sb.c +++ b/db/sb.c @@ -50,8 +50,8 @@ sb_init(void) add_command(&version_cmd); } -#define OFF(f) bitize(offsetof(xfs_sb_t, sb_ ## f)) -#define SZC(f) szcount(xfs_sb_t, sb_ ## f) +#define OFF(f) bitize(offsetof(struct xfs_dsb, sb_ ## f)) +#define SZC(f) szcount(struct xfs_dsb, sb_ ## f) const field_t sb_flds[] = { { "magicnum", FLDT_UINT32X, OI(OFF(magicnum)), C1, 0, TYP_NONE }, { "blocksize", FLDT_UINT32D, OI(OFF(blocksize)), C1, 0, TYP_NONE }, diff --git a/libxfs/xfs_format.h b/libxfs/xfs_format.h index b0aaa825539..c60af436963 100644 --- a/libxfs/xfs_format.h +++ b/libxfs/xfs_format.h @@ -90,8 +90,7 @@ struct xfs_ifork; #define XFSLABEL_MAX 12 /* - * Superblock - in core version. Must match the ondisk version below. - * Must be padded to 64 bit alignment. + * Superblock - in core version. Must be padded to 64 bit alignment. */ typedef struct xfs_sb { uint32_t sb_magicnum; /* magic number == XFS_SB_MAGIC */ @@ -178,10 +177,8 @@ typedef struct xfs_sb { /* must be padded to 64 bit alignment */ } xfs_sb_t; -#define XFS_SB_CRC_OFF offsetof(struct xfs_sb, sb_crc) - /* - * Superblock - on disk version. Must match the in core version above. + * Superblock - on disk version. * Must be padded to 64 bit alignment. */ struct xfs_dsb { @@ -265,6 +262,8 @@ struct xfs_dsb { /* must be padded to 64 bit alignment */ }; +#define XFS_SB_CRC_OFF offsetof(struct xfs_dsb, sb_crc) + /* * Misc. Flags - warning - these will be cleared by xfs_repair unless * a feature bit is set when the flag is used. diff --git a/libxfs/xfs_ondisk.h b/libxfs/xfs_ondisk.h index bffd39242d4..832d96f0f3c 100644 --- a/libxfs/xfs_ondisk.h +++ b/libxfs/xfs_ondisk.h @@ -85,6 +85,7 @@ xfs_check_ondisk_structs(void) XFS_CHECK_STRUCT_SIZE(xfs_attr_leaf_name_remote_t, 12); */ + XFS_CHECK_OFFSET(struct xfs_dsb, sb_crc, 224); XFS_CHECK_OFFSET(xfs_attr_leaf_name_local_t, valuelen, 0); XFS_CHECK_OFFSET(xfs_attr_leaf_name_local_t, namelen, 2); XFS_CHECK_OFFSET(xfs_attr_leaf_name_local_t, nameval, 3); diff --git a/mdrestore/xfs_mdrestore.c b/mdrestore/xfs_mdrestore.c index 8e3998db06c..6465a481ce3 100644 --- a/mdrestore/xfs_mdrestore.c +++ b/mdrestore/xfs_mdrestore.c @@ -101,10 +101,8 @@ fixup_superblock( memset(block_buffer, 0, sb->sb_sectsize); sb->sb_inprogress = 0; libxfs_sb_to_disk((struct xfs_dsb *)block_buffer, sb); - if (xfs_sb_version_hascrc(sb)) { - xfs_update_cksum(block_buffer, sb->sb_sectsize, - offsetof(struct xfs_sb, sb_crc)); - } + if (xfs_sb_version_hascrc(sb)) + xfs_update_cksum(block_buffer, sb->sb_sectsize, XFS_SB_CRC_OFF); if (pwrite(ddev_fd, block_buffer, sb->sb_sectsize, 0) < 0) fatal("error writing primary superblock: %s\n", strerror(errno)); diff --git a/repair/agheader.c b/repair/agheader.c index 762901581e1..3930a0ac091 100644 --- a/repair/agheader.c +++ b/repair/agheader.c @@ -358,22 +358,22 @@ secondary_sb_whack( * size is the size of data which is valid for this sb. */ if (xfs_sb_version_hasmetauuid(sb)) - size = offsetof(xfs_sb_t, sb_meta_uuid) + size = offsetof(struct xfs_dsb, sb_meta_uuid) + sizeof(sb->sb_meta_uuid); else if (xfs_sb_version_hascrc(sb)) - size = offsetof(xfs_sb_t, sb_lsn) + size = offsetof(struct xfs_dsb, sb_lsn) + sizeof(sb->sb_lsn); else if (xfs_sb_version_hasmorebits(sb)) - size = offsetof(xfs_sb_t, sb_bad_features2) + size = offsetof(struct xfs_dsb, sb_bad_features2) + sizeof(sb->sb_bad_features2); else if (xfs_sb_version_haslogv2(sb)) - size = offsetof(xfs_sb_t, sb_logsunit) + size = offsetof(struct xfs_dsb, sb_logsunit) + sizeof(sb->sb_logsunit); else if (xfs_sb_version_hassector(sb)) - size = offsetof(xfs_sb_t, sb_logsectsize) + size = offsetof(struct xfs_dsb, sb_logsectsize) + sizeof(sb->sb_logsectsize); else /* only support dirv2 or more recent */ - size = offsetof(xfs_sb_t, sb_dirblklog) + size = offsetof(struct xfs_dsb, sb_dirblklog) + sizeof(sb->sb_dirblklog); /* Check the buffer we read from disk for garbage outside size */ From patchwork Sun Dec 31 23:30:06 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13508119 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 2CE73C2C5 for ; Sun, 31 Dec 2023 23:30:07 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="dA2ZyRxO" Received: by smtp.kernel.org (Postfix) with ESMTPSA id EE41BC433C8; Sun, 31 Dec 2023 23:30:06 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704065407; bh=pUSOy3Vw5db8rp2xHfDpNqT5KqXasGa2yJM47klWTz0=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=dA2ZyRxOux/Q5R0Esmgb/QwqxowN+Wsev66CazgZCh11LZ0fDH03AKuipU0dgQK97 hFZgPXC8M9jRnsWJVmdYx5vhn2YanIl0twznSxPOq4N3R/SG25yQQL6pxCip8Ih69r G7owCVMtqxjMf+Tu/c8zgwG6+Ivu/z3p5JxUDn976JzOxnUwT76PDKTq7CN680piBu cpW1gOrCLVqPIzL347AFAbfySx5GhHXrEPr4HE0C5mEn1//js9ZWa2SC0YC0n7Xw4F 9pF9SeQPTKXVyugx9tVVxfapB1YeMd1RWoqNamzX6LuklKO2LMOQ/UX4cU+WqErxjU QeiR3Ro5FFPrw== Date: Sun, 31 Dec 2023 15:30:06 -0800 Subject: [PATCH 02/58] xfs: create imeta abstractions to get and set metadata inodes From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <170405009974.1809361.11171450188551849364.stgit@frogsfrogsfrogs> In-Reply-To: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> References: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Create some helper routines to get and set metadata inode numbers instead of open-coding them throughout xfs. Signed-off-by: Darrick J. Wong --- include/libxfs.h | 2 include/xfs_trace.h | 11 + libxfs/Makefile | 4 libxfs/imeta_utils.c | 190 +++++++++++++++++++++ libxfs/imeta_utils.h | 26 +++ libxfs/init.c | 30 +++ libxfs/libxfs_api_defs.h | 15 ++ libxfs/libxfs_priv.h | 2 libxfs/xfs_imeta.c | 410 ++++++++++++++++++++++++++++++++++++++++++++++ libxfs/xfs_imeta.h | 46 +++++ libxfs/xfs_types.c | 5 - mkfs/xfs_mkfs.c | 2 12 files changed, 739 insertions(+), 4 deletions(-) create mode 100644 libxfs/imeta_utils.c create mode 100644 libxfs/imeta_utils.h create mode 100644 libxfs/xfs_imeta.c create mode 100644 libxfs/xfs_imeta.h diff --git a/include/libxfs.h b/include/libxfs.h index 0d60b9f9f51..7fa061d5e1b 100644 --- a/include/libxfs.h +++ b/include/libxfs.h @@ -89,6 +89,8 @@ struct iomap; #include "xfs_symlink_remote.h" #include "xfs_ag_resv.h" #include "xfs_parent.h" +#include "xfs_imeta.h" +#include "imeta_utils.h" #ifndef ARRAY_SIZE #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) diff --git a/include/xfs_trace.h b/include/xfs_trace.h index 7dcf88b7900..dd6011af90e 100644 --- a/include/xfs_trace.h +++ b/include/xfs_trace.h @@ -360,6 +360,17 @@ #define trace_xlog_intent_recovery_failed(...) ((void) 0) +#define trace_xfs_imeta_teardown(...) ((void) 0) +#define trace_xfs_imeta_sb_create(...) ((void) 0) +#define trace_xfs_imeta_sb_link(...) ((void) 0) +#define trace_xfs_imeta_sb_lookup(...) ((void) 0) +#define trace_xfs_imeta_sb_unlink(...) ((void) 0) +#define trace_xfs_imeta_start_create(...) ((void) 0) +#define trace_xfs_imeta_start_link(...) ((void) 0) +#define trace_xfs_imeta_start_unlink(...) ((void) 0) +#define trace_xfs_imeta_update_cancel(...) ((void) 0) +#define trace_xfs_imeta_update_commit(...) ((void) 0) + #define trace_xfs_iunlink_update_bucket(...) ((void) 0) #define trace_xfs_iunlink_update_dinode(...) ((void) 0) #define trace_xfs_iunlink(...) ((void) 0) diff --git a/libxfs/Makefile b/libxfs/Makefile index 26781ceb913..258ce473200 100644 --- a/libxfs/Makefile +++ b/libxfs/Makefile @@ -24,6 +24,7 @@ HFILES = \ defer_item.h \ libxfs_io.h \ libxfs_api_defs.h \ + imeta_utils.h \ init.h \ iunlink.h \ libxfs_priv.h \ @@ -50,6 +51,7 @@ HFILES = \ xfs_errortag.h \ xfs_ialloc.h \ xfs_ialloc_btree.h \ + xfs_imeta.h \ xfs_inode_buf.h \ xfs_inode_fork.h \ xfs_inode_util.h \ @@ -69,6 +71,7 @@ HFILES = \ CFILES = cache.c \ defer_item.c \ + imeta_utils.c \ init.c \ inode.c \ iunlink.c \ @@ -104,6 +107,7 @@ CFILES = cache.c \ xfs_dquot_buf.c \ xfs_ialloc.c \ xfs_iext_tree.c \ + xfs_imeta.c \ xfs_inode_buf.c \ xfs_inode_fork.c \ xfs_inode_util.c \ diff --git a/libxfs/imeta_utils.c b/libxfs/imeta_utils.c new file mode 100644 index 00000000000..4610c2f49c8 --- /dev/null +++ b/libxfs/imeta_utils.c @@ -0,0 +1,190 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2018-2024 Oracle. All Rights Reserved. + * Author: Darrick J. Wong + */ +#include "libxfs_priv.h" +#include "xfs_fs.h" +#include "xfs_shared.h" +#include "xfs_format.h" +#include "xfs_log_format.h" +#include "xfs_da_format.h" +#include "xfs_trans_resv.h" +#include "xfs_trans_space.h" +#include "xfs_mount.h" +#include "xfs_trans.h" +#include "xfs_inode.h" +#include "xfs_da_btree.h" +#include "xfs_bmap_btree.h" +#include "xfs_bit.h" +#include "xfs_sb.h" +#include "xfs_imeta.h" +#include "xfs_trace.h" +#include "imeta_utils.h" + +/* Initialize a metadata update structure. */ +static inline int +xfs_imeta_init( + struct xfs_mount *mp, + const struct xfs_imeta_path *path, + struct xfs_imeta_update *upd) +{ + memset(upd, 0, sizeof(struct xfs_imeta_update)); + upd->mp = mp; + upd->path = path; + return 0; +} + +/* + * Unlock and release resources after committing (or cancelling) a metadata + * directory tree operation. The caller retains its reference to @upd->ip + * and must release it explicitly. + */ +static inline void +xfs_imeta_teardown( + struct xfs_imeta_update *upd, + int error) +{ + trace_xfs_imeta_teardown(upd, error); + + if (upd->ip) { + if (upd->ip_locked) + xfs_iunlock(upd->ip, XFS_ILOCK_EXCL); + upd->ip_locked = false; + } +} + +/* + * Begin the process of creating a metadata file by allocating transactions + * and taking whatever resources we're going to need. + */ +int +xfs_imeta_start_create( + struct xfs_mount *mp, + const struct xfs_imeta_path *path, + struct xfs_imeta_update *upd) +{ + int error; + + error = xfs_imeta_init(mp, path, upd); + if (error) + return error; + + error = xfs_trans_alloc(mp, &M_RES(mp)->tr_create, + xfs_create_space_res(mp, MAXNAMELEN), 0, 0, &upd->tp); + if (error) + goto out_teardown; + + trace_xfs_imeta_start_create(upd); + return 0; +out_teardown: + xfs_imeta_teardown(upd, error); + return error; +} + +/* + * Begin the process of linking a metadata file by allocating transactions + * and locking whatever resources we're going to need. + */ +static inline int +xfs_imeta_start_dir_update( + struct xfs_mount *mp, + const struct xfs_imeta_path *path, + struct xfs_inode *ip, + struct xfs_trans_res *tr_resv, + unsigned int resblks, + struct xfs_imeta_update *upd) +{ + int error; + + error = xfs_imeta_init(mp, path, upd); + if (error) + return error; + + upd->ip = ip; + + error = xfs_trans_alloc_inode(upd->ip, tr_resv, resblks, 0, false, + &upd->tp); + if (error) + goto out_teardown; + + upd->ip_locked = true; + return 0; +out_teardown: + xfs_imeta_teardown(upd, error); + return error; +} + +/* + * Begin the process of linking a metadata file by allocating transactions + * and locking whatever resources we're going to need. + */ +int +xfs_imeta_start_link( + struct xfs_mount *mp, + const struct xfs_imeta_path *path, + struct xfs_inode *ip, + struct xfs_imeta_update *upd) +{ + int error; + + error = xfs_imeta_start_dir_update(mp, path, ip, &M_RES(mp)->tr_link, + xfs_link_space_res(mp, MAXNAMELEN), upd); + if (error) + return error; + + trace_xfs_imeta_start_link(upd); + return 0; +} + +/* + * Begin the process of unlinking a metadata file by allocating transactions + * and locking whatever resources we're going to need. + */ +int +xfs_imeta_start_unlink( + struct xfs_mount *mp, + const struct xfs_imeta_path *path, + struct xfs_inode *ip, + struct xfs_imeta_update *upd) +{ + int error; + + error = xfs_imeta_start_dir_update(mp, path, ip, &M_RES(mp)->tr_remove, + xfs_remove_space_res(mp, MAXNAMELEN), upd); + if (error) + return error; + + trace_xfs_imeta_start_unlink(upd); + return 0; +} + +/* Commit a metadir update and unlock/drop all resources. */ +int +xfs_imeta_commit_update( + struct xfs_imeta_update *upd) +{ + int error; + + trace_xfs_imeta_update_commit(upd); + + error = xfs_trans_commit(upd->tp); + upd->tp = NULL; + + xfs_imeta_teardown(upd, error); + return error; +} + +/* Cancel a metadir update and unlock/drop all resources. */ +void +xfs_imeta_cancel_update( + struct xfs_imeta_update *upd, + int error) +{ + trace_xfs_imeta_update_cancel(upd); + + xfs_trans_cancel(upd->tp); + upd->tp = NULL; + + xfs_imeta_teardown(upd, error); +} diff --git a/libxfs/imeta_utils.h b/libxfs/imeta_utils.h new file mode 100644 index 00000000000..a2afc0f37ac --- /dev/null +++ b/libxfs/imeta_utils.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2018-2024 Oracle. All Rights Reserved. + * Author: Darrick J. Wong + */ +#ifndef __XFS_IMETA_UTILS_H__ +#define __XFS_IMETA_UTILS_H__ + +int xfs_imeta_start_create(struct xfs_mount *mp, + const struct xfs_imeta_path *path, + struct xfs_imeta_update *upd); + +int xfs_imeta_start_link(struct xfs_mount *mp, + const struct xfs_imeta_path *path, + struct xfs_inode *ip, struct xfs_imeta_update *upd); + +int xfs_imeta_start_unlink(struct xfs_mount *mp, + const struct xfs_imeta_path *path, + struct xfs_inode *ip, struct xfs_imeta_update *upd); + +int xfs_imeta_commit_update(struct xfs_imeta_update *upd); +void xfs_imeta_cancel_update(struct xfs_imeta_update *upd, int error); + +#endif /* __XFS_IMETA_UTILS_H__ */ + + diff --git a/libxfs/init.c b/libxfs/init.c index 397ce088d3a..c199aeea45e 100644 --- a/libxfs/init.c +++ b/libxfs/init.c @@ -669,6 +669,34 @@ libxfs_compute_all_maxlevels( } +/* Mount the metadata files under the metadata directory tree. */ +STATIC void +libxfs_mountfs_imeta( + struct xfs_mount *mp) +{ + struct xfs_trans *tp; + int error; + + /* Ignore filesystems that are under construction. */ + if (mp->m_sb.sb_inprogress) + return; + + error = -libxfs_trans_alloc_empty(mp, &tp); + if (error) + return; + + error = -xfs_imeta_mount(tp); + if (error) { + fprintf(stderr, + _("%s: Failed to load metadata inodes, error %d\n"), + progname, error); + goto err_cancel; + } + +err_cancel: + libxfs_trans_cancel(tp); +} + /* * precalculate the low space thresholds for dynamic speculative preallocation. */ @@ -843,6 +871,8 @@ libxfs_mount( } xfs_set_perag_data_loaded(mp); + libxfs_mountfs_imeta(mp); + return mp; out_da: xfs_da_unmount(mp); diff --git a/libxfs/libxfs_api_defs.h b/libxfs/libxfs_api_defs.h index 3ac0afec41f..9fd53415b47 100644 --- a/libxfs/libxfs_api_defs.h +++ b/libxfs/libxfs_api_defs.h @@ -162,6 +162,8 @@ #define xfs_iallocbt_calc_size libxfs_iallocbt_calc_size #define xfs_iallocbt_maxlevels_ondisk libxfs_iallocbt_maxlevels_ondisk #define xfs_ialloc_read_agi libxfs_ialloc_read_agi +#define xfs_icreate libxfs_icreate +#define xfs_icreate_args_rootfile libxfs_icreate_args_rootfile #define xfs_idata_realloc libxfs_idata_realloc #define xfs_idestroy_fork libxfs_idestroy_fork #define xfs_iext_first libxfs_iext_first @@ -170,6 +172,18 @@ #define xfs_iext_next libxfs_iext_next #define xfs_ifork_zap_attr libxfs_ifork_zap_attr #define xfs_imap_to_bp libxfs_imap_to_bp + +#define xfs_imeta_cancel_update libxfs_imeta_cancel_update +#define xfs_imeta_commit_update libxfs_imeta_commit_update +#define xfs_imeta_create libxfs_imeta_create +#define xfs_imeta_link libxfs_imeta_link +#define xfs_imeta_lookup libxfs_imeta_lookup +#define xfs_imeta_mount libxfs_imeta_mount +#define xfs_imeta_start_create libxfs_imeta_start_create +#define xfs_imeta_start_link libxfs_imeta_start_link +#define xfs_imeta_start_unlink libxfs_imeta_start_unlink +#define xfs_imeta_unlink libxfs_imeta_unlink + #define xfs_initialize_perag libxfs_initialize_perag #define xfs_initialize_perag_data libxfs_initialize_perag_data #define xfs_init_local_fork libxfs_init_local_fork @@ -188,6 +202,7 @@ #define xfs_iread_extents libxfs_iread_extents #define xfs_irele libxfs_irele +#define xfs_is_meta_ino libxfs_is_meta_ino #define xfs_iunlink libxfs_iunlink #define xfs_link_space_res libxfs_link_space_res #define xfs_log_calc_minimum_size libxfs_log_calc_minimum_size diff --git a/libxfs/libxfs_priv.h b/libxfs/libxfs_priv.h index 17e62c9fbb7..9bca059776d 100644 --- a/libxfs/libxfs_priv.h +++ b/libxfs/libxfs_priv.h @@ -484,6 +484,8 @@ void __xfs_buf_mark_corrupt(struct xfs_buf *bp, xfs_failaddr_t fa); static inline int retzero(void) { return 0; } #define xfs_trans_unreserve_quota_nblks(t,i,b,n,f) retzero() #define xfs_quota_unreserve_blkres(i,b) retzero() +#define xfs_qm_dqattach(i) (0) +#define xfs_qm_dqattach_locked(ip, alloc) (0) #define xfs_quota_reserve_blkres(i,b) (0) #define xfs_qm_dqattach(i) (0) diff --git a/libxfs/xfs_imeta.c b/libxfs/xfs_imeta.c new file mode 100644 index 00000000000..b89843926fe --- /dev/null +++ b/libxfs/xfs_imeta.c @@ -0,0 +1,410 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2018-2024 Oracle. All Rights Reserved. + * Author: Darrick J. Wong + */ +#include "libxfs_priv.h" +#include "xfs_fs.h" +#include "xfs_shared.h" +#include "xfs_format.h" +#include "xfs_log_format.h" +#include "xfs_trans_resv.h" +#include "xfs_bit.h" +#include "xfs_sb.h" +#include "xfs_mount.h" +#include "xfs_defer.h" +#include "xfs_trans.h" +#include "xfs_imeta.h" +#include "xfs_trace.h" +#include "xfs_inode.h" +#include "xfs_ialloc.h" + +/* + * Metadata File Management + * ======================== + * + * These functions provide an abstraction layer for looking up, creating, and + * deleting metadata inodes. These pointers live in the in-core superblock, + * so the functions moderate access to those fields and take care of logging. + * + * For the five existing metadata inodes (real time bitmap & summary; and the + * user, group, and quotas) we'll continue to maintain the in-core superblock + * inodes for reads and only require xfs_imeta_create and xfs_imeta_unlink to + * persist changes. New metadata inode types must only use the xfs_imeta_* + * functions. + * + * Callers wishing to create or unlink a metadata inode must pass in a + * xfs_imeta_end structure. After committing or cancelling the transaction, + * this structure must be passed to xfs_imeta_end_update to free resources that + * cannot be freed during the transaction. + * + * Right now we only support callers passing in the predefined metadata inode + * paths; the goal is that callers will some day locate metadata inodes based + * on path lookups into a metadata directory structure. + */ + +/* Static metadata inode paths */ + +const struct xfs_imeta_path XFS_IMETA_RTBITMAP = { + .bogus = 0, +}; + +const struct xfs_imeta_path XFS_IMETA_RTSUMMARY = { + .bogus = 1, +}; + +const struct xfs_imeta_path XFS_IMETA_USRQUOTA = { + .bogus = 2, +}; + +const struct xfs_imeta_path XFS_IMETA_GRPQUOTA = { + .bogus = 3, +}; + +const struct xfs_imeta_path XFS_IMETA_PRJQUOTA = { + .bogus = 4, +}; + +/* Are these two paths equal? */ +STATIC bool +xfs_imeta_path_compare( + const struct xfs_imeta_path *a, + const struct xfs_imeta_path *b) +{ + return a == b; +} + +/* Is this path ok? */ +static inline bool +xfs_imeta_path_check( + const struct xfs_imeta_path *path) +{ + return true; +} + +/* Functions for storing and retrieving superblock inode values. */ + +/* Mapping of metadata inode paths to in-core superblock values. */ +static const struct xfs_imeta_sbmap { + const struct xfs_imeta_path *path; + unsigned int offset; +} xfs_imeta_sbmaps[] = { + { + .path = &XFS_IMETA_RTBITMAP, + .offset = offsetof(struct xfs_sb, sb_rbmino), + }, + { + .path = &XFS_IMETA_RTSUMMARY, + .offset = offsetof(struct xfs_sb, sb_rsumino), + }, + { + .path = &XFS_IMETA_USRQUOTA, + .offset = offsetof(struct xfs_sb, sb_uquotino), + }, + { + .path = &XFS_IMETA_GRPQUOTA, + .offset = offsetof(struct xfs_sb, sb_gquotino), + }, + { + .path = &XFS_IMETA_PRJQUOTA, + .offset = offsetof(struct xfs_sb, sb_pquotino), + }, + { NULL, 0 }, +}; + +/* Return a pointer to the in-core superblock inode value. */ +static inline xfs_ino_t * +xfs_imeta_sbmap_to_inop( + struct xfs_mount *mp, + const struct xfs_imeta_sbmap *map) +{ + return (xfs_ino_t *)(((char *)&mp->m_sb) + map->offset); +} + +/* Compute location of metadata inode pointer in the in-core superblock */ +static inline xfs_ino_t * +xfs_imeta_path_to_sb_inop( + struct xfs_mount *mp, + const struct xfs_imeta_path *path) +{ + const struct xfs_imeta_sbmap *p; + + for (p = xfs_imeta_sbmaps; p->path; p++) + if (xfs_imeta_path_compare(p->path, path)) + return xfs_imeta_sbmap_to_inop(mp, p); + + return NULL; +} + +/* Look up a superblock metadata inode by its path. */ +STATIC int +xfs_imeta_sb_lookup( + struct xfs_mount *mp, + const struct xfs_imeta_path *path, + xfs_ino_t *inop) +{ + xfs_ino_t *sb_inop; + + sb_inop = xfs_imeta_path_to_sb_inop(mp, path); + if (!sb_inop) + return -EINVAL; + + trace_xfs_imeta_sb_lookup(mp, sb_inop); + *inop = *sb_inop; + return 0; +} + +/* Update inode pointers in the superblock. */ +static inline void +xfs_imeta_log_sb( + struct xfs_trans *tp) +{ + struct xfs_mount *mp = tp->t_mountp; + struct xfs_buf *bp = xfs_trans_getsb(tp); + + /* + * Update the inode flags in the ondisk superblock without touching + * the summary counters. We have not quiesced inode chunk allocation, + * so we cannot coordinate with updates to the icount and ifree percpu + * counters. + */ + xfs_sb_to_disk(bp->b_addr, &mp->m_sb); + xfs_trans_buf_set_type(tp, bp, XFS_BLFT_SB_BUF); + xfs_trans_log_buf(tp, bp, 0, sizeof(struct xfs_dsb) - 1); +} + +/* + * Create a new metadata inode and set a superblock pointer to this new inode. + * The superblock field must not already be pointing to an inode. + */ +STATIC int +xfs_imeta_sb_create( + struct xfs_imeta_update *upd, + umode_t mode) +{ + struct xfs_icreate_args args = { + .nlink = S_ISDIR(mode) ? 2 : 1, + }; + struct xfs_mount *mp = upd->mp; + xfs_ino_t *sb_inop; + xfs_ino_t ino; + int error; + + /* Files rooted in the superblock do not have parents. */ + xfs_icreate_args_rootfile(&args, mp, mode, false); + + /* Reject if the sb already points to some inode. */ + sb_inop = xfs_imeta_path_to_sb_inop(mp, upd->path); + if (!sb_inop) + return -EINVAL; + + if (*sb_inop != NULLFSINO) + return -EEXIST; + + /* Create a new inode and set the sb pointer. */ + error = xfs_dialloc(&upd->tp, 0, mode, &ino); + if (error) + return error; + error = xfs_icreate(upd->tp, ino, &args, &upd->ip); + if (error) + return error; + upd->ip_locked = true; + + /* + * If we ever need the ability to create rt metadata files on a + * pre-metadir filesystem, we'll need to dqattach the child here. + * Currently we assume that mkfs will create the files and quotacheck + * will account for them. + */ + + /* Update superblock pointer. */ + *sb_inop = ino; + xfs_imeta_log_sb(upd->tp); + + trace_xfs_imeta_sb_create(upd); + return 0; +} + +/* + * Clear the given inode pointer from the superblock and drop the link count + * of the metadata inode. + */ +STATIC int +xfs_imeta_sb_unlink( + struct xfs_imeta_update *upd) +{ + struct xfs_mount *mp = upd->mp; + xfs_ino_t *sb_inop; + + ASSERT(xfs_isilocked(upd->ip, XFS_ILOCK_EXCL)); + + sb_inop = xfs_imeta_path_to_sb_inop(mp, upd->path); + if (!sb_inop) + return -EINVAL; + + /* Reject if the sb doesn't point to the inode that was passed in. */ + if (*sb_inop != upd->ip->i_ino) + return -ENOENT; + + trace_xfs_imeta_sb_unlink(upd); + + *sb_inop = NULLFSINO; + xfs_imeta_log_sb(upd->tp); + return xfs_droplink(upd->tp, upd->ip); +} + +/* Set the given inode pointer in the superblock. */ +STATIC int +xfs_imeta_sb_link( + struct xfs_imeta_update *upd) +{ + struct xfs_mount *mp = upd->mp; + xfs_ino_t *sb_inop; + + ASSERT(xfs_isilocked(upd->ip, XFS_ILOCK_EXCL)); + + sb_inop = xfs_imeta_path_to_sb_inop(mp, upd->path); + if (!sb_inop) + return -EINVAL; + if (*sb_inop != NULLFSINO) + return -EEXIST; + + trace_xfs_imeta_sb_link(upd); + + xfs_bumplink(upd->tp, upd->ip); + xfs_imeta_log_sb(upd->tp); + + *sb_inop = upd->ip->i_ino; + return 0; +} + +/* General functions for managing metadata inode pointers */ + +/* + * Is this metadata inode pointer ok? We allow the fields to be set to + * NULLFSINO if the metadata structure isn't present, and we don't allow + * obviously incorrect inode pointers. + */ +static inline bool +xfs_imeta_verify( + struct xfs_mount *mp, + xfs_ino_t ino) +{ + if (ino == NULLFSINO) + return true; + return xfs_verify_ino(mp, ino); +} + +/* Look up a metadata inode by its path. */ +int +xfs_imeta_lookup( + struct xfs_trans *tp, + const struct xfs_imeta_path *path, + xfs_ino_t *inop) +{ + struct xfs_mount *mp = tp->t_mountp; + xfs_ino_t ino; + int error; + + ASSERT(xfs_imeta_path_check(path)); + + error = xfs_imeta_sb_lookup(mp, path, &ino); + if (error) + return error; + + if (!xfs_imeta_verify(mp, ino)) + return -EFSCORRUPTED; + + *inop = ino; + return 0; +} + +/* + * Create a metadata inode with the given @mode, and insert it into the + * metadata directory tree at the given @path. The path (up to the final + * component) must already exist. + * + * The new metadata inode will be attached to the update structure @upd->ip, + * with the ILOCK held until the caller releases it. @ipp is set to upd->ip + * as a convenience for callers. + * + * Callers must ensure that the root dquots are allocated, if applicable. + * + * NOTE: This function may return a new inode to the caller even if it returns + * a negative error code. If an inode is passed back, the caller must finish + * setting up the inode before releasing it. + */ +int +xfs_imeta_create( + struct xfs_imeta_update *upd, + umode_t mode, + struct xfs_inode **ipp) +{ + int error; + + ASSERT(xfs_imeta_path_check(upd->path)); + + *ipp = NULL; + + error = xfs_imeta_sb_create(upd, mode); + *ipp = upd->ip; + return error; +} + +/* + * Unlink a metadata inode @upd->ip from the metadata directory given by @path. + * The path must already exist. + */ +int +xfs_imeta_unlink( + struct xfs_imeta_update *upd) +{ + ASSERT(xfs_imeta_path_check(upd->path)); + ASSERT(xfs_imeta_verify(upd->mp, upd->ip->i_ino)); + + return xfs_imeta_sb_unlink(upd); +} + +/* + * Link the metadata directory given by @path to the inode @upd->ip. + * The path (up to the final component) must already exist, but the final + * component must not already exist. + */ +int +xfs_imeta_link( + struct xfs_imeta_update *upd) +{ + ASSERT(xfs_imeta_path_check(upd->path)); + + return xfs_imeta_sb_link(upd); +} + +/* Does this inode number refer to a static metadata inode? */ +bool +xfs_is_static_meta_ino( + struct xfs_mount *mp, + xfs_ino_t ino) +{ + const struct xfs_imeta_sbmap *p; + + if (ino == NULLFSINO) + return false; + + for (p = xfs_imeta_sbmaps; p->path; p++) + if (ino == *xfs_imeta_sbmap_to_inop(mp, p)) + return true; + + return false; +} + +/* + * Ensure that the in-core superblock has all the values that it should. + * Caller should pass in an empty transaction to avoid livelocking on btree + * cycles. + */ +int +xfs_imeta_mount( + struct xfs_trans *tp) +{ + return 0; +} diff --git a/libxfs/xfs_imeta.h b/libxfs/xfs_imeta.h new file mode 100644 index 00000000000..c1833b8b1c9 --- /dev/null +++ b/libxfs/xfs_imeta.h @@ -0,0 +1,46 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2018-2024 Oracle. All Rights Reserved. + * Author: Darrick J. Wong + */ +#ifndef __XFS_IMETA_H__ +#define __XFS_IMETA_H__ + +/* Key for looking up metadata inodes. */ +struct xfs_imeta_path { + /* Temporary: integer to keep the static imeta definitions unique */ + int bogus; +}; + +/* Cleanup widget for metadata inode creation and deletion. */ +struct xfs_imeta_update { + struct xfs_mount *mp; + struct xfs_trans *tp; + + const struct xfs_imeta_path *path; + + /* Metadata inode */ + struct xfs_inode *ip; + + unsigned int ip_locked:1; +}; + +/* Lookup keys for static metadata inodes. */ +extern const struct xfs_imeta_path XFS_IMETA_RTBITMAP; +extern const struct xfs_imeta_path XFS_IMETA_RTSUMMARY; +extern const struct xfs_imeta_path XFS_IMETA_USRQUOTA; +extern const struct xfs_imeta_path XFS_IMETA_GRPQUOTA; +extern const struct xfs_imeta_path XFS_IMETA_PRJQUOTA; + +int xfs_imeta_lookup(struct xfs_trans *tp, const struct xfs_imeta_path *path, + xfs_ino_t *ino); + +int xfs_imeta_create(struct xfs_imeta_update *upd, umode_t mode, + struct xfs_inode **ipp); +int xfs_imeta_unlink(struct xfs_imeta_update *upd); +int xfs_imeta_link(struct xfs_imeta_update *upd); + +bool xfs_is_static_meta_ino(struct xfs_mount *mp, xfs_ino_t ino); +int xfs_imeta_mount(struct xfs_trans *tp); + +#endif /* __XFS_IMETA_H__ */ diff --git a/libxfs/xfs_types.c b/libxfs/xfs_types.c index 74ab1965a8f..88720b297d7 100644 --- a/libxfs/xfs_types.c +++ b/libxfs/xfs_types.c @@ -12,6 +12,7 @@ #include "xfs_bit.h" #include "xfs_mount.h" #include "xfs_ag.h" +#include "xfs_imeta.h" /* @@ -115,9 +116,7 @@ xfs_internal_inum( struct xfs_mount *mp, xfs_ino_t ino) { - return ino == mp->m_sb.sb_rbmino || ino == mp->m_sb.sb_rsumino || - (xfs_has_quota(mp) && - xfs_is_quota_inode(&mp->m_sb, ino)); + return xfs_is_static_meta_ino(mp, ino); } /* diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c index 482275e0e0d..15be7e0fb60 100644 --- a/mkfs/xfs_mkfs.c +++ b/mkfs/xfs_mkfs.c @@ -3878,6 +3878,7 @@ start_superblock_setup( struct xfs_mount *mp, struct xfs_sb *sbp) { + sbp->sb_inprogress = 1; /* mkfs is in progress */ sbp->sb_magicnum = XFS_SB_MAGIC; sbp->sb_sectsize = (uint16_t)cfg->sectorsize; sbp->sb_sectlog = (uint8_t)cfg->sectorlog; @@ -3960,7 +3961,6 @@ finish_superblock_setup( sbp->sb_rbmblocks = cfg->rtbmblocks; sbp->sb_logblocks = (xfs_extlen_t)cfg->logblocks; sbp->sb_rextslog = libxfs_compute_rextslog(cfg->rtextents); - sbp->sb_inprogress = 1; /* mkfs is in progress */ sbp->sb_imax_pct = cfg->imaxpct; sbp->sb_icount = 0; sbp->sb_ifree = 0; From patchwork Sun Dec 31 23:30:22 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13508120 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 CD45CC2C5 for ; Sun, 31 Dec 2023 23:30:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="TG9dDmqg" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 973BEC433C8; Sun, 31 Dec 2023 23:30:22 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704065422; bh=UfGCM8qkXPM/AIDGwKwjQ3HpcnQ8UIlTRum8v+RUvFo=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=TG9dDmqgr9MibjiM4RtS0tfqsnHt8s86tGiyxyfPHJn0QOK783CBZyywll4iA69hp 02VbpbW6RLK2YTYUwTghd+MLb7dZff2I5sd0aeNDo6wuaE2NnJ86+oRaKV6YSoVLxI oSZw5Us0ruOybfjrxTx9ekCZnx7xQGMhRSeqwOde9dFbMfu2mhWcLoE6pqe6+URE3k 13Ui3BECzTOtVCeI++rMpuCQRxcCxODFs+YWtgz+A8SLDI7HTm3A44Oya/zCO9bwPk 2TlBCEj1FSAUIwj0FwWl8V4qCS62JqiJdbg7YLOvYiL0dpP1jhYe2Z1oAfzsbec/Wb JZNhGz/Auzk0w== Date: Sun, 31 Dec 2023 15:30:22 -0800 Subject: [PATCH 03/58] xfs: create transaction reservations for metadata inode operations From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <170405009987.1809361.15843525045056018505.stgit@frogsfrogsfrogs> In-Reply-To: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> References: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Create transaction reservation types and block reservation helpers to help us calculate transaction requirements. Right now the reservations are the same as always; we're just separating the symbols for a future patch. Signed-off-by: Darrick J. Wong --- libxfs/imeta_utils.c | 8 +++++--- libxfs/libxfs_api_defs.h | 3 +++ libxfs/xfs_imeta.c | 4 ++++ libxfs/xfs_imeta.h | 4 ++++ libxfs/xfs_trans_resv.c | 5 +++++ libxfs/xfs_trans_resv.h | 3 +++ 6 files changed, 24 insertions(+), 3 deletions(-) diff --git a/libxfs/imeta_utils.c b/libxfs/imeta_utils.c index 4610c2f49c8..f3165b5eed3 100644 --- a/libxfs/imeta_utils.c +++ b/libxfs/imeta_utils.c @@ -70,7 +70,7 @@ xfs_imeta_start_create( if (error) return error; - error = xfs_trans_alloc(mp, &M_RES(mp)->tr_create, + error = xfs_trans_alloc(mp, &M_RES(mp)->tr_imeta_create, xfs_create_space_res(mp, MAXNAMELEN), 0, 0, &upd->tp); if (error) goto out_teardown; @@ -128,7 +128,8 @@ xfs_imeta_start_link( { int error; - error = xfs_imeta_start_dir_update(mp, path, ip, &M_RES(mp)->tr_link, + error = xfs_imeta_start_dir_update(mp, path, ip, + &M_RES(mp)->tr_imeta_link, xfs_link_space_res(mp, MAXNAMELEN), upd); if (error) return error; @@ -150,7 +151,8 @@ xfs_imeta_start_unlink( { int error; - error = xfs_imeta_start_dir_update(mp, path, ip, &M_RES(mp)->tr_remove, + error = xfs_imeta_start_dir_update(mp, path, ip, + &M_RES(mp)->tr_imeta_unlink, xfs_remove_space_res(mp, MAXNAMELEN), upd); if (error) return error; diff --git a/libxfs/libxfs_api_defs.h b/libxfs/libxfs_api_defs.h index 9fd53415b47..167617771d8 100644 --- a/libxfs/libxfs_api_defs.h +++ b/libxfs/libxfs_api_defs.h @@ -176,13 +176,16 @@ #define xfs_imeta_cancel_update libxfs_imeta_cancel_update #define xfs_imeta_commit_update libxfs_imeta_commit_update #define xfs_imeta_create libxfs_imeta_create +#define xfs_imeta_create_space_res libxfs_imeta_create_space_res #define xfs_imeta_link libxfs_imeta_link +#define xfs_imeta_link_space_res libxfs_imeta_link_space_res #define xfs_imeta_lookup libxfs_imeta_lookup #define xfs_imeta_mount libxfs_imeta_mount #define xfs_imeta_start_create libxfs_imeta_start_create #define xfs_imeta_start_link libxfs_imeta_start_link #define xfs_imeta_start_unlink libxfs_imeta_start_unlink #define xfs_imeta_unlink libxfs_imeta_unlink +#define xfs_imeta_unlink_space_res libxfs_imeta_unlink_space_res #define xfs_initialize_perag libxfs_initialize_perag #define xfs_initialize_perag_data libxfs_initialize_perag_data diff --git a/libxfs/xfs_imeta.c b/libxfs/xfs_imeta.c index b89843926fe..086c250a3c2 100644 --- a/libxfs/xfs_imeta.c +++ b/libxfs/xfs_imeta.c @@ -18,6 +18,10 @@ #include "xfs_trace.h" #include "xfs_inode.h" #include "xfs_ialloc.h" +#include "xfs_bmap_btree.h" +#include "xfs_da_format.h" +#include "xfs_da_btree.h" +#include "xfs_trans_space.h" /* * Metadata File Management diff --git a/libxfs/xfs_imeta.h b/libxfs/xfs_imeta.h index c1833b8b1c9..7b3da865c09 100644 --- a/libxfs/xfs_imeta.h +++ b/libxfs/xfs_imeta.h @@ -43,4 +43,8 @@ int xfs_imeta_link(struct xfs_imeta_update *upd); bool xfs_is_static_meta_ino(struct xfs_mount *mp, xfs_ino_t ino); int xfs_imeta_mount(struct xfs_trans *tp); +unsigned int xfs_imeta_create_space_res(struct xfs_mount *mp); +unsigned int xfs_imeta_link_space_res(struct xfs_mount *mp); +unsigned int xfs_imeta_unlink_space_res(struct xfs_mount *mp); + #endif /* __XFS_IMETA_H__ */ diff --git a/libxfs/xfs_trans_resv.c b/libxfs/xfs_trans_resv.c index 78e7a575baa..5a1ad959870 100644 --- a/libxfs/xfs_trans_resv.c +++ b/libxfs/xfs_trans_resv.c @@ -1246,4 +1246,9 @@ xfs_trans_resv_calc( resp->tr_itruncate.tr_logcount += logcount_adj; resp->tr_write.tr_logcount += logcount_adj; resp->tr_qm_dqalloc.tr_logcount += logcount_adj; + + /* metadata inode creation and unlink */ + resp->tr_imeta_create = resp->tr_create; + resp->tr_imeta_link = resp->tr_link; + resp->tr_imeta_unlink = resp->tr_remove; } diff --git a/libxfs/xfs_trans_resv.h b/libxfs/xfs_trans_resv.h index 0554b9d775d..6b851dfe1ac 100644 --- a/libxfs/xfs_trans_resv.h +++ b/libxfs/xfs_trans_resv.h @@ -48,6 +48,9 @@ struct xfs_trans_resv { struct xfs_trans_res tr_qm_dqalloc; /* allocate quota on disk */ struct xfs_trans_res tr_sb; /* modify superblock */ struct xfs_trans_res tr_fsyncts; /* update timestamps on fsync */ + struct xfs_trans_res tr_imeta_create; /* create metadata inode */ + struct xfs_trans_res tr_imeta_link; /* link metadata inode */ + struct xfs_trans_res tr_imeta_unlink; /* unlink metadata inode */ }; /* shorthand way of accessing reservation structure */ From patchwork Sun Dec 31 23:30:37 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13508121 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 621A8C2C0 for ; Sun, 31 Dec 2023 23:30:38 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="lOb/j/PO" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 326EBC433C8; Sun, 31 Dec 2023 23:30:38 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704065438; bh=NGL2hBQkPChT3WaL7u1RO1TFMYXATSWgKT41d01mT2w=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=lOb/j/POnLc/rlb4JWCabsFwMKCq7Xt5fDh6XBlmhYtZnBgOu72Yv8V1SHUQzLOE/ ia2jqgnP6PG2T9vddbiMu3GwG1FvSTv/lRyaBdd0h9QJ/WzAJ6SMCfSk9VwlGrXVp5 uz0O6bVmXMyrg0bNBcTYsjts43Hne4nbFgEBqgOlhduIINAigHtM1uTE2EN3T5Jt0J 364/SP74T3b5LeUalDd6Ktfx/it0qW3vDJ1kig5oiyGt0T2uE8Og/EtnKxptxNlDO6 2kzuIxkKQpvi86iyc4p89JEeAedVoOsQG2Nu4MaxKJYvFPyYQRC0WD4Yqfk26bQF+r TsMEJq8+UZvOA== Date: Sun, 31 Dec 2023 15:30:37 -0800 Subject: [PATCH 04/58] mkfs: clean up the rtinit() function From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <170405010001.1809361.11639524525861448693.stgit@frogsfrogsfrogs> In-Reply-To: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> References: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Clean up some of the warts in this function, like the inconsistent use of @i for @error, missing comments, and make this more visually pleasing by adding some whitespace between major sections. Some things are left untouched for the next patch. Signed-off-by: Darrick J. Wong --- mkfs/proto.c | 70 ++++++++++++++++++++++++++++------------------------------ 1 file changed, 34 insertions(+), 36 deletions(-) diff --git a/mkfs/proto.c b/mkfs/proto.c index f9b0f837ed9..a519aaeb72b 100644 --- a/mkfs/proto.c +++ b/mkfs/proto.c @@ -750,28 +750,26 @@ parse_proto( */ static void rtinit( - xfs_mount_t *mp) + struct xfs_mount *mp) { - xfs_fileoff_t bno; - xfs_bmbt_irec_t *ep; - int error; - int i; - xfs_bmbt_irec_t map[XFS_BMAP_MAX_NMAP]; - xfs_extlen_t nsumblocks; - uint blocks; - int nmap; - xfs_inode_t *rbmip; - xfs_inode_t *rsumip; - xfs_trans_t *tp; - struct cred creds; - struct fsxattr fsxattrs; + struct cred creds; + struct fsxattr fsxattrs; + struct xfs_bmbt_irec map[XFS_BMAP_MAX_NMAP]; + struct xfs_inode *rbmip; + struct xfs_inode *rsumip; + struct xfs_trans *tp; + struct xfs_bmbt_irec *ep; + xfs_fileoff_t bno; + xfs_extlen_t nsumblocks; + uint blocks; + int i; + int nmap; + int error; - /* - * First, allocate the inodes. - */ - i = -libxfs_trans_alloc_rollable(mp, MKFS_BLOCKRES_INODE, &tp); - if (i) - res_failed(i); + /* Create the realtime bitmap inode. */ + error = -libxfs_trans_alloc_rollable(mp, MKFS_BLOCKRES_INODE, &tp); + if (error) + res_failed(error); memset(&creds, 0, sizeof(creds)); memset(&fsxattrs, 0, sizeof(fsxattrs)); @@ -792,6 +790,8 @@ rtinit( libxfs_trans_log_inode(tp, rbmip, XFS_ILOG_CORE); libxfs_log_sb(tp); mp->m_rbmip = rbmip; + + /* Create the realtime summary inode. */ error = creatproto(&tp, NULL, S_IFREG, 1, 0, &creds, &fsxattrs, &rsumip); if (error) { @@ -806,14 +806,13 @@ rtinit( fail(_("Completion of the realtime summary inode failed"), error); mp->m_rsumip = rsumip; - /* - * Next, give the bitmap file some zero-filled blocks. - */ + + /* Zero the realtime bitmap. */ blocks = mp->m_sb.sb_rbmblocks + XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) - 1; - i = -libxfs_trans_alloc_rollable(mp, blocks, &tp); - if (i) - res_failed(i); + error = -libxfs_trans_alloc_rollable(mp, blocks, &tp); + if (error) + res_failed(error); libxfs_trans_ijoin(tp, rbmip, 0); bno = 0; @@ -822,10 +821,10 @@ rtinit( error = -libxfs_bmapi_write(tp, rbmip, bno, (xfs_extlen_t)(mp->m_sb.sb_rbmblocks - bno), 0, mp->m_sb.sb_rbmblocks, map, &nmap); - if (error) { + if (error) fail(_("Allocation of the realtime bitmap failed"), error); - } + for (i = 0, ep = map; i < nmap; i++, ep++) { libxfs_device_zero(mp->m_ddev_targp, XFS_FSB_TO_DADDR(mp, ep->br_startblock), @@ -839,25 +838,24 @@ rtinit( fail(_("Block allocation of the realtime bitmap inode failed"), error); - /* - * Give the summary file some zero-filled blocks. - */ + /* Zero the summary file. */ nsumblocks = mp->m_rsumsize >> mp->m_sb.sb_blocklog; blocks = nsumblocks + XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) - 1; - i = -libxfs_trans_alloc_rollable(mp, blocks, &tp); - if (i) - res_failed(i); + error = -libxfs_trans_alloc_rollable(mp, blocks, &tp); + if (error) + res_failed(error); libxfs_trans_ijoin(tp, rsumip, 0); + bno = 0; while (bno < nsumblocks) { nmap = XFS_BMAP_MAX_NMAP; error = -libxfs_bmapi_write(tp, rsumip, bno, (xfs_extlen_t)(nsumblocks - bno), 0, nsumblocks, map, &nmap); - if (error) { + if (error) fail(_("Allocation of the realtime summary failed"), error); - } + for (i = 0, ep = map; i < nmap; i++, ep++) { libxfs_device_zero(mp->m_ddev_targp, XFS_FSB_TO_DADDR(mp, ep->br_startblock), From patchwork Sun Dec 31 23:30:53 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13508122 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 29824C2C0 for ; Sun, 31 Dec 2023 23:30:54 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="c7tOdHDF" Received: by smtp.kernel.org (Postfix) with ESMTPSA id E02AAC433C7; Sun, 31 Dec 2023 23:30:53 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704065454; bh=JqErQyL0PWBnQ8EM+Lh1JOtfnTWnt37370HC9jZqgdA=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=c7tOdHDFr/lhM7cQ+w7i6ltu1Fwu8la0P1KflOPPO13akxiUf6NOWn4gt3W1Pp0lM by6r4eIRY0A1rnD5YOjdfHqN7iCf5cbSZoWoyiAcsXeodlSB9PbHpG1OLwIzVjfmBq IqQfxgX0VXJdrH/63IvM1Vwx5WEfft4wsI0x/LZ2OCb2xeOPPHTCuFo/hKn6X+uiBj B1XkPgvGQIZD/qePVBn5YB4wJ5k2xiHFGayRcs3EvfzZZyEOwuoWM8K1VL8cJVU9jC amV7PwtF+B6gK7XEY8a4nO0YFdb8Fn5H0+T0dkM1v+/Q3c3zKUASUVIbijxTs6j3VB iov/DseUT2ujA== Date: Sun, 31 Dec 2023 15:30:53 -0800 Subject: [PATCH 05/58] libxfs: convert all users to libxfs_imeta_create From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <170405010014.1809361.6997364246808217554.stgit@frogsfrogsfrogs> In-Reply-To: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> References: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Convert all open-coded sb metadata inode pointer logging to use libxfs_imeta_create to create metadata inodes. Signed-off-by: Darrick J. Wong --- mkfs/proto.c | 44 ++++++++++++++++++++------------------------ 1 file changed, 20 insertions(+), 24 deletions(-) diff --git a/mkfs/proto.c b/mkfs/proto.c index a519aaeb72b..8ae0aba777c 100644 --- a/mkfs/proto.c +++ b/mkfs/proto.c @@ -752,8 +752,7 @@ static void rtinit( struct xfs_mount *mp) { - struct cred creds; - struct fsxattr fsxattrs; + struct xfs_imeta_update upd; struct xfs_bmbt_irec map[XFS_BMAP_MAX_NMAP]; struct xfs_inode *rbmip; struct xfs_inode *rsumip; @@ -767,41 +766,38 @@ rtinit( int error; /* Create the realtime bitmap inode. */ - error = -libxfs_trans_alloc_rollable(mp, MKFS_BLOCKRES_INODE, &tp); + error = -libxfs_imeta_start_create(mp, &XFS_IMETA_RTBITMAP, &upd); if (error) res_failed(error); - memset(&creds, 0, sizeof(creds)); - memset(&fsxattrs, 0, sizeof(fsxattrs)); - error = creatproto(&tp, NULL, S_IFREG, 1, 0, &creds, &fsxattrs, - &rbmip); - if (error) { + error = -libxfs_imeta_create(&upd, S_IFREG, &rbmip); + if (error) fail(_("Realtime bitmap inode allocation failed"), error); - } - /* - * Do our thing with rbmip before allocating rsumip, - * because the next call to createproto may - * commit the transaction in which rbmip was allocated. - */ - mp->m_sb.sb_rbmino = rbmip->i_ino; + rbmip->i_disk_size = mp->m_sb.sb_rbmblocks * mp->m_sb.sb_blocksize; - rbmip->i_diflags = XFS_DIFLAG_NEWRTBM; + rbmip->i_diflags |= XFS_DIFLAG_NEWRTBM; inode_set_atime(VFS_I(rbmip), 0, 0); libxfs_trans_log_inode(tp, rbmip, XFS_ILOG_CORE); - libxfs_log_sb(tp); + + error = -libxfs_imeta_commit_update(&upd); + if (error) + fail(_("Completion of the realtime bitmap inode failed"), + error); mp->m_rbmip = rbmip; /* Create the realtime summary inode. */ - error = creatproto(&tp, NULL, S_IFREG, 1, 0, &creds, &fsxattrs, - &rsumip); - if (error) { + error = -libxfs_imeta_start_create(mp, &XFS_IMETA_RTSUMMARY, &upd); + if (error) + res_failed(error); + + error = -libxfs_imeta_create(&upd, S_IFREG, &rsumip); + if (error) fail(_("Realtime summary inode allocation failed"), error); - } - mp->m_sb.sb_rsumino = rsumip->i_ino; + rsumip->i_disk_size = mp->m_rsumsize; libxfs_trans_log_inode(tp, rsumip, XFS_ILOG_CORE); - libxfs_log_sb(tp); - error = -libxfs_trans_commit(tp); + + error = -libxfs_imeta_commit_update(&upd); if (error) fail(_("Completion of the realtime summary inode failed"), error); From patchwork Sun Dec 31 23:31:09 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13508123 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 41127C2CC for ; Sun, 31 Dec 2023 23:31:09 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="pOrfueJX" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 94EC6C433C7; Sun, 31 Dec 2023 23:31:09 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704065469; bh=nmfSL3DhT/bHIIvXnob4elbU6kmAeTcVyQDNYjViMF8=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=pOrfueJXjqwn50iBzkbcS1TqOn5HL/061QIqONMfqAPVDF1vK4dQqIoyV8vpBh6Hr IP+MMJ5pJVB6jD5QSf758z0OckPhjJzCKG+5oJ47SFLhaK5a5N88Ix00MhQZ3XEW3b Wtz4bXzR3qj8mr8HMhwTFBreA1oKzP8j4c+ASxnYUhD9OMi4ohlGdzz3yu3fORL1BK mNgA6xw4StbZ1aK+RZ/6ZXO7DIY7dPDzDuFGink5xcKtzqe5a/cUk8UyuOLjOC5slU nGa5EDAaS7x8HV9nYIFwZ6YMcYJtL0NgvifpeZhE49oZb693KcE+jHzNkqdiXEe1PZ iEmw5XuEMWyYA== Date: Sun, 31 Dec 2023 15:31:09 -0800 Subject: [PATCH 06/58] mkfs: break up the rest of the rtinit() function From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <170405010027.1809361.17884123990207975871.stgit@frogsfrogsfrogs> In-Reply-To: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> References: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Break up this really long function into smaller functions that each do one thing. Signed-off-by: Darrick J. Wong --- mkfs/proto.c | 89 ++++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 64 insertions(+), 25 deletions(-) diff --git a/mkfs/proto.c b/mkfs/proto.c index 8ae0aba777c..2eff1f32173 100644 --- a/mkfs/proto.c +++ b/mkfs/proto.c @@ -745,27 +745,15 @@ parse_proto( parseproto(mp, NULL, fsx, pp, NULL); } -/* - * Allocate the realtime bitmap and summary inodes, and fill in data if any. - */ +/* Create the realtime bitmap inode. */ static void -rtinit( +rtbitmap_create( struct xfs_mount *mp) { struct xfs_imeta_update upd; - struct xfs_bmbt_irec map[XFS_BMAP_MAX_NMAP]; struct xfs_inode *rbmip; - struct xfs_inode *rsumip; - struct xfs_trans *tp; - struct xfs_bmbt_irec *ep; - xfs_fileoff_t bno; - xfs_extlen_t nsumblocks; - uint blocks; - int i; - int nmap; int error; - /* Create the realtime bitmap inode. */ error = -libxfs_imeta_start_create(mp, &XFS_IMETA_RTBITMAP, &upd); if (error) res_failed(error); @@ -777,15 +765,24 @@ rtinit( rbmip->i_disk_size = mp->m_sb.sb_rbmblocks * mp->m_sb.sb_blocksize; rbmip->i_diflags |= XFS_DIFLAG_NEWRTBM; inode_set_atime(VFS_I(rbmip), 0, 0); - libxfs_trans_log_inode(tp, rbmip, XFS_ILOG_CORE); + libxfs_trans_log_inode(upd.tp, rbmip, XFS_ILOG_CORE); error = -libxfs_imeta_commit_update(&upd); if (error) fail(_("Completion of the realtime bitmap inode failed"), error); mp->m_rbmip = rbmip; +} + +/* Create the realtime summary inode. */ +static void +rtsummary_create( + struct xfs_mount *mp) +{ + struct xfs_imeta_update upd; + struct xfs_inode *rsumip; + int error; - /* Create the realtime summary inode. */ error = -libxfs_imeta_start_create(mp, &XFS_IMETA_RTSUMMARY, &upd); if (error) res_failed(error); @@ -795,26 +792,40 @@ rtinit( fail(_("Realtime summary inode allocation failed"), error); rsumip->i_disk_size = mp->m_rsumsize; - libxfs_trans_log_inode(tp, rsumip, XFS_ILOG_CORE); + libxfs_trans_log_inode(upd.tp, rsumip, XFS_ILOG_CORE); error = -libxfs_imeta_commit_update(&upd); if (error) fail(_("Completion of the realtime summary inode failed"), error); mp->m_rsumip = rsumip; +} + +/* Zero the realtime bitmap. */ +static void +rtbitmap_init( + struct xfs_mount *mp) +{ + struct xfs_bmbt_irec map[XFS_BMAP_MAX_NMAP]; + struct xfs_trans *tp; + struct xfs_bmbt_irec *ep; + xfs_fileoff_t bno; + uint blocks; + int i; + int nmap; + int error; - /* Zero the realtime bitmap. */ blocks = mp->m_sb.sb_rbmblocks + XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) - 1; error = -libxfs_trans_alloc_rollable(mp, blocks, &tp); if (error) res_failed(error); - libxfs_trans_ijoin(tp, rbmip, 0); + libxfs_trans_ijoin(tp, mp->m_rbmip, 0); bno = 0; while (bno < mp->m_sb.sb_rbmblocks) { nmap = XFS_BMAP_MAX_NMAP; - error = -libxfs_bmapi_write(tp, rbmip, bno, + error = -libxfs_bmapi_write(tp, mp->m_rbmip, bno, (xfs_extlen_t)(mp->m_sb.sb_rbmblocks - bno), 0, mp->m_sb.sb_rbmblocks, map, &nmap); if (error) @@ -833,19 +844,34 @@ rtinit( if (error) fail(_("Block allocation of the realtime bitmap inode failed"), error); +} + +/* Zero the realtime summary file. */ +static void +rtsummary_init( + struct xfs_mount *mp) +{ + struct xfs_bmbt_irec map[XFS_BMAP_MAX_NMAP]; + struct xfs_trans *tp; + struct xfs_bmbt_irec *ep; + xfs_fileoff_t bno; + xfs_extlen_t nsumblocks; + uint blocks; + int i; + int nmap; + int error; - /* Zero the summary file. */ nsumblocks = mp->m_rsumsize >> mp->m_sb.sb_blocklog; blocks = nsumblocks + XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) - 1; error = -libxfs_trans_alloc_rollable(mp, blocks, &tp); if (error) res_failed(error); - libxfs_trans_ijoin(tp, rsumip, 0); + libxfs_trans_ijoin(tp, mp->m_rsumip, 0); bno = 0; while (bno < nsumblocks) { nmap = XFS_BMAP_MAX_NMAP; - error = -libxfs_bmapi_write(tp, rsumip, bno, + error = -libxfs_bmapi_write(tp, mp->m_rsumip, bno, (xfs_extlen_t)(nsumblocks - bno), 0, nsumblocks, map, &nmap); if (error) @@ -863,8 +889,6 @@ rtinit( if (error) fail(_("Block allocation of the realtime summary inode failed"), error); - - rtfreesp_init(mp); } /* @@ -903,6 +927,21 @@ rtfreesp_init( } } +/* + * Allocate the realtime bitmap and summary inodes, and fill in data if any. + */ +static void +rtinit( + struct xfs_mount *mp) +{ + rtbitmap_create(mp); + rtsummary_create(mp); + + rtbitmap_init(mp); + rtsummary_init(mp); + rtfreesp_init(mp); +} + static long filesize( int fd) From patchwork Sun Dec 31 23:31:24 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13508124 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 CA115C2C0 for ; Sun, 31 Dec 2023 23:31:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="SZJ7Jc08" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 40183C433C8; Sun, 31 Dec 2023 23:31:25 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704065485; bh=63A98CUfW5pyOJB5fJTGLvQUOAwEa9LASLOFFX55fbw=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=SZJ7Jc08tCcfkRJATYejbavLy98yAS9xEcqdTCHztun9cNYgqruup3bK58FlKqSMU Rz5bGwg5bt+9Jg6yjZIV2jxhlb9989zb8qV5d8fMxKlJ1203n5LkZ2eS59MTTDFvBY z/CB7+hFrTzgSdpXVBJ8kyPgkIHSKt8fGMMIc1E7LGqnkJN4cUA9KcZOvjhVKDDqJo YlJ8KJT4MCqGBpCx+RwF/dWhUwd4H1U7sSNE0ZM/ahwm0XaK8DtAXuReNF9pWIny1d ezYNo9iXNU1VkY+cucFb7yBe/MT+dcWJQYrVzGRY1LOYo8142+1pRfcT83lpLlFZWZ wd4bDZDwVA3Mg== Date: Sun, 31 Dec 2023 15:31:24 -0800 Subject: [PATCH 07/58] xfs: iget for metadata inodes From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <170405010040.1809361.4434787677428532445.stgit@frogsfrogsfrogs> In-Reply-To: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> References: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Create a xfs_iget_meta function for metadata inodes to ensure that we always check that the inobt thinks a metadata inode is in use. Signed-off-by: Darrick J. Wong --- libxfs/init.c | 4 ++-- libxfs/inode.c | 36 ++++++++++++++++++++++++++++++++++++ libxfs/libxfs_api_defs.h | 2 ++ libxfs/xfs_imeta.h | 5 +++++ 4 files changed, 45 insertions(+), 2 deletions(-) diff --git a/libxfs/init.c b/libxfs/init.c index c199aeea45e..c0f148e75a2 100644 --- a/libxfs/init.c +++ b/libxfs/init.c @@ -883,9 +883,9 @@ void libxfs_rtmount_destroy(xfs_mount_t *mp) { if (mp->m_rsumip) - libxfs_irele(mp->m_rsumip); + libxfs_imeta_irele(mp->m_rsumip); if (mp->m_rbmip) - libxfs_irele(mp->m_rbmip); + libxfs_imeta_irele(mp->m_rbmip); mp->m_rsumip = mp->m_rbmip = NULL; } diff --git a/libxfs/inode.c b/libxfs/inode.c index 47c9b9d6bd7..560b127ee9d 100644 --- a/libxfs/inode.c +++ b/libxfs/inode.c @@ -225,6 +225,35 @@ libxfs_iget( return error; } +/* + * Get a metadata inode. The ftype must match exactly. Caller must supply + * a transaction (even if empty) to avoid livelocking if the inobt has a cycle. + */ +int +libxfs_imeta_iget( + struct xfs_trans *tp, + xfs_ino_t ino, + unsigned char ftype, + struct xfs_inode **ipp) +{ + struct xfs_mount *mp = tp->t_mountp; + struct xfs_inode *ip; + int error; + + error = libxfs_iget(mp, tp, ino, XFS_IGET_UNTRUSTED, &ip); + if (error) + return error; + + if (ftype == XFS_DIR3_FT_UNKNOWN || + xfs_mode_to_ftype(VFS_I(ip)->i_mode) != ftype) { + libxfs_irele(ip); + return -EFSCORRUPTED; + } + + *ipp = ip; + return 0; +} + static void libxfs_idestroy( struct xfs_inode *ip) @@ -258,6 +287,13 @@ libxfs_irele( } } +void +libxfs_imeta_irele( + struct xfs_inode *ip) +{ + libxfs_irele(ip); +} + static inline void inode_fsgid_set(struct inode *inode, struct mnt_idmap *idmap) { diff --git a/libxfs/libxfs_api_defs.h b/libxfs/libxfs_api_defs.h index 167617771d8..873995f265c 100644 --- a/libxfs/libxfs_api_defs.h +++ b/libxfs/libxfs_api_defs.h @@ -177,6 +177,8 @@ #define xfs_imeta_commit_update libxfs_imeta_commit_update #define xfs_imeta_create libxfs_imeta_create #define xfs_imeta_create_space_res libxfs_imeta_create_space_res +#define xfs_imeta_iget libxfs_imeta_iget +#define xfs_imeta_irele libxfs_imeta_irele #define xfs_imeta_link libxfs_imeta_link #define xfs_imeta_link_space_res libxfs_imeta_link_space_res #define xfs_imeta_lookup libxfs_imeta_lookup diff --git a/libxfs/xfs_imeta.h b/libxfs/xfs_imeta.h index 7b3da865c09..0a4361bda1c 100644 --- a/libxfs/xfs_imeta.h +++ b/libxfs/xfs_imeta.h @@ -47,4 +47,9 @@ unsigned int xfs_imeta_create_space_res(struct xfs_mount *mp); unsigned int xfs_imeta_link_space_res(struct xfs_mount *mp); unsigned int xfs_imeta_unlink_space_res(struct xfs_mount *mp); +/* Must be implemented by the libxfs client */ +int xfs_imeta_iget(struct xfs_trans *tp, xfs_ino_t ino, unsigned char ftype, + struct xfs_inode **ipp); +void xfs_imeta_irele(struct xfs_inode *ip); + #endif /* __XFS_IMETA_H__ */ From patchwork Sun Dec 31 23:31:40 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13508125 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 64181C2C0 for ; Sun, 31 Dec 2023 23:31:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Ek0DwadF" Received: by smtp.kernel.org (Postfix) with ESMTPSA id E814CC433C7; Sun, 31 Dec 2023 23:31:40 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704065501; bh=8KQtq39YR2qxhC32eAg8QO8jYpaQkf7I69GzF/FlmL4=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=Ek0DwadFfa0fhYYxJh3ueWRzsqxfiaNGUjCb2/x4ixlRbBYBIE4zPYn/r23fHWDYd FW0zVg13XlbV6twCyjIZajnIPmr7PPSi48u/RFQm5UqU9DdzcEzNFBv0WkUGJ6t5pV qxdj6GYd1IKjWQJSkCuU7fjKICJoFuA/u8HX2COvlxkpAaZZ6cNtkde8b8+8caa9fU bgNg2x3MqI47UNMgtB2CW+biJM/OtF4Gl78eASS2xp/QzW3Uap3VyZDzo9z0VxV/6b 26amQVwdH4acxztcdSv4FwcEm/QcxmCiwaWo44BCxMUit2VPI+agM4D7Z5XUVJGqvF K9JK1tNuJEsXw== Date: Sun, 31 Dec 2023 15:31:40 -0800 Subject: [PATCH 08/58] xfs: define the on-disk format for the metadir feature From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <170405010053.1809361.17434100075820339651.stgit@frogsfrogsfrogs> In-Reply-To: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> References: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Define the on-disk layout and feature flags for the metadata inode directory feature. Signed-off-by: Darrick J. Wong --- include/xfs_inode.h | 5 ++++ include/xfs_mount.h | 2 ++ libxfs/xfs_format.h | 60 +++++++++++++++++++++++++++++++++++++++++------ libxfs/xfs_inode_util.c | 2 ++ libxfs/xfs_sb.c | 2 ++ 5 files changed, 63 insertions(+), 8 deletions(-) diff --git a/include/xfs_inode.h b/include/xfs_inode.h index 5d7bc69e3ff..1fdae6c1d3a 100644 --- a/include/xfs_inode.h +++ b/include/xfs_inode.h @@ -386,6 +386,11 @@ static inline bool xfs_is_always_cow_inode(struct xfs_inode *ip) return false; } +static inline bool xfs_is_metadir_inode(struct xfs_inode *ip) +{ + return ip->i_diflags2 & XFS_DIFLAG2_METADIR; +} + extern void libxfs_trans_inode_alloc_buf (struct xfs_trans *, struct xfs_buf *); diff --git a/include/xfs_mount.h b/include/xfs_mount.h index da621f3b992..7dfa94dfd9f 100644 --- a/include/xfs_mount.h +++ b/include/xfs_mount.h @@ -175,6 +175,7 @@ typedef struct xfs_mount { #define XFS_FEAT_BIGTIME (1ULL << 24) /* large timestamps */ #define XFS_FEAT_NEEDSREPAIR (1ULL << 25) /* needs xfs_repair */ #define XFS_FEAT_NREXT64 (1ULL << 26) /* large extent counters */ +#define XFS_FEAT_METADIR (1ULL << 27) /* metadata directory tree */ #define __XFS_HAS_FEAT(name, NAME) \ static inline bool xfs_has_ ## name (struct xfs_mount *mp) \ @@ -219,6 +220,7 @@ __XFS_HAS_FEAT(inobtcounts, INOBTCNT) __XFS_HAS_FEAT(bigtime, BIGTIME) __XFS_HAS_FEAT(needsrepair, NEEDSREPAIR) __XFS_HAS_FEAT(large_extent_counts, NREXT64) +__XFS_HAS_FEAT(metadir, METADIR) /* Kernel mount features that we don't support */ #define __XFS_UNSUPP_FEAT(name) \ diff --git a/libxfs/xfs_format.h b/libxfs/xfs_format.h index c60af436963..7596b928698 100644 --- a/libxfs/xfs_format.h +++ b/libxfs/xfs_format.h @@ -174,6 +174,16 @@ typedef struct xfs_sb { xfs_lsn_t sb_lsn; /* last write sequence */ uuid_t sb_meta_uuid; /* metadata file system unique id */ + /* Fields beyond here do not match xfs_dsb. Be very careful! */ + + /* + * Metadata Directory Inode. On disk this lives in the sb_rbmino slot, + * but we continue to use the in-core superblock to cache the classic + * inodes (rt bitmap; rt summary; user, group, and project quotas) so + * we cache the metadir inode value here too. + */ + xfs_ino_t sb_metadirino; + /* must be padded to 64 bit alignment */ } xfs_sb_t; @@ -190,7 +200,14 @@ struct xfs_dsb { uuid_t sb_uuid; /* user-visible file system unique id */ __be64 sb_logstart; /* starting block of log if internal */ __be64 sb_rootino; /* root inode number */ - __be64 sb_rbmino; /* bitmap inode for realtime extents */ + /* + * bitmap inode for realtime extents. + * + * The metadata directory feature uses the sb_rbmino field to point to + * the root of the metadata directory tree. All other sb inode + * pointers are no longer used. + */ + __be64 sb_rbmino; __be64 sb_rsumino; /* summary inode for rt bitmap */ __be32 sb_rextsize; /* realtime extent size, blocks */ __be32 sb_agblocks; /* size of an allocation group */ @@ -373,6 +390,7 @@ xfs_sb_has_ro_compat_feature( #define XFS_SB_FEAT_INCOMPAT_NEEDSREPAIR (1 << 4) /* needs xfs_repair */ #define XFS_SB_FEAT_INCOMPAT_NREXT64 (1 << 5) /* large extent counters */ #define XFS_SB_FEAT_INCOMPAT_PARENT (1 << 6) /* parent pointers */ +#define XFS_SB_FEAT_INCOMPAT_METADIR (1U << 31) /* metadata dir tree */ #define XFS_SB_FEAT_INCOMPAT_ALL \ (XFS_SB_FEAT_INCOMPAT_FTYPE| \ XFS_SB_FEAT_INCOMPAT_SPINODES| \ @@ -1109,17 +1127,43 @@ static inline void xfs_dinode_put_rdev(struct xfs_dinode *dip, xfs_dev_t rdev) #define XFS_DIFLAG2_REFLINK_BIT 1 /* file's blocks may be shared */ #define XFS_DIFLAG2_COWEXTSIZE_BIT 2 /* copy on write extent size hint */ #define XFS_DIFLAG2_BIGTIME_BIT 3 /* big timestamps */ -#define XFS_DIFLAG2_NREXT64_BIT 4 /* large extent counters */ +#define XFS_DIFLAG2_NREXT64_BIT 4 /* large extent counters */ +#define XFS_DIFLAG2_METADIR_BIT 63 /* filesystem metadata */ -#define XFS_DIFLAG2_DAX (1 << XFS_DIFLAG2_DAX_BIT) -#define XFS_DIFLAG2_REFLINK (1 << XFS_DIFLAG2_REFLINK_BIT) -#define XFS_DIFLAG2_COWEXTSIZE (1 << XFS_DIFLAG2_COWEXTSIZE_BIT) -#define XFS_DIFLAG2_BIGTIME (1 << XFS_DIFLAG2_BIGTIME_BIT) -#define XFS_DIFLAG2_NREXT64 (1 << XFS_DIFLAG2_NREXT64_BIT) +#define XFS_DIFLAG2_DAX (1ULL << XFS_DIFLAG2_DAX_BIT) +#define XFS_DIFLAG2_REFLINK (1ULL << XFS_DIFLAG2_REFLINK_BIT) +#define XFS_DIFLAG2_COWEXTSIZE (1ULL << XFS_DIFLAG2_COWEXTSIZE_BIT) +#define XFS_DIFLAG2_BIGTIME (1ULL << XFS_DIFLAG2_BIGTIME_BIT) +#define XFS_DIFLAG2_NREXT64 (1ULL << XFS_DIFLAG2_NREXT64_BIT) + +/* + * The inode contains filesystem metadata and can be found through the metadata + * directory tree. Metadata inodes must satisfy the following constraints: + * + * - V5 filesystem (and ftype) are enabled; + * - The only valid modes are regular files and directories; + * - The access bits must be zero; + * - DMAPI event and state masks are zero; + * - The user, group, and project IDs must be zero; + * - The immutable, sync, noatime, nodump, nodefrag flags must be set. + * - The dax flag must not be set. + * - Directories must have nosymlinks set. + * + * These requirements are chosen defensively to minimize the ability of + * userspace to read or modify the contents, should a metadata file ever + * escape to userspace. + * + * There are further constraints on the directory tree itself: + * + * - Metadata inodes must never be resolvable through the root directory; + * - They must never be accessed by userspace; + * - Metadata directory entries must have correct ftype. + */ +#define XFS_DIFLAG2_METADIR (1ULL << XFS_DIFLAG2_METADIR_BIT) #define XFS_DIFLAG2_ANY \ (XFS_DIFLAG2_DAX | XFS_DIFLAG2_REFLINK | XFS_DIFLAG2_COWEXTSIZE | \ - XFS_DIFLAG2_BIGTIME | XFS_DIFLAG2_NREXT64) + XFS_DIFLAG2_BIGTIME | XFS_DIFLAG2_NREXT64 | XFS_DIFLAG2_METADIR) static inline bool xfs_dinode_has_bigtime(const struct xfs_dinode *dip) { diff --git a/libxfs/xfs_inode_util.c b/libxfs/xfs_inode_util.c index 19d26950db9..b63aacb6971 100644 --- a/libxfs/xfs_inode_util.c +++ b/libxfs/xfs_inode_util.c @@ -222,6 +222,8 @@ xfs_inode_inherit_flags2( } if (pip->i_diflags2 & XFS_DIFLAG2_DAX) ip->i_diflags2 |= XFS_DIFLAG2_DAX; + if (pip->i_diflags2 & XFS_DIFLAG2_METADIR) + ip->i_diflags2 |= XFS_DIFLAG2_METADIR; /* Don't let invalid cowextsize hints propagate. */ failaddr = xfs_inode_validate_cowextsize(ip->i_mount, ip->i_cowextsize, diff --git a/libxfs/xfs_sb.c b/libxfs/xfs_sb.c index d150170d87b..49d62281995 100644 --- a/libxfs/xfs_sb.c +++ b/libxfs/xfs_sb.c @@ -176,6 +176,8 @@ xfs_sb_version_to_features( features |= XFS_FEAT_NREXT64; if (sbp->sb_features_incompat & XFS_SB_FEAT_INCOMPAT_PARENT) features |= XFS_FEAT_PARENT; + if (sbp->sb_features_incompat & XFS_SB_FEAT_INCOMPAT_METADIR) + features |= XFS_FEAT_METADIR; return features; } From patchwork Sun Dec 31 23:31:56 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13508126 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 EBB90C2C5 for ; Sun, 31 Dec 2023 23:31:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="kPsPaXCn" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 837D0C433C8; Sun, 31 Dec 2023 23:31:56 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704065516; bh=7uRS5G9klNxj6jdi7LLbA3iTIf+bYMr+els+NiORrHU=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=kPsPaXCnjuMIRkEqoFXULfz911TT0lmqAqvE6tIrRymBSEnvVbKcRodxH11rHXOrr I1a2f4gNPN+vEQ7opfaL8wOhpmwgT6JtzSo3yYoV6tywc7YpDjRae8K3bRHPFEmLCL 95HaZz91DepF63jlMPYW+PiXnF7AE+Agpi7JJPYNyArnxDt2NvEAi6Mrlp6ctrWcxc aIlKnA0kg9Mg/XAWODPDtemcIagMcGzgNa0t2txVtfzTklXqFgpFc7AtaTIG7DFuUF ynSrcE6FX2/kdRGLYMGCHH8KRullxRGTpOBXG9eYvoUH8MtIOan2g6epD4REYiRaXn oPI370c8jXZpg== Date: Sun, 31 Dec 2023 15:31:56 -0800 Subject: [PATCH 09/58] xfs: update imeta transaction reservations for metadir From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <170405010067.1809361.750161469464973114.stgit@frogsfrogsfrogs> In-Reply-To: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> References: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Update the new metadata inode transaction reservations to handle metadata directories if that feature is enabled. Signed-off-by: Darrick J. Wong --- libxfs/xfs_trans_resv.c | 101 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 98 insertions(+), 3 deletions(-) diff --git a/libxfs/xfs_trans_resv.c b/libxfs/xfs_trans_resv.c index 5a1ad959870..a46360e2bdb 100644 --- a/libxfs/xfs_trans_resv.c +++ b/libxfs/xfs_trans_resv.c @@ -1106,6 +1106,81 @@ xfs_calc_sb_reservation( return xfs_calc_buf_res(1, mp->m_sb.sb_sectsize); } +/* + * Metadata inode creation needs enough space to create or mkdir a directory, + * plus logging the superblock. + */ +static unsigned int +xfs_calc_imeta_create_resv( + struct xfs_mount *mp, + struct xfs_trans_resv *resp) +{ + unsigned int ret; + + ret = xfs_calc_buf_res(1, mp->m_sb.sb_sectsize); + ret += resp->tr_create.tr_logres; + return ret; +} + +/* Metadata inode creation needs enough rounds to create or mkdir a directory */ +static int +xfs_calc_imeta_create_count( + struct xfs_mount *mp, + struct xfs_trans_resv *resp) +{ + return resp->tr_create.tr_logcount; +} + +/* + * Metadata inode link needs enough space to add a file plus logging the + * superblock. + */ +static unsigned int +xfs_calc_imeta_link_resv( + struct xfs_mount *mp, + struct xfs_trans_resv *resp) +{ + unsigned int ret; + + ret = xfs_calc_buf_res(1, mp->m_sb.sb_sectsize); + ret += resp->tr_link.tr_logres; + return ret; +} + +/* Metadata inode linking needs enough rounds to remove a file. */ +static int +xfs_calc_imeta_link_count( + struct xfs_mount *mp, + struct xfs_trans_resv *resp) +{ + return resp->tr_link.tr_logcount; +} + +/* + * Metadata inode unlink needs enough space to remove a file plus logging the + * superblock. + */ +static unsigned int +xfs_calc_imeta_unlink_resv( + struct xfs_mount *mp, + struct xfs_trans_resv *resp) +{ + unsigned int ret; + + ret = xfs_calc_buf_res(1, mp->m_sb.sb_sectsize); + ret += resp->tr_remove.tr_logres; + return ret; +} + +/* Metadata inode unlinking needs enough rounds to remove a file. */ +static int +xfs_calc_imeta_unlink_count( + struct xfs_mount *mp, + struct xfs_trans_resv *resp) +{ + return resp->tr_remove.tr_logcount; +} + /* * Namespace reservations. * @@ -1248,7 +1323,27 @@ xfs_trans_resv_calc( resp->tr_qm_dqalloc.tr_logcount += logcount_adj; /* metadata inode creation and unlink */ - resp->tr_imeta_create = resp->tr_create; - resp->tr_imeta_link = resp->tr_link; - resp->tr_imeta_unlink = resp->tr_remove; + if (xfs_has_metadir(mp)) { + resp->tr_imeta_create.tr_logres = + xfs_calc_imeta_create_resv(mp, resp); + resp->tr_imeta_create.tr_logcount = + xfs_calc_imeta_create_count(mp, resp); + resp->tr_imeta_create.tr_logflags |= XFS_TRANS_PERM_LOG_RES; + + resp->tr_imeta_link.tr_logres = + xfs_calc_imeta_link_resv(mp, resp); + resp->tr_imeta_link.tr_logcount = + xfs_calc_imeta_link_count(mp, resp); + resp->tr_imeta_link.tr_logflags |= XFS_TRANS_PERM_LOG_RES; + + resp->tr_imeta_unlink.tr_logres = + xfs_calc_imeta_unlink_resv(mp, resp); + resp->tr_imeta_unlink.tr_logcount = + xfs_calc_imeta_unlink_count(mp, resp); + resp->tr_imeta_unlink.tr_logflags |= XFS_TRANS_PERM_LOG_RES; + } else { + resp->tr_imeta_create = resp->tr_create; + resp->tr_imeta_link = resp->tr_link; + resp->tr_imeta_unlink = resp->tr_remove; + } } From patchwork Sun Dec 31 23:32:11 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13508127 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 7F046C2C0 for ; Sun, 31 Dec 2023 23:32:12 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="G+x8CHX5" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 18F72C433C7; Sun, 31 Dec 2023 23:32:12 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704065532; bh=viBc982nQ80zJhQyCuFg35i8lVowkqJDzPvsvt5B928=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=G+x8CHX5mo9ia/xar4TB0ZsX/D+9+f4C6Uvz9Cjg0yn8srM+MgVbGyC4UQZAZSevF ENX6VwBAdPeB+pj3KXolqBDfDqkiOEqtduKV1UoSIYxKiChrxIJ1ZpYCOMzG1cISYm dH83MRlvvDFPob17e9J4Whg4ESAIhgVGAJoA5TurZuDkbuOrq1JldjGfo371HjZtFW uqM6hAwe7YmTkmyIiibJ1r8wuz+FujTBNfS2BSbOEUQTrzHa8TYKazujQ7oe/8SmSQ X1w3oWhtrwz0Eg9glZHSL5HBPLODosm/GSwjDNVleFJP1it3oGIBi/agh1yXICpIkj h1r8yVf57W7nw== Date: Sun, 31 Dec 2023 15:32:11 -0800 Subject: [PATCH 10/58] xfs: load metadata directory root at mount time From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <170405010080.1809361.5972158645244058110.stgit@frogsfrogsfrogs> In-Reply-To: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> References: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Load the metadata directory root inode into memory at mount time and release it at unmount time. We also make sure that the obsolete inode pointers in the superblock are not logged or read from the superblock. Signed-off-by: Darrick J. Wong --- include/xfs_mount.h | 1 + libxfs/init.c | 13 +++++++++++++ libxfs/xfs_sb.c | 31 +++++++++++++++++++++++++++++++ libxfs/xfs_types.c | 2 +- 4 files changed, 46 insertions(+), 1 deletion(-) diff --git a/include/xfs_mount.h b/include/xfs_mount.h index 7dfa94dfd9f..8952869d89a 100644 --- a/include/xfs_mount.h +++ b/include/xfs_mount.h @@ -66,6 +66,7 @@ typedef struct xfs_mount { uint8_t *m_rsum_cache; struct xfs_inode *m_rbmip; /* pointer to bitmap inode */ struct xfs_inode *m_rsumip; /* pointer to summary inode */ + struct xfs_inode *m_metadirip; /* ptr to metadata directory */ struct xfs_buftarg *m_ddev_targp; struct xfs_buftarg *m_logdev_targp; struct xfs_buftarg *m_rtdev_targp; diff --git a/libxfs/init.c b/libxfs/init.c index c0f148e75a2..67f9e1fe99b 100644 --- a/libxfs/init.c +++ b/libxfs/init.c @@ -685,6 +685,17 @@ libxfs_mountfs_imeta( if (error) return; + if (xfs_has_metadir(mp)) { + error = -libxfs_imeta_iget(tp, mp->m_sb.sb_metadirino, + XFS_DIR3_FT_DIR, &mp->m_metadirip); + if (error) { + fprintf(stderr, + _("%s: Failed to load metadir root directory, error %d\n"), + progname, error); + goto err_cancel; + } + } + error = -xfs_imeta_mount(tp); if (error) { fprintf(stderr, @@ -991,6 +1002,8 @@ libxfs_umount( int error; libxfs_rtmount_destroy(mp); + if (mp->m_metadirip) + libxfs_imeta_irele(mp->m_metadirip); /* * Purge the buffer cache to write all dirty buffers to disk and free diff --git a/libxfs/xfs_sb.c b/libxfs/xfs_sb.c index 49d62281995..b74a170605d 100644 --- a/libxfs/xfs_sb.c +++ b/libxfs/xfs_sb.c @@ -680,6 +680,25 @@ __xfs_sb_from_disk( /* Convert on-disk flags to in-memory flags? */ if (convert_xquota) xfs_sb_quota_from_disk(to); + + if (to->sb_features_incompat & XFS_SB_FEAT_INCOMPAT_METADIR) { + /* + * Set metadirino here and null out the in-core fields for + * the other inodes because metadir initialization will load + * them later. + */ + to->sb_metadirino = be64_to_cpu(from->sb_rbmino); + to->sb_rbmino = NULLFSINO; + to->sb_rsumino = NULLFSINO; + + /* + * We don't have to worry about quota inode conversion here + * because metadir requires a v5 filesystem. + */ + to->sb_uquotino = NULLFSINO; + to->sb_gquotino = NULLFSINO; + to->sb_pquotino = NULLFSINO; + } } void @@ -827,6 +846,18 @@ xfs_sb_to_disk( to->sb_lsn = cpu_to_be64(from->sb_lsn); if (from->sb_features_incompat & XFS_SB_FEAT_INCOMPAT_META_UUID) uuid_copy(&to->sb_meta_uuid, &from->sb_meta_uuid); + + if (from->sb_features_incompat & XFS_SB_FEAT_INCOMPAT_METADIR) { + /* + * Save metadirino here and null out the on-disk fields for + * the other inodes, at least until we reuse the fields. + */ + to->sb_rbmino = cpu_to_be64(from->sb_metadirino); + to->sb_rsumino = cpu_to_be64(NULLFSINO); + to->sb_uquotino = cpu_to_be64(NULLFSINO); + to->sb_gquotino = cpu_to_be64(NULLFSINO); + to->sb_pquotino = cpu_to_be64(NULLFSINO); + } } /* diff --git a/libxfs/xfs_types.c b/libxfs/xfs_types.c index 88720b297d7..f5eab8839e3 100644 --- a/libxfs/xfs_types.c +++ b/libxfs/xfs_types.c @@ -128,7 +128,7 @@ xfs_verify_dir_ino( struct xfs_mount *mp, xfs_ino_t ino) { - if (xfs_internal_inum(mp, ino)) + if (!xfs_has_metadir(mp) && xfs_internal_inum(mp, ino)) return false; return xfs_verify_ino(mp, ino); } From patchwork Sun Dec 31 23:32:27 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13508128 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 F1700C2C0 for ; Sun, 31 Dec 2023 23:32:27 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="V1s3oNnN" Received: by smtp.kernel.org (Postfix) with ESMTPSA id C0F0EC433C8; Sun, 31 Dec 2023 23:32:27 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704065547; bh=LTnO4CjatAseTVxeJ5Jbnvm3RDhaGj1g+Hoq1X1gIkk=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=V1s3oNnNgQerFWXcz07uhtCPIB4lmH7Z52h2ubcWEb7ohP+Tq2Y42zAw9oy/PTn97 K7y+1mrW10lo6XGG7QRyw/JCN6tHjmapv6PUvJw/tmFaIxDep9nmMgR2aIjpCsVWY9 FLLCt4qrlxL8f/iG0uwz2jRmgaW5/M9HmtXhQs+s+UNJ9ofyIJII2ekOJNY6n552N4 RG/VFgJ8jFSYmite4IDoEMjI2hgIH+Vli7T5PUAS2dUc9ONAzYDoU47KZ4jXSgUnzy L8v4a+zdZDXtggv14bo5ikZy5rFD3g4FN0iGVOWv9JYh1hRxmw9s5jKOTwJ6LNGt3v WExk2NNGElRAA== Date: Sun, 31 Dec 2023 15:32:27 -0800 Subject: [PATCH 11/58] xfs: convert metadata inode lookup keys to use paths From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <170405010094.1809361.127923577020344029.stgit@frogsfrogsfrogs> In-Reply-To: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> References: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Convert the magic metadata inode lookup keys to use actual strings for paths. Signed-off-by: Darrick J. Wong --- libxfs/xfs_imeta.c | 48 ++++++++++++++++++++++++++---------------------- libxfs/xfs_imeta.h | 27 +++++++++++++++++++++++++-- 2 files changed, 51 insertions(+), 24 deletions(-) diff --git a/libxfs/xfs_imeta.c b/libxfs/xfs_imeta.c index 086c250a3c2..e59b0f414ed 100644 --- a/libxfs/xfs_imeta.c +++ b/libxfs/xfs_imeta.c @@ -48,26 +48,17 @@ */ /* Static metadata inode paths */ - -const struct xfs_imeta_path XFS_IMETA_RTBITMAP = { - .bogus = 0, -}; - -const struct xfs_imeta_path XFS_IMETA_RTSUMMARY = { - .bogus = 1, -}; - -const struct xfs_imeta_path XFS_IMETA_USRQUOTA = { - .bogus = 2, -}; - -const struct xfs_imeta_path XFS_IMETA_GRPQUOTA = { - .bogus = 3, -}; - -const struct xfs_imeta_path XFS_IMETA_PRJQUOTA = { - .bogus = 4, -}; +static const unsigned char *rtbitmap_path[] = {"realtime", "bitmap"}; +static const unsigned char *rtsummary_path[] = {"realtime", "summary"}; +static const unsigned char *usrquota_path[] = {"quota", "user"}; +static const unsigned char *grpquota_path[] = {"quota", "group"}; +static const unsigned char *prjquota_path[] = {"quota", "project"}; + +XFS_IMETA_DEFINE_PATH(XFS_IMETA_RTBITMAP, rtbitmap_path); +XFS_IMETA_DEFINE_PATH(XFS_IMETA_RTSUMMARY, rtsummary_path); +XFS_IMETA_DEFINE_PATH(XFS_IMETA_USRQUOTA, usrquota_path); +XFS_IMETA_DEFINE_PATH(XFS_IMETA_GRPQUOTA, grpquota_path); +XFS_IMETA_DEFINE_PATH(XFS_IMETA_PRJQUOTA, prjquota_path); /* Are these two paths equal? */ STATIC bool @@ -75,7 +66,20 @@ xfs_imeta_path_compare( const struct xfs_imeta_path *a, const struct xfs_imeta_path *b) { - return a == b; + unsigned int i; + + if (a == b) + return true; + + if (a->im_depth != b->im_depth) + return false; + + for (i = 0; i < a->im_depth; i++) + if (a->im_path[i] != b->im_path[i] && + strcmp(a->im_path[i], b->im_path[i])) + return false; + + return true; } /* Is this path ok? */ @@ -83,7 +87,7 @@ static inline bool xfs_imeta_path_check( const struct xfs_imeta_path *path) { - return true; + return path->im_depth <= XFS_IMETA_MAX_DEPTH; } /* Functions for storing and retrieving superblock inode values. */ diff --git a/libxfs/xfs_imeta.h b/libxfs/xfs_imeta.h index 0a4361bda1c..60e0f6a6c13 100644 --- a/libxfs/xfs_imeta.h +++ b/libxfs/xfs_imeta.h @@ -6,10 +6,23 @@ #ifndef __XFS_IMETA_H__ #define __XFS_IMETA_H__ +/* How deep can we nest metadata dirs? */ +#define XFS_IMETA_MAX_DEPTH 64 + +/* Form an imeta path from a simple array of strings. */ +#define XFS_IMETA_DEFINE_PATH(name, path) \ +const struct xfs_imeta_path name = { \ + .im_path = (path), \ + .im_depth = ARRAY_SIZE(path), \ +} + /* Key for looking up metadata inodes. */ struct xfs_imeta_path { - /* Temporary: integer to keep the static imeta definitions unique */ - int bogus; + /* Array of string pointers. */ + const unsigned char **im_path; + + /* Number of strings in path. */ + uint8_t im_depth; }; /* Cleanup widget for metadata inode creation and deletion. */ @@ -25,6 +38,16 @@ struct xfs_imeta_update { unsigned int ip_locked:1; }; +/* Grab the last path component, mostly for tracing. */ +static inline const unsigned char * +xfs_imeta_lastpath( + const struct xfs_imeta_update *upd) +{ + if (upd->path && upd->path->im_path && upd->path->im_depth > 0) + return upd->path->im_path[upd->path->im_depth - 1]; + return "?"; +} + /* Lookup keys for static metadata inodes. */ extern const struct xfs_imeta_path XFS_IMETA_RTBITMAP; extern const struct xfs_imeta_path XFS_IMETA_RTSUMMARY; From patchwork Sun Dec 31 23:32:42 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13508133 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 9EA40C2C5 for ; Sun, 31 Dec 2023 23:32:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="YEXlnBke" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 722AEC433C8; Sun, 31 Dec 2023 23:32:43 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704065563; bh=SaXrvfuQZoCuE/QVc5c0xD6nuB2f3789/IfUozcAH+M=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=YEXlnBke5iQ4djKpFwQClv446h2EWCl3OvMpgNynyGLpU24muaBwQP6SDWsT3nO2H l8Nsp27Xzr+v8XGJVWmIoiI6Qt6thn4BNHk7D0LSP6gKuw9els6m7rYvqhFbpn9dkQ J0kCws2fMb7EuOWuG/a6GXNOxh29GOpnDOyhaybM27phO/d30fawd3Hl7whPS+AO4L VzqL1IBMQux6ynZjQ/VPWoK5wpXVu8hBF1aFVh5tLL4zy7/DMtYRRnR3fJ7WdhrwER BHCKdrHAyJV4lw6iyKMJaOPQ1Wn7JwwognmhVUcyTgcX0qm7u23zJdLfQaqmii1VeM sKyXvYqRfST3Q== Date: Sun, 31 Dec 2023 15:32:42 -0800 Subject: [PATCH 12/58] xfs: enforce metadata inode flag From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <170405010107.1809361.1975192314738430464.stgit@frogsfrogsfrogs> In-Reply-To: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> References: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Add checks for the metadata inode flag so that we don't ever leak metadata inodes out to userspace, and we don't ever try to read a regular inode as metadata. Signed-off-by: Darrick J. Wong --- libxfs/inode.c | 5 +++ libxfs/xfs_inode_buf.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++++ libxfs/xfs_inode_buf.h | 3 ++ 3 files changed, 80 insertions(+), 1 deletion(-) diff --git a/libxfs/inode.c b/libxfs/inode.c index 560b127ee9d..5cb2fd7891a 100644 --- a/libxfs/inode.c +++ b/libxfs/inode.c @@ -244,7 +244,8 @@ libxfs_imeta_iget( if (error) return error; - if (ftype == XFS_DIR3_FT_UNKNOWN || + if ((xfs_has_metadir(mp) && !xfs_is_metadir_inode(ip)) || + ftype == XFS_DIR3_FT_UNKNOWN || xfs_mode_to_ftype(VFS_I(ip)->i_mode) != ftype) { libxfs_irele(ip); return -EFSCORRUPTED; @@ -291,6 +292,8 @@ void libxfs_imeta_irele( struct xfs_inode *ip) { + ASSERT(!xfs_has_metadir(ip->i_mount) || xfs_is_metadir_inode(ip)); + libxfs_irele(ip); } diff --git a/libxfs/xfs_inode_buf.c b/libxfs/xfs_inode_buf.c index aee581d53c8..8d100595756 100644 --- a/libxfs/xfs_inode_buf.c +++ b/libxfs/xfs_inode_buf.c @@ -457,6 +457,73 @@ xfs_dinode_verify_nrext64( return NULL; } +/* + * Validate all the picky requirements we have for a file that claims to be + * filesystem metadata. + */ +xfs_failaddr_t +xfs_dinode_verify_metadir( + struct xfs_mount *mp, + struct xfs_dinode *dip, + uint16_t mode, + uint16_t flags, + uint64_t flags2) +{ + if (!xfs_has_metadir(mp)) + return __this_address; + + /* V5 filesystem only */ + if (dip->di_version < 3) + return __this_address; + + /* V3 inode fields that are always zero */ + if (dip->di_onlink) + return __this_address; + if ((flags2 & XFS_DIFLAG2_NREXT64) && dip->di_nrext64_pad) + return __this_address; + if (!(flags2 & XFS_DIFLAG2_NREXT64) && dip->di_flushiter) + return __this_address; + + /* Metadata files can only be directories or regular files */ + if (!S_ISDIR(mode) && !S_ISREG(mode)) + return __this_address; + + /* They must have zero access permissions */ + if (mode & 0777) + return __this_address; + + /* DMAPI event and state masks are zero */ + if (dip->di_dmevmask || dip->di_dmstate) + return __this_address; + + /* User, group, and project IDs must be zero */ + if (dip->di_uid || dip->di_gid || + dip->di_projid_lo || dip->di_projid_hi) + return __this_address; + + /* Immutable, sync, noatime, nodump, and nodefrag flags must be set */ + if (!(flags & XFS_DIFLAG_IMMUTABLE)) + return __this_address; + if (!(flags & XFS_DIFLAG_SYNC)) + return __this_address; + if (!(flags & XFS_DIFLAG_NOATIME)) + return __this_address; + if (!(flags & XFS_DIFLAG_NODUMP)) + return __this_address; + if (!(flags & XFS_DIFLAG_NODEFRAG)) + return __this_address; + + /* Directories must have nosymlinks flags set */ + if (S_ISDIR(mode) && !(flags & XFS_DIFLAG_NOSYMLINKS)) + return __this_address; + + /* dax flags2 must not be set */ + if (flags2 & XFS_DIFLAG2_DAX) + return __this_address; + + return NULL; +} + xfs_failaddr_t xfs_dinode_verify( struct xfs_mount *mp, @@ -621,6 +688,12 @@ xfs_dinode_verify( !xfs_has_bigtime(mp)) return __this_address; + if (flags2 & XFS_DIFLAG2_METADIR) { + fa = xfs_dinode_verify_metadir(mp, dip, mode, flags, flags2); + if (fa) + return fa; + } + return NULL; } diff --git a/libxfs/xfs_inode_buf.h b/libxfs/xfs_inode_buf.h index 585ed5a110a..8d43d2641c7 100644 --- a/libxfs/xfs_inode_buf.h +++ b/libxfs/xfs_inode_buf.h @@ -28,6 +28,9 @@ int xfs_inode_from_disk(struct xfs_inode *ip, struct xfs_dinode *from); xfs_failaddr_t xfs_dinode_verify(struct xfs_mount *mp, xfs_ino_t ino, struct xfs_dinode *dip); +xfs_failaddr_t xfs_dinode_verify_metadir(struct xfs_mount *mp, + struct xfs_dinode *dip, uint16_t mode, uint16_t flags, + uint64_t flags2); xfs_failaddr_t xfs_inode_validate_extsize(struct xfs_mount *mp, uint32_t extsize, uint16_t mode, uint16_t flags); xfs_failaddr_t xfs_inode_validate_cowextsize(struct xfs_mount *mp, From patchwork Sun Dec 31 23:32:58 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13508134 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 554DCC2C0 for ; Sun, 31 Dec 2023 23:32:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="JHwBC3Jh" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 2765EC433C8; Sun, 31 Dec 2023 23:32:59 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704065579; bh=JqodD+mwE8JdGYNa40gKTt/FY++8KHq3IaRbdcamr44=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=JHwBC3Jh7M5df9ywlz9Vail8P1DfH7dWhYdjUaGOXV1H/1/lamd8aojKd4Gdws5s8 LXn7F++k6hVkuuSDEDIdZoyag8ozOxRgra8zSmdg9OxhCwQWaZO8HMbOZxki/cD7kx 1p4khnD8ZZcxQzjD8jfGfVBqkDIsTTlVNWgrsQNJCD48dHe5ZkSRlGe0yUZGKG+ezi WiCP7WwKLoUw/nFADxFKhFwCGkKn4ln13MXh8N5H/aHcCSxrTFcKAiEW+mXmNapbPY lpelolSgykyKkLD8A3Pt8k/K3eo2TA1L9we1GXxKgx2hjnxUztsIGb5Ih+87LjDH7K s89YBpCJluVTQ== Date: Sun, 31 Dec 2023 15:32:58 -0800 Subject: [PATCH 13/58] xfs: allow deletion of metadata directory files From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <170405010120.1809361.3163682949496483488.stgit@frogsfrogsfrogs> In-Reply-To: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> References: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Make it possible to free metadata files once we've unlinked them from the directory structure. We don't do this in the kernel, at least not yet, but don't leave a logic bomb for later. Signed-off-by: Darrick J. Wong --- include/xfs_inode.h | 3 + libxfs/inode.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++ libxfs/libxfs_api_defs.h | 1 libxfs/xfs_imeta.c | 49 ++++++++++++++++++++++++ 4 files changed, 145 insertions(+), 1 deletion(-) diff --git a/include/xfs_inode.h b/include/xfs_inode.h index 1fdae6c1d3a..4aacc488fa5 100644 --- a/include/xfs_inode.h +++ b/include/xfs_inode.h @@ -418,4 +418,7 @@ extern void libxfs_irele(struct xfs_inode *ip); #define xfs_inherit_nosymlinks (false) #define xfs_inherit_nodefrag (false) +int libxfs_ifree_cluster(struct xfs_trans *tp, struct xfs_perag *pag, + struct xfs_inode *free_ip, struct xfs_icluster *xic); + #endif /* __XFS_INODE_H__ */ diff --git a/libxfs/inode.c b/libxfs/inode.c index 5cb2fd7891a..87b5df84f2a 100644 --- a/libxfs/inode.c +++ b/libxfs/inode.c @@ -317,3 +317,96 @@ void inode_init_owner(struct mnt_idmap *idmap, struct inode *inode, inode_fsgid_set(inode, idmap); inode->i_mode = mode; } + +/* + * This call is used to indicate that the buffer is going to + * be staled and was an inode buffer. This means it gets + * special processing during unpin - where any inodes + * associated with the buffer should be removed from ail. + * There is also special processing during recovery, + * any replay of the inodes in the buffer needs to be + * prevented as the buffer may have been reused. + */ +static void +xfs_trans_stale_inode_buf( + xfs_trans_t *tp, + struct xfs_buf *bp) +{ + ASSERT(bp->b_transp == tp); + ASSERT(bip != NULL); + ASSERT(atomic_read(&bip->bli_refcount) > 0); + + bp->b_flags |= _XBF_INODES; + xfs_trans_buf_set_type(tp, bp, XFS_BLFT_DINO_BUF); +} + +/* + * A big issue when freeing the inode cluster is that we _cannot_ skip any + * inodes that are in memory - they all must be marked stale and attached to + * the cluster buffer. + */ +int +libxfs_ifree_cluster( + struct xfs_trans *tp, + struct xfs_perag *pag, + struct xfs_inode *free_ip, + struct xfs_icluster *xic) +{ + struct xfs_mount *mp = free_ip->i_mount; + struct xfs_ino_geometry *igeo = M_IGEO(mp); + struct xfs_buf *bp; + xfs_daddr_t blkno; + xfs_ino_t inum = xic->first_ino; + int nbufs; + int j; + int ioffset; + int error; + + nbufs = igeo->ialloc_blks / igeo->blocks_per_cluster; + + for (j = 0; j < nbufs; j++, inum += igeo->inodes_per_cluster) { + /* + * The allocation bitmap tells us which inodes of the chunk were + * physically allocated. Skip the cluster if an inode falls into + * a sparse region. + */ + ioffset = inum - xic->first_ino; + if ((xic->alloc & XFS_INOBT_MASK(ioffset)) == 0) { + ASSERT(ioffset % igeo->inodes_per_cluster == 0); + continue; + } + + blkno = XFS_AGB_TO_DADDR(mp, XFS_INO_TO_AGNO(mp, inum), + XFS_INO_TO_AGBNO(mp, inum)); + + /* + * We obtain and lock the backing buffer first in the process + * here to ensure dirty inodes attached to the buffer remain in + * the flushing state while we mark them stale. + * + * If we scan the in-memory inodes first, then buffer IO can + * complete before we get a lock on it, and hence we may fail + * to mark all the active inodes on the buffer stale. + */ + error = xfs_trans_get_buf(tp, mp->m_ddev_targp, blkno, + mp->m_bsize * igeo->blocks_per_cluster, + XBF_UNMAPPED, &bp); + if (error) + return error; + + /* + * This buffer may not have been correctly initialised as we + * didn't read it from disk. That's not important because we are + * only using to mark the buffer as stale in the log, and to + * attach stale cached inodes on it. That means it will never be + * dispatched for IO. If it is, we want to know about it, and we + * want it to fail. We can acheive this by adding a write + * verifier to the buffer. + */ + bp->b_ops = &xfs_inode_buf_ops; + + xfs_trans_stale_inode_buf(tp, bp); + xfs_trans_binval(tp, bp); + } + return 0; +} diff --git a/libxfs/libxfs_api_defs.h b/libxfs/libxfs_api_defs.h index 873995f265c..a0cdad40ff9 100644 --- a/libxfs/libxfs_api_defs.h +++ b/libxfs/libxfs_api_defs.h @@ -171,6 +171,7 @@ #define xfs_iext_lookup_extent libxfs_iext_lookup_extent #define xfs_iext_next libxfs_iext_next #define xfs_ifork_zap_attr libxfs_ifork_zap_attr +#define xfs_ifree_cluster libxfs_ifree_cluster #define xfs_imap_to_bp libxfs_imap_to_bp #define xfs_imeta_cancel_update libxfs_imeta_cancel_update diff --git a/libxfs/xfs_imeta.c b/libxfs/xfs_imeta.c index e59b0f414ed..672aba4d0e7 100644 --- a/libxfs/xfs_imeta.c +++ b/libxfs/xfs_imeta.c @@ -22,6 +22,7 @@ #include "xfs_da_format.h" #include "xfs_da_btree.h" #include "xfs_trans_space.h" +#include "xfs_ag.h" /* * Metadata File Management @@ -359,6 +360,38 @@ xfs_imeta_create( return error; } +/* Free a file from the metadata directory tree. */ +STATIC int +xfs_imeta_ifree( + struct xfs_trans *tp, + struct xfs_inode *ip) +{ + struct xfs_mount *mp = ip->i_mount; + struct xfs_perag *pag; + struct xfs_icluster xic = { 0 }; + int error; + + ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); + ASSERT(VFS_I(ip)->i_nlink == 0); + ASSERT(ip->i_df.if_nextents == 0); + ASSERT(ip->i_disk_size == 0 || !S_ISREG(VFS_I(ip)->i_mode)); + ASSERT(ip->i_nblocks == 0); + + pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, ip->i_ino)); + + error = xfs_dir_ifree(tp, pag, ip, &xic); + if (error) + goto out; + + /* Metadata files do not support ownership changes or DMAPI. */ + + if (xic.deleted) + error = xfs_ifree_cluster(tp, pag, ip, &xic); +out: + xfs_perag_put(pag); + return error; +} + /* * Unlink a metadata inode @upd->ip from the metadata directory given by @path. * The path must already exist. @@ -367,10 +400,24 @@ int xfs_imeta_unlink( struct xfs_imeta_update *upd) { + int error; + ASSERT(xfs_imeta_path_check(upd->path)); ASSERT(xfs_imeta_verify(upd->mp, upd->ip->i_ino)); - return xfs_imeta_sb_unlink(upd); + error = xfs_imeta_sb_unlink(upd); + if (error) + return error; + + /* + * Metadata files require explicit resource cleanup. In other words, + * the inactivation system will not touch these files, so we must free + * the ondisk inode by ourselves if warranted. + */ + if (VFS_I(upd->ip)->i_nlink > 0) + return 0; + + return xfs_imeta_ifree(upd->tp, upd->ip); } /* From patchwork Sun Dec 31 23:33:14 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13508135 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 EAEF9C2C0 for ; Sun, 31 Dec 2023 23:33:14 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="QZXw863B" Received: by smtp.kernel.org (Postfix) with ESMTPSA id B75ABC433C8; Sun, 31 Dec 2023 23:33:14 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704065594; bh=SDcZLSNyIo/HvYA3tVyM0bE+aE4fhBTp1X4T1v59dTc=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=QZXw863BaZhFPNxB4uohGXzQY9S5jywlzQ4te7R42KeBDAuA7Ae35Mhr1HZB48ZgJ OnSx+G/kFEk3cRr/w5rGPCHXWCVYmac2ivKC7M22SFlSxXOvkPS2/soI1wSCGsYTDW RbNj1HxaRbSotFndEKC4CE0DqiSqnggbKPDacQpLegunkFmqOOOzfsohafpkbsfaZC G6zWy3b5HFZKx4B4kQoOvEPHOH+sUYf7RkAsYeJxNOlhopnRCNS2QuIuLj4+gNjbhM +Em6pSwTzxtiWcU9c0gMZNNaDuTplZuz03Lc+4q20udYcOvtZoqZGVSTjqI0zG4rgr XNVeYlA6OPn1g== Date: Sun, 31 Dec 2023 15:33:14 -0800 Subject: [PATCH 14/58] xfs: read and write metadata inode directory From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <170405010134.1809361.2699363137966234355.stgit@frogsfrogsfrogs> In-Reply-To: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> References: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Plumb in the bits we need to look up metadata inode numbers from the metadata inode directory and save them back. Signed-off-by: Darrick J. Wong --- include/xfs_inode.h | 5 include/xfs_trace.h | 5 include/xfs_trans.h | 3 libxfs/imeta_utils.c | 66 +++++ libxfs/libxfs_api_defs.h | 2 libxfs/libxfs_priv.h | 2 libxfs/trans.c | 33 +++ libxfs/xfs_imeta.c | 563 ++++++++++++++++++++++++++++++++++++++++++++++ libxfs/xfs_imeta.h | 17 + libxfs/xfs_inode_util.c | 3 libxfs/xfs_trans_resv.c | 8 + 11 files changed, 695 insertions(+), 12 deletions(-) diff --git a/include/xfs_inode.h b/include/xfs_inode.h index 4aacc488fa5..2675abdffcd 100644 --- a/include/xfs_inode.h +++ b/include/xfs_inode.h @@ -32,6 +32,11 @@ static inline kgid_t make_kgid(gid_t gid) return v; } +#define KUIDT_INIT(value) (kuid_t){ value } +#define KGIDT_INIT(value) (kgid_t){ value } +#define GLOBAL_ROOT_UID KUIDT_INIT(0) +#define GLOBAL_ROOT_GID KGIDT_INIT(0) + /* These match kernel side includes */ #include "xfs_inode_buf.h" #include "xfs_inode_fork.h" diff --git a/include/xfs_trace.h b/include/xfs_trace.h index dd6011af90e..2cca9394b70 100644 --- a/include/xfs_trace.h +++ b/include/xfs_trace.h @@ -360,6 +360,11 @@ #define trace_xlog_intent_recovery_failed(...) ((void) 0) +#define trace_xfs_imeta_dir_link(...) ((void) 0) +#define trace_xfs_imeta_dir_lookup(...) ((void) 0) +#define trace_xfs_imeta_dir_try_create(...) ((void) 0) +#define trace_xfs_imeta_dir_create(...) ((void) 0) +#define trace_xfs_imeta_dir_unlink(...) ((void) 0) #define trace_xfs_imeta_teardown(...) ((void) 0) #define trace_xfs_imeta_sb_create(...) ((void) 0) #define trace_xfs_imeta_sb_link(...) ((void) 0) diff --git a/include/xfs_trans.h b/include/xfs_trans.h index b7f01ff073c..183163e81a5 100644 --- a/include/xfs_trans.h +++ b/include/xfs_trans.h @@ -93,6 +93,9 @@ int libxfs_trans_alloc(struct xfs_mount *mp, struct xfs_trans_res *resp, int libxfs_trans_alloc_inode(struct xfs_inode *ip, struct xfs_trans_res *resv, unsigned int dblocks, unsigned int rblocks, bool force, struct xfs_trans **tpp); +int libxfs_trans_alloc_dir(struct xfs_inode *dp, struct xfs_trans_res *resv, + struct xfs_inode *ip, unsigned int dblocks, + struct xfs_trans **tpp); int libxfs_trans_alloc_rollable(struct xfs_mount *mp, uint blocks, struct xfs_trans **tpp); int libxfs_trans_alloc_empty(struct xfs_mount *mp, struct xfs_trans **tpp); diff --git a/libxfs/imeta_utils.c b/libxfs/imeta_utils.c index f3165b5eed3..ce6000530d3 100644 --- a/libxfs/imeta_utils.c +++ b/libxfs/imeta_utils.c @@ -20,6 +20,7 @@ #include "xfs_sb.h" #include "xfs_imeta.h" #include "xfs_trace.h" +#include "xfs_parent.h" #include "imeta_utils.h" /* Initialize a metadata update structure. */ @@ -29,10 +30,33 @@ xfs_imeta_init( const struct xfs_imeta_path *path, struct xfs_imeta_update *upd) { + struct xfs_trans *tp; + int error; + memset(upd, 0, sizeof(struct xfs_imeta_update)); upd->mp = mp; upd->path = path; - return 0; + + if (!xfs_has_metadir(mp)) + return 0; + + /* + * Find the parent of the last path component. If the parent path does + * not exist, we consider this corruption because paths are supposed + * to exist. For example, if the path is /quota/user, we require that + * /quota already exists. + */ + error = xfs_trans_alloc_empty(mp, &tp); + if (error) + return error; + error = xfs_imeta_dir_parent(tp, upd->path, &upd->dp); + xfs_trans_cancel(tp); + if (error == -ENOENT) + return -EFSCORRUPTED; + if (error) + return error; + + return xfs_parent_start(mp, &upd->ppargs); } /* @@ -47,11 +71,25 @@ xfs_imeta_teardown( { trace_xfs_imeta_teardown(upd, error); + if (upd->ppargs) { + xfs_parent_finish(upd->mp, upd->ppargs); + upd->ppargs = NULL; + } + if (upd->ip) { if (upd->ip_locked) xfs_iunlock(upd->ip, XFS_ILOCK_EXCL); upd->ip_locked = false; } + + if (upd->dp) { + if (upd->dp_locked) + xfs_iunlock(upd->dp, XFS_ILOCK_EXCL); + upd->dp_locked = false; + + xfs_imeta_irele(upd->dp); + upd->dp = NULL; + } } /* @@ -75,6 +113,15 @@ xfs_imeta_start_create( if (error) goto out_teardown; + /* + * Lock the parent directory if there is one. We can't ijoin it to + * the transaction until after the child file has been created. + */ + if (upd->dp) { + xfs_ilock(upd->dp, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT); + upd->dp_locked = true; + } + trace_xfs_imeta_start_create(upd); return 0; out_teardown: @@ -103,10 +150,19 @@ xfs_imeta_start_dir_update( upd->ip = ip; - error = xfs_trans_alloc_inode(upd->ip, tr_resv, resblks, 0, false, - &upd->tp); - if (error) - goto out_teardown; + if (upd->dp) { + error = xfs_trans_alloc_dir(upd->dp, tr_resv, upd->ip, + resblks, &upd->tp); + if (error) + goto out_teardown; + + upd->dp_locked = true; + } else { + error = xfs_trans_alloc_inode(upd->ip, tr_resv, resblks, 0, + false, &upd->tp); + if (error) + goto out_teardown; + } upd->ip_locked = true; return 0; diff --git a/libxfs/libxfs_api_defs.h b/libxfs/libxfs_api_defs.h index a0cdad40ff9..90304da8983 100644 --- a/libxfs/libxfs_api_defs.h +++ b/libxfs/libxfs_api_defs.h @@ -184,6 +184,7 @@ #define xfs_imeta_link_space_res libxfs_imeta_link_space_res #define xfs_imeta_lookup libxfs_imeta_lookup #define xfs_imeta_mount libxfs_imeta_mount +#define xfs_imeta_set_metaflag libxfs_imeta_set_metaflag #define xfs_imeta_start_create libxfs_imeta_start_create #define xfs_imeta_start_link libxfs_imeta_start_link #define xfs_imeta_start_unlink libxfs_imeta_start_unlink @@ -289,6 +290,7 @@ #define xfs_trans_add_item libxfs_trans_add_item #define xfs_trans_alloc_empty libxfs_trans_alloc_empty #define xfs_trans_alloc libxfs_trans_alloc +#define xfs_trans_alloc_dir libxfs_trans_alloc_dir #define xfs_trans_alloc_inode libxfs_trans_alloc_inode #define xfs_trans_bhold libxfs_trans_bhold #define xfs_trans_bhold_release libxfs_trans_bhold_release diff --git a/libxfs/libxfs_priv.h b/libxfs/libxfs_priv.h index 9bca059776d..f4614ee9631 100644 --- a/libxfs/libxfs_priv.h +++ b/libxfs/libxfs_priv.h @@ -175,6 +175,8 @@ enum ce { CE_DEBUG, CE_CONT, CE_NOTE, CE_WARN, CE_ALERT, CE_PANIC }; #define XFS_ERRLEVEL_LOW 1 #define XFS_ILOCK_EXCL 0 +#define XFS_IOLOCK_SHARED 0 +#define XFS_IOLOCK_EXCL 0 #define XFS_STATS_INC(mp, count) do { (mp) = (mp); } while (0) #define XFS_STATS_DEC(mp, count, x) do { (mp) = (mp); } while (0) #define XFS_STATS_ADD(mp, count, x) do { (mp) = (mp); } while (0) diff --git a/libxfs/trans.c b/libxfs/trans.c index 7fec2caff49..8d969400984 100644 --- a/libxfs/trans.c +++ b/libxfs/trans.c @@ -1184,6 +1184,39 @@ libxfs_trans_alloc_inode( return 0; } +/* + * Allocate an transaction, lock and join the directory and child inodes to it, + * and reserve quota for a directory update. + * + * The ILOCKs will be dropped when the transaction is committed or cancelled. + * + * Caller is responsible for unlocking the inodes manually upon return + */ +int +libxfs_trans_alloc_dir( + struct xfs_inode *dp, + struct xfs_trans_res *resv, + struct xfs_inode *ip, + unsigned int resblks, + struct xfs_trans **tpp) +{ + struct xfs_trans *tp; + struct xfs_mount *mp = ip->i_mount; + int error; + + error = xfs_trans_alloc(mp, resv, resblks, 0, 0, &tp); + if (error) + return error; + + xfs_lock_two_inodes(dp, XFS_ILOCK_EXCL, ip, XFS_ILOCK_EXCL); + + xfs_trans_ijoin(tp, dp, 0); + xfs_trans_ijoin(tp, ip, 0); + + *tpp = tp; + return 0; +} + /* * Try to reserve more blocks for a transaction. The single use case we * support is for offline repair -- use a transaction to gather data without diff --git a/libxfs/xfs_imeta.c b/libxfs/xfs_imeta.c index 672aba4d0e7..b1c5c6ec5e6 100644 --- a/libxfs/xfs_imeta.c +++ b/libxfs/xfs_imeta.c @@ -23,6 +23,8 @@ #include "xfs_da_btree.h" #include "xfs_trans_space.h" #include "xfs_ag.h" +#include "xfs_dir2.h" +#include "xfs_dir2_priv.h" /* * Metadata File Management @@ -43,9 +45,16 @@ * this structure must be passed to xfs_imeta_end_update to free resources that * cannot be freed during the transaction. * - * Right now we only support callers passing in the predefined metadata inode - * paths; the goal is that callers will some day locate metadata inodes based - * on path lookups into a metadata directory structure. + * When the metadata directory tree (metadir) feature is enabled, we can create + * a complex directory tree in which to store metadata inodes. Inodes within + * the metadata directory tree should have the "metadata" inode flag set to + * prevent them from being exposed to the outside world. + * + * Callers are not expected to take the IOLOCK of metadata directories. They + * are expected to take the ILOCK of any inode in the metadata directory tree + * (just like the regular to synchronize access to that inode. It is not + * necessary to take the MMAPLOCK since metadata inodes should never be exposed + * to user space. */ /* Static metadata inode paths */ @@ -61,6 +70,11 @@ XFS_IMETA_DEFINE_PATH(XFS_IMETA_USRQUOTA, usrquota_path); XFS_IMETA_DEFINE_PATH(XFS_IMETA_GRPQUOTA, grpquota_path); XFS_IMETA_DEFINE_PATH(XFS_IMETA_PRJQUOTA, prjquota_path); +const struct xfs_imeta_path XFS_IMETA_METADIR = { + .im_depth = 0, + .im_ftype = XFS_DIR3_FT_DIR, +}; + /* Are these two paths equal? */ STATIC bool xfs_imeta_path_compare( @@ -118,6 +132,10 @@ static const struct xfs_imeta_sbmap { .path = &XFS_IMETA_PRJQUOTA, .offset = offsetof(struct xfs_sb, sb_pquotino), }, + { + .path = &XFS_IMETA_METADIR, + .offset = offsetof(struct xfs_sb, sb_metadirino), + }, { NULL, 0 }, }; @@ -287,6 +305,521 @@ xfs_imeta_sb_link( return 0; } +/* Functions for storing and retrieving metadata directory inode values. */ + +static inline void +xfs_imeta_set_xname( + struct xfs_name *xname, + const struct xfs_imeta_path *path, + unsigned int path_idx, + unsigned char ftype) +{ + xname->name = (const unsigned char *)path->im_path[path_idx]; + xname->len = strlen(path->im_path[path_idx]); + xname->type = ftype; +} + +/* + * Look up the inode number and filetype for an exact name in a directory. + * Caller must hold ILOCK_EXCL. + */ +static inline int +xfs_imeta_dir_lookup( + struct xfs_trans *tp, + struct xfs_inode *dp, + struct xfs_name *xname, + xfs_ino_t *ino) +{ + struct xfs_da_args args = { + .trans = tp, + .dp = dp, + .geo = dp->i_mount->m_dir_geo, + .name = xname->name, + .namelen = xname->len, + .hashval = xfs_dir2_hashname(dp->i_mount, xname), + .whichfork = XFS_DATA_FORK, + .op_flags = XFS_DA_OP_OKNOENT, + .owner = dp->i_ino, + }; + bool isblock, isleaf; + int error; + + if (xfs_is_shutdown(dp->i_mount)) + return -EIO; + + if (dp->i_df.if_format == XFS_DINODE_FMT_LOCAL) { + error = xfs_dir2_sf_lookup(&args); + goto out_unlock; + } + + /* dir2 functions require that the data fork is loaded */ + error = xfs_iread_extents(tp, dp, XFS_DATA_FORK); + if (error) + goto out_unlock; + + error = xfs_dir2_isblock(&args, &isblock); + if (error) + goto out_unlock; + + if (isblock) { + error = xfs_dir2_block_lookup(&args); + goto out_unlock; + } + + error = xfs_dir2_isleaf(&args, &isleaf); + if (error) + goto out_unlock; + + if (isleaf) { + error = xfs_dir2_leaf_lookup(&args); + goto out_unlock; + } + + error = xfs_dir2_node_lookup(&args); + +out_unlock: + if (error == -EEXIST) + error = 0; + if (error) + return error; + + *ino = args.inumber; + xname->type = args.filetype; + return 0; +} + +/* + * Given a parent directory @dp and a metadata inode path component @xname, + * Look up the inode number in the directory, returning it in @ino. + * @xname.type must match the directory entry's ftype. + * + * Caller must hold ILOCK_EXCL. + */ +static inline int +xfs_imeta_dir_lookup_component( + struct xfs_trans *tp, + struct xfs_inode *dp, + struct xfs_name *xname, + xfs_ino_t *ino) +{ + int type_wanted = xname->type; + int error; + + if (!S_ISDIR(VFS_I(dp)->i_mode)) + return -EFSCORRUPTED; + + error = xfs_imeta_dir_lookup(tp, dp, xname, ino); + if (error) + return error; + if (!xfs_verify_ino(dp->i_mount, *ino)) + return -EFSCORRUPTED; + if (type_wanted != XFS_DIR3_FT_UNKNOWN && xname->type != type_wanted) + return -EFSCORRUPTED; + + trace_xfs_imeta_dir_lookup(dp, xname, *ino); + return 0; +} + +/* + * Traverse a metadata directory tree path, returning the inode corresponding + * to the parent of the last path component. If any of the path components do + * not exist, return -ENOENT. Caller must supply a transaction to avoid + * livelocks on btree cycles. + * + * @dp is returned without any locks held. + */ +int +xfs_imeta_dir_parent( + struct xfs_trans *tp, + const struct xfs_imeta_path *path, + struct xfs_inode **dpp) +{ + struct xfs_name xname; + struct xfs_mount *mp = tp->t_mountp; + struct xfs_inode *dp = NULL; + xfs_ino_t ino; + unsigned int i; + int error; + + /* Caller wanted the root, we're done! */ + if (path->im_depth == 0) + goto out; + + /* No metadata directory means no parent. */ + if (mp->m_metadirip == NULL) + return -ENOENT; + + /* Grab a new reference to the metadir root dir. */ + error = xfs_imeta_iget(tp, mp->m_metadirip->i_ino, XFS_DIR3_FT_DIR, + &dp); + if (error) + return error; + + for (i = 0; i < path->im_depth - 1; i++) { + struct xfs_inode *ip = NULL; + + xfs_ilock(dp, XFS_ILOCK_EXCL); + + /* Look up the name in the current directory. */ + xfs_imeta_set_xname(&xname, path, i, XFS_DIR3_FT_DIR); + error = xfs_imeta_dir_lookup_component(tp, dp, &xname, &ino); + if (error) + goto out_rele; + + /* + * Grab the child inode while we still have the parent + * directory locked. + */ + error = xfs_imeta_iget(tp, ino, XFS_DIR3_FT_DIR, &ip); + if (error) + goto out_rele; + + xfs_iunlock(dp, XFS_ILOCK_EXCL); + xfs_imeta_irele(dp); + dp = ip; + } + +out: + *dpp = dp; + return 0; + +out_rele: + xfs_iunlock(dp, XFS_ILOCK_EXCL); + xfs_imeta_irele(dp); + return error; +} + +/* + * Look up a metadata inode from the metadata directory. If the last path + * component doesn't exist, return NULLFSINO. If any other part of the path + * does not exist, return -ENOENT so we can distinguish the two. + */ +STATIC int +xfs_imeta_dir_lookup_int( + struct xfs_trans *tp, + const struct xfs_imeta_path *path, + xfs_ino_t *inop) +{ + struct xfs_name xname; + struct xfs_inode *dp = NULL; + xfs_ino_t ino; + int error; + + /* metadir ino is recorded in superblock */ + if (xfs_imeta_path_compare(path, &XFS_IMETA_METADIR)) + return xfs_imeta_sb_lookup(tp->t_mountp, path, inop); + + ASSERT(path->im_depth > 0); + + /* Find the parent of the last path component. */ + error = xfs_imeta_dir_parent(tp, path, &dp); + if (error) + return error; + + xfs_ilock(dp, XFS_ILOCK_EXCL); + + /* Look up the name in the current directory. */ + xfs_imeta_set_xname(&xname, path, path->im_depth - 1, path->im_ftype); + error = xfs_imeta_dir_lookup_component(tp, dp, &xname, &ino); + switch (error) { + case 0: + *inop = ino; + break; + case -ENOENT: + *inop = NULLFSINO; + error = 0; + break; + } + + xfs_iunlock(dp, XFS_ILOCK_EXCL); + xfs_imeta_irele(dp); + return error; +} + +/* + * Load all the metadata inode pointers that are cached in the in-core + * superblock but live somewhere in the metadata directory tree. + */ +STATIC int +xfs_imeta_dir_mount( + struct xfs_trans *tp) +{ + struct xfs_mount *mp = tp->t_mountp; + const struct xfs_imeta_sbmap *p; + xfs_ino_t *sb_inop; + int err2; + int error = 0; + + for (p = xfs_imeta_sbmaps; p->path && p->path->im_depth > 0; p++) { + if (p->path == &XFS_IMETA_METADIR) + continue; + sb_inop = xfs_imeta_sbmap_to_inop(mp, p); + err2 = xfs_imeta_dir_lookup_int(tp, p->path, sb_inop); + if (err2 == -ENOENT) { + *sb_inop = NULLFSINO; + continue; + } + if (!error && err2) + error = err2; + } + + return error; +} + +/* Set up an inode to be recognized as a metadata directory inode. */ +void +xfs_imeta_set_iflag( + struct xfs_trans *tp, + struct xfs_inode *ip) +{ + VFS_I(ip)->i_mode &= ~0777; + VFS_I(ip)->i_uid = GLOBAL_ROOT_UID; + VFS_I(ip)->i_gid = GLOBAL_ROOT_GID; + ip->i_projid = 0; + ip->i_diflags |= (XFS_DIFLAG_IMMUTABLE | XFS_DIFLAG_SYNC | + XFS_DIFLAG_NOATIME | XFS_DIFLAG_NODUMP | + XFS_DIFLAG_NODEFRAG); + if (S_ISDIR(VFS_I(ip)->i_mode)) + ip->i_diflags |= XFS_DIFLAG_NOSYMLINKS; + ip->i_diflags2 &= ~XFS_DIFLAG2_DAX; + ip->i_diflags2 |= XFS_DIFLAG2_METADIR; + xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); +} + + +/* Clear the metadata directory inode flag. */ +void +xfs_imeta_clear_iflag( + struct xfs_trans *tp, + struct xfs_inode *ip) +{ + ASSERT(xfs_is_metadir_inode(ip)); + ASSERT(VFS_I(ip)->i_nlink == 0); + + ip->i_diflags2 &= ~XFS_DIFLAG2_METADIR; + xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); +} +/* + * Create a new metadata inode accessible via the given metadata directory path. + * Callers must ensure that the directory entry does not already exist; a new + * one will be created. + */ +STATIC int +xfs_imeta_dir_create( + struct xfs_imeta_update *upd, + umode_t mode) +{ + struct xfs_icreate_args args = { + .pip = upd->dp, + .nlink = S_ISDIR(mode) ? 2 : 1, + }; + struct xfs_name xname; + struct xfs_dir_update du = { + .dp = upd->dp, + .name = &xname, + .ppargs = upd->ppargs, + }; + struct xfs_mount *mp = upd->mp; + xfs_ino_t *sb_inop; + xfs_ino_t ino; + unsigned int resblks; + int error; + + ASSERT(xfs_isilocked(upd->dp, XFS_ILOCK_EXCL)); + + /* metadir ino is recorded in superblock; only mkfs gets to do this */ + if (xfs_imeta_path_compare(upd->path, &XFS_IMETA_METADIR)) { + error = xfs_imeta_sb_create(upd, mode); + if (error) + return error; + + /* Set the metadata iflag, initialize directory. */ + xfs_imeta_set_iflag(upd->tp, upd->ip); + return xfs_dir_init(upd->tp, upd->ip, upd->ip); + } + + ASSERT(upd->path->im_depth > 0); + + xfs_icreate_args_rootfile(&args, mp, mode, xfs_has_parent(mp)); + + /* Check that the name does not already exist in the directory. */ + xfs_imeta_set_xname(&xname, upd->path, upd->path->im_depth - 1, + XFS_DIR3_FT_UNKNOWN); + error = xfs_imeta_dir_lookup_component(upd->tp, upd->dp, &xname, &ino); + switch (error) { + case -ENOENT: + break; + case 0: + error = -EEXIST; + fallthrough; + default: + return error; + } + + /* + * A newly created regular or special file just has one directory + * entry pointing to them, but a directory also the "." entry + * pointing to itself. + */ + error = xfs_dialloc(&upd->tp, upd->dp->i_ino, mode, &ino); + if (error) + return error; + error = xfs_icreate(upd->tp, ino, &args, &upd->ip); + if (error) + return error; + du.ip = upd->ip; + xfs_imeta_set_iflag(upd->tp, upd->ip); + upd->ip_locked = true; + + /* + * Join the directory inode to the transaction. We do not do it + * earlier because xfs_dialloc rolls the transaction. + */ + xfs_trans_ijoin(upd->tp, upd->dp, 0); + + /* Create the entry. */ + if (S_ISDIR(args.mode)) + resblks = xfs_mkdir_space_res(mp, xname.len); + else + resblks = xfs_create_space_res(mp, xname.len); + xname.type = xfs_mode_to_ftype(args.mode); + + trace_xfs_imeta_dir_try_create(upd); + + error = xfs_dir_create_child(upd->tp, resblks, &du); + if (error) + return error; + + /* Metadir files are not accounted to quota. */ + + trace_xfs_imeta_dir_create(upd); + + /* Update the in-core superblock value if there is one. */ + sb_inop = xfs_imeta_path_to_sb_inop(mp, upd->path); + if (sb_inop) + *sb_inop = ino; + return 0; +} + +/* + * Remove the given entry from the metadata directory and drop the link count + * of the metadata inode. + */ +STATIC int +xfs_imeta_dir_unlink( + struct xfs_imeta_update *upd) +{ + struct xfs_name xname; + struct xfs_dir_update du = { + .dp = upd->dp, + .name = &xname, + .ip = upd->ip, + .ppargs = upd->ppargs, + }; + struct xfs_mount *mp = upd->mp; + xfs_ino_t *sb_inop; + xfs_ino_t ino; + unsigned int resblks; + int error; + + ASSERT(xfs_isilocked(upd->dp, XFS_ILOCK_EXCL)); + ASSERT(xfs_isilocked(upd->ip, XFS_ILOCK_EXCL)); + + /* Metadata directory root cannot be unlinked. */ + if (xfs_imeta_path_compare(upd->path, &XFS_IMETA_METADIR)) { + ASSERT(0); + return -EFSCORRUPTED; + } + + ASSERT(upd->path->im_depth > 0); + + /* Look up the name in the current directory. */ + xfs_imeta_set_xname(&xname, upd->path, upd->path->im_depth - 1, + xfs_mode_to_ftype(VFS_I(upd->ip)->i_mode)); + error = xfs_imeta_dir_lookup_component(upd->tp, upd->dp, &xname, &ino); + switch (error) { + case 0: + if (ino != upd->ip->i_ino) + error = -ENOENT; + break; + case -ENOENT: + error = -EFSCORRUPTED; + break; + } + if (error) + return error; + + resblks = xfs_remove_space_res(mp, xname.len); + error = xfs_dir_remove_child(upd->tp, resblks, &du); + if (error) + return error; + + trace_xfs_imeta_dir_unlink(upd); + + /* Update the in-core superblock value if there is one. */ + sb_inop = xfs_imeta_path_to_sb_inop(mp, upd->path); + if (sb_inop) + *sb_inop = NULLFSINO; + return 0; +} + +/* Set the given path in the metadata directory to point to an inode. */ +STATIC int +xfs_imeta_dir_link( + struct xfs_imeta_update *upd) +{ + struct xfs_name xname; + struct xfs_dir_update du = { + .dp = upd->dp, + .name = &xname, + .ip = upd->ip, + .ppargs = upd->ppargs, + }; + struct xfs_mount *mp = upd->mp; + xfs_ino_t *sb_inop; + xfs_ino_t ino; + unsigned int resblks; + int error; + + ASSERT(xfs_isilocked(upd->dp, XFS_ILOCK_EXCL)); + ASSERT(xfs_isilocked(upd->ip, XFS_ILOCK_EXCL)); + + /* Metadata directory root cannot be linked. */ + if (xfs_imeta_path_compare(upd->path, &XFS_IMETA_METADIR)) { + ASSERT(0); + return -EFSCORRUPTED; + } + + ASSERT(upd->path->im_depth > 0); + + /* Look up the name in the current directory. */ + xfs_imeta_set_xname(&xname, upd->path, upd->path->im_depth - 1, + xfs_mode_to_ftype(VFS_I(upd->ip)->i_mode)); + error = xfs_imeta_dir_lookup_component(upd->tp, upd->dp, &xname, &ino); + switch (error) { + case -ENOENT: + break; + case 0: + error = -EEXIST; + fallthrough; + default: + return error; + } + + resblks = xfs_link_space_res(mp, xname.len); + error = xfs_dir_add_child(upd->tp, resblks, &du); + if (error) + return error; + + trace_xfs_imeta_dir_link(upd); + + /* Update the in-core superblock value if there is one. */ + sb_inop = xfs_imeta_path_to_sb_inop(mp, upd->path); + if (sb_inop) + *sb_inop = upd->ip->i_ino; + return 0; +} + /* General functions for managing metadata inode pointers */ /* @@ -317,7 +850,13 @@ xfs_imeta_lookup( ASSERT(xfs_imeta_path_check(path)); - error = xfs_imeta_sb_lookup(mp, path, &ino); + if (xfs_has_metadir(mp)) { + error = xfs_imeta_dir_lookup_int(tp, path, &ino); + if (error == -ENOENT) + return -EFSCORRUPTED; + } else { + error = xfs_imeta_sb_lookup(mp, path, &ino); + } if (error) return error; @@ -349,13 +888,17 @@ xfs_imeta_create( umode_t mode, struct xfs_inode **ipp) { + struct xfs_mount *mp = upd->mp; int error; ASSERT(xfs_imeta_path_check(upd->path)); *ipp = NULL; - error = xfs_imeta_sb_create(upd, mode); + if (xfs_has_metadir(mp)) + error = xfs_imeta_dir_create(upd, mode); + else + error = xfs_imeta_sb_create(upd, mode); *ipp = upd->ip; return error; } @@ -405,7 +948,10 @@ xfs_imeta_unlink( ASSERT(xfs_imeta_path_check(upd->path)); ASSERT(xfs_imeta_verify(upd->mp, upd->ip->i_ino)); - error = xfs_imeta_sb_unlink(upd); + if (xfs_has_metadir(upd->mp)) + error = xfs_imeta_dir_unlink(upd); + else + error = xfs_imeta_sb_unlink(upd); if (error) return error; @@ -431,6 +977,8 @@ xfs_imeta_link( { ASSERT(xfs_imeta_path_check(upd->path)); + if (xfs_has_metadir(upd->mp)) + return xfs_imeta_dir_link(upd); return xfs_imeta_sb_link(upd); } @@ -461,5 +1009,8 @@ int xfs_imeta_mount( struct xfs_trans *tp) { + if (xfs_has_metadir(tp->t_mountp)) + return xfs_imeta_dir_mount(tp); + return 0; } diff --git a/libxfs/xfs_imeta.h b/libxfs/xfs_imeta.h index 60e0f6a6c13..b8e360bbdfb 100644 --- a/libxfs/xfs_imeta.h +++ b/libxfs/xfs_imeta.h @@ -13,6 +13,7 @@ #define XFS_IMETA_DEFINE_PATH(name, path) \ const struct xfs_imeta_path name = { \ .im_path = (path), \ + .im_ftype = XFS_DIR3_FT_REG_FILE, \ .im_depth = ARRAY_SIZE(path), \ } @@ -23,6 +24,9 @@ struct xfs_imeta_path { /* Number of strings in path. */ uint8_t im_depth; + + /* Expected file type. */ + uint8_t im_ftype; }; /* Cleanup widget for metadata inode creation and deletion. */ @@ -32,9 +36,16 @@ struct xfs_imeta_update { const struct xfs_imeta_path *path; + /* Parent pointer update context */ + struct xfs_parent_args *ppargs; + + /* Parent directory */ + struct xfs_inode *dp; + /* Metadata inode */ struct xfs_inode *ip; + unsigned int dp_locked:1; unsigned int ip_locked:1; }; @@ -54,9 +65,15 @@ extern const struct xfs_imeta_path XFS_IMETA_RTSUMMARY; extern const struct xfs_imeta_path XFS_IMETA_USRQUOTA; extern const struct xfs_imeta_path XFS_IMETA_GRPQUOTA; extern const struct xfs_imeta_path XFS_IMETA_PRJQUOTA; +extern const struct xfs_imeta_path XFS_IMETA_METADIR; int xfs_imeta_lookup(struct xfs_trans *tp, const struct xfs_imeta_path *path, xfs_ino_t *ino); +int xfs_imeta_dir_parent(struct xfs_trans *tp, + const struct xfs_imeta_path *path, struct xfs_inode **dpp); + +void xfs_imeta_set_iflag(struct xfs_trans *tp, struct xfs_inode *ip); +void xfs_imeta_clear_iflag(struct xfs_trans *tp, struct xfs_inode *ip); int xfs_imeta_create(struct xfs_imeta_update *upd, umode_t mode, struct xfs_inode **ipp); diff --git a/libxfs/xfs_inode_util.c b/libxfs/xfs_inode_util.c index b63aacb6971..c2e51a6ee94 100644 --- a/libxfs/xfs_inode_util.c +++ b/libxfs/xfs_inode_util.c @@ -19,6 +19,7 @@ #include "xfs_bmap.h" #include "xfs_trace.h" #include "xfs_ag.h" +#include "xfs_imeta.h" #include "iunlink.h" uint16_t @@ -646,6 +647,8 @@ xfs_droplink( if (inode->i_nlink) return 0; + if (xfs_is_metadir_inode(ip)) + xfs_imeta_clear_iflag(tp, ip); return xfs_iunlink(tp, ip); } diff --git a/libxfs/xfs_trans_resv.c b/libxfs/xfs_trans_resv.c index a46360e2bdb..74f46539179 100644 --- a/libxfs/xfs_trans_resv.c +++ b/libxfs/xfs_trans_resv.c @@ -1118,7 +1118,10 @@ xfs_calc_imeta_create_resv( unsigned int ret; ret = xfs_calc_buf_res(1, mp->m_sb.sb_sectsize); - ret += resp->tr_create.tr_logres; + if (xfs_has_metadir(mp)) + ret += max(resp->tr_create.tr_logres, resp->tr_mkdir.tr_logres); + else + ret += resp->tr_create.tr_logres; return ret; } @@ -1128,6 +1131,9 @@ xfs_calc_imeta_create_count( struct xfs_mount *mp, struct xfs_trans_resv *resp) { + if (xfs_has_metadir(mp)) + return max(resp->tr_create.tr_logcount, + resp->tr_mkdir.tr_logcount); return resp->tr_create.tr_logcount; } From patchwork Sun Dec 31 23:33:29 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13508136 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 52C94C2D4 for ; Sun, 31 Dec 2023 23:33:30 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="NIKh9wE0" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 77DDBC433C7; Sun, 31 Dec 2023 23:33:30 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704065610; bh=IJK4kDvCJ3MaaVevr4yOhr2MnTikIq/FugGuwaAlsCA=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=NIKh9wE0OaWnY1tShTi8HAltNceqByIL7JfeECtVSRnlWwN/v9ku6xtrfHUd4xbdQ ZQXouYfW1CgXMJMYq/avtFhhkVhSCm008X0WO5M0GlNo8u6eWodTXJxOWLLDnRyzU4 YBkkfHrMg/MoyXWukLdkE+7zm8gLqe/SvkOSuRQyPt0sYLV8+bBKuaJ9w7+13fQmwy oySLsXDfjHZp2NwqjGX4Db3m5XcpYYz6MPrAkOyUhRpKPUwDv/t4KxhI+qr4Sio0xM 15FkGJKsmghYtpDnluZekE4Bh9Sk9engtNFdjXqLi42+iiQ7WDr044F9rk46sW6f3C bDEvpDYrMYiyg== Date: Sun, 31 Dec 2023 15:33:29 -0800 Subject: [PATCH 15/58] xfs: ensure metadata directory paths exist before creating files From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <170405010148.1809361.16643842176885546069.stgit@frogsfrogsfrogs> In-Reply-To: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> References: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Since xfs_imeta_create can create new metadata files arbitrarily deep in the metadata directory tree, we must supply a function that can ensure that all directories in a path exist, and call it before the quota functions create the quota inodes. Signed-off-by: Darrick J. Wong --- libxfs/imeta_utils.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++ libxfs/imeta_utils.h | 3 ++ libxfs/libxfs_api_defs.h | 1 + mkfs/proto.c | 8 +++++ 4 files changed, 81 insertions(+) diff --git a/libxfs/imeta_utils.c b/libxfs/imeta_utils.c index ce6000530d3..0186968ed3e 100644 --- a/libxfs/imeta_utils.c +++ b/libxfs/imeta_utils.c @@ -246,3 +246,72 @@ xfs_imeta_cancel_update( xfs_imeta_teardown(upd, error); } + +/* Create a metadata for the last component of the path. */ +STATIC int +xfs_imeta_mkdir( + struct xfs_mount *mp, + const struct xfs_imeta_path *path) +{ + struct xfs_imeta_update upd; + struct xfs_inode *ip = NULL; + int error; + + if (xfs_is_shutdown(mp)) + return -EIO; + + /* Allocate a transaction to create the last directory. */ + error = xfs_imeta_start_create(mp, path, &upd); + if (error) + return error; + + /* Create the subdirectory and take our reference. */ + error = xfs_imeta_create(&upd, S_IFDIR, &ip); + if (error) + goto out_cancel; + + error = xfs_imeta_commit_update(&upd); + + /* + * We don't pass the directory we just created to the caller, so finish + * setting up the inode, then release the dir and the dquots. + */ + goto out_irele; + +out_cancel: + xfs_imeta_cancel_update(&upd, error); +out_irele: + /* Have to finish setting up the inode to ensure it's deleted. */ + if (ip) + xfs_irele(ip); + return error; +} + +/* + * Make sure that every metadata directory path component exists and is a + * directory. + */ +int +xfs_imeta_ensure_dirpath( + struct xfs_mount *mp, + const struct xfs_imeta_path *path) +{ + struct xfs_imeta_path temp_path = { + .im_path = path->im_path, + .im_depth = 1, + .im_ftype = XFS_DIR3_FT_DIR, + }; + unsigned int i; + int error = 0; + + if (!xfs_has_metadir(mp)) + return 0; + + for (i = 0; i < path->im_depth - 1; i++, temp_path.im_depth++) { + error = xfs_imeta_mkdir(mp, &temp_path); + if (error && error != -EEXIST) + return error; + } + + return 0; +} diff --git a/libxfs/imeta_utils.h b/libxfs/imeta_utils.h index a2afc0f37ac..8ab81149b05 100644 --- a/libxfs/imeta_utils.h +++ b/libxfs/imeta_utils.h @@ -18,6 +18,9 @@ int xfs_imeta_start_unlink(struct xfs_mount *mp, const struct xfs_imeta_path *path, struct xfs_inode *ip, struct xfs_imeta_update *upd); +int xfs_imeta_ensure_dirpath(struct xfs_mount *mp, + const struct xfs_imeta_path *path); + int xfs_imeta_commit_update(struct xfs_imeta_update *upd); void xfs_imeta_cancel_update(struct xfs_imeta_update *upd, int error); diff --git a/libxfs/libxfs_api_defs.h b/libxfs/libxfs_api_defs.h index 90304da8983..e08be764a49 100644 --- a/libxfs/libxfs_api_defs.h +++ b/libxfs/libxfs_api_defs.h @@ -178,6 +178,7 @@ #define xfs_imeta_commit_update libxfs_imeta_commit_update #define xfs_imeta_create libxfs_imeta_create #define xfs_imeta_create_space_res libxfs_imeta_create_space_res +#define xfs_imeta_ensure_dirpath libxfs_imeta_ensure_dirpath #define xfs_imeta_iget libxfs_imeta_iget #define xfs_imeta_irele libxfs_imeta_irele #define xfs_imeta_link libxfs_imeta_link diff --git a/mkfs/proto.c b/mkfs/proto.c index 2eff1f32173..5e17ea420f4 100644 --- a/mkfs/proto.c +++ b/mkfs/proto.c @@ -754,6 +754,10 @@ rtbitmap_create( struct xfs_inode *rbmip; int error; + error = -libxfs_imeta_ensure_dirpath(mp, &XFS_IMETA_RTBITMAP); + if (error) + fail(_("Realtime bitmap directory allocation failed"), error); + error = -libxfs_imeta_start_create(mp, &XFS_IMETA_RTBITMAP, &upd); if (error) res_failed(error); @@ -783,6 +787,10 @@ rtsummary_create( struct xfs_inode *rsumip; int error; + error = -libxfs_imeta_ensure_dirpath(mp, &XFS_IMETA_RTSUMMARY); + if (error) + fail(_("Realtime summary directory allocation failed"), error); + error = -libxfs_imeta_start_create(mp, &XFS_IMETA_RTSUMMARY, &upd); if (error) res_failed(error); From patchwork Sun Dec 31 23:33:45 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13508137 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 9D387C2CC for ; Sun, 31 Dec 2023 23:33:46 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="EJkkd5cp" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 1015FC433C7; Sun, 31 Dec 2023 23:33:46 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704065626; bh=MC2F6Q7YfONYnFvHKdwpYwt47ePA4MKYkY2oE5uNGvc=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=EJkkd5cpkgtliJmsuCN7ayu9yr/BRIqf1xUQ2E269LSHoP5TaeH/oMqoPdqEIvz/6 IEsA3gVm92FbErL3bWG158Mtg5YpUXIFxHxtgBvQ/R1JslnUgSEW4ckH1lSIBI/Gn3 tfD6wDw9sAQBICWXbEdHtoK7DWwQ23lRMr6wJBTYi4BEKbyf1DXEM81lWDN2nCRC7i pvgTq0YH6nsGvyMeJc3w76V0FgrKyYp4c38FPuJEob39we/aCrgOwkKzrFZ+qDaPg3 XEJOu5G6jtmC/Uyfc6DCkHboVEJX03e5NtiKsIZoa65cuD9OPg0Jy53C9n8r2gVAeQ wZgFjHUokg6/A== Date: Sun, 31 Dec 2023 15:33:45 -0800 Subject: [PATCH 16/58] xfs: disable the agi rotor for metadata inodes From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <170405010161.1809361.14825279080058332772.stgit@frogsfrogsfrogs> In-Reply-To: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> References: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Ideally, we'd put all the metadata inodes in one place if we could, so that the metadata all stay reasonably close together instead of spreading out over the disk. Furthermore, if the log is internal we'd probably prefer to keep the metadata near the log. Therefore, disable AGI rotoring for metadata inode allocations. Signed-off-by: Darrick J. Wong --- db/iunlink.c | 2 +- libxfs/xfs_ialloc.c | 56 +++++++++++++++++++++++++++++++++++---------------- libxfs/xfs_ialloc.h | 2 +- libxfs/xfs_imeta.c | 4 ++-- mkfs/proto.c | 3 +-- repair/phase6.c | 2 +- 6 files changed, 44 insertions(+), 25 deletions(-) diff --git a/db/iunlink.c b/db/iunlink.c index c87b98431e5..fd5ed64c9e2 100644 --- a/db/iunlink.c +++ b/db/iunlink.c @@ -221,7 +221,7 @@ create_unlinked( return error; } - error = -libxfs_dialloc(&tp, 0, args.mode, &ino); + error = -libxfs_dialloc(&tp, args.pip, args.mode, &ino); if (error) { dbprintf(_("alloc inode: %s\n"), strerror(error)); goto out_cancel; diff --git a/libxfs/xfs_ialloc.c b/libxfs/xfs_ialloc.c index 2c941603986..19543f76994 100644 --- a/libxfs/xfs_ialloc.c +++ b/libxfs/xfs_ialloc.c @@ -1794,6 +1794,37 @@ xfs_dialloc_try_ag( return error; } +/* + * Pick an AG for the new inode. + * + * Directories, symlinks, and regular files frequently allocate at least one + * block, so factor that potential expansion when we examine whether an AG has + * enough space for file creation. Try to keep metadata files all in the same + * AG. + */ +static inline xfs_agnumber_t +xfs_dialloc_pick_ag( + struct xfs_mount *mp, + struct xfs_inode *dp, + umode_t mode) +{ + xfs_agnumber_t start_agno; + + if (!dp) + return 0; + if (xfs_is_metadir_inode(dp)) + return 0; + + if (S_ISDIR(mode)) + return (atomic_inc_return(&mp->m_agirotor) - 1) % mp->m_maxagi; + + start_agno = XFS_INO_TO_AGNO(mp, dp->i_ino); + if (start_agno >= mp->m_maxagi) + start_agno = 0; + + return start_agno; +} + /* * Allocate an on-disk inode. * @@ -1805,34 +1836,23 @@ xfs_dialloc_try_ag( int xfs_dialloc( struct xfs_trans **tpp, - xfs_ino_t parent, + struct xfs_inode *dp, umode_t mode, xfs_ino_t *new_ino) { struct xfs_mount *mp = (*tpp)->t_mountp; - xfs_agnumber_t agno; - int error = 0; - xfs_agnumber_t start_agno; struct xfs_perag *pag; struct xfs_ino_geometry *igeo = M_IGEO(mp); + xfs_ino_t ino = NULLFSINO; + xfs_ino_t parent = dp ? dp->i_ino : 0; + xfs_agnumber_t agno; + xfs_agnumber_t start_agno; bool ok_alloc = true; bool low_space = false; int flags; - xfs_ino_t ino = NULLFSINO; + int error = 0; - /* - * Directories, symlinks, and regular files frequently allocate at least - * one block, so factor that potential expansion when we examine whether - * an AG has enough space for file creation. - */ - if (S_ISDIR(mode)) - start_agno = (atomic_inc_return(&mp->m_agirotor) - 1) % - mp->m_maxagi; - else { - start_agno = XFS_INO_TO_AGNO(mp, parent); - if (start_agno >= mp->m_maxagi) - start_agno = 0; - } + start_agno = xfs_dialloc_pick_ag(mp, dp, mode); /* * If we have already hit the ceiling of inode blocks then clear diff --git a/libxfs/xfs_ialloc.h b/libxfs/xfs_ialloc.h index f1412183bb4..9bfe2d8d84b 100644 --- a/libxfs/xfs_ialloc.h +++ b/libxfs/xfs_ialloc.h @@ -37,7 +37,7 @@ xfs_make_iptr(struct xfs_mount *mp, struct xfs_buf *b, int o) * Allocate an inode on disk. Mode is used to tell whether the new inode will * need space, and whether it is a directory. */ -int xfs_dialloc(struct xfs_trans **tpp, xfs_ino_t parent, umode_t mode, +int xfs_dialloc(struct xfs_trans **tpp, struct xfs_inode *dp, umode_t mode, xfs_ino_t *new_ino); int xfs_difree(struct xfs_trans *tp, struct xfs_perag *pag, diff --git a/libxfs/xfs_imeta.c b/libxfs/xfs_imeta.c index b1c5c6ec5e6..2defee9562b 100644 --- a/libxfs/xfs_imeta.c +++ b/libxfs/xfs_imeta.c @@ -229,7 +229,7 @@ xfs_imeta_sb_create( return -EEXIST; /* Create a new inode and set the sb pointer. */ - error = xfs_dialloc(&upd->tp, 0, mode, &ino); + error = xfs_dialloc(&upd->tp, NULL, mode, &ino); if (error) return error; error = xfs_icreate(upd->tp, ino, &args, &upd->ip); @@ -661,7 +661,7 @@ xfs_imeta_dir_create( * entry pointing to them, but a directory also the "." entry * pointing to itself. */ - error = xfs_dialloc(&upd->tp, upd->dp->i_ino, mode, &ino); + error = xfs_dialloc(&upd->tp, upd->dp, mode, &ino); if (error) return error; error = xfs_icreate(upd->tp, ino, &args, &upd->ip); diff --git a/mkfs/proto.c b/mkfs/proto.c index 5e17ea420f4..0103fe54a5d 100644 --- a/mkfs/proto.c +++ b/mkfs/proto.c @@ -431,7 +431,6 @@ creatproto( XFS_ICREATE_ARGS_FORCE_MODE, }; struct xfs_inode *ip; - xfs_ino_t parent_ino = dp ? dp->i_ino : 0; xfs_ino_t ino; int error; @@ -442,7 +441,7 @@ creatproto( * Call the space management code to pick the on-disk inode to be * allocated. */ - error = -libxfs_dialloc(tpp, parent_ino, mode, &ino); + error = -libxfs_dialloc(tpp, dp, mode, &ino); if (error) return error; diff --git a/repair/phase6.c b/repair/phase6.c index 6a3c5e2a37a..fe9a4da62dc 100644 --- a/repair/phase6.c +++ b/repair/phase6.c @@ -870,7 +870,7 @@ mk_orphanage( if (i) res_failed(i); - error = -libxfs_dialloc(&tp, mp->m_sb.sb_rootino, mode, &ino); + error = -libxfs_dialloc(&tp, du.dp, mode, &ino); if (error) do_error(_("%s inode allocation failed %d\n"), ORPHANAGE, error); From patchwork Sun Dec 31 23:34:01 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13508138 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 DDD80C2C5 for ; Sun, 31 Dec 2023 23:34:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="hSHxZvui" Received: by smtp.kernel.org (Postfix) with ESMTPSA id B1359C433C7; Sun, 31 Dec 2023 23:34:01 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704065641; bh=oy0VWtjmvgOgjtInILcKWeLeIiqOffTKc/5EZ2ft2uk=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=hSHxZvuiQXhFLmJkcBDDBkvSTbVN+bEt+y9WrqaZFRIkcboaLBPV0lMGW8xG8ymh8 EwpY4fp9S1VczcPf3jDslDmQ4mDzrtYxapvoxUx0xdjLUOcFZoAN0Z0O0EA4T20H6T XfWuJnCojNv2RuyjZS0zgqp4ayDZcJL54XUQFOusb4BWbEepwt0afDBnf7F/1MohVX BszHwn0vBqLdyZ0QEgjmGJpAVDvVjrglbD1ToRhh9393uyB2UHl5ihDVk+exDcnpui sYpv2kYFynMllBEoYWe/4n4s0kXsIVnwmK1bb8bYt/40QzMzIwXypTd//58Ma+bOcL 5M80W9ByMEqvA== Date: Sun, 31 Dec 2023 15:34:01 -0800 Subject: [PATCH 17/58] xfs: advertise metadata directory feature From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <170405010175.1809361.13950167954596436119.stgit@frogsfrogsfrogs> In-Reply-To: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> References: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Advertise the existence of the metadata directory feature; this will be used by scrub to decide if it needs to scan the metadir too. Signed-off-by: Darrick J. Wong --- libxfs/xfs_fs.h | 1 + libxfs/xfs_sb.c | 2 ++ man/man2/ioctl_xfs_fsgeometry.2 | 3 +++ 3 files changed, 6 insertions(+) diff --git a/libxfs/xfs_fs.h b/libxfs/xfs_fs.h index 77fbca573e1..2e31fc2240e 100644 --- a/libxfs/xfs_fs.h +++ b/libxfs/xfs_fs.h @@ -239,6 +239,7 @@ typedef struct xfs_fsop_resblks { #define XFS_FSOP_GEOM_FLAGS_BIGTIME (1 << 21) /* 64-bit nsec timestamps */ #define XFS_FSOP_GEOM_FLAGS_INOBTCNT (1 << 22) /* inobt btree counter */ #define XFS_FSOP_GEOM_FLAGS_NREXT64 (1 << 23) /* large extent counters */ +#define XFS_FSOP_GEOM_FLAGS_METADIR (1U << 29) /* metadata directories */ #define XFS_FSOP_GEOM_FLAGS_PARENT (1U << 30) /* parent pointers */ /* atomic file extent swap available to userspace */ diff --git a/libxfs/xfs_sb.c b/libxfs/xfs_sb.c index b74a170605d..719da346d36 100644 --- a/libxfs/xfs_sb.c +++ b/libxfs/xfs_sb.c @@ -1296,6 +1296,8 @@ xfs_fs_geometry( geo->flags |= XFS_FSOP_GEOM_FLAGS_NREXT64; if (xfs_atomic_swap_supported(mp)) geo->flags |= XFS_FSOP_GEOM_FLAGS_ATOMIC_SWAP; + if (xfs_has_metadir(mp)) + geo->flags |= XFS_FSOP_GEOM_FLAGS_METADIR; geo->rtsectsize = sbp->sb_blocksize; geo->dirblocksize = xfs_dir2_dirblock_bytes(sbp); diff --git a/man/man2/ioctl_xfs_fsgeometry.2 b/man/man2/ioctl_xfs_fsgeometry.2 index 4c7ff9a270b..9c0ad165cbe 100644 --- a/man/man2/ioctl_xfs_fsgeometry.2 +++ b/man/man2/ioctl_xfs_fsgeometry.2 @@ -214,6 +214,9 @@ Filesystem supports sharing blocks between files. .TP .B XFS_FSOP_GEOM_FLAGS_ATOMICSWAP Filesystem can exchange file contents atomically via XFS_IOC_EXCHANGE_RANGE. +.TP +.B XFS_FSOP_GEOM_FLAGS_METADIR +Filesystem contains a metadata directory tree. .RE .SH XFS METADATA HEALTH REPORTING .PP From patchwork Sun Dec 31 23:34:16 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13508139 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 79F50C2DA for ; Sun, 31 Dec 2023 23:34:17 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="ZYlhMorI" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 4A1EEC433C7; Sun, 31 Dec 2023 23:34:17 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704065657; bh=GTYM4YePpQzaZbIjnxH3IEMv+II+VgzHDRWDDCem6Ko=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=ZYlhMorIGc+Maiq6EWL9q/dY7/m+uKhSaxSx6wkdlJdaALgnSxbCqcggiHQGUDXGX 8/pewYNbtlLP29ABJHfLArcoxSh3FBoSb3enYfD0vO9uBuwkdiyRacycXuewjv2SRs xUFhFO8775bv+3ejBUfiRIMgdRLHg4qQOIFSGnbWYxN4pEHg6Uyo4B7CSh0a5PSSac eRe2fLAnNo/HnP872AEP9mjTgB+M2u9zkIE9B+YoBN/3gs5oianpD27p5Id67DG/e/ Myrs5FkCvVWsVBRrGzeW0vgNfk4fyf//rnMvS+n1dg6zHxdY4zf1PyNYHDuGmfgQ3I 9GW22VbGkxJHw== Date: Sun, 31 Dec 2023 15:34:16 -0800 Subject: [PATCH 18/58] xfs: allow bulkstat to return metadata directories From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <170405010188.1809361.9107414533584480320.stgit@frogsfrogsfrogs> In-Reply-To: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> References: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Allow the V5 bulkstat ioctl to return information about metadata directory files so that xfs_scrub can find and scrub them, since they are otherwise ordinary directories. (Metadata files of course require per-file scrub code and hence do not need exposure.) Signed-off-by: Darrick J. Wong --- libxfs/xfs_fs.h | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/libxfs/xfs_fs.h b/libxfs/xfs_fs.h index 2e31fc2240e..ab961a01181 100644 --- a/libxfs/xfs_fs.h +++ b/libxfs/xfs_fs.h @@ -491,9 +491,17 @@ struct xfs_bulk_ireq { */ #define XFS_BULK_IREQ_NREXT64 (1U << 2) +/* + * Allow bulkstat to return information about metadata directories. This + * enables xfs_scrub to find them for scanning, as they are otherwise ordinary + * directories. + */ +#define XFS_BULK_IREQ_METADIR (1U << 31) + #define XFS_BULK_IREQ_FLAGS_ALL (XFS_BULK_IREQ_AGNO | \ XFS_BULK_IREQ_SPECIAL | \ - XFS_BULK_IREQ_NREXT64) + XFS_BULK_IREQ_NREXT64 | \ + XFS_BULK_IREQ_METADIR) /* Operate on the root directory inode. */ #define XFS_BULK_IREQ_SPECIAL_ROOT (1) From patchwork Sun Dec 31 23:34:32 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13508140 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 6D4CBC2C0 for ; Sun, 31 Dec 2023 23:34:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="I9aHTMlA" Received: by smtp.kernel.org (Postfix) with ESMTPSA id CBA3BC433C7; Sun, 31 Dec 2023 23:34:32 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704065672; bh=TGxSjdfx7zOFwG9Z650fXg96RooMi8rWVUjngu10MMw=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=I9aHTMlAn/1MX4Hk3sjLpBmC2btgW6THPL46iowwaTXJKhi1ETj/YWHRz2mauUsIl TMsoMGFLrDzKmc05T5hrSST23g8jfFPifOa8qfi/h3swHR9Wz9ntsWOOuI0Qq8t+RB XYB/SsOSAaORtbgMQqw0jYII+JwDIenrFJ8iRNW1YpLjRppP57qbKPbl3TGb4OTvzb PQOWhqeiZDMGcU30SGNCuDX2uFe9AlxHFObqoM39GUblNU5GbCGP/iz22ogxboUP5i TMVO5P3ANUAIz6xWj9uuU0xFE+AiHWybpm9VfEdiGFGm9ImU7cYCJOboGNUSdRx0Ki uIue+RtqaQ0vQ== Date: Sun, 31 Dec 2023 15:34:32 -0800 Subject: [PATCH 19/58] xfs: enable creation of dynamically allocated metadir path structures From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <170405010201.1809361.5265276208797149157.stgit@frogsfrogsfrogs> In-Reply-To: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> References: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Add a few helper functions so that it's possible to allocate xfs_imeta_path objects dynamically, along with dynamically allocated path components. Eventually we're going to want to support paths of the form "/realtime/$rtgroup.rmap", and this is necessary for that. Signed-off-by: Darrick J. Wong --- include/kmem.h | 5 ++++- libxfs/libxfs_api_defs.h | 2 ++ libxfs/xfs_imeta.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ libxfs/xfs_imeta.h | 15 +++++++++++++++ 4 files changed, 67 insertions(+), 1 deletion(-) diff --git a/include/kmem.h b/include/kmem.h index 8ae919c7066..c71e311cabc 100644 --- a/include/kmem.h +++ b/include/kmem.h @@ -26,7 +26,7 @@ typedef unsigned int __bitwise gfp_t; #define __GFP_NOFAIL ((__force gfp_t)0) #define __GFP_NOLOCKDEP ((__force gfp_t)0) -#define __GFP_ZERO (__force gfp_t)1 +#define __GFP_ZERO ((__force gfp_t)1) struct kmem_cache * kmem_cache_create(const char *name, unsigned int size, unsigned int align, unsigned int slab_flags, @@ -65,6 +65,9 @@ static inline void *kmalloc(size_t size, gfp_t flags) return kvmalloc(size, flags); } +#define kvcalloc(nr, size, gfp) kvmalloc((nr) * (size), (gfp) | __GFP_ZERO) +#define kzalloc(size, gfp) kvmalloc((size), (gfp) | __GFP_ZERO) + static inline void kfree(const void *ptr) { return kmem_free(ptr); diff --git a/libxfs/libxfs_api_defs.h b/libxfs/libxfs_api_defs.h index e08be764a49..ca8e231c0fd 100644 --- a/libxfs/libxfs_api_defs.h +++ b/libxfs/libxfs_api_defs.h @@ -177,8 +177,10 @@ #define xfs_imeta_cancel_update libxfs_imeta_cancel_update #define xfs_imeta_commit_update libxfs_imeta_commit_update #define xfs_imeta_create libxfs_imeta_create +#define xfs_imeta_create_file_path libxfs_imeta_create_file_path #define xfs_imeta_create_space_res libxfs_imeta_create_space_res #define xfs_imeta_ensure_dirpath libxfs_imeta_ensure_dirpath +#define xfs_imeta_free_path libxfs_imeta_free_path #define xfs_imeta_iget libxfs_imeta_iget #define xfs_imeta_irele libxfs_imeta_irele #define xfs_imeta_link libxfs_imeta_link diff --git a/libxfs/xfs_imeta.c b/libxfs/xfs_imeta.c index 2defee9562b..ad429c82b47 100644 --- a/libxfs/xfs_imeta.c +++ b/libxfs/xfs_imeta.c @@ -1014,3 +1014,49 @@ xfs_imeta_mount( return 0; } + +/* Create a path to a file within the metadata directory tree. */ +int +xfs_imeta_create_file_path( + struct xfs_mount *mp, + unsigned int nr_components, + struct xfs_imeta_path **pathp) +{ + struct xfs_imeta_path *p; + unsigned char **components; + + p = kzalloc(sizeof(struct xfs_imeta_path), GFP_KERNEL); + if (!p) + return -ENOMEM; + + components = kvcalloc(nr_components, sizeof(unsigned char *), + GFP_KERNEL); + if (!components) { + kfree(p); + return -ENOMEM; + } + + p->im_depth = nr_components; + p->im_path = (const unsigned char **)components; + p->im_ftype = XFS_DIR3_FT_REG_FILE; + *pathp = p; + return 0; +} + +/* Free a metadata directory tree path. */ +void +xfs_imeta_free_path( + const struct xfs_imeta_path *path) +{ + unsigned int i; + + if (path->im_flags & XFS_IMETA_PATH_STATIC) + return; + + for (i = 0; i < path->im_depth; i++) { + if ((path->im_dynamicmask & (1ULL << i)) && path->im_path[i]) + kfree(path->im_path[i]); + } + kfree(path->im_path); + kfree(path); +} diff --git a/libxfs/xfs_imeta.h b/libxfs/xfs_imeta.h index b8e360bbdfb..3b5953efc01 100644 --- a/libxfs/xfs_imeta.h +++ b/libxfs/xfs_imeta.h @@ -15,6 +15,8 @@ const struct xfs_imeta_path name = { \ .im_path = (path), \ .im_ftype = XFS_DIR3_FT_REG_FILE, \ .im_depth = ARRAY_SIZE(path), \ + .im_flags = XFS_IMETA_PATH_STATIC, \ + .im_dynamicmask = 0, \ } /* Key for looking up metadata inodes. */ @@ -22,6 +24,12 @@ struct xfs_imeta_path { /* Array of string pointers. */ const unsigned char **im_path; + /* Each bit corresponds to an element of im_path needing to be freed */ + unsigned long long im_dynamicmask; + + /* XFS_IMETA_* path flags */ + uint16_t im_flags; + /* Number of strings in path. */ uint8_t im_depth; @@ -29,6 +37,9 @@ struct xfs_imeta_path { uint8_t im_ftype; }; +/* Path is statically allocated. */ +#define XFS_IMETA_PATH_STATIC (1U << 0) + /* Cleanup widget for metadata inode creation and deletion. */ struct xfs_imeta_update { struct xfs_mount *mp; @@ -72,6 +83,10 @@ int xfs_imeta_lookup(struct xfs_trans *tp, const struct xfs_imeta_path *path, int xfs_imeta_dir_parent(struct xfs_trans *tp, const struct xfs_imeta_path *path, struct xfs_inode **dpp); +int xfs_imeta_create_file_path(struct xfs_mount *mp, + unsigned int nr_components, struct xfs_imeta_path **pathp); +void xfs_imeta_free_path(const struct xfs_imeta_path *path); + void xfs_imeta_set_iflag(struct xfs_trans *tp, struct xfs_inode *ip); void xfs_imeta_clear_iflag(struct xfs_trans *tp, struct xfs_inode *ip); From patchwork Sun Dec 31 23:34:47 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13508141 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 033CBC2D4 for ; Sun, 31 Dec 2023 23:34:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="GfHh+A0e" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 804DDC433C7; Sun, 31 Dec 2023 23:34:48 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704065688; bh=Q7yDz277FkeY2usHqxP+V4UC3ap0PLDgNChcD/xMX/8=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=GfHh+A0eYVepReEPyqLRtlTIheD91icUhn9YbQBLuxr2UOvqfNcQ7Lh/7oydySyR8 CjqLj9qrqOpWjJKcrbMt62XI6DJlPCDaTYmRxMzM2lxT+1C457yCZs3bhlbjWKuJym 9RM3N0am2CmkEuJTKSYDf7d0g8tRghDz/u5nb4JTRo5h/VwK45moYyeXD3vq0/X8bm OghP0JcXiZKSo3Rk7ciGp5KGueF3jwCiYp/iMLvSWxSFkXXu73U53E6RxFsmZTeqXF oaTR6c/+F5A1sRe1T8fNLMgczoZxawBBZXJ1l57k6TUCzd/Dczmc+0X5nmabquMJ6Z IisRyhbMD26Qw== Date: Sun, 31 Dec 2023 15:34:47 -0800 Subject: [PATCH 20/58] xfs: adjust xfs_bmap_add_attrfork for metadir From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <170405010214.1809361.8608139201414860751.stgit@frogsfrogsfrogs> In-Reply-To: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> References: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Online repair might use the xfs_bmap_add_attrfork to repair a file in the metadata directory tree if (say) the metadata file lacks the correct parent pointers. In that case, it is not correct to check that the file is dqattached -- metadata files must be not have /any/ dquot attached at all. Signed-off-by: Darrick J. Wong --- libxfs/xfs_attr.c | 5 ++++- libxfs/xfs_bmap.c | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/libxfs/xfs_attr.c b/libxfs/xfs_attr.c index 5da0ac9f706..aa391f4bae5 100644 --- a/libxfs/xfs_attr.c +++ b/libxfs/xfs_attr.c @@ -944,7 +944,10 @@ xfs_attr_add_fork( unsigned int blks; /* space reservation */ int error; /* error return value */ - ASSERT(!XFS_NOT_DQATTACHED(mp, ip)); + if (xfs_is_metadir_inode(ip)) + ASSERT(XFS_IS_DQDETACHED(ip->i_mount, ip)); + else + ASSERT(!XFS_NOT_DQATTACHED(mp, ip)); blks = XFS_ADDAFORK_SPACE_RES(mp); diff --git a/libxfs/xfs_bmap.c b/libxfs/xfs_bmap.c index ed50bb90e6a..0dfb37073a7 100644 --- a/libxfs/xfs_bmap.c +++ b/libxfs/xfs_bmap.c @@ -1018,7 +1018,10 @@ xfs_bmap_add_attrfork( int error; /* error return value */ ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); - ASSERT(!XFS_NOT_DQATTACHED(mp, ip)); + if (xfs_is_metadir_inode(ip)) + ASSERT(XFS_IS_DQDETACHED(ip->i_mount, ip)); + else + ASSERT(!XFS_NOT_DQATTACHED(mp, ip)); ASSERT(!xfs_inode_has_attr_fork(ip)); xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); From patchwork Sun Dec 31 23:35:03 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13508142 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 628A9C2CC for ; Sun, 31 Dec 2023 23:35:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Buw87/AQ" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 2C7F1C433C8; Sun, 31 Dec 2023 23:35:04 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704065704; bh=ByptrlMGc6Zq405DrCdniI3nU9mv1SqnUV2VRQyxQnI=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=Buw87/AQWshCZ0ofhCCFzagpjrTijLPl0qIP8Nrj6O1EMNvroTMYgNTiemzOYGkiV rvHfXjj9/KoRXCjrfBIkS+dLy/v9Yp7A2N0hUM+RPEzJVQXRYQ1PQNG5Sm3uOCO3Om JUSCypWLWrPco2FWj29xqqLjCpFJaKUfwbQkF7D6dRvxEDffN1KaA5saGT4ks7upO4 zbDuV5WA7xFfda8cThH4xAQS8KmGTT5wfS8ivwnnVW76zBdX5uKDFq1wEvQJD1vIk+ 59kZJes/LIyTU44qKjb8tXgP/pGoNw/Bh3cgNyTwyELIWaaLz4LyJOzBTe324tQVIE mRQGsM3q7WRHw== Date: Sun, 31 Dec 2023 15:35:03 -0800 Subject: [PATCH 21/58] xfs: record health problems with the metadata directory From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <170405010227.1809361.12610565692089952318.stgit@frogsfrogsfrogs> In-Reply-To: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> References: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Make a report to the health monitoring subsystem any time we encounter something in the metadata directory tree that looks like corruption. Signed-off-by: Darrick J. Wong --- libxfs/imeta_utils.c | 5 ++++- libxfs/xfs_fs.h | 1 + libxfs/xfs_health.h | 4 +++- libxfs/xfs_imeta.c | 24 +++++++++++++++++++----- 4 files changed, 27 insertions(+), 7 deletions(-) diff --git a/libxfs/imeta_utils.c b/libxfs/imeta_utils.c index 0186968ed3e..3b6e891d2a6 100644 --- a/libxfs/imeta_utils.c +++ b/libxfs/imeta_utils.c @@ -21,6 +21,7 @@ #include "xfs_imeta.h" #include "xfs_trace.h" #include "xfs_parent.h" +#include "xfs_health.h" #include "imeta_utils.h" /* Initialize a metadata update structure. */ @@ -51,8 +52,10 @@ xfs_imeta_init( return error; error = xfs_imeta_dir_parent(tp, upd->path, &upd->dp); xfs_trans_cancel(tp); - if (error == -ENOENT) + if (error == -ENOENT) { + xfs_fs_mark_sick(mp, XFS_SICK_FS_METADIR); return -EFSCORRUPTED; + } if (error) return error; diff --git a/libxfs/xfs_fs.h b/libxfs/xfs_fs.h index ab961a01181..952e4fc93c4 100644 --- a/libxfs/xfs_fs.h +++ b/libxfs/xfs_fs.h @@ -197,6 +197,7 @@ struct xfs_fsop_geom { #define XFS_FSOP_GEOM_SICK_RT_SUMMARY (1 << 5) /* realtime summary */ #define XFS_FSOP_GEOM_SICK_QUOTACHECK (1 << 6) /* quota counts */ #define XFS_FSOP_GEOM_SICK_NLINKS (1 << 7) /* inode link counts */ +#define XFS_FSOP_GEOM_SICK_METADIR (1 << 8) /* metadata directory */ /* Output for XFS_FS_COUNTS */ typedef struct xfs_fsop_counts { diff --git a/libxfs/xfs_health.h b/libxfs/xfs_health.h index bca1990f71d..d9b9968607f 100644 --- a/libxfs/xfs_health.h +++ b/libxfs/xfs_health.h @@ -60,6 +60,7 @@ struct xfs_da_args; #define XFS_SICK_FS_PQUOTA (1 << 3) /* project quota */ #define XFS_SICK_FS_QUOTACHECK (1 << 4) /* quota counts */ #define XFS_SICK_FS_NLINKS (1 << 5) /* inode link counts */ +#define XFS_SICK_FS_METADIR (1 << 6) /* metadata directory tree */ /* Observable health issues for realtime volume metadata. */ #define XFS_SICK_RT_BITMAP (1 << 0) /* realtime bitmap */ @@ -103,7 +104,8 @@ struct xfs_da_args; XFS_SICK_FS_GQUOTA | \ XFS_SICK_FS_PQUOTA | \ XFS_SICK_FS_QUOTACHECK | \ - XFS_SICK_FS_NLINKS) + XFS_SICK_FS_NLINKS | \ + XFS_SICK_FS_METADIR) #define XFS_SICK_RT_PRIMARY (XFS_SICK_RT_BITMAP | \ XFS_SICK_RT_SUMMARY) diff --git a/libxfs/xfs_imeta.c b/libxfs/xfs_imeta.c index ad429c82b47..6ada36d5559 100644 --- a/libxfs/xfs_imeta.c +++ b/libxfs/xfs_imeta.c @@ -25,6 +25,7 @@ #include "xfs_ag.h" #include "xfs_dir2.h" #include "xfs_dir2_priv.h" +#include "xfs_health.h" /* * Metadata File Management @@ -405,16 +406,22 @@ xfs_imeta_dir_lookup_component( int type_wanted = xname->type; int error; - if (!S_ISDIR(VFS_I(dp)->i_mode)) + if (!S_ISDIR(VFS_I(dp)->i_mode)) { + xfs_fs_mark_sick(dp->i_mount, XFS_SICK_FS_METADIR); return -EFSCORRUPTED; + } error = xfs_imeta_dir_lookup(tp, dp, xname, ino); if (error) return error; - if (!xfs_verify_ino(dp->i_mount, *ino)) + if (!xfs_verify_ino(dp->i_mount, *ino)) { + xfs_fs_mark_sick(dp->i_mount, XFS_SICK_FS_METADIR); return -EFSCORRUPTED; - if (type_wanted != XFS_DIR3_FT_UNKNOWN && xname->type != type_wanted) + } + if (type_wanted != XFS_DIR3_FT_UNKNOWN && xname->type != type_wanted) { + xfs_fs_mark_sick(dp->i_mount, XFS_SICK_FS_METADIR); return -EFSCORRUPTED; + } trace_xfs_imeta_dir_lookup(dp, xname, *ino); return 0; @@ -728,6 +735,7 @@ xfs_imeta_dir_unlink( /* Metadata directory root cannot be unlinked. */ if (xfs_imeta_path_compare(upd->path, &XFS_IMETA_METADIR)) { ASSERT(0); + xfs_fs_mark_sick(mp, XFS_SICK_FS_METADIR); return -EFSCORRUPTED; } @@ -743,6 +751,7 @@ xfs_imeta_dir_unlink( error = -ENOENT; break; case -ENOENT: + xfs_fs_mark_sick(mp, XFS_SICK_FS_METADIR); error = -EFSCORRUPTED; break; } @@ -787,6 +796,7 @@ xfs_imeta_dir_link( /* Metadata directory root cannot be linked. */ if (xfs_imeta_path_compare(upd->path, &XFS_IMETA_METADIR)) { ASSERT(0); + xfs_fs_mark_sick(mp, XFS_SICK_FS_METADIR); return -EFSCORRUPTED; } @@ -852,16 +862,20 @@ xfs_imeta_lookup( if (xfs_has_metadir(mp)) { error = xfs_imeta_dir_lookup_int(tp, path, &ino); - if (error == -ENOENT) + if (error == -ENOENT) { + xfs_fs_mark_sick(mp, XFS_SICK_FS_METADIR); return -EFSCORRUPTED; + } } else { error = xfs_imeta_sb_lookup(mp, path, &ino); } if (error) return error; - if (!xfs_imeta_verify(mp, ino)) + if (!xfs_imeta_verify(mp, ino)) { + xfs_fs_mark_sick(mp, XFS_SICK_FS_METADIR); return -EFSCORRUPTED; + } *inop = ino; return 0; From patchwork Sun Dec 31 23:35:19 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13508143 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 F3AECC2C5 for ; Sun, 31 Dec 2023 23:35:19 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="huSzE6/z" Received: by smtp.kernel.org (Postfix) with ESMTPSA id C2036C433C8; Sun, 31 Dec 2023 23:35:19 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704065719; bh=XflgPEAVTZMN3uTiFG6K9VuwjZ8mAV3dvhHyYOt7B3c=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=huSzE6/zzXq96TGqyVf3X3aFtvpQCNYikC8sUmQ5ohXHCzq4R/LuRJRGPl/rjZ8q8 kjnnOu3IWc1BF7pfdicVo8ze5eKuPan1zKFSH9bpM7XEcAGQpBi10HwSDmgSZx1gd0 mhqUK1Um31C3irCf9l0KxqQCNKZkgCO7t+6PE7fRd2DrltZxxHJt5PoIPdCsH4R132 DAKpVaGLadolJKhvmTmuI1bLE/BpkX+LY/HRA+PiZEVSYwEnRDf+bw6Ej8bzwOSoY4 PXM6VuJaTlPXKmjBIUoMq4DwkRELmmO7kOAky9yMNTsmBEPgDTkPJQEYiZduxRAdQa vPrO9BfZpm7TQ== Date: Sun, 31 Dec 2023 15:35:19 -0800 Subject: [PATCH 22/58] xfs: check metadata directory file path connectivity From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <170405010241.1809361.1551820119699455070.stgit@frogsfrogsfrogs> In-Reply-To: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> References: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Create a new scrubber type that checks that well known metadata directory paths are connected to the metadata inode that the incore structures think is in use. IOWs, check that "/quota/user" in the metadata directory tree actually points to mp->m_quotainfo->qi_uquotaip->i_ino. Signed-off-by: Darrick J. Wong --- libxfs/xfs_fs.h | 17 +++++++++++++++- libxfs/xfs_health.h | 4 +++- man/man2/ioctl_xfs_scrub_metadata.2 | 38 +++++++++++++++++++++++++++++++++++ 3 files changed, 57 insertions(+), 2 deletions(-) diff --git a/libxfs/xfs_fs.h b/libxfs/xfs_fs.h index 952e4fc93c4..a0efcbde5ae 100644 --- a/libxfs/xfs_fs.h +++ b/libxfs/xfs_fs.h @@ -198,6 +198,7 @@ struct xfs_fsop_geom { #define XFS_FSOP_GEOM_SICK_QUOTACHECK (1 << 6) /* quota counts */ #define XFS_FSOP_GEOM_SICK_NLINKS (1 << 7) /* inode link counts */ #define XFS_FSOP_GEOM_SICK_METADIR (1 << 8) /* metadata directory */ +#define XFS_FSOP_GEOM_SICK_METAPATH (1 << 9) /* metadir tree path */ /* Output for XFS_FS_COUNTS */ typedef struct xfs_fsop_counts { @@ -731,9 +732,10 @@ struct xfs_scrub_metadata { #define XFS_SCRUB_TYPE_NLINKS 26 /* inode link counts */ #define XFS_SCRUB_TYPE_HEALTHY 27 /* everything checked out ok */ #define XFS_SCRUB_TYPE_DIRTREE 28 /* directory tree structure */ +#define XFS_SCRUB_TYPE_METAPATH 29 /* metadata directory tree paths */ /* Number of scrub subcommands. */ -#define XFS_SCRUB_TYPE_NR 29 +#define XFS_SCRUB_TYPE_NR 30 /* * This special type code only applies to the vectored scrub implementation. @@ -788,6 +790,19 @@ struct xfs_scrub_metadata { XFS_SCRUB_OFLAG_NO_REPAIR_NEEDED) #define XFS_SCRUB_FLAGS_ALL (XFS_SCRUB_FLAGS_IN | XFS_SCRUB_FLAGS_OUT) +/* + * i: sm_ino values for XFS_SCRUB_TYPE_METAPATH to select a metadata file for + * path checking. + */ +#define XFS_SCRUB_METAPATH_RTBITMAP 0 +#define XFS_SCRUB_METAPATH_RTSUMMARY 1 +#define XFS_SCRUB_METAPATH_USRQUOTA 2 +#define XFS_SCRUB_METAPATH_GRPQUOTA 3 +#define XFS_SCRUB_METAPATH_PRJQUOTA 4 + +/* Number of metapath sm_ino values */ +#define XFS_SCRUB_METAPATH_NR 5 + /* * ioctl limits */ diff --git a/libxfs/xfs_health.h b/libxfs/xfs_health.h index d9b9968607f..1816c67351a 100644 --- a/libxfs/xfs_health.h +++ b/libxfs/xfs_health.h @@ -61,6 +61,7 @@ struct xfs_da_args; #define XFS_SICK_FS_QUOTACHECK (1 << 4) /* quota counts */ #define XFS_SICK_FS_NLINKS (1 << 5) /* inode link counts */ #define XFS_SICK_FS_METADIR (1 << 6) /* metadata directory tree */ +#define XFS_SICK_FS_METAPATH (1 << 7) /* metadata directory tree path */ /* Observable health issues for realtime volume metadata. */ #define XFS_SICK_RT_BITMAP (1 << 0) /* realtime bitmap */ @@ -105,7 +106,8 @@ struct xfs_da_args; XFS_SICK_FS_PQUOTA | \ XFS_SICK_FS_QUOTACHECK | \ XFS_SICK_FS_NLINKS | \ - XFS_SICK_FS_METADIR) + XFS_SICK_FS_METADIR | \ + XFS_SICK_FS_METAPATH) #define XFS_SICK_RT_PRIMARY (XFS_SICK_RT_BITMAP | \ XFS_SICK_RT_SUMMARY) diff --git a/man/man2/ioctl_xfs_scrub_metadata.2 b/man/man2/ioctl_xfs_scrub_metadata.2 index 44aa139b297..b1db740560d 100644 --- a/man/man2/ioctl_xfs_scrub_metadata.2 +++ b/man/man2/ioctl_xfs_scrub_metadata.2 @@ -200,6 +200,44 @@ Scan all inodes in the filesystem to verify each file's link count. Mark everything healthy after a clean scrub run. This clears out all the indirect health problem markers that might remain in the system. + +.TP +.B XFS_SCRUB_TYPE_METAPATH +Check that a metadata directory path actually points to the active metadata +inode. +Metadata inodes are usually cached for the duration of the mount, so this +scrubber ensures that the same inode will still be reachable after an unmount +and mount cycle. +Discrepancies can happen if the directory or parent pointer scrubbers rebuild +a metadata directory but lose a link in the process. +The +.B sm_ino +field should be passed one of the following special values to communicate which +path to check: + +.RS 7 +.TP +.B XFS_SCRUB_METAPATH_RTBITMAP +Realtime bitmap file. +.TP +.B XFS_SCRUB_METAPATH_RTSUMMARY +Realtime summary file. +.TP +.B XFS_SCRUB_METAPATH_USRQUOTA +User quota file. +.TP +.B XFS_SCRUB_METAPATH_GRPQUOTA +Group quota file. +.TP +.B XFS_SCRUB_METAPATH_PRJQUOTA +Project quota file. +.RE + +The values of +.I sm_agno +and +.I sm_gen +must be zero. .RE .PD 1 From patchwork Sun Dec 31 23:35:34 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13508144 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 CEF26C2C0 for ; Sun, 31 Dec 2023 23:35:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="mTaTytir" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 5D2D1C433C7; Sun, 31 Dec 2023 23:35:35 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704065735; bh=3DT7IoWfIRhiyFfPAgoW7O41WYRFKeirmoIb3shkogA=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=mTaTytirWbnPA23jVssYjuwIRXstDe/Z3cYECt6jQc7so4nWlflSa0I72j6fkyem3 q/IMKNjCai3tcpQsaGDNGkuK5h57gird+g0Hi+P6vy9jcC9pxLBoG9dDN5GCztJLrK N1CIEkGnbyaSRHszRC4A8qnM2JAgr/jcCEowVe68gD9vuJjg3ajQFDPOhK4IeC5Ro/ sIWm76PbBYvD5BXGBdun7lqLYoQxHaRzdEU/xbJVypm9IRVDc1nQj5BKMKG3Kw4Em9 slXSq599Z+7OfB+QfFDdOyb9eyjf4OxTFY3FZQ52OpDp7aRIhzwN7Jkoe4za87Nmb3 Fk14cuMcgPAUQ== Date: Sun, 31 Dec 2023 15:35:34 -0800 Subject: [PATCH 23/58] libfrog: report metadata directories in the geometry report From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <170405010254.1809361.9550201092255962244.stgit@frogsfrogsfrogs> In-Reply-To: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> References: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Report the presence of a metadata directory tree in the geometry report. Signed-off-by: Darrick J. Wong --- libfrog/fsgeom.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libfrog/fsgeom.c b/libfrog/fsgeom.c index 061995fa2c7..e2732fb7a09 100644 --- a/libfrog/fsgeom.c +++ b/libfrog/fsgeom.c @@ -32,6 +32,7 @@ xfs_report_geom( int inobtcount; int nrext64; int parent; + int metadir; isint = geo->logstart > 0; lazycount = geo->flags & XFS_FSOP_GEOM_FLAGS_LAZYSB ? 1 : 0; @@ -51,12 +52,14 @@ xfs_report_geom( inobtcount = geo->flags & XFS_FSOP_GEOM_FLAGS_INOBTCNT ? 1 : 0; nrext64 = geo->flags & XFS_FSOP_GEOM_FLAGS_NREXT64 ? 1 : 0; parent = geo->flags & XFS_FSOP_GEOM_FLAGS_PARENT ? 1 : 0; + metadir = geo->flags & XFS_FSOP_GEOM_FLAGS_METADIR ? 1 : 0; printf(_( "meta-data=%-22s isize=%-6d agcount=%u, agsize=%u blks\n" " =%-22s sectsz=%-5u attr=%u, projid32bit=%u\n" " =%-22s crc=%-8u finobt=%u, sparse=%u, rmapbt=%u\n" " =%-22s reflink=%-4u bigtime=%u inobtcount=%u nrext64=%u\n" +" =%-22s metadir=%u\n" "data =%-22s bsize=%-6u blocks=%llu, imaxpct=%u\n" " =%-22s sunit=%-6u swidth=%u blks\n" "naming =version %-14u bsize=%-6u ascii-ci=%d, ftype=%d, parent=%d\n" @@ -67,6 +70,7 @@ xfs_report_geom( "", geo->sectsize, attrversion, projid32bit, "", crcs_enabled, finobt_enabled, spinodes, rmapbt_enabled, "", reflink_enabled, bigtime_enabled, inobtcount, nrext64, + "", metadir, "", geo->blocksize, (unsigned long long)geo->datablocks, geo->imaxpct, "", geo->sunit, geo->swidth, From patchwork Sun Dec 31 23:35:50 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13508145 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 6BC1CC2C0 for ; Sun, 31 Dec 2023 23:35:51 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="uDBNOSp3" Received: by smtp.kernel.org (Postfix) with ESMTPSA id EFA2BC433C8; Sun, 31 Dec 2023 23:35:50 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704065751; bh=VLEEEL+brq0fY1eCPkIo4kRZkUZRogQKkxQjxhhir+c=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=uDBNOSp3JOzWYEIt0e3LhztmAIRFFoRppEaJO23TqgnhF3rN/NymYXkMQyXh/0cVl AXKO995tpMDQ/6oU9bmgFDEUeNKcX7O9zOyz+6hLdolN5Ou4LcpQ+bFhpkITHvvlgn OEsLmjQM8W8HJIyj1LDHdQQIqkrPgC6mi8xGTVxOXdVi/TpETmmYZLKQOKY8/0hp+c /Q1pI5T67oj5gjDGYY86kAM0ayfhTSXtxtVEnR9Gy7NRZrNJPrNk5gSUAI/76XeTQW cRBI7Lsa+dWCF2e9ma7oMJVuvbAF8fMW9GR63+QLsLkMBhQoaNqmWhEKdAYuE9zzcf mV0lgMnQsZNKw== Date: Sun, 31 Dec 2023 15:35:50 -0800 Subject: [PATCH 24/58] libfrog: allow METADIR in xfrog_bulkstat_single5 From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <170405010267.1809361.12271360880102247710.stgit@frogsfrogsfrogs> In-Reply-To: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> References: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong This is a valid flag for a single-file bulkstat, so add that to the filter. Signed-off-by: Darrick J. Wong --- libfrog/bulkstat.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libfrog/bulkstat.c b/libfrog/bulkstat.c index c863bcb6bf8..6eceef2a8fa 100644 --- a/libfrog/bulkstat.c +++ b/libfrog/bulkstat.c @@ -53,7 +53,8 @@ xfrog_bulkstat_single5( struct xfs_bulkstat_req *req; int ret; - if (flags & ~(XFS_BULK_IREQ_SPECIAL | XFS_BULK_IREQ_NREXT64)) + if (flags & ~(XFS_BULK_IREQ_SPECIAL | XFS_BULK_IREQ_NREXT64 | + XFS_BULK_IREQ_METADIR)) return -EINVAL; if (xfd->fsgeom.flags & XFS_FSOP_GEOM_FLAGS_NREXT64) From patchwork Sun Dec 31 23:36:06 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13508146 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 CB7D7C2C5 for ; Sun, 31 Dec 2023 23:36:06 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="iPi/NYs3" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 9904AC433C7; Sun, 31 Dec 2023 23:36:06 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704065766; bh=pGv8pJqxaIkvagYKFnvYntaJOiEE8SmNEHZMQUksg+s=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=iPi/NYs3vo7ebhh0EuxLctDU6Rg0RJ24PiYM3vqkIFFF/MQIjLtexlRSUAB3KTfzj LZIyFvGs6Q8/C583EaRB68XYiEM59d0GAdLDJ839rmNgCR1SLIuyBm5fTLv0LMGnUv jDmD2SG3LuZqTtSwu3JY/ehGTu7KhIUUP/rhWdWOc0n7Azivv6krK7V4Qpbcam/z56 2FMw6dFJThTIm+ATC3PsmY59ys4bVIVYQR8NKXyZOEn6U9KRYskUdY6eIgcaNEhio6 Bn6KBIulx4kgZeF5MeKX64B+O9BQS+LBYqgj+3knmCp41tvJ0bE+jWWT3/XrpLQeHM 0pqto+PisQ5hw== Date: Sun, 31 Dec 2023 15:36:06 -0800 Subject: [PATCH 25/58] xfs_io: support scrubbing metadata directory paths From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <170405010281.1809361.10040112335448075566.stgit@frogsfrogsfrogs> In-Reply-To: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> References: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 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 invoking the metadata directory path scrubber from xfs_io for testing. Signed-off-by: Darrick J. Wong --- libfrog/scrub.c | 34 +++++++++++++++++++++++++++++++++- libfrog/scrub.h | 2 ++ scrub/scrub.c | 18 ++++++++++++++++++ 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/libfrog/scrub.c b/libfrog/scrub.c index 8264aab00ef..f48bb1a0d2b 100644 --- a/libfrog/scrub.c +++ b/libfrog/scrub.c @@ -154,8 +154,40 @@ const struct xfrog_scrub_descr xfrog_scrubbers[XFS_SCRUB_TYPE_NR] = { .descr = "directory tree structure", .group = XFROG_SCRUB_GROUP_INODE, }, + [XFS_SCRUB_TYPE_METAPATH] = { + .name = "metapath", + .descr = "metadata directory paths", + .group = XFROG_SCRUB_GROUP_METAPATH, + }, +}; + +const struct xfrog_scrub_descr xfrog_metapaths[XFS_SCRUB_METAPATH_NR] = { + [XFS_SCRUB_METAPATH_RTBITMAP] = { + .name = "rtbitmap", + .descr = "realtime bitmap metadir path", + .group = XFROG_SCRUB_GROUP_FS, + }, + [XFS_SCRUB_METAPATH_RTSUMMARY] = { + .name = "rtsummary", + .descr = "realtime summary metadir path", + .group = XFROG_SCRUB_GROUP_FS, + }, + [XFS_SCRUB_METAPATH_USRQUOTA] = { + .name = "usrquota", + .descr = "user quota metadir path", + .group = XFROG_SCRUB_GROUP_FS, + }, + [XFS_SCRUB_METAPATH_GRPQUOTA] = { + .name = "grpquota", + .descr = "group quota metadir path", + .group = XFROG_SCRUB_GROUP_FS, + }, + [XFS_SCRUB_METAPATH_PRJQUOTA] = { + .name = "prjquota", + .descr = "project quota metadir path", + .group = XFROG_SCRUB_GROUP_FS, + }, }; -#undef DEP /* Invoke the scrub ioctl. Returns zero or negative error code. */ int diff --git a/libfrog/scrub.h b/libfrog/scrub.h index 43456230479..5fa0fafef56 100644 --- a/libfrog/scrub.h +++ b/libfrog/scrub.h @@ -15,6 +15,7 @@ enum xfrog_scrub_group { XFROG_SCRUB_GROUP_INODE, /* per-inode metadata */ XFROG_SCRUB_GROUP_ISCAN, /* metadata requiring full inode scan */ XFROG_SCRUB_GROUP_SUMMARY, /* summary metadata */ + XFROG_SCRUB_GROUP_METAPATH, /* metadata directory path */ }; /* Catalog of scrub types and names, indexed by XFS_SCRUB_TYPE_* */ @@ -25,6 +26,7 @@ struct xfrog_scrub_descr { }; extern const struct xfrog_scrub_descr xfrog_scrubbers[XFS_SCRUB_TYPE_NR]; +extern const struct xfrog_scrub_descr xfrog_metapaths[XFS_SCRUB_METAPATH_NR]; int xfrog_scrub_metadata(struct xfs_fd *xfd, struct xfs_scrub_metadata *meta); diff --git a/scrub/scrub.c b/scrub/scrub.c index 2ec3cbc9aac..bad1384dcfb 100644 --- a/scrub/scrub.c +++ b/scrub/scrub.c @@ -53,6 +53,22 @@ static const unsigned int scrub_deps[XFS_SCRUB_TYPE_NR] = { }; #undef DEP +static int +format_metapath_descr( + char *buf, + size_t buflen, + struct xfs_scrub_vec_head *vhead) +{ + const struct xfrog_scrub_descr *sc; + + if (vhead->svh_ino >= XFS_SCRUB_METAPATH_NR) + return snprintf(buf, buflen, _("unknown metadir path %llu"), + (unsigned long long)vhead->svh_ino); + + sc = &xfrog_metapaths[vhead->svh_ino]; + return snprintf(buf, buflen, "%s", _(sc->descr)); +} + /* Describe the current state of a vectored scrub. */ int format_scrubv_descr( @@ -80,6 +96,8 @@ format_scrubv_descr( case XFROG_SCRUB_GROUP_ISCAN: case XFROG_SCRUB_GROUP_NONE: return snprintf(buf, buflen, _("%s"), _(sc->descr)); + case XFROG_SCRUB_GROUP_METAPATH: + return format_metapath_descr(buf, buflen, vhead); } return -1; } From patchwork Sun Dec 31 23:36:21 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13508147 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 D42A9C2C0 for ; Sun, 31 Dec 2023 23:36:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="bN+AK5p7" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 4B6CEC433C8; Sun, 31 Dec 2023 23:36:22 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704065782; bh=tBvnMlYmcEEjkeIgXJLgjQWp/CO/n5qW60eFb7tEdeE=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=bN+AK5p7W/GlDv+3jewLrHBc+ozTqvQ5D5V7d2uGM87gU3KEM9e3guR6HTRHFKtHC 5zFBvqKmIXniF6qg6dfySRVCfeD+CdhYREzewt53Qq5ipwtOWFs6BWqMOIr3nRNq92 6Rkda5wFRl1pXKceTRT7JCNSdq2JzIdUFTHdxLlzscRWdtzgrJRXJsTQMdDhryQsrn BS1sEIALcS4aOY2c4n0nkBkvLwa3abFukRlcnjJ0xVLbkM8Rpi6Pb3V+Ue8z3wcVf+ uQ9cpAeRyeZQcPbtF1LBrgmTPWZI1Zti5lLf7ZqZDa9gjZ9iBHnWcskXdUec0/2QV1 0tfidGaZWK/kw== Date: Sun, 31 Dec 2023 15:36:21 -0800 Subject: [PATCH 26/58] xfs_db: basic xfs_check support for metadir From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <170405010294.1809361.16491233404708859058.stgit@frogsfrogsfrogs> In-Reply-To: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> References: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 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 metadata directories in xfs_check. Signed-off-by: Darrick J. Wong --- db/check.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/db/check.c b/db/check.c index 2f2fbc7cbd8..ae527471161 100644 --- a/db/check.c +++ b/db/check.c @@ -2663,7 +2663,9 @@ process_dir( if (!sflag || id->ilist || CHECK_BLIST(bno)) dbprintf(_("no .. entry for directory %lld\n"), id->ino); error++; - } else if (parent == id->ino && id->ino != mp->m_sb.sb_rootino) { + } else if (parent == id->ino && + id->ino != mp->m_sb.sb_rootino && + id->ino != mp->m_sb.sb_metadirino) { if (!sflag || id->ilist || CHECK_BLIST(bno)) dbprintf(_(". and .. same for non-root directory %lld\n"), id->ino); @@ -2673,6 +2675,11 @@ process_dir( dbprintf(_("root directory %lld has .. %lld\n"), id->ino, parent); error++; + } else if (id->ino == mp->m_sb.sb_metadirino && id->ino != parent) { + if (!sflag || id->ilist || CHECK_BLIST(bno)) + dbprintf(_("metadata directory %lld has .. %lld\n"), + id->ino, parent); + error++; } else if (parent != NULLFSINO && id->ino != parent) addparent_inode(id, parent); } @@ -2916,6 +2923,9 @@ process_inode( type = DBM_DIR; if (dip->di_format == XFS_DINODE_FMT_LOCAL) break; + if (xfs_has_metadir(mp) && + id->ino == mp->m_sb.sb_metadirino) + addlink_inode(id); blkmap = blkmap_alloc(dnextents); break; case S_IFREG: @@ -2924,18 +2934,21 @@ process_inode( else if (id->ino == mp->m_sb.sb_rbmino) { type = DBM_RTBITMAP; blkmap = blkmap_alloc(dnextents); - addlink_inode(id); + if (!xfs_has_metadir(mp)) + addlink_inode(id); } else if (id->ino == mp->m_sb.sb_rsumino) { type = DBM_RTSUM; blkmap = blkmap_alloc(dnextents); - addlink_inode(id); + if (!xfs_has_metadir(mp)) + addlink_inode(id); } else if (id->ino == mp->m_sb.sb_uquotino || id->ino == mp->m_sb.sb_gquotino || id->ino == mp->m_sb.sb_pquotino) { type = DBM_QUOTA; blkmap = blkmap_alloc(dnextents); - addlink_inode(id); + if (!xfs_has_metadir(mp)) + addlink_inode(id); } else type = DBM_DATA; From patchwork Sun Dec 31 23:36:37 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13508148 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 2E630C2C5 for ; Sun, 31 Dec 2023 23:36:38 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="pCSkAE+W" Received: by smtp.kernel.org (Postfix) with ESMTPSA id F2785C433C7; Sun, 31 Dec 2023 23:36:37 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704065798; bh=tF7oXD00Ys8KmbxmC+AUFOlBCaIkdmk10h0iJ9sCOOc=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=pCSkAE+Wiu/jaWdxtkE5V0t9F/DwcM7kfju5fQMRA7AZm08dqkTrr8PsxYhCIB/+5 66gXincPdrlvYvPBG7sNreFF9a3fcWJbUwW+AdlreJ4e0j01tfgArMKYMutuZI+Ce2 UfpONVdn0V7dKl+e5Na4tJjROf7W1HiKb7Dj0GEsB69OCjG+SIY///banXc+uGR04Y v+l9CT0ZFFMavt3Th3xNQu+EchoFE7qxNg1TJkTX5MKQfWNbxlysqzZqBqgxiKKbV3 GufoiIf6LEJqHkbfbgyt6bwZb3czzlU/M3N5qvchOKLgTmfoYJtKprZRn2eEBfsUok KfOMqK9vCPqkg== Date: Sun, 31 Dec 2023 15:36:37 -0800 Subject: [PATCH 27/58] xfs_db: report metadir support for version command From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <170405010308.1809361.1415783380543629932.stgit@frogsfrogsfrogs> In-Reply-To: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> References: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Report metadir support if we have it enabled. Signed-off-by: Darrick J. Wong --- db/inode.c | 3 +++ db/sb.c | 2 ++ 2 files changed, 5 insertions(+) diff --git a/db/inode.c b/db/inode.c index c9b506b905d..4e2be6a1156 100644 --- a/db/inode.c +++ b/db/inode.c @@ -207,6 +207,9 @@ const field_t inode_v3_flds[] = { { "nrext64", FLDT_UINT1, OI(COFF(flags2) + bitsz(uint64_t) - XFS_DIFLAG2_NREXT64_BIT - 1), C1, 0, TYP_NONE }, + { "metadir", FLDT_UINT1, + OI(COFF(flags2) + bitsz(uint64_t) - XFS_DIFLAG2_METADIR_BIT-1), C1, + 0, TYP_NONE }, { NULL } }; diff --git a/db/sb.c b/db/sb.c index e738065b5be..002736b02b7 100644 --- a/db/sb.c +++ b/db/sb.c @@ -708,6 +708,8 @@ version_string( strcat(s, ",NREXT64"); if (xfs_has_parent(mp)) strcat(s, ",PARENT"); + if (xfs_has_metadir(mp)) + strcat(s, ",METADIR"); return s; } From patchwork Sun Dec 31 23:36:53 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13508149 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 D201DC2C5 for ; Sun, 31 Dec 2023 23:36:53 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="sRlR5Cno" Received: by smtp.kernel.org (Postfix) with ESMTPSA id A3B26C433C7; Sun, 31 Dec 2023 23:36:53 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704065813; bh=FgxN001mOTmk+AxBT61V344SXu/FkvWCV2TW9r9au2I=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=sRlR5CnovjWK/WCPi+BBtMKNQMDfytlusvrFTv+fnf07CvZWc3LZ+YzwZbAoqGgyi opM8nh6fB5sESGFOdlR+VXVPnrF+c7jw+TuYor5VFzE3bERWZG/P0DUIIPwv47zcVh D6ovsKX/lHAi+Atxk/GxKb87oDFpVV7PXg8cVRwP3HzRLIpzyu7zXpDRagKRUk0+fj 6/yo8TsfHATZcBPxy8+MIOsxhaKY9JNHc7QX+/sGU/iColiyJFTK0TLy1HFjN6PuFk YSHeKuR36E2ovG/lEvNgprWIBzRA1XDD3ALtWIbcW2GlBm105V7rjhAsF+Are9jXDk DEL8/E8qcbVWQ== Date: Sun, 31 Dec 2023 15:36:53 -0800 Subject: [PATCH 28/58] xfs_db: don't obfuscate metadata directories and attributes From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <170405010321.1809361.10825471775307243751.stgit@frogsfrogsfrogs> In-Reply-To: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> References: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Don't obfuscate the directory and attribute names of metadata inodes. Signed-off-by: Darrick J. Wong --- db/metadump.c | 114 ++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 79 insertions(+), 35 deletions(-) diff --git a/db/metadump.c b/db/metadump.c index f5b930d51d2..714be862231 100644 --- a/db/metadump.c +++ b/db/metadump.c @@ -1056,9 +1056,16 @@ generate_obfuscated_name( free(orig_name); } +static inline bool +want_obfuscate_dirents(bool is_meta) +{ + return metadump.obfuscate && !is_meta; +} + static void process_sf_dir( - struct xfs_dinode *dip) + struct xfs_dinode *dip, + bool is_meta) { struct xfs_dir2_sf_hdr *sfp; xfs_dir2_sf_entry_t *sfep; @@ -1105,7 +1112,7 @@ process_sf_dir( (char *)sfp); } - if (metadump.obfuscate) + if (want_obfuscate_dirents(is_meta)) generate_obfuscated_name( libxfs_dir2_sf_get_ino(mp, sfp, sfep), namelen, &sfep->name[0]); @@ -1195,9 +1202,10 @@ want_obfuscate_pptr( const void *name, unsigned int namelen, const void *value, - unsigned int valuelen) + unsigned int valuelen, + bool is_meta) { - if (!metadump.obfuscate) + if (!metadump.obfuscate || is_meta) return false; /* Ignore if parent pointers aren't enabled. */ @@ -1293,9 +1301,10 @@ want_obfuscate_attr( const void *name, unsigned int namelen, const void *value, - unsigned int valuelen) + unsigned int valuelen, + bool is_meta) { - if (!metadump.obfuscate) + if (!metadump.obfuscate || is_meta) return false; /* @@ -1310,7 +1319,8 @@ want_obfuscate_attr( static void process_sf_attr( - struct xfs_dinode *dip) + struct xfs_dinode *dip, + bool is_meta) { /* * with extended attributes, obfuscate the names and fill the actual @@ -1357,11 +1367,11 @@ process_sf_attr( name = &asfep->nameval[0]; value = &asfep->nameval[asfep->namelen]; - if (want_obfuscate_pptr(asfep->flags, name, namelen, value, - asfep->valuelen)) { + if (want_obfuscate_pptr(asfep->flags, name, namelen, + value, asfep->valuelen, is_meta)) { obfuscate_parent_pointer(name, value, asfep->valuelen); } else if (want_obfuscate_attr(asfep->flags, name, namelen, - value, asfep->valuelen)) { + value, asfep->valuelen, is_meta)) { generate_obfuscated_name(0, asfep->namelen, name); memset(value, 'v', asfep->valuelen); } @@ -1463,7 +1473,8 @@ static void process_dir_data_block( char *block, xfs_fileoff_t offset, - int is_block_format) + int is_block_format, + bool is_meta) { /* * we have to rely on the fileoffset and signature of the block to @@ -1570,7 +1581,7 @@ process_dir_data_block( dir_offset) return; - if (metadump.obfuscate) + if (want_obfuscate_dirents(is_meta)) generate_obfuscated_name(be64_to_cpu(dep->inumber), dep->namelen, &dep->name[0]); dir_offset += length; @@ -1595,7 +1606,8 @@ process_symlink_block( xfs_fsblock_t s, xfs_filblks_t c, typnm_t btype, - xfs_fileoff_t last) + xfs_fileoff_t last, + bool is_meta) { struct bbmap map; char *link; @@ -1620,7 +1632,7 @@ process_symlink_block( if (xfs_has_crc((mp))) link += sizeof(struct xfs_dsymlink_hdr); - if (metadump.obfuscate) + if (want_obfuscate_dirents(is_meta)) obfuscate_path_components(link, XFS_SYMLINK_BUF_SPACE(mp, mp->m_sb.sb_blocksize)); if (metadump.zero_stale_data) { @@ -1671,7 +1683,8 @@ add_remote_vals( static void process_attr_block( char *block, - xfs_fileoff_t offset) + xfs_fileoff_t offset, + bool is_meta) { struct xfs_attr_leafblock *leaf; struct xfs_attr3_icleaf_hdr hdr; @@ -1750,11 +1763,11 @@ process_attr_block( if (want_obfuscate_pptr(entry->flags, name, local->namelen, value, - valuelen)) { + valuelen, is_meta)) { obfuscate_parent_pointer(name, value, valuelen); } else if (want_obfuscate_attr(entry->flags, name, local->namelen, value, - valuelen)) { + valuelen, is_meta)) { generate_obfuscated_name(0, local->namelen, name); memset(value, 'v', valuelen); @@ -1776,7 +1789,7 @@ process_attr_block( (long long)metadump.cur_ino); break; } - if (metadump.obfuscate) { + if (want_obfuscate_dirents(is_meta)) { generate_obfuscated_name(0, remote->namelen, &remote->name[0]); add_remote_vals(be32_to_cpu(remote->valueblk), @@ -1809,7 +1822,8 @@ process_single_fsb_objects( xfs_fsblock_t s, xfs_filblks_t c, typnm_t btype, - xfs_fileoff_t last) + xfs_fileoff_t last, + bool is_meta) { int rval = 1; char *dp; @@ -1879,12 +1893,13 @@ process_single_fsb_objects( process_dir_leaf_block(dp); } else { process_dir_data_block(dp, o, - last == mp->m_dir_geo->fsbcount); + last == mp->m_dir_geo->fsbcount, + is_meta); } iocur_top->need_crc = 1; break; case TYP_ATTR: - process_attr_block(dp, o); + process_attr_block(dp, o, is_meta); iocur_top->need_crc = 1; break; default: @@ -1917,7 +1932,8 @@ process_multi_fsb_dir( xfs_fsblock_t s, xfs_filblks_t c, typnm_t btype, - xfs_fileoff_t last) + xfs_fileoff_t last, + bool is_meta) { char *dp; int rval = 1; @@ -1961,7 +1977,8 @@ process_multi_fsb_dir( process_dir_leaf_block(dp); } else { process_dir_data_block(dp, o, - last == mp->m_dir_geo->fsbcount); + last == mp->m_dir_geo->fsbcount, + is_meta); } iocur_top->need_crc = 1; write: @@ -1998,13 +2015,14 @@ process_multi_fsb_objects( xfs_fsblock_t s, xfs_filblks_t c, typnm_t btype, - xfs_fileoff_t last) + xfs_fileoff_t last, + bool is_meta) { switch (btype) { case TYP_DIR2: - return process_multi_fsb_dir(o, s, c, btype, last); + return process_multi_fsb_dir(o, s, c, btype, last, is_meta); case TYP_SYMLINK: - return process_symlink_block(o, s, c, btype, last); + return process_symlink_block(o, s, c, btype, last, is_meta); default: print_warning("bad type for multi-fsb object %d", btype); return 1; @@ -2016,7 +2034,8 @@ static int process_bmbt_reclist( xfs_bmbt_rec_t *rp, int numrecs, - typnm_t btype) + typnm_t btype, + bool is_meta) { int i; xfs_fileoff_t o, op = NULLFILEOFF; @@ -2096,10 +2115,10 @@ process_bmbt_reclist( /* multi-extent blocks require special handling */ if (is_multi_fsb) rval = process_multi_fsb_objects(o, s, c, btype, - last); + last, is_meta); else rval = process_single_fsb_objects(o, s, c, btype, - last); + last, is_meta); if (!rval) break; } @@ -2107,6 +2126,11 @@ process_bmbt_reclist( return rval; } +struct scan_bmap { + enum typnm typ; + bool is_meta; +}; + static int scanfunc_bmap( struct xfs_btree_block *block, @@ -2116,6 +2140,7 @@ scanfunc_bmap( typnm_t btype, void *arg) /* ptr to itype */ { + struct scan_bmap *sbm = arg; int i; xfs_bmbt_ptr_t *pp; int nrecs; @@ -2131,7 +2156,7 @@ scanfunc_bmap( return 1; } return process_bmbt_reclist(XFS_BMBT_REC_ADDR(mp, block, 1), - nrecs, *(typnm_t*)arg); + nrecs, sbm->typ, sbm->is_meta); } if (nrecs > mp->m_bmap_dmxr[1]) { @@ -2163,6 +2188,15 @@ scanfunc_bmap( return 1; } +static inline bool +is_metadata_ino( + struct xfs_dinode *dip) +{ + return xfs_has_metadir(mp) && + dip->di_version >= 3 && + (dip->di_flags2 & cpu_to_be64(XFS_DIFLAG2_METADIR)); +} + static int process_btinode( struct xfs_dinode *dip, @@ -2176,6 +2210,7 @@ process_btinode( int maxrecs; int whichfork; typnm_t btype; + bool is_meta = is_metadata_ino(dip); whichfork = (itype == TYP_ATTR) ? XFS_ATTR_FORK : XFS_DATA_FORK; btype = (itype == TYP_ATTR) ? TYP_BMAPBTA : TYP_BMAPBTD; @@ -2194,7 +2229,7 @@ process_btinode( if (level == 0) { return process_bmbt_reclist(XFS_BMDR_REC_ADDR(dib, 1), - nrecs, itype); + nrecs, itype, is_meta); } maxrecs = libxfs_bmdr_maxrecs(XFS_DFORK_SIZE(dip, mp, whichfork), 0); @@ -2221,6 +2256,10 @@ process_btinode( } for (i = 0; i < nrecs; i++) { + struct scan_bmap sbm = { + .typ = itype, + .is_meta = is_meta, + }; xfs_agnumber_t ag; xfs_agblock_t bno; @@ -2237,7 +2276,7 @@ process_btinode( continue; } - if (!scan_btree(ag, bno, level, btype, &itype, scanfunc_bmap)) + if (!scan_btree(ag, bno, level, btype, &sbm, scanfunc_bmap)) return 0; } return 1; @@ -2251,6 +2290,7 @@ process_exinode( int whichfork; int used; xfs_extnum_t nex, max_nex; + bool is_meta = is_metadata_ino(dip); whichfork = (itype == TYP_ATTR) ? XFS_ATTR_FORK : XFS_DATA_FORK; @@ -2275,7 +2315,7 @@ process_exinode( return process_bmbt_reclist((xfs_bmbt_rec_t *)XFS_DFORK_PTR(dip, - whichfork), nex, itype); + whichfork), nex, itype, is_meta); } static int @@ -2283,6 +2323,8 @@ process_inode_data( struct xfs_dinode *dip, typnm_t itype) { + bool is_meta = is_metadata_ino(dip); + switch (dip->di_format) { case XFS_DINODE_FMT_LOCAL: if (!(metadump.obfuscate || metadump.zero_stale_data)) @@ -2303,7 +2345,7 @@ process_inode_data( switch (itype) { case TYP_DIR2: - process_sf_dir(dip); + process_sf_dir(dip, is_meta); break; case TYP_SYMLINK: @@ -2421,13 +2463,15 @@ process_inode( /* copy extended attributes if they exist and forkoff is valid */ if (XFS_DFORK_DSIZE(dip, mp) < XFS_LITINO(mp)) { + bool is_meta = is_metadata_ino(dip); + attr_data.remote_val_count = 0; switch (dip->di_aformat) { case XFS_DINODE_FMT_LOCAL: need_new_crc = true; if (metadump.obfuscate || metadump.zero_stale_data) - process_sf_attr(dip); + process_sf_attr(dip, is_meta); break; case XFS_DINODE_FMT_EXTENTS: From patchwork Sun Dec 31 23:37:08 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13508150 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 E0EA5C2CC for ; Sun, 31 Dec 2023 23:37:09 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Pk7dxP25" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 4FA73C433C7; Sun, 31 Dec 2023 23:37:09 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704065829; bh=w+qr40siuZmQsqNI3VFds+3NnrnU9eNEBafYLxQTANc=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=Pk7dxP25YDSyKyu5MrRJaFeYHfeVuiYVyhzen+atCIKwp6ooIt7ZjCeZ8Xyb5UIjM MvlIOWsrUIBIn9a/yPfEdUFMCUpqe7Sp/mN46c6QTHPgCRxJO3wQf+k5RJb/DPfKUC FHN5s2J/Mt+LGkPaeCNO8Sn0zCeIPQ81tLv5GPak5u18EwHNSLOuCCSKyCeeHGw6tA 9jjmYhwg+ATh/DZpMmmcUHpd/r6nji3y8FCq1W3cTMAMY2YtgFJ0U3k1X9sGZ2t61A lpM7OHWmXQYU3QF6UFN9vYLiVpJ482p63AWd+acLx3AB7qNLZYhr+Yye63mV8pAyWm 746VGbuTxOaFQ== Date: Sun, 31 Dec 2023 15:37:08 -0800 Subject: [PATCH 29/58] xfs_db: support metadata directories in the path command From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <170405010334.1809361.8685129977917604647.stgit@frogsfrogsfrogs> In-Reply-To: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> References: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Teach the path command to traverse the metadata directory tree by passing a '\' as the first letter in the path. Signed-off-by: Darrick J. Wong --- db/namei.c | 71 ++++++++++++++++++++++++++++++++++++++++++++--------- man/man8/xfs_db.8 | 23 ++++++++++++++--- 2 files changed, 78 insertions(+), 16 deletions(-) diff --git a/db/namei.c b/db/namei.c index e75179b2c67..db467141f13 100644 --- a/db/namei.c +++ b/db/namei.c @@ -139,11 +139,11 @@ path_navigate( /* Walk a directory path to an inode and set the io cursor to that inode. */ static int path_walk( + xfs_ino_t rootino, char *path) { struct dirpath *dirpath; char *p = path; - xfs_ino_t rootino = mp->m_sb.sb_rootino; int error = 0; if (*p == '/') { @@ -173,6 +173,9 @@ path_help(void) dbprintf(_( "\n" " Navigate to an inode via directory path.\n" +"\n" +" Options:\n" +" -m -- Walk an absolute path down the metadata directory tree.\n" )); } @@ -181,18 +184,34 @@ path_f( int argc, char **argv) { + xfs_ino_t rootino = mp->m_sb.sb_rootino; int c; int error; - while ((c = getopt(argc, argv, "")) != -1) { + while ((c = getopt(argc, argv, "m")) != -1) { switch (c) { + case 'm': + /* Absolute path, start from metadata rootdir. */ + if (!xfs_has_metadir(mp)) { + dbprintf( + _("filesystem does not support metadata directories.\n")); + exitcode = 1; + return 0; + } + rootino = mp->m_sb.sb_metadirino; + break; default: path_help(); return 0; } } - error = path_walk(argv[optind]); + if (argc == optind || argc > optind + 1) { + dbprintf(_("Only supply one path.\n")); + return -1; + } + + error = path_walk(rootino, argv[optind]); if (error) { dbprintf("%s: %s\n", argv[optind], strerror(error)); exitcode = 1; @@ -206,7 +225,7 @@ static struct cmdinfo path_cmd = { .altname = NULL, .cfunc = path_f, .argmin = 1, - .argmax = 1, + .argmax = -1, .canpush = 0, .args = "", .help = path_help, @@ -521,6 +540,7 @@ ls_help(void) " Options:\n" " -i -- Resolve the given paths to their corresponding inode numbers.\n" " If no paths are given, display the current inode number.\n" +" -m -- Walk an absolute path down the metadata directory tree.\n" "\n" " Directory contents will be listed in the format:\n" " dir_cookie inode_number type hash name_length name\n" @@ -532,15 +552,26 @@ ls_f( int argc, char **argv) { + xfs_ino_t rootino = mp->m_sb.sb_rootino; bool inum_only = false; int c; int error = 0; - while ((c = getopt(argc, argv, "i")) != -1) { + while ((c = getopt(argc, argv, "im")) != -1) { switch (c) { case 'i': inum_only = true; break; + case 'm': + /* Absolute path, start from metadata rootdir. */ + if (!xfs_has_metadir(mp)) { + dbprintf( + _("filesystem does not support metadata directories.\n")); + exitcode = 1; + return 0; + } + rootino = mp->m_sb.sb_metadirino; + break; default: ls_help(); return 0; @@ -563,7 +594,7 @@ ls_f( for (c = optind; c < argc; c++) { push_cur(); - error = path_walk(argv[c]); + error = path_walk(rootino, argv[c]); if (error) goto err_cur; @@ -874,11 +905,22 @@ parent_f( int argc, char **argv) { + xfs_ino_t rootino = mp->m_sb.sb_rootino; int c; int error = 0; - while ((c = getopt(argc, argv, "")) != -1) { + while ((c = getopt(argc, argv, "m")) != -1) { switch (c) { + case 'm': + /* Absolute path, start from metadata rootdir. */ + if (!xfs_has_metadir(mp)) { + dbprintf( + _("filesystem does not support metadata directories.\n")); + exitcode = 1; + return 0; + } + rootino = mp->m_sb.sb_metadirino; + break; default: ls_help(); return 0; @@ -898,7 +940,7 @@ parent_f( for (c = optind; c < argc; c++) { push_cur(); - error = path_walk(argv[c]); + error = path_walk(rootino, argv[c]); if (error) goto err_cur; @@ -926,7 +968,7 @@ static struct cmdinfo parent_cmd = { .argmin = 0, .argmax = -1, .canpush = 0, - .args = "[paths...]", + .args = "[-m] [paths...]", .help = parent_help, }; @@ -940,6 +982,7 @@ link_help(void) "\n" " Options:\n" " -i -- Point to this specific inode number.\n" +" -m -- Select the metadata directory tree.\n" " -p -- Point to the inode given by this path.\n" " -t -- Set the file type to this value.\n" " name -- Create this directory entry with this name.\n" @@ -1051,11 +1094,12 @@ link_f( { xfs_ino_t child_ino = NULLFSINO; int ftype = XFS_DIR3_FT_UNKNOWN; + xfs_ino_t rootino = mp->m_sb.sb_rootino; unsigned int i; int c; int error = 0; - while ((c = getopt(argc, argv, "i:p:t:")) != -1) { + while ((c = getopt(argc, argv, "i:mp:t:")) != -1) { switch (c) { case 'i': errno = 0; @@ -1066,9 +1110,12 @@ link_f( return 0; } break; + case 'm': + rootino = mp->m_sb.sb_metadirino; + break; case 'p': push_cur(); - error = path_walk(optarg); + error = path_walk(rootino, optarg); if (error) { printf("%s: %s\n", optarg, strerror(error)); exitcode = 1; @@ -1138,7 +1185,7 @@ static struct cmdinfo link_cmd = { .argmin = 0, .argmax = -1, .canpush = 0, - .args = "[-i ino] [-p path] [-t ftype] name", + .args = "[-i ino] [-m] [-p path] [-t ftype] name", .help = link_help, }; diff --git a/man/man8/xfs_db.8 b/man/man8/xfs_db.8 index 638a8dc9352..b1712a92f76 100644 --- a/man/man8/xfs_db.8 +++ b/man/man8/xfs_db.8 @@ -884,7 +884,7 @@ will result in truncation and a warning will be issued. If no .I label is given, the current filesystem label is printed. .TP -.BI "link [-i " ino "] [-p " path "] [-t " ftype "] name" +.BI "link [-i " ino "] [-m] [-p " path "] [-t " ftype "] name" In the current directory, create a directory entry with the given .I name pointing to a file. @@ -897,6 +897,10 @@ The file type in the directory entry will be determined from the mode of the child file unless the .I ftype option is given. +The +.B -m +option specifies that the path lookup should be done in the metadata directory +tree. The file being targetted must not be on the iunlink list. .TP .BI "log [stop | start " filename ] @@ -917,7 +921,7 @@ This makes it easier to find discrepancies in the reservation calculations between xfsprogs and the kernel, which will help when diagnosing minimum log size calculation errors. .TP -.BI "ls [\-i] [" paths "]..." +.BI "ls [\-im] [" paths "]..." List the contents of a directory. If a path resolves to a directory, the directory will be listed. If no paths are supplied and the IO cursor points at a directory inode, @@ -931,6 +935,9 @@ directory cookie, inode number, file type, hash, name length, name. Resolve each of the given paths to an inode number and print that number. If no paths are given and the IO cursor points to an inode, print the inode number. +.TP +.B \-m +Absolute paths should be walked from the root of the metadata directory tree. .RE .TP .BI "metadump [\-egow] " filename @@ -958,18 +965,26 @@ See the .B print command. .TP -.BI "parent [" paths "]..." +.BI "parent [\-m] [" paths "]..." List the parents of a file. If a path resolves to a file, the parents of that file will be listed. If no paths are supplied and the IO cursor points at an inode, the parents of that file will be listed. +The +.B \-m +option causes absolute paths to be walked from the root of the metadata +directory tree. The output format is: inode number, inode generation, ondisk namehash, namehash, name length, name. .TP -.BI "path " dir_path +.BI "path [\-m] " dir_path Walk the directory tree to an inode using the supplied path. Absolute and relative paths are supported. +The +.B \-m +option causes absolute paths to be walked from the root of the metadata +directory tree. .TP .B pop Pop location from the stack. From patchwork Sun Dec 31 23:37:24 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13508151 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 2C6C7C2CC for ; Sun, 31 Dec 2023 23:37:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="ZPGKfG0A" Received: by smtp.kernel.org (Postfix) with ESMTPSA id F0B8EC433C7; Sun, 31 Dec 2023 23:37:24 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704065845; bh=ZJLA3wGzvbr5Kx1tGYi37vRiY6nQCe6HUeLQHWadUWA=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=ZPGKfG0Axxlcj7RW1WD+p9FgfbfkacwtPun3FHHfwhb0CI5rrXI6XPex12w454HTm GuqV8yNiAYM2MEJoZ4+ZFTpyfUOOUPIJ54HPNUo+SvXIj8JQQSyu97nFrnDuBeEzHw dQqkkbtaFg1C6bLzHrb++Me31xfDJ8PsOSBB34KifXPmLliVT3poHrgU9I+vDygLYK 2VWnYvM1/XhqX4Vn5KotZcIQKCnl3AZ6vn+1KBE1H5PXFzpisVw3zlVzmIyuSY9Xkj lDU/cWA8mvIWF2CwBDB67+LWUkxA0jr7b6BUgMIswlazSqixTyxy9a1jLHZ+DnudFc a7G9S95WZ2mZw== Date: Sun, 31 Dec 2023 15:37:24 -0800 Subject: [PATCH 30/58] xfs_db: mask superblock fields when metadir feature is enabled From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <170405010347.1809361.15324047232203894359.stgit@frogsfrogsfrogs> In-Reply-To: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> References: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong When the metadata directory feature is enabled, mask the superblock fields (rt, quota inodes) that got migrated to the directory tree. Similarly, hide the 'metadirino' field when the feature is disabled. Signed-off-by: Darrick J. Wong --- db/sb.c | 41 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/db/sb.c b/db/sb.c index 002736b02b7..2ad032cc81a 100644 --- a/db/sb.c +++ b/db/sb.c @@ -50,6 +50,30 @@ sb_init(void) add_command(&version_cmd); } +/* + * Counts superblock fields that only exist when the metadata directory feature + * is enabled. + */ +static int +metadirino_count( + void *obj, + int startoff) +{ + return xfs_has_metadir(mp) ? 1 : 0; +} + +/* + * Counts superblock fields that only existed before the metadata directory + * feature came along. + */ +static int +rootino_count( + void *obj, + int startoff) +{ + return xfs_has_metadir(mp) ? 0 : 1; +} + #define OFF(f) bitize(offsetof(struct xfs_dsb, sb_ ## f)) #define SZC(f) szcount(struct xfs_dsb, sb_ ## f) const field_t sb_flds[] = { @@ -61,8 +85,12 @@ const field_t sb_flds[] = { { "uuid", FLDT_UUID, OI(OFF(uuid)), C1, 0, TYP_NONE }, { "logstart", FLDT_DFSBNO, OI(OFF(logstart)), C1, 0, TYP_LOG }, { "rootino", FLDT_INO, OI(OFF(rootino)), C1, 0, TYP_INODE }, - { "rbmino", FLDT_INO, OI(OFF(rbmino)), C1, 0, TYP_INODE }, - { "rsumino", FLDT_INO, OI(OFF(rsumino)), C1, 0, TYP_INODE }, + { "metadirino", FLDT_INO, OI(OFF(rbmino)), metadirino_count, + FLD_COUNT, TYP_INODE }, + { "rbmino", FLDT_INO, OI(OFF(rbmino)), rootino_count, FLD_COUNT, + TYP_INODE }, + { "rsumino", FLDT_INO, OI(OFF(rsumino)), rootino_count, FLD_COUNT, + TYP_INODE }, { "rextsize", FLDT_AGBLOCK, OI(OFF(rextsize)), C1, 0, TYP_NONE }, { "agblocks", FLDT_AGBLOCK, OI(OFF(agblocks)), C1, 0, TYP_NONE }, { "agcount", FLDT_AGNUMBER, OI(OFF(agcount)), C1, 0, TYP_NONE }, @@ -85,8 +113,10 @@ const field_t sb_flds[] = { { "ifree", FLDT_UINT64D, OI(OFF(ifree)), C1, 0, TYP_NONE }, { "fdblocks", FLDT_UINT64D, OI(OFF(fdblocks)), C1, 0, TYP_NONE }, { "frextents", FLDT_UINT64D, OI(OFF(frextents)), C1, 0, TYP_NONE }, - { "uquotino", FLDT_INO, OI(OFF(uquotino)), C1, 0, TYP_INODE }, - { "gquotino", FLDT_INO, OI(OFF(gquotino)), C1, 0, TYP_INODE }, + { "uquotino", FLDT_INO, OI(OFF(uquotino)), rootino_count, FLD_COUNT, + TYP_INODE }, + { "gquotino", FLDT_INO, OI(OFF(gquotino)), rootino_count, FLD_COUNT, + TYP_INODE }, { "qflags", FLDT_UINT16X, OI(OFF(qflags)), C1, 0, TYP_NONE }, { "flags", FLDT_UINT8X, OI(OFF(flags)), C1, 0, TYP_NONE }, { "shared_vn", FLDT_UINT8D, OI(OFF(shared_vn)), C1, 0, TYP_NONE }, @@ -110,7 +140,8 @@ const field_t sb_flds[] = { C1, 0, TYP_NONE }, { "crc", FLDT_CRC, OI(OFF(crc)), C1, 0, TYP_NONE }, { "spino_align", FLDT_EXTLEN, OI(OFF(spino_align)), C1, 0, TYP_NONE }, - { "pquotino", FLDT_INO, OI(OFF(pquotino)), C1, 0, TYP_INODE }, + { "pquotino", FLDT_INO, OI(OFF(pquotino)), rootino_count, FLD_COUNT, + TYP_INODE }, { "lsn", FLDT_UINT64X, OI(OFF(lsn)), C1, 0, TYP_NONE }, { "meta_uuid", FLDT_UUID, OI(OFF(meta_uuid)), C1, 0, TYP_NONE }, { NULL } From patchwork Sun Dec 31 23:37:40 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13508152 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 E3C5AC2CC for ; Sun, 31 Dec 2023 23:37:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="QG89Zk6y" Received: by smtp.kernel.org (Postfix) with ESMTPSA id B4162C433C7; Sun, 31 Dec 2023 23:37:40 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704065860; bh=LrmUAeD1dxIFIDkTTojkSt6NAXHcFcrmx/mj3CIXHhs=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=QG89Zk6yY6FqQ/3k+7bZzHdS05rgpqjXtcI3eR+GQ7ZnJLEakcqM9DDjap/XA8qBn gJC8n9tWmQRBrVTf1rjRBuVVQ7Y+F7nCE71xGo8vMGAwWAOLL09DgJNn4SVnSn9tzw 4dqspaHLK06Q/FIfijVsPFbBrkwcxYweJW5kimoadhrJ0k9pWDwG2SsqfSCIb7dNc9 zLASUWbypSTJiJvO685dWCSgssym02vNviYpNdxrnQBgNlfV4P4P9jEA7kWeI2JSsj R0Mws1efQEjRefBXRiKUg0WgncJ7uzJ1zrP0kST2ZTqrU4g9zJVXFdRbc8hyAyRXJA Gk2kZ0T63lG0A== Date: Sun, 31 Dec 2023 15:37:40 -0800 Subject: [PATCH 31/58] xfs_io: support the bulkstat metadata directory flag From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <170405010361.1809361.3505805825987122661.stgit@frogsfrogsfrogs> In-Reply-To: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> References: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 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 the new XFS_BULK_IREQ_METADIR flag for bulkstat commands. Signed-off-by: Darrick J. Wong --- io/bulkstat.c | 16 +++++++++++++++- man/man8/xfs_io.8 | 10 +++++++--- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/io/bulkstat.c b/io/bulkstat.c index a9ad87ca183..829f6a02515 100644 --- a/io/bulkstat.c +++ b/io/bulkstat.c @@ -70,6 +70,7 @@ bulkstat_help(void) " -d Print debugging output.\n" " -q Be quiet, no output.\n" " -e Stop after this inode.\n" +" -m Include metadata directories.\n" " -n Ask for this many results at once.\n" " -s Inode to start with.\n" " -v Use this version of the ioctl (1 or 5).\n")); @@ -107,11 +108,12 @@ bulkstat_f( bool has_agno = false; bool debug = false; bool quiet = false; + bool metadir = false; unsigned int i; int c; int ret; - while ((c = getopt(argc, argv, "a:de:n:qs:v:")) != -1) { + while ((c = getopt(argc, argv, "a:de:mn:qs:v:")) != -1) { switch (c) { case 'a': agno = cvt_u32(optarg, 10); @@ -131,6 +133,9 @@ bulkstat_f( return 1; } break; + case 'm': + metadir = true; + break; case 'n': batch_size = cvt_u32(optarg, 10); if (errno) { @@ -185,6 +190,8 @@ bulkstat_f( if (has_agno) xfrog_bulkstat_set_ag(breq, agno); + if (metadir) + breq->hdr.flags |= XFS_BULK_IREQ_METADIR; set_xfd_flags(&xfd, ver); @@ -253,6 +260,7 @@ bulkstat_single_f( unsigned long ver = 0; unsigned int i; bool debug = false; + bool metadir = false; int c; int ret; @@ -261,6 +269,9 @@ bulkstat_single_f( case 'd': debug = true; break; + case 'm': + metadir = true; + break; case 'v': errno = 0; ver = strtoull(optarg, NULL, 10); @@ -313,6 +324,9 @@ bulkstat_single_f( } } + if (metadir) + flags |= XFS_BULK_IREQ_METADIR; + ret = -xfrog_bulkstat_single(&xfd, ino, flags, &bulkstat); if (ret) { xfrog_perror(ret, "xfrog_bulkstat_single"); diff --git a/man/man8/xfs_io.8 b/man/man8/xfs_io.8 index 5a6b2724504..1975f5d1011 100644 --- a/man/man8/xfs_io.8 +++ b/man/man8/xfs_io.8 @@ -1240,7 +1240,7 @@ for the current memory mapping. .SH FILESYSTEM COMMANDS .TP -.BI "bulkstat [ \-a " agno " ] [ \-d ] [ \-e " endino " ] [ \-n " batchsize " ] [ \-q ] [ \-s " startino " ] [ \-v " version" ] +.BI "bulkstat [ \-a " agno " ] [ \-d ] [ \-e " endino " ] [ \-m ] [ \-n " batchsize " ] [ \-q ] [ \-s " startino " ] [ \-v " version" ] Display raw stat information about a bunch of inodes in an XFS filesystem. Options are as follows: .RS 1.0i @@ -1257,6 +1257,9 @@ Print debugging information about call results. Stop displaying records when this inode number is reached. Defaults to stopping when the system call stops returning results. .TP +.BI \-m +Include metadata directories in the output. +.TP .BI \-n " batchsize" Retrieve at most this many records per call. Defaults to 4,096. @@ -1277,10 +1280,11 @@ Currently supported versions are 1 and 5. .RE .PD .TP -.BI "bulkstat_single [ \-d ] [ \-v " version " ] [ " inum... " | " special... " ] +.BI "bulkstat_single [ \-d ] [ \-m ] [ \-v " version " ] [ " inum... " | " special... " ] Display raw stat information about individual inodes in an XFS filesystem. The -.B \-d +.BR \-d , +.BR \-m , and .B \-v options are the same as the From patchwork Sun Dec 31 23:37:55 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13508153 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 9002EC2CC for ; Sun, 31 Dec 2023 23:37:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="sWhJXZ9K" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 66653C433C7; Sun, 31 Dec 2023 23:37:56 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704065876; bh=keXaPgE/1BEarJHHihhlh1+dc0D95dd+Mq2Jlja6cFs=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=sWhJXZ9KQtwq0ywrQnmKfl/BFiuNQNj2m8J6+9jIMyNmF007d9NZJ7tkhNQPhHP8k 3nWn7eWsc98eTtRmpuk3vEzNEpmINW0Kb44CDhNkPwdXXzj+fQFlNnsacEpi+/nzQZ JqnmTD78dH+G8JyTa3cK0zso6shUfq65r8jYPAInmVzLb/h2oApvQ2cNAPdWPmCtLY +mbR1VKXlz2Z7BwUh+NLzItdBCxGtxXnG7uAqx3frxUEMhy5RiHyolH/d7fKraDwjm 64JeBws0DImGPiQheTkyVz7cRPEptEhpBT3STRgaKtsJLJVVqABbuureK8m+i3AenG k9nj/6LEtx/qA== Date: Sun, 31 Dec 2023 15:37:55 -0800 Subject: [PATCH 32/58] xfs_io: support scrubbing metadata directory paths From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <170405010374.1809361.13532991232757135946.stgit@frogsfrogsfrogs> In-Reply-To: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> References: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 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 invoking the metadata directory path scrubber from xfs_io for testing. Signed-off-by: Darrick J. Wong --- io/scrub.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++-- man/man8/xfs_io.8 | 3 ++- 2 files changed, 62 insertions(+), 3 deletions(-) diff --git a/io/scrub.c b/io/scrub.c index 456d1594f22..cb4e24503dc 100644 --- a/io/scrub.c +++ b/io/scrub.c @@ -41,6 +41,12 @@ scrub_help(void) " Known metadata scrub types are:")); for (i = 0, d = xfrog_scrubbers; i < XFS_SCRUB_TYPE_NR; i++, d++) printf(" %s", d->name); + printf(_( +"\n" +"\n" +" Known metapath scrub arguments are:")); + for (i = 0, d = xfrog_metapaths; i < XFS_SCRUB_METAPATH_NR; i++, d++) + printf(" %s", d->name); printf("\n"); } @@ -125,6 +131,40 @@ parse_none( return true; } +static bool +parse_metapath( + int argc, + char **argv, + int optind, + __u64 *ino) +{ + char *p; + unsigned long long control; + int i; + + if (optind != argc - 1) { + fprintf(stderr, _("Must specify metapath number.\n")); + return false; + } + + for (i = 0; i < XFS_SCRUB_METAPATH_NR; i++) { + if (!strcmp(argv[optind], xfrog_metapaths[i].name)) { + *ino = i; + return true; + } + } + + control = strtoll(argv[optind], &p, 0); + if (*p != '\0') { + fprintf(stderr, _("Bad metapath number '%s'.\n"), + argv[optind]); + return false; + } + + *ino = control; + return true; +} + static int parse_args( int argc, @@ -170,6 +210,12 @@ parse_args( meta->sm_flags = flags; switch (d->group) { + case XFROG_SCRUB_GROUP_METAPATH: + if (!parse_metapath(argc, argv, optind, &meta->sm_ino)) { + exitcode = 1; + return command_usage(cmdinfo); + } + break; case XFROG_SCRUB_GROUP_INODE: if (!parse_inode(argc, argv, optind, &meta->sm_ino, &meta->sm_gen)) { @@ -244,7 +290,7 @@ scrub_init(void) scrub_cmd.argmin = 1; scrub_cmd.argmax = -1; scrub_cmd.flags = CMD_NOMAP_OK; - scrub_cmd.args = _("type [agno|ino gen]"); + scrub_cmd.args = _("type [agno|ino gen|metapath]"); scrub_cmd.oneline = _("scrubs filesystem metadata"); scrub_cmd.help = scrub_help; @@ -275,6 +321,12 @@ repair_help(void) " Known metadata repair types are:")); for (i = 0, d = xfrog_scrubbers; i < XFS_SCRUB_TYPE_NR; i++, d++) printf(" %s", d->name); + printf(_( +"\n" +"\n" +" Known metapath repair arguments are:")); + for (i = 0, d = xfrog_metapaths; i < XFS_SCRUB_METAPATH_NR; i++, d++) + printf(" %s", d->name); printf("\n"); } @@ -327,7 +379,7 @@ repair_init(void) repair_cmd.argmin = 1; repair_cmd.argmax = -1; repair_cmd.flags = CMD_NOMAP_OK; - repair_cmd.args = _("type [agno|ino gen]"); + repair_cmd.args = _("type [agno|ino gen|metapath]"); repair_cmd.oneline = _("repairs filesystem metadata"); repair_cmd.help = repair_help; @@ -500,6 +552,12 @@ scrubv_f( optind++; switch (group) { + case XFROG_SCRUB_GROUP_METAPATH: + if (!parse_metapath(argc, argv, optind, &vhead->svh_ino)) { + exitcode = 1; + return command_usage(&scrubv_cmd); + } + break; case XFROG_SCRUB_GROUP_INODE: if (!parse_inode(argc, argv, optind, &vhead->svh_ino, &vhead->svh_gen)) { diff --git a/man/man8/xfs_io.8 b/man/man8/xfs_io.8 index 1975f5d1011..ef3a5681a1a 100644 --- a/man/man8/xfs_io.8 +++ b/man/man8/xfs_io.8 @@ -1422,13 +1422,14 @@ Currently supported versions are 1 and 5. .RE .PD .TP -.BI "scrub " type " [ " agnumber " | " "ino" " " "gen" " ]" +.BI "scrub " type " [ " agnumber " | " "ino" " " "gen" " | " metapath " ]" Scrub internal XFS filesystem metadata. The .BI type parameter specifies which type of metadata to scrub. For AG metadata, one AG number must be specified. For file metadata, the scrub is applied to the open file unless the inode number and generation number are specified. +For metapath, the name of a file or a raw number must be specified. .RE .PD .TP From patchwork Sun Dec 31 23:38:11 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13508154 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 4085AC2D4 for ; Sun, 31 Dec 2023 23:38:12 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="VfUZUCpu" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 0B0AAC433C8; Sun, 31 Dec 2023 23:38:12 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704065892; bh=zLthbS7jPwqlBiGnSmS71nekqEWLWXiUWEe8trziTJ0=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=VfUZUCpuKaOgdBT6FPTZaAUtbamLzJD97YNbQ4uk6qs/zRViRghPUSJw2DAQBcYtM ATlLDiOrcEvIce9K8WxlsDC5A5H0uMkEJt7GL/foW890RUc5Ej5MgRPJvJkbbhOhdO HOSTk2xbpghovbkAYObqJ6zDgN3zt8Zy8LtmrzBhToA9nHda/MfD7J29TjxApX4r3A PV/b1SToyqbcgM5Qw9sq+vtZRQmvK7xDfGe9YfCOKQlb46XIIOn1GYXjBhUmt1dgIy UV+Q53+d8GoBaNld4n3dMR2ZLoAJp4OqgqtzDCqqKcuW0Z+fgoxeTMfySiQ3dvNsCR +obrzWfhPL0dA== Date: Sun, 31 Dec 2023 15:38:11 -0800 Subject: [PATCH 33/58] xfs_spaceman: report health of metadir inodes too From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <170405010388.1809361.8669562355794267273.stgit@frogsfrogsfrogs> In-Reply-To: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> References: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 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 the filesystem has a metadata directory tree, we should include those inodes in the health report. Signed-off-by: Darrick J. Wong --- spaceman/health.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/spaceman/health.c b/spaceman/health.c index 8ba78152cb6..47cf9099492 100644 --- a/spaceman/health.c +++ b/spaceman/health.c @@ -328,6 +328,8 @@ report_bulkstat_health( if (agno != NULLAGNUMBER) xfrog_bulkstat_set_ag(breq, agno); + if (file->xfd.fsgeom.flags & XFS_FSOP_GEOM_FLAGS_METADIR) + breq->hdr.flags |= XFS_BULK_IREQ_METADIR; do { error = -xfrog_bulkstat(&file->xfd, breq); From patchwork Sun Dec 31 23:38:27 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13508155 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 1E5F7D301 for ; Sun, 31 Dec 2023 23:38:27 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="mPzWFFX7" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 94262C433C8; Sun, 31 Dec 2023 23:38:27 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704065907; bh=mkpgEJwVOnRROSfvNFu1E4O78fSYXVOXDNrfmsFSWHY=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=mPzWFFX7pBC4xveSkNDIa/6S1J7SX3NDNt+ocANvCvbKYPBlkgex7B+kC7s6u72Kl APX5m6xNFHWr4qelykSAUrJhFp83mA5qrP4AoVNxB5NuOJYbBLWEDW5Ap+iiLDJ7vV 6uW1MLBlWTuKabr+iHxT1wy0LkHt+Pyuh9wO04RN7/gOSkNglIT+R1mOxR1QtGGcdw mobxM8Wuk/QTq8TmjM08QwLlTLZL8gYPZKbNiAgc7T7yarq3m3W6LSt16liBUPXzgy 8cUAIGgLTaQ4fBkoG3tTKs9TuxbPNm5bbZqMfT7akdeC2P9m//ieMK7GgbJTSgj7Pt vvjNc7KUhX1gA== Date: Sun, 31 Dec 2023 15:38:27 -0800 Subject: [PATCH 34/58] xfs_scrub: scan metadata directories during phase 3 From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <170405010401.1809361.8188720179188151580.stgit@frogsfrogsfrogs> In-Reply-To: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> References: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Scan metadata directories for correctness during phase 3. Signed-off-by: Darrick J. Wong --- scrub/inodes.c | 11 ++++++++++- scrub/inodes.h | 5 ++++- scrub/phase3.c | 7 ++++++- scrub/phase5.c | 5 ++++- scrub/phase6.c | 2 +- 5 files changed, 25 insertions(+), 5 deletions(-) diff --git a/scrub/inodes.c b/scrub/inodes.c index 16c79cf495c..3fe759e8f48 100644 --- a/scrub/inodes.c +++ b/scrub/inodes.c @@ -56,6 +56,7 @@ bulkstat_for_inumbers( { struct xfs_bulkstat *bstat = breq->bulkstat; struct xfs_bulkstat *bs; + unsigned int flags = 0; int i; int error; @@ -70,6 +71,9 @@ bulkstat_for_inumbers( strerror_r(error, errbuf, DESCR_BUFSZ)); } + if (breq->hdr.flags & XFS_BULK_IREQ_METADIR) + flags |= XFS_BULK_IREQ_METADIR; + /* * Check each of the stats we got back to make sure we got the inodes * we asked for. @@ -84,7 +88,7 @@ bulkstat_for_inumbers( /* Load the one inode. */ error = -xfrog_bulkstat_single(&ctx->mnt, - inumbers->xi_startino + i, 0, bs); + inumbers->xi_startino + i, flags, bs); if (error || bs->bs_ino != inumbers->xi_startino + i) { memset(bs, 0, sizeof(struct xfs_bulkstat)); bs->bs_ino = inumbers->xi_startino + i; @@ -100,6 +104,7 @@ struct scan_inodes { scrub_inode_iter_fn fn; void *arg; unsigned int nr_threads; + unsigned int flags; bool aborted; }; @@ -158,6 +163,8 @@ alloc_ichunk( breq = ichunk_to_bulkstat(ichunk); breq->hdr.icount = LIBFROG_BULKSTAT_CHUNKSIZE; + if (si->flags & SCRUB_SCAN_METADIR) + breq->hdr.flags |= XFS_BULK_IREQ_METADIR; *ichunkp = ichunk; return 0; @@ -380,10 +387,12 @@ int scrub_scan_all_inodes( struct scrub_ctx *ctx, scrub_inode_iter_fn fn, + unsigned int flags, void *arg) { struct scan_inodes si = { .fn = fn, + .flags = flags, .arg = arg, .nr_threads = scrub_nproc_workqueue(ctx), }; diff --git a/scrub/inodes.h b/scrub/inodes.h index 9447fb56aa6..7a0b275e575 100644 --- a/scrub/inodes.h +++ b/scrub/inodes.h @@ -17,8 +17,11 @@ typedef int (*scrub_inode_iter_fn)(struct scrub_ctx *ctx, struct xfs_handle *handle, struct xfs_bulkstat *bs, void *arg); +/* Return metadata directories too. */ +#define SCRUB_SCAN_METADIR (1 << 0) + int scrub_scan_all_inodes(struct scrub_ctx *ctx, scrub_inode_iter_fn fn, - void *arg); + unsigned int flags, void *arg); int scrub_open_handle(struct xfs_handle *handle); diff --git a/scrub/phase3.c b/scrub/phase3.c index 046a42c1da8..c90da784394 100644 --- a/scrub/phase3.c +++ b/scrub/phase3.c @@ -312,6 +312,7 @@ phase3_func( struct scrub_inode_ctx ictx = { .ctx = ctx }; uint64_t val; xfs_agnumber_t agno; + unsigned int scan_flags = 0; int err; err = -ptvar_alloc(scrub_nproc(ctx), sizeof(struct action_list), @@ -328,6 +329,10 @@ phase3_func( goto out_ptvar; } + /* Scan the metadata directory tree too. */ + if (ctx->mnt.fsgeom.flags & XFS_FSOP_GEOM_FLAGS_METADIR) + scan_flags |= SCRUB_SCAN_METADIR; + /* * If we already have ag/fs metadata to repair from previous phases, * we would rather not try to repair file metadata until we've tried @@ -338,7 +343,7 @@ phase3_func( ictx.always_defer_repairs = true; } - err = scrub_scan_all_inodes(ctx, scrub_inode, &ictx); + err = scrub_scan_all_inodes(ctx, scrub_inode, scan_flags, &ictx); if (!err && ictx.aborted) err = ECANCELED; if (err) diff --git a/scrub/phase5.c b/scrub/phase5.c index f6c295c64ad..b922f53398e 100644 --- a/scrub/phase5.c +++ b/scrub/phase5.c @@ -455,6 +455,9 @@ retry_deferred_inode( unsigned int flags = 0; int error; + if (ctx->mnt.fsgeom.flags & XFS_FSOP_GEOM_FLAGS_METADIR) + flags |= XFS_BULK_IREQ_METADIR; + error = -xfrog_bulkstat_single(&ctx->mnt, ino, flags, &bstat); if (error == ENOENT) { /* Directory is gone, mark it clear. */ @@ -765,7 +768,7 @@ _("Filesystem has errors, skipping connectivity checks.")); pthread_mutex_init(&ncs.lock, NULL); - ret = scrub_scan_all_inodes(ctx, check_inode_names, &ncs); + ret = scrub_scan_all_inodes(ctx, check_inode_names, 0, &ncs); if (ret) goto out_lock; if (ncs.aborted) { diff --git a/scrub/phase6.c b/scrub/phase6.c index 66ca57507e9..b95966c1f82 100644 --- a/scrub/phase6.c +++ b/scrub/phase6.c @@ -558,7 +558,7 @@ report_all_media_errors( } /* Scan for unlinked files. */ - return scrub_scan_all_inodes(ctx, report_inode_loss, vs); + return scrub_scan_all_inodes(ctx, report_inode_loss, 0, vs); } /* Schedule a read-verify of a (data block) extent. */ From patchwork Sun Dec 31 23:38:42 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13508156 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 A29E7D527 for ; Sun, 31 Dec 2023 23:38:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="ZI/WTttc" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 26B86C433C7; Sun, 31 Dec 2023 23:38:43 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704065923; bh=uhkrAwSn9YDN3LU2hBpf8JlND93rsrsYOoRgNIi0zkw=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=ZI/WTttcmTakfW51xB84mdCOa5F4xlkHwc8UO2OhAjNgEbxeklG9xwRppBo4bSSrK NlI6XQIxM2RN8CkUfyZfLTzG+ODzZTHFXyyPOJ8iQve7R66u+c2H/o8kJE3Hll1Bao FV8vL6k5bVrI6OjyfluCFUGFl//fDyBrB1L7o5Og3oiTDqRyil3M1N03Tl03KmQUnp xSLOo9elnlhrxZkHTs8DNv6b+eLTe+SQ9Ozce8hT33UHIVB2FLhzVsIfLJiEOo6G55 f/lUCPlt1RXHrsnZdqd6TG00S+gOe01NCn6iqcqPEUSbZuvLmcq/ZEFSZgttSc00I4 VSjFtMGvWa0dg== Date: Sun, 31 Dec 2023 15:38:42 -0800 Subject: [PATCH 35/58] xfs_scrub: re-run metafile scrubbers during phase 5 From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <170405010414.1809361.2743640004913728693.stgit@frogsfrogsfrogs> In-Reply-To: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> References: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong For metadata files on a metadir filesystem, re-run the scrubbers during phase 5 to ensure that the metadata files are still connected. Signed-off-by: Darrick J. Wong --- scrub/phase5.c | 97 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- scrub/scrub.h | 7 ++++ 2 files changed, 103 insertions(+), 1 deletion(-) diff --git a/scrub/phase5.c b/scrub/phase5.c index b922f53398e..3b8daf39ae6 100644 --- a/scrub/phase5.c +++ b/scrub/phase5.c @@ -738,6 +738,87 @@ run_kernel_fs_scan_scrubbers( return ret; } +/* Queue one metapath scrubber. */ +static int +queue_metapath_scan( + struct workqueue *wq, + bool *abortedp, + uint64_t type) +{ + struct fs_scan_item *item; + struct scrub_ctx *ctx = wq->wq_ctx; + int ret; + + item = malloc(sizeof(struct fs_scan_item)); + if (!item) { + ret = ENOMEM; + str_liberror(ctx, ret, _("setting up metapath scan")); + return ret; + } + scrub_item_init_metapath(&item->sri, type); + scrub_item_schedule(&item->sri, XFS_SCRUB_TYPE_METAPATH); + item->abortedp = abortedp; + + ret = -workqueue_add(wq, fs_scan_worker, 0, item); + if (ret) + str_liberror(ctx, ret, _("queuing metapath scan work")); + + return ret; +} + +/* + * Scrub metadata directory file paths to ensure that fs metadata are still + * connected where the fs needs to find them. + */ +static int +run_kernel_metadir_path_scrubbers( + struct scrub_ctx *ctx) +{ + struct workqueue wq; + const struct xfrog_scrub_descr *sc; + uint64_t type; + unsigned int nr_threads = scrub_nproc_workqueue(ctx); + bool aborted = false; + int ret, ret2; + + ret = -workqueue_create(&wq, (struct xfs_mount *)ctx, nr_threads); + if (ret) { + str_liberror(ctx, ret, _("setting up metapath scan workqueue")); + return ret; + } + + /* + * Scan all the metadata files in parallel if metadata directories + * are enabled, because the phase 3 scrubbers might have taken out + * parts of the metadir tree. + */ + for (type = 0; type < XFS_SCRUB_METAPATH_NR; type++) { + sc = &xfrog_metapaths[type]; + if (sc->group != XFROG_SCRUB_GROUP_FS) + continue; + + ret = queue_metapath_scan(&wq, &aborted, type); + if (ret) { + str_liberror(ctx, ret, + _("queueing metapath scrub work")); + goto wait; + } + } + +wait: + ret2 = -workqueue_terminate(&wq); + if (ret2) { + str_liberror(ctx, ret2, _("joining metapath scan workqueue")); + if (!ret) + ret = ret2; + } + if (aborted && !ret) + ret = ECANCELED; + + workqueue_destroy(&wq); + return ret; +} + /* Check directory connectivity. */ int phase5_func( @@ -746,6 +827,16 @@ phase5_func( struct ncheck_state ncs = { .ctx = ctx }; int ret; + /* + * Make sure metadata files are still connected to the metadata + * directory tree now that phase 3 pruned all corrupt directory tree + * links. + */ + if (ctx->mnt.fsgeom.flags & XFS_FSOP_GEOM_FLAGS_METADIR) { + ret = run_kernel_metadir_path_scrubbers(ctx); + if (ret) + return ret; + } /* * Check and fix anything that requires a full filesystem scan. We do @@ -798,8 +889,12 @@ phase5_estimate( unsigned int *nr_threads, int *rshift) { + unsigned int scans = 2; + *items = scrub_estimate_iscan_work(ctx); - *nr_threads = scrub_nproc(ctx) * 2; + if (ctx->mnt.fsgeom.flags & XFS_FSOP_GEOM_FLAGS_METADIR) + scans++; + *nr_threads = scrub_nproc(ctx) * scans; *rshift = 0; return 0; } diff --git a/scrub/scrub.h b/scrub/scrub.h index c3eed1b261d..3bb3ea1d07b 100644 --- a/scrub/scrub.h +++ b/scrub/scrub.h @@ -108,6 +108,13 @@ scrub_item_init_file(struct scrub_item *sri, const struct xfs_bulkstat *bstat) sri->sri_gen = bstat->bs_gen; } +static inline void +scrub_item_init_metapath(struct scrub_item *sri, uint64_t metapath) +{ + memset(sri, 0, sizeof(*sri)); + sri->sri_ino = metapath; +} + void scrub_item_dump(struct scrub_item *sri, unsigned int group_mask, const char *tag); From patchwork Sun Dec 31 23:38:58 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13508157 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 55EACDDAB for ; Sun, 31 Dec 2023 23:38:58 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="ugy1ZNux" Received: by smtp.kernel.org (Postfix) with ESMTPSA id BC08EC433C7; Sun, 31 Dec 2023 23:38:58 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704065938; bh=vMLZ+LkznQWz9EJZ/wEbgjkVPEuFX0uUH5rKt9wLLcE=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=ugy1ZNux3EccN9bjCJ+S9qw9a+HqCIqIPdf6m3bgxHhPjO6ou3FR8AaNAq5yVmJ02 a30o+5rp9nUhYn7vQqE8zPejqCVV00kiB70llJ8NDUwSy1Zz7Nx1ZizyyzpB2jsoaF ExunBP0wIZ9MYvPM2ulWBP9YCHSF7f0kNFwYBr34Z03l3xQBjQ32OP02FP3w45LQBn v2JvzV/sigba7qgz854UbSFYzb2c/qCiA19JeMHvL/clKhtf5hXrPmCMApRin1TQdg XXlc0IXsVVylc/oM6txajNRassn0fHTWiS81kj8cTVKIXn25ueRtDaCWSSYXEMxuXF IsVALAf0SpQww== Date: Sun, 31 Dec 2023 15:38:58 -0800 Subject: [PATCH 36/58] xfs_repair: don't zero the incore secondary super when zeroing From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <170405010427.1809361.9818118347695597896.stgit@frogsfrogsfrogs> In-Reply-To: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> References: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 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 secondary_sb_whack detects nonzero bytes beyond the end of the ondisk superblock, it will try to zero the end of the ondisk buffer as well as the incore superblock prior to scan_ag using that incore super to rewrite the ondisk super. However, the metadata directory feature adds a sb_metadirino field to the incore super. On disk, this is stored in the same slot as sb_rbmino, but we wanted to cache both inumbers incore to minimize the churn. Therefore, it is now only safe to zero the "end" of an xfs_dsb buffer, and never an xfs_sb object. Most of the XFS codebase moved off that second behavior long ago, with the exception of this one part of repair. The zeroing probably ought to be turned into explicit logic to zero fields that weren't defined with the featureset encoded in the primary superblock, but for now we'll resort to always resetting the values from the xfs_mount's xfs_sb. Signed-off-by: Darrick J. Wong --- repair/agheader.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/repair/agheader.c b/repair/agheader.c index 3930a0ac091..af88802ffdf 100644 --- a/repair/agheader.c +++ b/repair/agheader.c @@ -405,6 +405,13 @@ secondary_sb_whack( mp->m_sb.sb_sectsize - size); /* Preserve meta_uuid so we don't fail uuid checks */ memcpy(&sb->sb_meta_uuid, &tmpuuid, sizeof(uuid_t)); + + /* + * Preserve the parts of the incore super that extend + * beyond the part that's supposed to match the ondisk + * super byte for byte. + */ + sb->sb_metadirino = mp->m_sb.sb_metadirino; } else do_warn( _("would zero unused portion of %s superblock (AG #%u)\n"), From patchwork Sun Dec 31 23:39:13 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13508158 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 9A45ADDAB for ; Sun, 31 Dec 2023 23:39:14 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="HZbMkGV0" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 6B3FFC433C8; Sun, 31 Dec 2023 23:39:14 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704065954; bh=14eHtdD5jSHQyDFP9B17384soC8eNFjJob8d9b//RKs=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=HZbMkGV0w/SWoxrsOQ9nrxHp0gLLiGZjNdwvEI2Hy4N0ok4S+Biwox2EYVKJ+Sk1c c/HUVfw+6xMQPyctbSINQGFdJf+aHEQGQJUKctx0rN4+7ugZ68EPBlkraSUIaKoLFW yx7rwbXobWe9itziUPe3nOUAVw0lThcdc3OZjxz6N/I86C5VdWCdV+2aaxMBeNOnJT XvvZFb+P6yD48HIx10X2PxIUlEIDhrQfpapcCzyP6ZGyA4bnCI+hdPKlX0qg6Vdpd7 vcP3OHP1Lbt4qIwx9diiEAENFswSm7QmnKjYy2eYkgfyIemqK+Hjwc38P34R+vNESW NGXXqM0Q6QhiQ== Date: Sun, 31 Dec 2023 15:39:13 -0800 Subject: [PATCH 37/58] xfs_repair: refactor metadata inode tagging From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <170405010440.1809361.17433659396936418067.stgit@frogsfrogsfrogs> In-Reply-To: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> References: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Refactor tagging of metadata inodes into a single helper function instead of open-coding a if-else statement. Signed-off-by: Darrick J. Wong --- repair/dir2.c | 60 ++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 36 insertions(+), 24 deletions(-) diff --git a/repair/dir2.c b/repair/dir2.c index e46ae9ae46f..9f10fde09a1 100644 --- a/repair/dir2.c +++ b/repair/dir2.c @@ -136,6 +136,31 @@ process_sf_dir2_fixoff( } } +static bool +is_meta_ino( + struct xfs_mount *mp, + xfs_ino_t dirino, + xfs_ino_t lino, + char **junkreason) +{ + char *reason = NULL; + + if (lino == mp->m_sb.sb_rbmino) + reason = _("realtime bitmap"); + else if (lino == mp->m_sb.sb_rsumino) + reason = _("realtime summary"); + else if (lino == mp->m_sb.sb_uquotino) + reason = _("user quota"); + else if (lino == mp->m_sb.sb_gquotino) + reason = _("group quota"); + else if (lino == mp->m_sb.sb_pquotino) + reason = _("project quota"); + + if (reason) + *junkreason = reason; + return reason != NULL; +} + /* * this routine performs inode discovery and tries to fix things * in place. available redundancy -- inode data size should match @@ -227,21 +252,12 @@ process_sf_dir2( } else if (!libxfs_verify_dir_ino(mp, lino)) { junkit = 1; junkreason = _("invalid"); - } else if (lino == mp->m_sb.sb_rbmino) { + } else if (is_meta_ino(mp, ino, lino, &junkreason)) { + /* + * Directories that are not in the metadir tree should + * not be linking to metadata files. + */ junkit = 1; - junkreason = _("realtime bitmap"); - } else if (lino == mp->m_sb.sb_rsumino) { - junkit = 1; - junkreason = _("realtime summary"); - } else if (lino == mp->m_sb.sb_uquotino) { - junkit = 1; - junkreason = _("user quota"); - } else if (lino == mp->m_sb.sb_gquotino) { - junkit = 1; - junkreason = _("group quota"); - } else if (lino == mp->m_sb.sb_pquotino) { - junkit = 1; - junkreason = _("project quota"); } else if ((irec_p = find_inode_rec(mp, XFS_INO_TO_AGNO(mp, lino), XFS_INO_TO_AGINO(mp, lino))) != NULL) { @@ -698,16 +714,12 @@ process_dir2_data( * directory since it's still structurally intact. */ clearreason = _("invalid"); - } else if (ent_ino == mp->m_sb.sb_rbmino) { - clearreason = _("realtime bitmap"); - } else if (ent_ino == mp->m_sb.sb_rsumino) { - clearreason = _("realtime summary"); - } else if (ent_ino == mp->m_sb.sb_uquotino) { - clearreason = _("user quota"); - } else if (ent_ino == mp->m_sb.sb_gquotino) { - clearreason = _("group quota"); - } else if (ent_ino == mp->m_sb.sb_pquotino) { - clearreason = _("project quota"); + } else if (is_meta_ino(mp, ino, ent_ino, &clearreason)) { + /* + * Directories that are not in the metadir tree should + * not be linking to metadata files. + */ + clearino = 1; } else { irec_p = find_inode_rec(mp, XFS_INO_TO_AGNO(mp, ent_ino), From patchwork Sun Dec 31 23:39:29 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13508159 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 32DB9DDA9 for ; Sun, 31 Dec 2023 23:39:30 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="qQ0v3zLD" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 005B7C433C7; Sun, 31 Dec 2023 23:39:29 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704065970; bh=Y1Q1VZLrS9JbZN0QfqKnwQvpVJvoW0QoVCDCUa6XYTw=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=qQ0v3zLDvxLfNFhvQmb/tbjRzyTakN5n2iREoVUeWm3joj/Pe1Gx3sQR866Qqiaxg JbOY/57iHz60lBMnSjyEPbErXpZNcTzHqndFPJTwC37VW0mlMffjEKqLI1avVLa92Z tjssqG2MEy8R8o7fWrLu2kbgu74R8erSnvfj8MBr2R4BC8JBH3wmATAmEV1vQSEL0n Zb6gEaO5RDX+iXDYRt/FcTC6hIQddx6A3MEqY2miIIhg/Gx2P/epH/x0JmyOWbfTrw Jq8KxTI+ON4mSY9xhy8DqPtsyDDKT3P05eYHJ4CXbbbs6VTwyNjanqd+TSCV30WHR6 7udSTJ3+NTewA== Date: Sun, 31 Dec 2023 15:39:29 -0800 Subject: [PATCH 38/58] xfs_repair: reject regular directory dirents that point to metadata fieles From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <170405010454.1809361.7205361258702682954.stgit@frogsfrogsfrogs> In-Reply-To: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> References: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 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 a directory that's in the regular (non-metadata) directory tree has an entry that points to a metadata file, trash the dirent. Files are not allowed to cross between the two trees. Signed-off-by: Darrick J. Wong --- repair/dir2.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/repair/dir2.c b/repair/dir2.c index 9f10fde09a1..b4ebcd56d57 100644 --- a/repair/dir2.c +++ b/repair/dir2.c @@ -140,6 +140,7 @@ static bool is_meta_ino( struct xfs_mount *mp, xfs_ino_t dirino, + const struct xfs_dinode *dip, xfs_ino_t lino, char **junkreason) { @@ -155,6 +156,9 @@ is_meta_ino( reason = _("group quota"); else if (lino == mp->m_sb.sb_pquotino) reason = _("project quota"); + else if (dip->di_version >= 3 && + (dip->di_flags2 & cpu_to_be64(XFS_DIFLAG2_METADIR))) + reason = _("metadata directory file"); if (reason) *junkreason = reason; @@ -252,7 +256,7 @@ process_sf_dir2( } else if (!libxfs_verify_dir_ino(mp, lino)) { junkit = 1; junkreason = _("invalid"); - } else if (is_meta_ino(mp, ino, lino, &junkreason)) { + } else if (is_meta_ino(mp, ino, dip, lino, &junkreason)) { /* * Directories that are not in the metadir tree should * not be linking to metadata files. @@ -714,7 +718,7 @@ process_dir2_data( * directory since it's still structurally intact. */ clearreason = _("invalid"); - } else if (is_meta_ino(mp, ino, ent_ino, &clearreason)) { + } else if (is_meta_ino(mp, ino, dip, ent_ino, &clearreason)) { /* * Directories that are not in the metadir tree should * not be linking to metadata files. From patchwork Sun Dec 31 23:39:45 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13508160 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 38A20DDA9 for ; Sun, 31 Dec 2023 23:39:45 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="U0j/sDG5" Received: by smtp.kernel.org (Postfix) with ESMTPSA id B1375C433C8; Sun, 31 Dec 2023 23:39:45 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704065985; bh=PEZ6dQLon4Mar3SF8ooZq5QfKOeYVAnhltKRlBiRigU=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=U0j/sDG5hbfNvXyPgrlpGZLVuPjX2rMtofJMPf6iHum8jx2Q511Pm+5WSQ9O0Wv3J bcYaSp5bjiyAyApPD9UNBWDJI7AvZP3i0VKRc/0Cy2kAn3jz/6nj7kgC/06EpXpBJs Yz4eFN3H47x8Q6zS1w1G0l14RCpzDBKr4f1KTD2WNUbAZOcq7QsuaI66IbDGCCWA6F 4LAj3s5KsvnaU4Jeq8+hYIk5GeVaPNTjpqPIlOcUCjGn2zQOMfPlnCrQ01HYheCP15 Xi5SdhsIT3q2q8YjNW/6c3MlCSIrkEDfPbofiFpUzZeINkdGueaQvri+Me1Z3y+hSu 0BRKTh8OV9tcg== Date: Sun, 31 Dec 2023 15:39:45 -0800 Subject: [PATCH 39/58] xfs_repair: dont check metadata directory dirent inumbers From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <170405010467.1809361.17760617458885170181.stgit@frogsfrogsfrogs> In-Reply-To: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> References: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Phase 6 always rebuilds the entire metadata directory tree, and repair quietly ignores all the DIFLAG2_METADATA directory inodes that it finds. As a result, none of the metadata directories are marked inuse in the incore data. Therefore, the is_inode_free checks are not valid for anything we find in a metadata directory. Therefore, avoid checking is_inode_free when scanning metadata directory dirents. Signed-off-by: Darrick J. Wong --- libxfs/libxfs_api_defs.h | 1 + repair/dir2.c | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/libxfs/libxfs_api_defs.h b/libxfs/libxfs_api_defs.h index ca8e231c0fd..e171755a6f0 100644 --- a/libxfs/libxfs_api_defs.h +++ b/libxfs/libxfs_api_defs.h @@ -106,6 +106,7 @@ #define xfs_dinode_calc_crc libxfs_dinode_calc_crc #define xfs_dinode_good_version libxfs_dinode_good_version #define xfs_dinode_verify libxfs_dinode_verify +#define xfs_dinode_verify_metadir libxfs_dinode_verify_metadir #define xfs_dir2_data_bestfree_p libxfs_dir2_data_bestfree_p #define xfs_dir2_data_entry_tag_p libxfs_dir2_data_entry_tag_p diff --git a/repair/dir2.c b/repair/dir2.c index b4ebcd56d57..1184392ff47 100644 --- a/repair/dir2.c +++ b/repair/dir2.c @@ -165,6 +165,28 @@ is_meta_ino( return reason != NULL; } +static inline bool +is_metadata_directory( + struct xfs_mount *mp, + struct xfs_dinode *dip) +{ + xfs_failaddr_t fa; + uint16_t mode; + uint16_t flags; + uint64_t flags2; + + if (!xfs_has_metadir(mp)) + return false; + if (!(dip->di_flags2 & cpu_to_be64(XFS_DIFLAG2_METADIR))) + return false; + + mode = be16_to_cpu(dip->di_mode); + flags = be16_to_cpu(dip->di_flags); + flags2 = be64_to_cpu(dip->di_flags2); + fa = libxfs_dinode_verify_metadir(mp, dip, mode, flags, flags2); + return fa == NULL; +} + /* * this routine performs inode discovery and tries to fix things * in place. available redundancy -- inode data size should match @@ -256,6 +278,12 @@ process_sf_dir2( } else if (!libxfs_verify_dir_ino(mp, lino)) { junkit = 1; junkreason = _("invalid"); + } else if (is_metadata_directory(mp, dip)) { + /* + * Metadata directories are always rebuilt, so don't + * bother checking if the child inode is free or not. + */ + junkit = 0; } else if (is_meta_ino(mp, ino, dip, lino, &junkreason)) { /* * Directories that are not in the metadir tree should @@ -718,6 +746,12 @@ process_dir2_data( * directory since it's still structurally intact. */ clearreason = _("invalid"); + } else if (is_metadata_directory(mp, dip)) { + /* + * Metadata directories are always rebuilt, so don't + * bother checking if the child inode is free or not. + */ + clearino = 0; } else if (is_meta_ino(mp, ino, dip, ent_ino, &clearreason)) { /* * Directories that are not in the metadir tree should From patchwork Sun Dec 31 23:40:00 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13508161 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 02D33C2C0 for ; Sun, 31 Dec 2023 23:40:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="O+fV5CC4" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 65F2AC433C7; Sun, 31 Dec 2023 23:40:01 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704066001; bh=zvtRPGX4QxKHhVFTKrR3El3Eo6SiiLHLtMrXNQ2vMQk=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=O+fV5CC4a0I2evIOoGvsdHLg5VLAsjd40OGDKbzV229gVn0LYy3pfqRQMsO8b6CyK vxntsM0a56uVL1D5Hovm25D5+NARcDo+GBmlXsbWIkD7HE9vispj0RMpq8t/tjKrBR 5bHM/LytZxotwdk+oEI+xRIc+t7BXSMjGTOT0Rdm2Guc3mueeCo1fg5oFaZbk34bWh ABBi0qQVx1WY2ToUNDy9+ENwRLVxcpEfHBJOhZDfSerPGEQpg/GunTUQ3t96aJPZ1q hpLh8DWFX1ZA4PiwLb+1BSH/k4F+EdsAVo1Z/jvkFEtc9En4sMENqIybj9eMmtqjzI 5zopkFLrEX1RA== Date: Sun, 31 Dec 2023 15:40:00 -0800 Subject: [PATCH 40/58] xfs_repair: refactor fixing dotdot From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <170405010480.1809361.418418179550995939.stgit@frogsfrogsfrogs> In-Reply-To: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> References: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Pull the code that fixes a directory's dot-dot entry into a separate helper function so that we can call it on the rootdir and (later) the metadir. Signed-off-by: Darrick J. Wong --- repair/phase6.c | 96 +++++++++++++++++++++++++++++++++---------------------- 1 file changed, 57 insertions(+), 39 deletions(-) diff --git a/repair/phase6.c b/repair/phase6.c index fe9a4da62dc..65a387aa97f 100644 --- a/repair/phase6.c +++ b/repair/phase6.c @@ -2829,6 +2829,62 @@ dir_hash_add_parent_ptrs( } } +/* + * If we have to create a .. for /, do it now *before* we delete the bogus + * entries, otherwise the directory could transform into a shortform dir which + * would probably cause the simulation to choke. Even if the illegal entries + * get shifted around, it's ok because the entries are structurally intact and + * in in hash-value order so the simulation won't get confused if it has to + * move them around. + */ +static void +fix_dotdot( + struct xfs_mount *mp, + xfs_ino_t ino, + struct xfs_inode *ip, + xfs_ino_t rootino, + const char *tag, + int *need_dotdot) +{ + struct xfs_trans *tp; + int nres; + int error; + + if (ino != rootino || !*need_dotdot) + return; + + if (no_modify) { + do_warn(_("would recreate %s directory .. entry\n"), tag); + return; + } + + ASSERT(ip->i_df.if_format != XFS_DINODE_FMT_LOCAL); + + do_warn(_("recreating %s directory .. entry\n"), tag); + + nres = libxfs_mkdir_space_res(mp, 2); + error = -libxfs_trans_alloc(mp, &M_RES(mp)->tr_mkdir, nres, 0, 0, &tp); + if (error) + res_failed(error); + + libxfs_trans_ijoin(tp, ip, 0); + + error = -libxfs_dir_createname(tp, ip, &xfs_name_dotdot, ip->i_ino, + nres); + if (error) + do_error( +_("can't make \"..\" entry in %s inode %" PRIu64 ", createname error %d\n"), + tag ,ino, error); + + libxfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); + error = -libxfs_trans_commit(tp); + if (error) + do_error( +_("%s inode \"..\" entry recreation failed (%d)\n"), tag, error); + + *need_dotdot = 0; +} + /* * processes all reachable inodes in directories */ @@ -2958,45 +3014,7 @@ _("error %d fixing shortform directory %llu\n"), dir_hash_add_parent_ptrs(ip, hashtab); dir_hash_done(hashtab); - /* - * if we have to create a .. for /, do it now *before* - * we delete the bogus entries, otherwise the directory - * could transform into a shortform dir which would - * probably cause the simulation to choke. Even - * if the illegal entries get shifted around, it's ok - * because the entries are structurally intact and in - * in hash-value order so the simulation won't get confused - * if it has to move them around. - */ - if (!no_modify && need_root_dotdot && ino == mp->m_sb.sb_rootino) { - ASSERT(ip->i_df.if_format != XFS_DINODE_FMT_LOCAL); - - do_warn(_("recreating root directory .. entry\n")); - - nres = libxfs_mkdir_space_res(mp, 2); - error = -libxfs_trans_alloc(mp, &M_RES(mp)->tr_mkdir, - nres, 0, 0, &tp); - if (error) - res_failed(error); - - libxfs_trans_ijoin(tp, ip, 0); - - error = -libxfs_dir_createname(tp, ip, &xfs_name_dotdot, - ip->i_ino, nres); - if (error) - do_error( - _("can't make \"..\" entry in root inode %" PRIu64 ", createname error %d\n"), ino, error); - - libxfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); - error = -libxfs_trans_commit(tp); - if (error) - do_error( - _("root inode \"..\" entry recreation failed (%d)\n"), error); - - need_root_dotdot = 0; - } else if (need_root_dotdot && ino == mp->m_sb.sb_rootino) { - do_warn(_("would recreate root directory .. entry\n")); - } + fix_dotdot(mp, ino, ip, mp->m_sb.sb_rootino, "root", &need_root_dotdot); /* * if we need to create the '.' entry, do so only if From patchwork Sun Dec 31 23:40:16 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13508162 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 2E388C2C0 for ; Sun, 31 Dec 2023 23:40:17 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="W5fy7l3J" Received: by smtp.kernel.org (Postfix) with ESMTPSA id EFFC2C433C7; Sun, 31 Dec 2023 23:40:16 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704066017; bh=V1ZOrDlH9SGMpvoNpNWy8jN3daYiAF3YaZUnI/4AfaE=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=W5fy7l3JUgU4bGKDohTChsBI9adZTRZNKLVVH9WqIuXFUm+3wCEE93ybiI3Og7Gkf P1+8smBfQgcARbp82IyloOZcM/gvfgjVjLZt1vBeYq8/cv3fsskDe5AL7VJJopKYIS aP4GtasIqov+2tEMZ0ZKvgRIQM4w8Sm4njJ6gMvH1xvzkrQnmYPMG0axmHSueMwE7k +Dalvy+5HfDo+t2U63kZVh/z4anoEO9yMD57EVOJBCsfDfw66u+WFH5XrRjWsryVfm mW1qJ2VnbciQhYJWkSOzK1lxWUPc07RFlmHgw2C5ZToaLNcS+nxCOfSfyxkNiiAACv 4ozHcrLeQ0lIg== Date: Sun, 31 Dec 2023 15:40:16 -0800 Subject: [PATCH 41/58] xfs_repair: refactor marking of metadata inodes From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <170405010493.1809361.16695490725924720170.stgit@frogsfrogsfrogs> In-Reply-To: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> References: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Refactor the mechanics of marking a metadata inode into a helper function so that we don't have to open-code that for every single metadata inode. Signed-off-by: Darrick J. Wong --- repair/phase6.c | 76 ++++++++++++++++++++----------------------------------- 1 file changed, 28 insertions(+), 48 deletions(-) diff --git a/repair/phase6.c b/repair/phase6.c index 65a387aa97f..e01e81ae014 100644 --- a/repair/phase6.c +++ b/repair/phase6.c @@ -3071,6 +3071,22 @@ _("error %d fixing shortform directory %llu\n"), libxfs_irele(ip); } +static void +mark_inode( + struct xfs_mount *mp, + xfs_ino_t ino) +{ + struct ino_tree_node *irec; + int offset; + + irec = find_inode_rec(mp, XFS_INO_TO_AGNO(mp, ino), + XFS_INO_TO_AGINO(mp, ino)); + + offset = XFS_INO_TO_AGINO(mp, ino) - irec->ino_startnum; + + add_inode_reached(irec, offset); +} + /* * mark realtime bitmap and summary inodes as reached. * quota inode will be marked here as well @@ -3078,54 +3094,18 @@ _("error %d fixing shortform directory %llu\n"), static void mark_standalone_inodes(xfs_mount_t *mp) { - ino_tree_node_t *irec; - int offset; - - irec = find_inode_rec(mp, XFS_INO_TO_AGNO(mp, mp->m_sb.sb_rbmino), - XFS_INO_TO_AGINO(mp, mp->m_sb.sb_rbmino)); - - offset = XFS_INO_TO_AGINO(mp, mp->m_sb.sb_rbmino) - - irec->ino_startnum; - - add_inode_reached(irec, offset); - - irec = find_inode_rec(mp, XFS_INO_TO_AGNO(mp, mp->m_sb.sb_rsumino), - XFS_INO_TO_AGINO(mp, mp->m_sb.sb_rsumino)); - - offset = XFS_INO_TO_AGINO(mp, mp->m_sb.sb_rsumino) - - irec->ino_startnum; - - add_inode_reached(irec, offset); - - if (fs_quotas) { - if (mp->m_sb.sb_uquotino - && mp->m_sb.sb_uquotino != NULLFSINO) { - 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)); - offset = XFS_INO_TO_AGINO(mp, mp->m_sb.sb_uquotino) - - irec->ino_startnum; - add_inode_reached(irec, offset); - } - if (mp->m_sb.sb_gquotino - && mp->m_sb.sb_gquotino != NULLFSINO) { - 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)); - offset = XFS_INO_TO_AGINO(mp, mp->m_sb.sb_gquotino) - - irec->ino_startnum; - add_inode_reached(irec, offset); - } - if (mp->m_sb.sb_pquotino - && mp->m_sb.sb_pquotino != NULLFSINO) { - 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)); - offset = XFS_INO_TO_AGINO(mp, mp->m_sb.sb_pquotino) - - irec->ino_startnum; - add_inode_reached(irec, offset); - } - } + mark_inode(mp, mp->m_sb.sb_rbmino); + mark_inode(mp, mp->m_sb.sb_rsumino); + + 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); } static void From patchwork Sun Dec 31 23:40:32 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13508163 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 39683C2C0 for ; Sun, 31 Dec 2023 23:40:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="ITuFrA1x" Received: by smtp.kernel.org (Postfix) with ESMTPSA id A16CFC433C7; Sun, 31 Dec 2023 23:40:32 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704066032; bh=bCeMXBu7C10Z+pudnyV8K/59uBY8IW3/L1KgjRGCyC0=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=ITuFrA1xhTcTp5z0Wb2BvQ9m7l9YkQn4y6BAd778ASCr03SlhAzH6to62kGXn2vit N2gEXj8ep1otTp/3l6QdGYmqg5aKG20jA74UyZm6ZbwWD9JYhjC3SJHsQ7vI7fIuPQ NsNOJddRGJGnfrWbafl4ju6+C/0o2VKKRdO21zCtSQQLHMZrDNTbLcggNQ5nI0uBA0 ucWQUCmAqq/5kRPVdT7FQwUgFErnekv1r6NBgoZTmfaSC40BIKkSsW9pEmCoTl2Epe PvEEKbcaWHreNvfcpbPWxcukYIC/s6YL0aGC6MjPLI3xpeoYmkSvyynJNCn78Cq6LA iIt+wOaJQ8uqg== Date: Sun, 31 Dec 2023 15:40:32 -0800 Subject: [PATCH 42/58] xfs_repair: refactor root directory initialization From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <170405010506.1809361.2695340498551995034.stgit@frogsfrogsfrogs> In-Reply-To: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> References: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Refactor root directory initialization into a separate function we can call for both the root dir and the metadir. Signed-off-by: Darrick J. Wong --- repair/phase6.c | 63 +++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 40 insertions(+), 23 deletions(-) diff --git a/repair/phase6.c b/repair/phase6.c index e01e81ae014..017c46f43af 100644 --- a/repair/phase6.c +++ b/repair/phase6.c @@ -773,27 +773,27 @@ mk_rsumino(xfs_mount_t *mp) libxfs_irele(ip); } -/* - * makes a new root directory. - */ -static void -mk_root_dir(xfs_mount_t *mp) +/* Initialize a root directory. */ +static int +init_fs_root_dir( + struct xfs_mount *mp, + xfs_ino_t ino, + mode_t mode, + struct xfs_inode **ipp) { - xfs_trans_t *tp; - xfs_inode_t *ip; - int i; - int error; - const mode_t mode = 0755; - ino_tree_node_t *irec; + struct xfs_trans *tp; + struct xfs_inode *ip = NULL; + struct ino_tree_node *irec; + int error; - ip = NULL; - i = -libxfs_trans_alloc(mp, &M_RES(mp)->tr_ichange, 10, 0, 0, &tp); - if (i) - res_failed(i); + error = -libxfs_trans_alloc(mp, &M_RES(mp)->tr_ichange, 10, 0, 0, &tp); + if (error) + return error; - error = -libxfs_iget(mp, tp, mp->m_sb.sb_rootino, 0, &ip); + error = -libxfs_iget(mp, tp, ino, 0, &ip); if (error) { - do_error(_("could not iget root inode -- error - %d\n"), error); + libxfs_trans_cancel(tp); + return error; } /* Reset the root directory. */ @@ -802,14 +802,31 @@ mk_root_dir(xfs_mount_t *mp) error = -libxfs_trans_commit(tp); if (error) - do_error(_("%s: commit failed, error %d\n"), __func__, error); + return error; + + irec = find_inode_rec(mp, XFS_INO_TO_AGNO(mp, ino), + XFS_INO_TO_AGINO(mp, ino)); + set_inode_isadir(irec, XFS_INO_TO_AGINO(mp, ino) - irec->ino_startnum); + *ipp = ip; + return 0; +} + +/* + * makes a new root directory. + */ +static void +mk_root_dir(xfs_mount_t *mp) +{ + struct xfs_inode *ip = NULL; + int error; + + error = init_fs_root_dir(mp, mp->m_sb.sb_rootino, 0755, &ip); + if (error) + do_error( + _("Could not reinitialize root directory inode, error %d\n"), + error); libxfs_irele(ip); - - irec = find_inode_rec(mp, XFS_INO_TO_AGNO(mp, mp->m_sb.sb_rootino), - XFS_INO_TO_AGINO(mp, mp->m_sb.sb_rootino)); - set_inode_isadir(irec, XFS_INO_TO_AGINO(mp, mp->m_sb.sb_rootino) - - irec->ino_startnum); } /* From patchwork Sun Dec 31 23:40:47 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13508164 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 76F9DC2CC for ; Sun, 31 Dec 2023 23:40:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="GszBo6nD" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 46CDDC433C7; Sun, 31 Dec 2023 23:40:48 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704066048; bh=KpsHVfLM0Z7bKtM2Xb7zuRQ0txlVnlDKg3L4DCVW8oY=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=GszBo6nD3BCHAvNAXKBeBbavOOZmT4loxSNwxP7OEisI7p+N69QNrs5YeUWoygIy+ P1mX7keVJEu/HFnm+lU6Xfq93qieT2He1fOab16p84LG31vOgwnCE0o1qtqOnmq/Vn UlpiweQ1YBrv+Z0TJuVue8sUcUqCL9PjRVFdBR/hn9lXrZMko7CIUc9wKFWmshmZGe KmKcnrXZPGMX1cFsRTDGfuRWna6p3jCGeWt1Yi34ViHroazzdd6pcC25VRPkgfKEt1 efJu5HE18PasqMwXVLRkzGk7nKFuZca22FTfaTsGKbHXy/CMa9q1Lqt8/rvy3jAkki kfBNcCVBslmBw== Date: Sun, 31 Dec 2023 15:40:47 -0800 Subject: [PATCH 43/58] xfs_repair: refactor grabbing realtime metadata inodes From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <170405010520.1809361.17407986062622776380.stgit@frogsfrogsfrogs> In-Reply-To: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> References: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Create a helper function to grab a realtime metadata inode. When metadir arrives, the bitmap and summary inodes can float, so we'll turn this function into a "load or allocate" function. Signed-off-by: Darrick J. Wong --- repair/phase6.c | 90 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 53 insertions(+), 37 deletions(-) diff --git a/repair/phase6.c b/repair/phase6.c index 017c46f43af..afb09ff7232 100644 --- a/repair/phase6.c +++ b/repair/phase6.c @@ -471,18 +471,37 @@ reset_root_ino( libxfs_inode_init(tp, &args, ip); } +/* Load a realtime metadata inode from disk and reset it. */ +static int +ensure_rtino( + struct xfs_trans *tp, + xfs_ino_t ino, + struct xfs_inode **ipp) +{ + struct xfs_mount *mp = tp->t_mountp; + int error; + + error = -libxfs_iget(mp, tp, ino, 0, ipp); + if (error) + return error; + + reset_root_ino(tp, S_IFREG, *ipp); + return 0; +} + static void -mk_rbmino(xfs_mount_t *mp) +mk_rbmino( + struct xfs_mount *mp) { - xfs_trans_t *tp; - xfs_inode_t *ip; - xfs_bmbt_irec_t *ep; - int i; - int nmap; - int error; - xfs_fileoff_t bno; - xfs_bmbt_irec_t map[XFS_BMAP_MAX_NMAP]; - uint blocks; + struct xfs_trans *tp; + struct xfs_inode *ip; + struct xfs_bmbt_irec *ep; + int i; + int nmap; + int error; + xfs_fileoff_t bno; + struct xfs_bmbt_irec map[XFS_BMAP_MAX_NMAP]; + uint blocks; /* * first set up inode @@ -491,15 +510,13 @@ mk_rbmino(xfs_mount_t *mp) if (i) res_failed(i); - error = -libxfs_iget(mp, tp, mp->m_sb.sb_rbmino, 0, &ip); - if (error) { - do_error( - _("couldn't iget realtime bitmap inode -- error - %d\n"), - error); - } - /* Reset the realtime bitmap inode. */ - reset_root_ino(tp, S_IFREG, ip); + error = ensure_rtino(tp, mp->m_sb.sb_rbmino, &ip); + if (error) { + do_error( + _("couldn't iget realtime bitmap inode -- error - %d\n"), + error); + } ip->i_disk_size = mp->m_sb.sb_rbmblocks * mp->m_sb.sb_blocksize; libxfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); error = -libxfs_trans_commit(tp); @@ -700,18 +717,19 @@ _("can't access block %" PRIu64 " (fsbno %" PRIu64 ") of realtime summary inode } static void -mk_rsumino(xfs_mount_t *mp) +mk_rsumino( + struct xfs_mount *mp) { - xfs_trans_t *tp; - xfs_inode_t *ip; - xfs_bmbt_irec_t *ep; - int i; - int nmap; - int error; - int nsumblocks; - xfs_fileoff_t bno; - xfs_bmbt_irec_t map[XFS_BMAP_MAX_NMAP]; - uint blocks; + struct xfs_trans *tp; + struct xfs_inode *ip; + struct xfs_bmbt_irec *ep; + int i; + int nmap; + int error; + int nsumblocks; + xfs_fileoff_t bno; + struct xfs_bmbt_irec map[XFS_BMAP_MAX_NMAP]; + uint blocks; /* * first set up inode @@ -720,15 +738,13 @@ mk_rsumino(xfs_mount_t *mp) if (i) res_failed(i); - error = -libxfs_iget(mp, tp, mp->m_sb.sb_rsumino, 0, &ip); - if (error) { - do_error( - _("couldn't iget realtime summary inode -- error - %d\n"), - error); - } - /* Reset the rt summary inode. */ - reset_root_ino(tp, S_IFREG, ip); + error = ensure_rtino(tp, mp->m_sb.sb_rsumino, &ip); + if (error) { + do_error( + _("couldn't iget realtime summary inode -- error - %d\n"), + error); + } ip->i_disk_size = mp->m_rsumsize; libxfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); error = -libxfs_trans_commit(tp); From patchwork Sun Dec 31 23:41:03 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13508165 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 28A69C2C0 for ; Sun, 31 Dec 2023 23:41:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="oNjnT0BL" Received: by smtp.kernel.org (Postfix) with ESMTPSA id EBCD2C433C8; Sun, 31 Dec 2023 23:41:03 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704066064; bh=W7EaV+SZo5/9boffTuMfBXBm4JR9DxZ+BgjQTgAM4GQ=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=oNjnT0BLg+SLP9x1dXoL5fFMPOk4Sz4l6XQ+u5y0OaZuEQnQeOjry1QBUo6MlU4A4 xHEKiE2T7PaxPU0XoNdrLVazM2/skcw2DDOUJ/2kX228eA0Ztgka1NSC9ujfbO9jJ6 Kkxjl3/KcOFsY4M575kMw769+uaSiwvqy52TIoQD2x4tHPM9NkXuf3XqVJxxYOr+AD UNvqKzQZ9ryaOAR1UJ0RvmyDTkdoomQNMQB1Dji+/NLucUi3HfHEhqaG7NzrW5K6oR lYZu5ZvJ0g1YnuCZcc4763YTbe1iICRKKracxES1vjql4OV3IGY6mQ0V84n6e43ePI TA9AKDt+Dsa1w== Date: Sun, 31 Dec 2023 15:41:03 -0800 Subject: [PATCH 44/58] xfs_repair: check metadata inode flag From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <170405010533.1809361.10226253768657395190.stgit@frogsfrogsfrogs> In-Reply-To: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> References: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Check whether or not the metadata inode flag is set appropriately. Signed-off-by: Darrick J. Wong --- repair/dinode.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/repair/dinode.c b/repair/dinode.c index f2da4325d5e..4af7c91d5c9 100644 --- a/repair/dinode.c +++ b/repair/dinode.c @@ -2669,6 +2669,20 @@ _("bad (negative) size %" PRId64 " on inode %" PRIu64 "\n"), } } + if (flags2 & XFS_DIFLAG2_METADIR) { + xfs_failaddr_t fa; + + fa = libxfs_dinode_verify_metadir(mp, dino, di_mode, + be16_to_cpu(dino->di_flags), flags2); + if (fa) { + if (!uncertain) + do_warn( + _("inode %" PRIu64 " is incorrectly marked as metadata\n"), + lino); + goto clear_bad_out; + } + } + if ((flags2 & XFS_DIFLAG2_REFLINK) && !xfs_has_reflink(mp)) { if (!uncertain) { From patchwork Sun Dec 31 23:41:19 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13508166 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 BA0ADC2C5 for ; Sun, 31 Dec 2023 23:41:19 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="uEM3uOvC" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 8274FC433C7; Sun, 31 Dec 2023 23:41:19 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704066079; bh=53DXZrN34nrYzVjtwFlNLxASjeSy3NbolYryVjmKhrk=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=uEM3uOvCzYJmq7zztE4UBLu3cSbH5BUpRkA5mXwye1ZQVREnLV4Dn40Vn4UsfQHJd cB68YqgEodys3aO+O0tE3EQRC0Zjb6HMV8G3wh72KKRQmf/fy4eMqWyeysF/TSBiAR xElgHmcBsLZa6GuUEbEO77WByiinWVNl9mpdN0iNypVuvB1C8Y6yuGghAM0Uo6KSz9 MJ/2zZkqWcvsCgRt05Pk5MTyqR6aTUtxevU4yKCVce+U9rTQ84xjTSkv7cxHqkYyqz kyUXS+4/xW+CMbN8JUcV+NajYePJ6W2B6tZapuL+pma0BUHDw9Izj168bYMjauFJXY EyH5toR9qG7aw== Date: Sun, 31 Dec 2023 15:41:19 -0800 Subject: [PATCH 45/58] xfs_repair: rebuild the metadata directory From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <170405010546.1809361.1266895681831439993.stgit@frogsfrogsfrogs> In-Reply-To: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> References: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Check the metadata directory for problems and rebuild it if necessary. Signed-off-by: Darrick J. Wong --- libxfs/libxfs_api_defs.h | 2 repair/dino_chunks.c | 12 ++ repair/dir2.c | 25 +++ repair/globals.c | 3 repair/globals.h | 3 repair/phase1.c | 2 repair/phase2.c | 7 + repair/phase4.c | 16 ++ repair/phase6.c | 361 ++++++++++++++++++++++++++++++++++++++++++---- repair/pptr.c | 51 ++++++ repair/pptr.h | 2 repair/sb.c | 3 repair/xfs_repair.c | 81 ++++++++++ 13 files changed, 526 insertions(+), 42 deletions(-) diff --git a/libxfs/libxfs_api_defs.h b/libxfs/libxfs_api_defs.h index e171755a6f0..5f2250ac5e2 100644 --- a/libxfs/libxfs_api_defs.h +++ b/libxfs/libxfs_api_defs.h @@ -188,7 +188,7 @@ #define xfs_imeta_link_space_res libxfs_imeta_link_space_res #define xfs_imeta_lookup libxfs_imeta_lookup #define xfs_imeta_mount libxfs_imeta_mount -#define xfs_imeta_set_metaflag libxfs_imeta_set_metaflag +#define xfs_imeta_set_iflag libxfs_imeta_set_iflag #define xfs_imeta_start_create libxfs_imeta_start_create #define xfs_imeta_start_link libxfs_imeta_start_link #define xfs_imeta_start_unlink libxfs_imeta_start_unlink diff --git a/repair/dino_chunks.c b/repair/dino_chunks.c index 19536133451..479dc9db760 100644 --- a/repair/dino_chunks.c +++ b/repair/dino_chunks.c @@ -932,6 +932,18 @@ process_inode_chunk( _("would clear root inode %" PRIu64 "\n"), ino); } + } else if (mp->m_sb.sb_metadirino == ino) { + need_metadir_inode = true; + + if (!no_modify) { + do_warn( + _("cleared metadata directory %" PRIu64 "\n"), + ino); + } else { + do_warn( + _("would clear metadata directory %" PRIu64 "\n"), + ino); + } } else if (mp->m_sb.sb_rbmino == ino) { need_rbmino = 1; diff --git a/repair/dir2.c b/repair/dir2.c index 1184392ff47..a7f5018fba2 100644 --- a/repair/dir2.c +++ b/repair/dir2.c @@ -146,6 +146,10 @@ is_meta_ino( { char *reason = NULL; + /* in metadir land we don't have static metadata inodes anymore */ + if (xfs_has_metadir(mp)) + return false; + if (lino == mp->m_sb.sb_rbmino) reason = _("realtime bitmap"); else if (lino == mp->m_sb.sb_rsumino) @@ -160,6 +164,16 @@ is_meta_ino( (dip->di_flags2 & cpu_to_be64(XFS_DIFLAG2_METADIR))) reason = _("metadata directory file"); + if (xfs_has_metadir(mp) && + dirino == mp->m_sb.sb_metadirino) { + if (reason == NULL) { + /* no regular files in the metadir */ + *junkreason = _("non-metadata inode"); + return true; + } + return false; + } + if (reason) *junkreason = reason; return reason != NULL; @@ -583,7 +597,8 @@ _("corrected root directory %" PRIu64 " .. entry, was %" PRIu64 ", now %" PRIu64 _("would have corrected root directory %" PRIu64 " .. entry from %" PRIu64" to %" PRIu64 "\n"), ino, *parent, ino); } - } else if (ino == *parent && ino != mp->m_sb.sb_rootino) { + } else if (ino == *parent && ino != mp->m_sb.sb_rootino && + ino != mp->m_sb.sb_metadirino) { /* * likewise, non-root directories can't have .. pointing * to . @@ -879,7 +894,8 @@ _("entry at block %u offset %" PRIdPTR " in directory inode %" PRIu64 " has ille * NULLFSINO otherwise. */ if (ino == ent_ino && - ino != mp->m_sb.sb_rootino) { + ino != mp->m_sb.sb_rootino && + ino != mp->m_sb.sb_metadirino) { *parent = NULLFSINO; do_warn( _("bad .. entry in directory inode %" PRIu64 ", points to self: "), @@ -1520,9 +1536,14 @@ process_dir2( } else if (dotdot == 0 && ino == mp->m_sb.sb_rootino) { do_warn(_("no .. entry for root directory %" PRIu64 "\n"), ino); need_root_dotdot = 1; + } else if (dotdot == 0 && ino == mp->m_sb.sb_metadirino) { + do_warn(_("no .. entry for metaino directory %" PRIu64 "\n"), ino); + need_metadir_dotdot = 1; } ASSERT((ino != mp->m_sb.sb_rootino && ino != *parent) || + (ino == mp->m_sb.sb_metadirino && + (ino == *parent || need_metadir_dotdot == 1)) || (ino == mp->m_sb.sb_rootino && (ino == *parent || need_root_dotdot == 1))); diff --git a/repair/globals.c b/repair/globals.c index 7d95e210e8e..22cb096c6a4 100644 --- a/repair/globals.c +++ b/repair/globals.c @@ -69,6 +69,9 @@ int fs_is_dirty; int need_root_inode; int need_root_dotdot; +bool need_metadir_inode; +int need_metadir_dotdot; + int need_rbmino; int need_rsumino; diff --git a/repair/globals.h b/repair/globals.h index 71a64b94365..c3709f11874 100644 --- a/repair/globals.h +++ b/repair/globals.h @@ -110,6 +110,9 @@ extern int fs_is_dirty; extern int need_root_inode; extern int need_root_dotdot; +extern bool need_metadir_inode; +extern int need_metadir_dotdot; + extern int need_rbmino; extern int need_rsumino; diff --git a/repair/phase1.c b/repair/phase1.c index 00b98584eed..40e7f164c55 100644 --- a/repair/phase1.c +++ b/repair/phase1.c @@ -48,6 +48,8 @@ phase1(xfs_mount_t *mp) primary_sb_modified = 0; need_root_inode = 0; need_root_dotdot = 0; + need_metadir_inode = false; + need_metadir_dotdot = 0; need_rbmino = 0; need_rsumino = 0; lost_quotas = 0; diff --git a/repair/phase2.c b/repair/phase2.c index a58fa7d8a7b..5a08cbc31c6 100644 --- a/repair/phase2.c +++ b/repair/phase2.c @@ -646,8 +646,11 @@ phase2( * make sure we know about the root inode chunk */ if ((ino_rec = find_inode_rec(mp, 0, mp->m_sb.sb_rootino)) == NULL) { - ASSERT(mp->m_sb.sb_rbmino == mp->m_sb.sb_rootino + 1 && - mp->m_sb.sb_rsumino == mp->m_sb.sb_rootino + 2); + ASSERT(!xfs_has_metadir(mp) || + mp->m_sb.sb_metadirino == mp->m_sb.sb_rootino + 1); + ASSERT(xfs_has_metadir(mp) || + (mp->m_sb.sb_rbmino == mp->m_sb.sb_rootino + 1 && + mp->m_sb.sb_rsumino == mp->m_sb.sb_rootino + 2)); do_warn(_("root inode chunk not found\n")); /* diff --git a/repair/phase4.c b/repair/phase4.c index 5e5d8c3c7d9..f004111ea4e 100644 --- a/repair/phase4.c +++ b/repair/phase4.c @@ -264,6 +264,22 @@ phase4(xfs_mount_t *mp) do_warn(_("root inode lost\n")); } + /* + * If metadata directory trees are enabled, the metadata root directory + * always comes immediately after the regular root directory, even if + * it's free. + */ + if (xfs_has_metadir(mp) && + (is_inode_free(irec, 1) || !inode_isadir(irec, 1))) { + need_metadir_inode = true; + if (no_modify) + do_warn( + _("metadata directory root inode would be lost\n")); + else + do_warn( + _("metadata directory root inode lost\n")); + } + for (i = 0; i < mp->m_sb.sb_agcount; i++) { ag_end = (i < mp->m_sb.sb_agcount - 1) ? mp->m_sb.sb_agblocks : mp->m_sb.sb_dblocks - diff --git a/repair/phase6.c b/repair/phase6.c index afb09ff7232..05e0b8ac593 100644 --- a/repair/phase6.c +++ b/repair/phase6.c @@ -471,6 +471,144 @@ reset_root_ino( libxfs_inode_init(tp, &args, ip); } +/* Mark a newly allocated inode in use in the incore bitmap. */ +static void +mark_ino_inuse( + struct xfs_mount *mp, + xfs_ino_t ino, + int mode, + xfs_ino_t parent) +{ + struct ino_tree_node *irec; + int ino_offset; + int i; + + irec = find_inode_rec(mp, XFS_INO_TO_AGNO(mp, ino), + XFS_INO_TO_AGINO(mp, ino)); + + if (irec == NULL) { + /* + * This inode is allocated from a newly created inode + * chunk and therefore did not exist when inode chunks + * were processed in phase3. Add this group of inodes to + * the entry avl tree as if they were discovered in phase3. + */ + irec = set_inode_free_alloc(mp, + XFS_INO_TO_AGNO(mp, ino), + XFS_INO_TO_AGINO(mp, ino)); + alloc_ex_data(irec); + + for (i = 0; i < XFS_INODES_PER_CHUNK; i++) + set_inode_free(irec, i); + } + + ino_offset = get_inode_offset(mp, ino, irec); + + /* + * Mark the inode allocated so it is not skipped in phase 7. We'll + * find it with the directory traverser soon, so we don't need to + * mark it reached. + */ + set_inode_used(irec, ino_offset); + set_inode_ftype(irec, ino_offset, libxfs_mode_to_ftype(mode)); + set_inode_parent(irec, ino_offset, parent); + if (S_ISDIR(mode)) + set_inode_isadir(irec, ino_offset); +} + +/* Make sure this metadata directory path exists. */ +static int +ensure_imeta_dirpath( + struct xfs_mount *mp, + const struct xfs_imeta_path *path) +{ + struct xfs_imeta_path temp_path = { + .im_path = path->im_path, + .im_depth = 1, + .im_ftype = XFS_DIR3_FT_DIR, + }; + struct xfs_trans *tp; + unsigned int i; + xfs_ino_t parent; + int error; + + if (!xfs_has_metadir(mp)) + return 0; + + error = -libxfs_imeta_ensure_dirpath(mp, path); + if (error) + return error; + + error = -libxfs_trans_alloc_empty(mp, &tp); + if (error) + return error; + + /* Mark all directories in this path as inuse. */ + parent = mp->m_metadirip->i_ino; + for (i = 0; i < path->im_depth - 1; i++, temp_path.im_depth++) { + xfs_ino_t ino; + + error = -libxfs_imeta_lookup(tp, &temp_path, &ino); + if (error) + break; + if (ino == NULLFSINO) { + error = ENOENT; + break; + } + + mark_ino_inuse(mp, ino, S_IFDIR, parent); + parent = ino; + } + + libxfs_trans_cancel(tp); + return error; +} + +/* Look up the parent of this path. */ +static xfs_ino_t +lookup_imeta_path_dirname( + struct xfs_mount *mp, + const struct xfs_imeta_path *path) +{ + struct xfs_imeta_path temp_path = { + .im_path = path->im_path, + .im_depth = path->im_depth - 1, + .im_ftype = XFS_DIR3_FT_DIR, + }; + struct xfs_trans *tp; + xfs_ino_t ino; + int error; + + if (!xfs_has_metadir(mp)) + return NULLFSINO; + + error = -libxfs_trans_alloc_empty(mp, &tp); + if (error) + return NULLFSINO; + error = -libxfs_imeta_lookup(tp, &temp_path, &ino); + libxfs_trans_cancel(tp); + if (error) + return NULLFSINO; + + return ino; +} + +static inline bool +is_inode_inuse( + struct xfs_mount *mp, + xfs_ino_t inum) +{ + struct ino_tree_node *irec; + int ino_offset; + + irec = find_inode_rec(mp, XFS_INO_TO_AGNO(mp, inum), + XFS_INO_TO_AGINO(mp, inum)); + if (!irec) + return false; + ino_offset = XFS_INO_TO_AGINO(mp, inum) - irec->ino_startnum; + return !is_inode_free(irec, ino_offset); +} + /* Load a realtime metadata inode from disk and reset it. */ static int ensure_rtino( @@ -489,12 +627,95 @@ ensure_rtino( return 0; } +/* + * Either link the old rtbitmap/summary inode into the (reinitialized) metadata + * directory tree, or create new ones. + */ +static void +ensure_rtino_metadir( + struct xfs_mount *mp, + const struct xfs_imeta_path *path, + xfs_ino_t *inop, + struct xfs_inode **ipp, + struct xfs_imeta_update *upd) +{ + struct xfs_trans *tp; + xfs_ino_t ino = *inop; + int error; + + /* + * If the incore inode pointer is null or points to an inode that is + * not allocated, we need to create a new file. + */ + if (ino == NULLFSINO || !is_inode_inuse(mp, ino)) { + error = -libxfs_imeta_start_create(mp, path, upd); + if (error) + do_error( + _("failed to allocate resources to recreate rt metadata inode, error %d\n"), + error); + + /* Allocate a new inode. */ + error = -libxfs_imeta_create(upd, S_IFREG, ipp); + if (error) + do_error( + _("couldn't create new rt metadata inode, error %d\n"), error); + + ASSERT(*inop == upd->ip->i_ino); + + mark_ino_inuse(mp, upd->ip->i_ino, S_IFREG, + lookup_imeta_path_dirname(mp, path)); + return; + } + + /* + * We found the old rt metadata file and it looks ok. Link it into + * the metadata directory tree. Null out the superblock pointer before + * we re-link this file into it. + */ + *inop = NULLFSINO; + + error = -libxfs_trans_alloc_empty(mp, &tp); + if (error) + do_error( + _("failed to allocate trans to iget rt metadata inode 0x%llx, error %d\n"), + (unsigned long long)ino, error); + error = -libxfs_imeta_iget(tp, ino, XFS_DIR3_FT_REG_FILE, ipp); + libxfs_trans_cancel(tp); + if (error) + do_error( + _("failed to iget rt metadata inode 0x%llx, error %d\n"), + (unsigned long long)ino, error); + + /* + * Since we're reattaching this file to the metadata directory tree, + * try to remove all the parent pointers that might be attached. + */ + try_erase_parent_ptrs(*ipp); + + error = -libxfs_imeta_start_link(mp, path, *ipp, upd); + if (error) + do_error( + _("failed to allocate resources to reinsert rt metadata inode 0x%llx, error %d\n"), + (unsigned long long)ino, error); + + error = -libxfs_imeta_link(upd); + if (error) + do_error( + _("failed to link rt metadata inode 0x%llx, error %d\n"), + (unsigned long long)ino, error); + + /* Reset the link count to something sane. */ + set_nlink(VFS_I(upd->ip), 1); + libxfs_trans_log_inode(upd->tp, upd->ip, XFS_ILOG_CORE); +} + static void mk_rbmino( struct xfs_mount *mp) { - struct xfs_trans *tp; - struct xfs_inode *ip; + struct xfs_imeta_update upd = { }; + struct xfs_trans *tp = NULL; + struct xfs_inode *ip = NULL; struct xfs_bmbt_irec *ep; int i; int nmap; @@ -503,23 +724,32 @@ mk_rbmino( struct xfs_bmbt_irec map[XFS_BMAP_MAX_NMAP]; uint blocks; - /* - * first set up inode - */ - i = -libxfs_trans_alloc_rollable(mp, 10, &tp); - if (i) - res_failed(i); - /* Reset the realtime bitmap inode. */ - error = ensure_rtino(tp, mp->m_sb.sb_rbmino, &ip); - if (error) { - do_error( - _("couldn't iget realtime bitmap inode -- error - %d\n"), - error); + if (!xfs_has_metadir(mp)) { + i = -libxfs_trans_alloc_rollable(mp, 10, &upd.tp); + if (i) + res_failed(i); + + error = ensure_rtino(upd.tp, mp->m_sb.sb_rbmino, &ip); + if (error) { + do_error( + _("couldn't iget realtime bitmap inode -- error - %d\n"), + error); + } + } else { + error = ensure_imeta_dirpath(mp, &XFS_IMETA_RTBITMAP); + if (error) + do_error( + _("Couldn't create realtime metadata directory, error %d\n"), error); + + ensure_rtino_metadir(mp, &XFS_IMETA_RTBITMAP, + &mp->m_sb.sb_rbmino, &ip, &upd); } + ip->i_disk_size = mp->m_sb.sb_rbmblocks * mp->m_sb.sb_blocksize; - libxfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); - error = -libxfs_trans_commit(tp); + libxfs_trans_log_inode(upd.tp, ip, XFS_ILOG_CORE); + + error = -libxfs_imeta_commit_update(&upd); if (error) do_error(_("%s: commit failed, error %d\n"), __func__, error); @@ -720,8 +950,9 @@ static void mk_rsumino( struct xfs_mount *mp) { - struct xfs_trans *tp; - struct xfs_inode *ip; + struct xfs_imeta_update upd = { }; + struct xfs_trans *tp = NULL; + struct xfs_inode *ip = NULL; struct xfs_bmbt_irec *ep; int i; int nmap; @@ -731,23 +962,32 @@ mk_rsumino( struct xfs_bmbt_irec map[XFS_BMAP_MAX_NMAP]; uint blocks; - /* - * first set up inode - */ - i = -libxfs_trans_alloc(mp, &M_RES(mp)->tr_ichange, 10, 0, 0, &tp); - if (i) - res_failed(i); + /* Reset the realtime summary inode. */ + if (!xfs_has_metadir(mp)) { + i = -libxfs_trans_alloc_rollable(mp, 10, &upd.tp); + if (i) + res_failed(i); - /* Reset the rt summary inode. */ - error = ensure_rtino(tp, mp->m_sb.sb_rsumino, &ip); - if (error) { - do_error( - _("couldn't iget realtime summary inode -- error - %d\n"), - error); + error = ensure_rtino(upd.tp, mp->m_sb.sb_rsumino, &ip); + if (error) { + do_error( + _("couldn't iget realtime summary inode -- error - %d\n"), + error); + } + } else { + error = ensure_imeta_dirpath(mp, &XFS_IMETA_RTSUMMARY); + if (error) + do_error( + _("Couldn't create realtime metadata directory, error %d\n"), error); + + ensure_rtino_metadir(mp, &XFS_IMETA_RTSUMMARY, + &mp->m_sb.sb_rsumino, &ip, &upd); } + ip->i_disk_size = mp->m_rsumsize; - libxfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); - error = -libxfs_trans_commit(tp); + libxfs_trans_log_inode(upd.tp, ip, XFS_ILOG_CORE); + + error = -libxfs_imeta_commit_update(&upd); if (error) do_error(_("%s: commit failed, error %d\n"), __func__, error); @@ -845,6 +1085,36 @@ mk_root_dir(xfs_mount_t *mp) libxfs_irele(ip); } +/* Create a new metadata directory root. */ +static void +mk_metadir( + struct xfs_mount *mp) +{ + struct xfs_trans *tp; + int error; + + error = init_fs_root_dir(mp, mp->m_sb.sb_metadirino, 0, + &mp->m_metadirip); + if (error) + do_error( + _("Initialization of the metadata root directory failed, error %d\n"), + error); + + /* Mark the new metadata root dir as metadata. */ + error = -libxfs_trans_alloc(mp, &M_RES(mp)->tr_ichange, 0, 0, 0, &tp); + if (error) + do_error( + _("Marking metadata root directory failed")); + + libxfs_trans_ijoin(tp, mp->m_metadirip, 0); + libxfs_imeta_set_iflag(tp, mp->m_metadirip); + + error = -libxfs_trans_commit(tp); + if (error) + do_error( + _("Marking metadata root directory failed, error %d\n"), error); +} + /* * orphanage name == lost+found */ @@ -1354,6 +1624,8 @@ longform_dir2_rebuild( if (ino == mp->m_sb.sb_rootino) need_root_dotdot = 0; + else if (ino == mp->m_sb.sb_metadirino) + need_metadir_dotdot = 0; /* go through the hash list and re-add the inodes */ @@ -2973,7 +3245,7 @@ process_dir_inode( need_dot = dirty = num_illegal = 0; - if (mp->m_sb.sb_rootino == ino) { + if (mp->m_sb.sb_rootino == ino || mp->m_sb.sb_metadirino == ino) { /* * mark root inode reached and bump up * link count for root inode to account @@ -3048,6 +3320,9 @@ _("error %d fixing shortform directory %llu\n"), dir_hash_done(hashtab); fix_dotdot(mp, ino, ip, mp->m_sb.sb_rootino, "root", &need_root_dotdot); + if (xfs_has_metadir(mp)) + fix_dotdot(mp, ino, ip, mp->m_sb.sb_metadirino, "metadata", + &need_metadir_dotdot); /* * if we need to create the '.' entry, do so only if @@ -3127,6 +3402,15 @@ mark_inode( static void mark_standalone_inodes(xfs_mount_t *mp) { + if (xfs_has_metadir(mp)) { + /* + * The directory connectivity scanner will pick up the metadata + * inode directory, which will mark the rest of the metadata + * inodes. + */ + return; + } + mark_inode(mp, mp->m_sb.sb_rbmino); mark_inode(mp, mp->m_sb.sb_rsumino); @@ -3305,6 +3589,17 @@ phase6(xfs_mount_t *mp) } } + if (need_metadir_inode) { + if (!no_modify) { + do_warn(_("reinitializing metadata root directory\n")); + mk_metadir(mp); + need_metadir_inode = false; + need_metadir_dotdot = 0; + } else { + do_warn(_("would reinitialize metadata root directory\n")); + } + } + if (need_rbmino) { if (!no_modify) { do_warn(_("reinitializing realtime bitmap inode\n")); diff --git a/repair/pptr.c b/repair/pptr.c index 77f49dbcb84..f554919d525 100644 --- a/repair/pptr.c +++ b/repair/pptr.c @@ -1301,3 +1301,54 @@ check_parent_ptrs( destroy_work_queue(&wq); } + +static int +erase_pptrs( + struct xfs_inode *ip, + unsigned int attr_flags, + const unsigned char *name, + unsigned int namelen, + const void *value, + unsigned int valuelen, + void *priv) +{ + struct xfs_da_args args = { + .dp = ip, + .attr_filter = attr_flags, + .name = name, + .namelen = namelen, + .value = (void *)value, + .valuelen = valuelen, + .op_flags = XFS_DA_OP_REMOVE | XFS_DA_OP_NVLOOKUP, + }; + int error; + + if (!(attr_flags & XFS_ATTR_PARENT)) + return 0; + + error = -libxfs_attr_set(&args); + if (error) + do_warn( +_("removing ino %llu parent pointer failed: %s\n"), + (unsigned long long)ip->i_ino, + strerror(error)); + + return 0; +} + +/* Delete all of this file's parent pointers if we can. */ +void +try_erase_parent_ptrs( + struct xfs_inode *ip) +{ + int error; + + if (!xfs_has_parent(ip->i_mount)) + return; + + error = xattr_walk(ip, erase_pptrs, NULL); + if (error) + do_warn(_("ino %llu parent pointer erasure failed: %s\n"), + (unsigned long long)ip->i_ino, + strerror(error)); +} diff --git a/repair/pptr.h b/repair/pptr.h index f5ffcc137e3..9c9f244cd68 100644 --- a/repair/pptr.h +++ b/repair/pptr.h @@ -14,4 +14,6 @@ void add_parent_ptr(xfs_ino_t ino, const unsigned char *fname, void check_parent_ptrs(struct xfs_mount *mp); +void try_erase_parent_ptrs(struct xfs_inode *ip); + #endif /* __REPAIR_PPTR_H__ */ diff --git a/repair/sb.c b/repair/sb.c index faf79d9d083..5f2a08136d7 100644 --- a/repair/sb.c +++ b/repair/sb.c @@ -28,6 +28,7 @@ copy_sb(xfs_sb_t *source, xfs_sb_t *dest) xfs_ino_t uquotino; xfs_ino_t gquotino; xfs_ino_t pquotino; + xfs_ino_t metadirino; uint16_t versionnum; rootino = dest->sb_rootino; @@ -36,6 +37,7 @@ copy_sb(xfs_sb_t *source, xfs_sb_t *dest) uquotino = dest->sb_uquotino; gquotino = dest->sb_gquotino; pquotino = dest->sb_pquotino; + metadirino = dest->sb_metadirino; versionnum = dest->sb_versionnum; @@ -47,6 +49,7 @@ copy_sb(xfs_sb_t *source, xfs_sb_t *dest) dest->sb_uquotino = uquotino; dest->sb_gquotino = gquotino; dest->sb_pquotino = pquotino; + dest->sb_metadirino = metadirino; dest->sb_versionnum = versionnum; diff --git a/repair/xfs_repair.c b/repair/xfs_repair.c index 32c28a980ff..d881d5ec4ac 100644 --- a/repair/xfs_repair.c +++ b/repair/xfs_repair.c @@ -639,6 +639,70 @@ guess_correct_sunit( do_warn(_("Would reset sb_width to %u\n"), new_sunit); } +/* + * Check that the metadata directory inode comes immediately after the root + * directory inode and that it seems to look like a metadata directory. + */ +STATIC void +check_metadir_inode( + struct xfs_mount *mp, + xfs_ino_t rootino) +{ + int error; + + validate_sb_ino(&mp->m_sb.sb_metadirino, rootino + 1, + _("metadata root directory")); + + /* If we changed the metadir inode, try reloading it. */ + if (!mp->m_metadirip || + mp->m_metadirip->i_ino != mp->m_sb.sb_metadirino) { + struct xfs_trans *tp; + + if (mp->m_metadirip) + libxfs_irele(mp->m_metadirip); + + error = -libxfs_trans_alloc_empty(mp, &tp); + if (error) + do_error( + _("could not allocate transaction to load metadir inode")); + + error = -libxfs_imeta_iget(tp, mp->m_sb.sb_metadirino, + XFS_DIR3_FT_DIR, &mp->m_metadirip); + if (error) { + libxfs_trans_cancel(tp); + need_metadir_inode = true; + goto done; + } + + error = -libxfs_imeta_mount(tp); + if (error) + need_metadir_inode = true; + + libxfs_trans_cancel(tp); + } + +done: + if (need_metadir_inode) { + if (!no_modify) + do_warn(_("will reset metadata root directory\n")); + else + do_warn(_("would reset metadata root directory\n")); + if (mp->m_metadirip) + libxfs_irele(mp->m_metadirip); + mp->m_metadirip = NULL; + } + + /* + * Since these two realtime inodes are no longer fixed, we must + * remember to regenerate them if we still haven't gotten a pointer to + * a valid realtime inode. + */ + if (!libxfs_verify_ino(mp, mp->m_sb.sb_rbmino)) + need_rbmino = 1; + if (!libxfs_verify_ino(mp, mp->m_sb.sb_rsumino)) + need_rsumino = 1; +} + /* * Make sure that the first 3 inodes in the filesystem are the root directory, * the realtime bitmap, and the realtime summary, in that order. @@ -668,10 +732,19 @@ _("sb root inode value %" PRIu64 " valid but in unaligned location (expected %"P validate_sb_ino(&mp->m_sb.sb_rootino, rootino, _("root")); - validate_sb_ino(&mp->m_sb.sb_rbmino, rootino + 1, - _("realtime bitmap")); - validate_sb_ino(&mp->m_sb.sb_rsumino, rootino + 2, - _("realtime summary")); + + if (xfs_has_metadir(mp)) { + check_metadir_inode(mp, rootino); + } else { + /* + * The realtime bitmap and summary inodes only comes after the + * root directory when the metadir feature is not enabled. + */ + validate_sb_ino(&mp->m_sb.sb_rbmino, rootino + 1, + _("realtime bitmap")); + validate_sb_ino(&mp->m_sb.sb_rsumino, rootino + 2, + _("realtime summary")); + } } /* From patchwork Sun Dec 31 23:41:34 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13508167 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 6E7FDC2C0 for ; Sun, 31 Dec 2023 23:41:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="uHjqsweE" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 41DEEC433C7; Sun, 31 Dec 2023 23:41:35 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704066095; bh=xJE6aIicalWzdsK4RiB/lHliCyNdc5IFeurqiSchu8k=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=uHjqsweE8z+a7rpHAe9g4MMlw0mkHK8KdjAlm+cvCN54HqUmyphZT/tS+IMio8CIt Vxw/+8SLpboickhYpCLFE9g+p8/9a5PDhJI9b0Y3n+3hlfZzZFCLC+Ku/mUR5Eb50R TXR5v+ZwT6J4Il1+Fx6P2rDKtTuTtqcCAhdGSwngf+clZO4cSzKTs5L7MGGOkm+bWP hxaSRiY8EZgcOz2nTQ4ld1SCLYyjvGD07XMLx5n1iu5SptyxdJJgFQKbLoOTt6Wf8n vCSWHF0RCsKVvPHIo0LSq/EJ7ZmhX8g91WxA/z85K5DmqJg42sOULbLWJBXQrtkRDZ yc5TYDlLsJc2w== Date: Sun, 31 Dec 2023 15:41:34 -0800 Subject: [PATCH 46/58] xfs_repair: don't let metadata and regular files mix From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <170405010560.1809361.13344497598278668677.stgit@frogsfrogsfrogs> In-Reply-To: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> References: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Track whether or not inodes thought they were metadata inodes. We cannot allow metadata inodes to appear in the regular directory tree, and we cannot allow regular inodes to appear in the metadata directory tree. Signed-off-by: Darrick J. Wong --- repair/dinode.c | 21 +++++++++++++++++ repair/incore.h | 19 +++++++++++++++ repair/incore_ino.c | 1 + repair/phase6.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 104 insertions(+) diff --git a/repair/dinode.c b/repair/dinode.c index 4af7c91d5c9..7c3e5d86404 100644 --- a/repair/dinode.c +++ b/repair/dinode.c @@ -2361,6 +2361,7 @@ process_dinode_int( struct xfs_dinode *dino = *dinop; xfs_agino_t unlinked_ino; struct xfs_perag *pag; + bool is_meta = false; *dirty = *isa_dir = 0; *used = is_used; @@ -2933,6 +2934,18 @@ _("Bad CoW extent size %u on inode %" PRIu64 ", "), if (collect_rmaps) record_inode_reflink_flag(mp, dino, agno, ino, lino); + /* Does this inode think it was metadata? */ + if (dino->di_version >= 3 && + (dino->di_flags2 & cpu_to_be64(XFS_DIFLAG2_METADIR))) { + struct ino_tree_node *irec; + int off; + + irec = find_inode_rec(mp, agno, ino); + off = get_inode_offset(mp, lino, irec); + set_inode_is_meta(irec, off); + is_meta = true; + } + /* * check data fork -- if it's bad, clear the inode */ @@ -3019,6 +3032,14 @@ _("Bad CoW extent size %u on inode %" PRIu64 ", "), *used = is_free; *isa_dir = 0; blkmap_free(dblkmap); + if (is_meta) { + struct ino_tree_node *irec; + int off; + + irec = find_inode_rec(mp, agno, ino); + off = get_inode_offset(mp, lino, irec); + clear_inode_is_meta(irec, off); + } return 1; } diff --git a/repair/incore.h b/repair/incore.h index 9ad5f1972d3..90eb1242cd8 100644 --- a/repair/incore.h +++ b/repair/incore.h @@ -271,6 +271,7 @@ typedef struct ino_tree_node { uint64_t ino_isa_dir; /* bit == 1 if a directory */ uint64_t ino_was_rl; /* bit == 1 if reflink flag set */ uint64_t ino_is_rl; /* bit == 1 if reflink flag should be set */ + uint64_t ino_was_meta; /* bit == 1 if metadata */ uint8_t nlink_size; union ino_nlink disk_nlinks; /* on-disk nlinks, set in P3 */ union { @@ -538,6 +539,24 @@ static inline int inode_is_rl(struct ino_tree_node *irec, int offset) return (irec->ino_is_rl & IREC_MASK(offset)) != 0; } +/* + * set/clear/test was inode marked as metadata + */ +static inline void set_inode_is_meta(struct ino_tree_node *irec, int offset) +{ + irec->ino_was_meta |= IREC_MASK(offset); +} + +static inline void clear_inode_is_meta(struct ino_tree_node *irec, int offset) +{ + irec->ino_was_meta &= ~IREC_MASK(offset); +} + +static inline int inode_is_meta(struct ino_tree_node *irec, int offset) +{ + return (irec->ino_was_meta & IREC_MASK(offset)) != 0; +} + /* * add_inode_reached() is set on inode I only if I has been reached * by an inode P claiming to be the parent and if I is a directory, diff --git a/repair/incore_ino.c b/repair/incore_ino.c index b0b41a2cc5c..e33f7cef758 100644 --- a/repair/incore_ino.c +++ b/repair/incore_ino.c @@ -254,6 +254,7 @@ alloc_ino_node( irec->ino_isa_dir = 0; irec->ino_was_rl = 0; irec->ino_is_rl = 0; + irec->ino_was_meta = 0; irec->ir_free = (xfs_inofree_t) - 1; irec->ir_sparse = 0; irec->ino_un.ex_data = NULL; diff --git a/repair/phase6.c b/repair/phase6.c index 05e0b8ac593..21bd2b75050 100644 --- a/repair/phase6.c +++ b/repair/phase6.c @@ -2020,6 +2020,38 @@ longform_dir2_entry_check_data( continue; } + /* + * Regular directories cannot point to metadata files. If + * we find such a thing, blow out the entry. + */ + if (!xfs_is_metadir_inode(ip) && + inode_is_meta(irec, ino_offset)) { + nbad++; + if (entry_junked( + _("entry \"%s\" in regular dir %" PRIu64" points to a metadata inode %" PRIu64 ", "), + fname, ip->i_ino, inum)) { + dep->name[0] = '/'; + libxfs_dir2_data_log_entry(&da, bp, dep); + } + continue; + } + + /* + * Metadata directories cannot point to regular files. If + * we find such a thing, blow out the entry. + */ + if (xfs_is_metadir_inode(ip) && + !inode_is_meta(irec, ino_offset)) { + nbad++; + if (entry_junked( + _("entry \"%s\" in metadata dir %" PRIu64" points to a regular inode %" PRIu64 ", "), + fname, ip->i_ino, inum)) { + dep->name[0] = '/'; + libxfs_dir2_data_log_entry(&da, bp, dep); + } + continue; + } + /* * check if this inode is lost+found dir in the root */ @@ -2931,6 +2963,37 @@ shortform_dir2_entry_check( ino_dirty); continue; } + + /* + * Regular directories cannot point to metadata files. If + * we find such a thing, blow out the entry. + */ + if (!xfs_is_metadir_inode(ip) && + inode_is_meta(irec, ino_offset)) { + do_warn( + _("entry \"%s\" in regular dir %" PRIu64" points to a metadata inode %" PRIu64 ", "), + fname, ip->i_ino, lino); + next_sfep = shortform_dir2_junk(mp, sfp, sfep, lino, + &max_size, &i, &bytes_deleted, + ino_dirty); + continue; + } + + /* + * Metadata directories cannot point to regular files. If + * we find such a thing, blow out the entry. + */ + if (xfs_is_metadir_inode(ip) && + !inode_is_meta(irec, ino_offset)) { + do_warn( + _("entry \"%s\" in metadata dir %" PRIu64" points to a regular inode %" PRIu64 ", "), + fname, ip->i_ino, lino); + next_sfep = shortform_dir2_junk(mp, sfp, sfep, lino, + &max_size, &i, &bytes_deleted, + ino_dirty); + continue; + } + /* * check if this inode is lost+found dir in the root */ From patchwork Sun Dec 31 23:41:50 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13508168 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 37A25C2DA for ; Sun, 31 Dec 2023 23:41:50 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="FmGYZW0f" Received: by smtp.kernel.org (Postfix) with ESMTPSA id C5D49C433C7; Sun, 31 Dec 2023 23:41:50 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704066110; bh=1V1z9cunnmGzE/mIfdxsuNHXZFcCVu5bM5t2SpghaYo=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=FmGYZW0fs+ylaKJ/gKkMnFco09H24cfRWX4jRwU7HMzp+z9NrPPLpNwFhIjuankef kbc4UcqGW+5eNTTV5EHkzqKnDSEtx+VzHT6RchDBVlMA6BIIfN1UtRUfFg81GRNMmS lTO5s/hQ2qjrAPNvKxeTqCog0aC1gcSeUJVUYbQWgXNIKm+S4CHqA14+O1dtix4B7S t5SHWXN0rMNF6nrFBzBtPSO4wYW3VSrvdHSDyrDieK4BhpKXdI+vP3ZkwO5bV0SzJ9 gYvO5OIQV/P37lWjRKMyJ75gXR9r6xmKneFp1seG5BrilSWs62cBbW7T/NZ3ukQhY1 VDox+ang+2wMw== Date: Sun, 31 Dec 2023 15:41:50 -0800 Subject: [PATCH 47/58] xfs_repair: update incore metadata state whenever we create new files From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <170405010574.1809361.14769763572771262563.stgit@frogsfrogsfrogs> In-Reply-To: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> References: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Make sure that we update our incore metadata inode bookkeepping whenever we create new metadata files. Signed-off-by: Darrick J. Wong --- repair/phase6.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/repair/phase6.c b/repair/phase6.c index 21bd2b75050..9ad586602cb 100644 --- a/repair/phase6.c +++ b/repair/phase6.c @@ -516,6 +516,24 @@ mark_ino_inuse( set_inode_isadir(irec, ino_offset); } +/* + * Mark a newly allocated inode as metadata in the incore bitmap. Callers + * must have already called mark_ino_inuse to ensure there is an incore record. + */ +static void +mark_ino_metadata( + struct xfs_mount *mp, + xfs_ino_t ino) +{ + struct ino_tree_node *irec; + int ino_offset; + + irec = find_inode_rec(mp, XFS_INO_TO_AGNO(mp, ino), + XFS_INO_TO_AGINO(mp, ino)); + ino_offset = get_inode_offset(mp, ino, irec); + set_inode_is_meta(irec, ino_offset); +} + /* Make sure this metadata directory path exists. */ static int ensure_imeta_dirpath( @@ -557,6 +575,7 @@ ensure_imeta_dirpath( } mark_ino_inuse(mp, ino, S_IFDIR, parent); + mark_ino_metadata(mp, ino); parent = ino; } @@ -664,6 +683,7 @@ ensure_rtino_metadir( mark_ino_inuse(mp, upd->ip->i_ino, S_IFREG, lookup_imeta_path_dirname(mp, path)); + mark_ino_metadata(mp, upd->ip->i_ino); return; } @@ -1108,6 +1128,7 @@ mk_metadir( libxfs_trans_ijoin(tp, mp->m_metadirip, 0); libxfs_imeta_set_iflag(tp, mp->m_metadirip); + mark_ino_metadata(mp, mp->m_metadirip->i_ino); error = -libxfs_trans_commit(tp); if (error) From patchwork Sun Dec 31 23:42:05 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13508169 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 EF8CCC2C5 for ; Sun, 31 Dec 2023 23:42:06 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="e72nA/JI" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 67AEFC433C7; Sun, 31 Dec 2023 23:42:06 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704066126; bh=UJcPyPCG4LkPa+5aSj+fzHcXYjc3egkGXyBzRY0MT+Y=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=e72nA/JItSXwxwziF/LhJvUfTkZBoOk8bZIVGobhtj/ldofxaQcSumUt+WM6yMYsZ s0KkzDHP7nyetDPoOVKSnM4HYnrRk6+qRCFjKQPLa1ue+C5OOWYoIp+Q7NH03fgcB+ vFxK2jomWYjAwa1wY6kk4rBilxTcVXXRKCfrQ7PeJXZ7RfPLSc4ogYF/lF8t7Er6J9 zAcrH/6nLz73hi24lSfKM3/1L/+eGzSX4/3Vs4gI01cJeuvgulBl48jAYFXF6cN/Gx m+n9QzyHMjwWtt/RHyu1WW/rPriADJcve8IxQTH2H3zX9g4TXnF7SXB85x7KUoPS2m zX45BsX7NR5GQ== Date: Sun, 31 Dec 2023 15:42:05 -0800 Subject: [PATCH 48/58] xfs_repair: pass private data pointer to scan_lbtree From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <170405010587.1809361.13220845218706420190.stgit@frogsfrogsfrogs> In-Reply-To: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> References: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Pass a private data pointer through scan_lbtree. We'll use this later when scanning the rtrmapbt to keep track of scan state. Signed-off-by: Darrick J. Wong --- repair/dinode.c | 2 +- repair/scan.c | 11 +++++++---- repair/scan.h | 7 +++++-- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/repair/dinode.c b/repair/dinode.c index 7c3e5d86404..9b7309afcaf 100644 --- a/repair/dinode.c +++ b/repair/dinode.c @@ -839,7 +839,7 @@ _("bad bmap btree ptr 0x%" PRIx64 " in ino %" PRIu64 "\n"), if (scan_lbtree(get_unaligned_be64(&pp[i]), level, scan_bmapbt, type, whichfork, lino, tot, nex, blkmapp, - &cursor, 1, check_dups, magic, + &cursor, 1, check_dups, magic, NULL, &xfs_bmbt_buf_ops)) return(1); /* diff --git a/repair/scan.c b/repair/scan.c index fbe1916ac6c..8822f0f05fb 100644 --- a/repair/scan.c +++ b/repair/scan.c @@ -139,7 +139,8 @@ scan_lbtree( int isroot, int check_dups, int *dirty, - uint64_t magic), + uint64_t magic, + void *priv), int type, int whichfork, xfs_ino_t ino, @@ -150,6 +151,7 @@ scan_lbtree( int isroot, int check_dups, uint64_t magic, + void *priv, const struct xfs_buf_ops *ops) { struct xfs_buf *bp; @@ -181,7 +183,7 @@ scan_lbtree( err = (*func)(XFS_BUF_TO_BLOCK(bp), nlevels - 1, type, whichfork, root, ino, tot, nex, blkmapp, bm_cursor, isroot, check_dups, &dirty, - magic); + magic, priv); ASSERT(dirty == 0 || (dirty && !no_modify)); @@ -210,7 +212,8 @@ scan_bmapbt( int isroot, int check_dups, int *dirty, - uint64_t magic) + uint64_t magic, + void *priv) { int i; int err; @@ -497,7 +500,7 @@ _("bad bmap btree ptr 0x%llx in ino %" PRIu64 "\n"), err = scan_lbtree(be64_to_cpu(pp[i]), level, scan_bmapbt, type, whichfork, ino, tot, nex, blkmapp, - bm_cursor, 0, check_dups, magic, + bm_cursor, 0, check_dups, magic, priv, &xfs_bmbt_buf_ops); if (err) return(1); diff --git a/repair/scan.h b/repair/scan.h index ee16362b6d3..4da788becbe 100644 --- a/repair/scan.h +++ b/repair/scan.h @@ -26,7 +26,8 @@ int scan_lbtree( int isroot, int check_dups, int *dirty, - uint64_t magic), + uint64_t magic, + void *priv), int type, int whichfork, xfs_ino_t ino, @@ -37,6 +38,7 @@ int scan_lbtree( int isroot, int check_dups, uint64_t magic, + void *priv, const struct xfs_buf_ops *ops); int scan_bmapbt( @@ -53,7 +55,8 @@ int scan_bmapbt( int isroot, int check_dups, int *dirty, - uint64_t magic); + uint64_t magic, + void *priv); void scan_ags( From patchwork Sun Dec 31 23:42:21 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13508170 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 BE5B6C2C0 for ; Sun, 31 Dec 2023 23:42:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Vz4DorRe" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 326CBC433C8; Sun, 31 Dec 2023 23:42:22 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704066142; bh=qUkzTzm5QKuzlovIRvl2YhL1vFCovFp8kYeddOO3T3A=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=Vz4DorRei2BLorf6IIjmhvNHOPQPbUeGD3Iq8lN9OFaqFnnYu/UKSsDuFvYeMkhkf Z087uDCv/69J/RGiXsoVtvXrjGRa7iXlQrjZ0EEKI68EF8xrL2TlQ6IgORu3Rc07o0 X8W7+H92Bs7Fm4pKoClvK0BBc1bSQ8Lb2drY2rTGifsmRo11+t3+7t7IHoH0O0pihD 1zp+MEn7hpsBCfXHmltDL4mJ/spS1F9StUeiRU/hUgZteYTpyc04qtgF3GKqQ/sd8L 7ot69YYvHDobRh8FH/f8XEV/9Sk2Kd4yKR3O/Y05FUA7qEdGSVqn22+clVixmgCMEY 0ar/e66wSWFWw== Date: Sun, 31 Dec 2023 15:42:21 -0800 Subject: [PATCH 49/58] xfs_repair: mark space used by metadata files From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <170405010600.1809361.15192493026697894678.stgit@frogsfrogsfrogs> In-Reply-To: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> References: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Track space used by metadata files as a separate incore extent type. This ensures that we can warn about cross-linked metadata files, even though we are going to rebuild the entire metadata directory tree in the end. Signed-off-by: Darrick J. Wong --- repair/dino_chunks.c | 31 +++++++++++++ repair/dinode.c | 121 ++++++++++++++++++++++++++++++++++++++------------ repair/dinode.h | 6 ++ repair/incore.h | 39 ++++++++++------ repair/incore_ino.c | 2 - repair/phase4.c | 2 + repair/scan.c | 30 +++++++++++- 7 files changed, 179 insertions(+), 52 deletions(-) diff --git a/repair/dino_chunks.c b/repair/dino_chunks.c index 479dc9db760..7e18991a3d5 100644 --- a/repair/dino_chunks.c +++ b/repair/dino_chunks.c @@ -141,6 +141,16 @@ verify_inode_chunk(xfs_mount_t *mp, _("uncertain inode block %d/%d already known\n"), agno, agbno); break; + case XR_E_METADATA: + /* + * Files in the metadata directory tree are always + * reconstructed, so it's ok to let go if this block + * is also a valid inode cluster. + */ + do_warn( + _("inode block %d/%d claimed by metadata file\n"), + agno, agbno); + fallthrough; case XR_E_UNKNOWN: case XR_E_FREE1: case XR_E_FREE: @@ -430,6 +440,7 @@ verify_inode_chunk(xfs_mount_t *mp, set_bmap_ext(agno, cur_agbno, blen, XR_E_MULT); pthread_mutex_unlock(&ag_locks[agno].lock); return 0; + case XR_E_METADATA: case XR_E_INO: do_error( _("uncertain inode block overlap, agbno = %d, ino = %" PRIu64 "\n"), @@ -474,6 +485,16 @@ verify_inode_chunk(xfs_mount_t *mp, _("uncertain inode block %" PRIu64 " already known\n"), XFS_AGB_TO_FSB(mp, agno, cur_agbno)); break; + case XR_E_METADATA: + /* + * Files in the metadata directory tree are always + * reconstructed, so it's ok to let go if this block + * is also a valid inode cluster. + */ + do_warn( + _("inode block %d/%d claimed by metadata file\n"), + agno, agbno); + fallthrough; case XR_E_UNKNOWN: case XR_E_FREE1: case XR_E_FREE: @@ -559,6 +580,16 @@ process_inode_agbno_state( switch (state) { case XR_E_INO: /* already marked */ break; + case XR_E_METADATA: + /* + * Files in the metadata directory tree are always + * reconstructed, so it's ok to let go if this block is also a + * valid inode cluster. + */ + do_warn( + _("inode block %d/%d claimed by metadata file\n"), + agno, agbno); + fallthrough; case XR_E_UNKNOWN: case XR_E_FREE: case XR_E_FREE1: diff --git a/repair/dinode.c b/repair/dinode.c index 9b7309afcaf..52830a85a6f 100644 --- a/repair/dinode.c +++ b/repair/dinode.c @@ -220,6 +220,7 @@ static int process_rt_rec_state( struct xfs_mount *mp, xfs_ino_t ino, + bool zap_metadata, struct xfs_bmbt_irec *irec) { xfs_fsblock_t b = irec->br_startblock; @@ -256,7 +257,13 @@ _("data fork in rt inode %" PRIu64 " found invalid rt extent %"PRIu64" state %d switch (state) { case XR_E_FREE: case XR_E_UNKNOWN: - set_rtbmap(ext, XR_E_INUSE); + set_rtbmap(ext, zap_metadata ? XR_E_METADATA : + XR_E_INUSE); + break; + case XR_E_METADATA: + do_error( +_("data fork in rt inode %" PRIu64 " found metadata file block %" PRIu64 " in rt bmap\n"), + ino, ext); break; case XR_E_BAD_STATE: do_error( @@ -293,7 +300,8 @@ process_rt_rec( struct xfs_bmbt_irec *irec, xfs_ino_t ino, xfs_rfsblock_t *tot, - int check_dups) + int check_dups, + bool zap_metadata) { xfs_fsblock_t lastb; int bad; @@ -333,7 +341,7 @@ _("inode %" PRIu64 " - bad rt extent overflows - start %" PRIu64 ", " if (check_dups) bad = process_rt_rec_dups(mp, ino, irec); else - bad = process_rt_rec_state(mp, ino, irec); + bad = process_rt_rec_state(mp, ino, zap_metadata, irec); if (bad) return bad; @@ -364,7 +372,8 @@ process_bmbt_reclist_int( xfs_fileoff_t *first_key, xfs_fileoff_t *last_key, int check_dups, - int whichfork) + int whichfork, + bool zap_metadata) { xfs_bmbt_irec_t irec; xfs_filblks_t cp = 0; /* prev count */ @@ -443,7 +452,8 @@ _("zero length extent (off = %" PRIu64 ", fsbno = %" PRIu64 ") in ino %" PRIu64 if (type == XR_INO_RTDATA && whichfork == XFS_DATA_FORK) { pthread_mutex_lock(&rt_lock.lock); - error2 = process_rt_rec(mp, &irec, ino, tot, check_dups); + error2 = process_rt_rec(mp, &irec, ino, tot, check_dups, + zap_metadata); pthread_mutex_unlock(&rt_lock.lock); if (error2) return error2; @@ -558,6 +568,11 @@ _("%s fork in ino %" PRIu64 " claims free block %" PRIu64 "\n"), case XR_E_INUSE_FS1: do_warn(_("rmap claims metadata use!\n")); fallthrough; + case XR_E_METADATA: + do_warn( +_("%s fork in inode %" PRIu64 " claims metadata file block %" PRIu64 "\n"), + forkname, ino, b); + break; case XR_E_FS_MAP: case XR_E_INO: case XR_E_INUSE_FS: @@ -614,15 +629,28 @@ _("illegal state %d in block map %" PRIu64 "\n"), for (; agbno < ebno; agbno += blen) { state = get_bmap_ext(agno, agbno, ebno, &blen); switch (state) { + case XR_E_METADATA: + /* + * The entire metadata directory tree is rebuilt + * every time, so we can let regular files take + * ownership of this block. + */ + if (zap_metadata) + break; + fallthrough; case XR_E_FREE: case XR_E_FREE1: case XR_E_INUSE1: case XR_E_UNKNOWN: - set_bmap_ext(agno, agbno, blen, XR_E_INUSE); + set_bmap_ext(agno, agbno, blen, zap_metadata ? + XR_E_METADATA : XR_E_INUSE); break; + case XR_E_INUSE: case XR_E_MULT: - set_bmap_ext(agno, agbno, blen, XR_E_MULT); + if (!zap_metadata) + set_bmap_ext(agno, agbno, blen, + XR_E_MULT); break; default: break; @@ -661,10 +689,12 @@ process_bmbt_reclist( blkmap_t **blkmapp, xfs_fileoff_t *first_key, xfs_fileoff_t *last_key, - int whichfork) + int whichfork, + bool zap_metadata) { return process_bmbt_reclist_int(mp, rp, numrecs, type, ino, tot, - blkmapp, first_key, last_key, 0, whichfork); + blkmapp, first_key, last_key, 0, whichfork, + zap_metadata); } /* @@ -679,13 +709,15 @@ scan_bmbt_reclist( int type, xfs_ino_t ino, xfs_rfsblock_t *tot, - int whichfork) + int whichfork, + bool zap_metadata) { xfs_fileoff_t first_key = 0; xfs_fileoff_t last_key = 0; return process_bmbt_reclist_int(mp, rp, numrecs, type, ino, tot, - NULL, &first_key, &last_key, 1, whichfork); + NULL, &first_key, &last_key, 1, whichfork, + zap_metadata); } /* @@ -760,7 +792,8 @@ process_btinode( xfs_extnum_t *nex, blkmap_t **blkmapp, int whichfork, - int check_dups) + int check_dups, + bool zap_metadata) { xfs_bmdr_block_t *dib; xfs_fileoff_t last_key; @@ -839,8 +872,8 @@ _("bad bmap btree ptr 0x%" PRIx64 " in ino %" PRIu64 "\n"), if (scan_lbtree(get_unaligned_be64(&pp[i]), level, scan_bmapbt, type, whichfork, lino, tot, nex, blkmapp, - &cursor, 1, check_dups, magic, NULL, - &xfs_bmbt_buf_ops)) + &cursor, 1, check_dups, magic, + (void *)zap_metadata, &xfs_bmbt_buf_ops)) return(1); /* * fix key (offset) mismatches between the keys in root @@ -935,7 +968,8 @@ process_exinode( xfs_extnum_t *nex, blkmap_t **blkmapp, int whichfork, - int check_dups) + int check_dups, + bool zap_metadata) { xfs_ino_t lino; xfs_bmbt_rec_t *rp; @@ -969,10 +1003,10 @@ process_exinode( if (check_dups == 0) ret = process_bmbt_reclist(mp, rp, &numrecs, type, lino, tot, blkmapp, &first_key, &last_key, - whichfork); + whichfork, zap_metadata); else ret = scan_bmbt_reclist(mp, rp, &numrecs, type, lino, tot, - whichfork); + whichfork, zap_metadata); *nex = numrecs; return ret; @@ -1898,7 +1932,8 @@ process_inode_data_fork( xfs_extnum_t *nextents, blkmap_t **dblkmap, int check_dups, - struct xfs_buf **ino_bpp) + struct xfs_buf **ino_bpp, + bool zap_metadata) { struct xfs_dinode *dino = *dinop; xfs_ino_t lino = XFS_AGINO_TO_INO(mp, agno, ino); @@ -1939,14 +1974,14 @@ process_inode_data_fork( try_rebuild = 1; err = process_exinode(mp, agno, ino, dino, type, dirty, totblocks, nextents, dblkmap, XFS_DATA_FORK, - check_dups); + check_dups, zap_metadata); break; case XFS_DINODE_FMT_BTREE: if (!rmapbt_suspect && try_rebuild == -1) try_rebuild = 1; err = process_btinode(mp, agno, ino, dino, type, dirty, totblocks, nextents, dblkmap, XFS_DATA_FORK, - check_dups); + check_dups, zap_metadata); break; case XFS_DINODE_FMT_DEV: err = 0; @@ -1999,12 +2034,12 @@ _("would have tried to rebuild inode %"PRIu64" data fork\n"), case XFS_DINODE_FMT_EXTENTS: err = process_exinode(mp, agno, ino, dino, type, dirty, totblocks, nextents, dblkmap, - XFS_DATA_FORK, 0); + XFS_DATA_FORK, 0, zap_metadata); break; case XFS_DINODE_FMT_BTREE: err = process_btinode(mp, agno, ino, dino, type, dirty, totblocks, nextents, dblkmap, - XFS_DATA_FORK, 0); + XFS_DATA_FORK, 0, zap_metadata); break; case XFS_DINODE_FMT_DEV: err = 0; @@ -2039,7 +2074,8 @@ process_inode_attr_fork( int check_dups, int extra_attr_check, int *retval, - struct xfs_buf **ino_bpp) + struct xfs_buf **ino_bpp, + bool zap_metadata) { xfs_ino_t lino = XFS_AGINO_TO_INO(mp, agno, ino); struct xfs_dinode *dino = *dinop; @@ -2087,7 +2123,7 @@ process_inode_attr_fork( *anextents = 0; err = process_exinode(mp, agno, ino, dino, type, dirty, atotblocks, anextents, &ablkmap, - XFS_ATTR_FORK, check_dups); + XFS_ATTR_FORK, check_dups, zap_metadata); break; case XFS_DINODE_FMT_BTREE: if (!rmapbt_suspect && try_rebuild == -1) @@ -2096,7 +2132,7 @@ process_inode_attr_fork( *anextents = 0; err = process_btinode(mp, agno, ino, dino, type, dirty, atotblocks, anextents, &ablkmap, - XFS_ATTR_FORK, check_dups); + XFS_ATTR_FORK, check_dups, zap_metadata); break; default: do_warn(_("illegal attribute format %d, ino %" PRIu64 "\n"), @@ -2160,12 +2196,12 @@ _("would have tried to rebuild inode %"PRIu64" attr fork or cleared it\n"), case XFS_DINODE_FMT_EXTENTS: err = process_exinode(mp, agno, ino, dino, type, dirty, atotblocks, anextents, - &ablkmap, XFS_ATTR_FORK, 0); + &ablkmap, XFS_ATTR_FORK, 0, zap_metadata); break; case XFS_DINODE_FMT_BTREE: err = process_btinode(mp, agno, ino, dino, type, dirty, atotblocks, anextents, - &ablkmap, XFS_ATTR_FORK, 0); + &ablkmap, XFS_ATTR_FORK, 0, zap_metadata); break; default: do_error(_("illegal attribute fmt %d, ino %" PRIu64 "\n"), @@ -2362,6 +2398,7 @@ process_dinode_int( xfs_agino_t unlinked_ino; struct xfs_perag *pag; bool is_meta = false; + bool zap_metadata = false; *dirty = *isa_dir = 0; *used = is_used; @@ -2944,6 +2981,32 @@ _("Bad CoW extent size %u on inode %" PRIu64 ", "), off = get_inode_offset(mp, lino, irec); set_inode_is_meta(irec, off); is_meta = true; + + /* + * We always rebuild the metadata directory tree during phase + * 6, so we use this flag to get all the directory blocks + * marked as free, and any other metadata files whose contents + * we don't want to save. + * + * Currently, there are no metadata files that use xattrs, so + * we always drop the xattr blocks of metadata files. + */ + switch (type) { + case XR_INO_RTBITMAP: + case XR_INO_RTSUM: + case XR_INO_UQUOTA: + case XR_INO_GQUOTA: + case XR_INO_PQUOTA: + /* + * This inode was recognized as being filesystem + * metadata, so preserve the inode and its contents for + * later checking and repair. + */ + break; + default: + zap_metadata = true; + break; + } } /* @@ -2951,7 +3014,7 @@ _("Bad CoW extent size %u on inode %" PRIu64 ", "), */ if (process_inode_data_fork(mp, agno, ino, dinop, type, dirty, &totblocks, &nextents, &dblkmap, check_dups, - ino_bpp) != 0) + ino_bpp, zap_metadata) != 0) goto bad_out; dino = *dinop; @@ -2961,7 +3024,7 @@ _("Bad CoW extent size %u on inode %" PRIu64 ", "), */ if (process_inode_attr_fork(mp, agno, ino, dinop, type, dirty, &atotblocks, &anextents, check_dups, extra_attr_check, - &retval, ino_bpp)) + &retval, ino_bpp, is_meta)) goto bad_out; dino = *dinop; diff --git a/repair/dinode.h b/repair/dinode.h index 92df83da621..ed2ec4ca238 100644 --- a/repair/dinode.h +++ b/repair/dinode.h @@ -27,7 +27,8 @@ process_bmbt_reclist(xfs_mount_t *mp, struct blkmap **blkmapp, uint64_t *first_key, uint64_t *last_key, - int whichfork); + int whichfork, + bool zap_metadata); int scan_bmbt_reclist( @@ -37,7 +38,8 @@ scan_bmbt_reclist( int type, xfs_ino_t ino, xfs_rfsblock_t *tot, - int whichfork); + int whichfork, + bool zap_metadata); void update_rootino(xfs_mount_t *mp); diff --git a/repair/incore.h b/repair/incore.h index 90eb1242cd8..645cc5317c8 100644 --- a/repair/incore.h +++ b/repair/incore.h @@ -85,18 +85,25 @@ typedef struct rt_extent_tree_node { #define XR_E_UNKNOWN 0 /* unknown state */ #define XR_E_FREE1 1 /* free block (marked by one fs space tree) */ #define XR_E_FREE 2 /* free block (marked by both fs space trees) */ -#define XR_E_INUSE 3 /* extent used by file/dir data or metadata */ -#define XR_E_INUSE_FS 4 /* extent used by fs ag header or log */ -#define XR_E_MULT 5 /* extent is multiply referenced */ -#define XR_E_INO 6 /* extent used by inodes (inode blocks) */ -#define XR_E_FS_MAP 7 /* extent used by fs space/inode maps */ -#define XR_E_INUSE1 8 /* used block (marked by rmap btree) */ -#define XR_E_INUSE_FS1 9 /* used by fs ag header or log (rmap btree) */ -#define XR_E_INO1 10 /* used by inodes (marked by rmap btree) */ -#define XR_E_FS_MAP1 11 /* used by fs space/inode maps (rmap btree) */ -#define XR_E_REFC 12 /* used by fs ag reference count btree */ -#define XR_E_COW 13 /* leftover cow extent */ -#define XR_E_BAD_STATE 14 +/* + * Space used by metadata files. The entire metadata directory tree will be + * rebuilt from scratch during phase 6, so this value must be less than + * XR_E_INUSE so that the space will go back to the free space btrees during + * phase 5. + */ +#define XR_E_METADATA 3 +#define XR_E_INUSE 4 /* extent used by file/dir data or metadata */ +#define XR_E_INUSE_FS 5 /* extent used by fs ag header or log */ +#define XR_E_MULT 6 /* extent is multiply referenced */ +#define XR_E_INO 7 /* extent used by inodes (inode blocks) */ +#define XR_E_FS_MAP 8 /* extent used by fs space/inode maps */ +#define XR_E_INUSE1 9 /* used block (marked by rmap btree) */ +#define XR_E_INUSE_FS1 10 /* used by fs ag header or log (rmap btree) */ +#define XR_E_INO1 11 /* used by inodes (marked by rmap btree) */ +#define XR_E_FS_MAP1 12 /* used by fs space/inode maps (rmap btree) */ +#define XR_E_REFC 13 /* used by fs ag reference count btree */ +#define XR_E_COW 14 /* leftover cow extent */ +#define XR_E_BAD_STATE 15 /* separate state bit, OR'ed into high (4th) bit of ex_state field */ @@ -271,7 +278,7 @@ typedef struct ino_tree_node { uint64_t ino_isa_dir; /* bit == 1 if a directory */ uint64_t ino_was_rl; /* bit == 1 if reflink flag set */ uint64_t ino_is_rl; /* bit == 1 if reflink flag should be set */ - uint64_t ino_was_meta; /* bit == 1 if metadata */ + uint64_t ino_is_meta; /* bit == 1 if metadata */ uint8_t nlink_size; union ino_nlink disk_nlinks; /* on-disk nlinks, set in P3 */ union { @@ -544,17 +551,17 @@ static inline int inode_is_rl(struct ino_tree_node *irec, int offset) */ static inline void set_inode_is_meta(struct ino_tree_node *irec, int offset) { - irec->ino_was_meta |= IREC_MASK(offset); + irec->ino_is_meta |= IREC_MASK(offset); } static inline void clear_inode_is_meta(struct ino_tree_node *irec, int offset) { - irec->ino_was_meta &= ~IREC_MASK(offset); + irec->ino_is_meta &= ~IREC_MASK(offset); } static inline int inode_is_meta(struct ino_tree_node *irec, int offset) { - return (irec->ino_was_meta & IREC_MASK(offset)) != 0; + return (irec->ino_is_meta & IREC_MASK(offset)) != 0; } /* diff --git a/repair/incore_ino.c b/repair/incore_ino.c index e33f7cef758..1b7540d5148 100644 --- a/repair/incore_ino.c +++ b/repair/incore_ino.c @@ -254,7 +254,7 @@ alloc_ino_node( irec->ino_isa_dir = 0; irec->ino_was_rl = 0; irec->ino_is_rl = 0; - irec->ino_was_meta = 0; + irec->ino_is_meta = 0; irec->ir_free = (xfs_inofree_t) - 1; irec->ir_sparse = 0; irec->ino_un.ex_data = NULL; diff --git a/repair/phase4.c b/repair/phase4.c index f004111ea4e..e8bd5982147 100644 --- a/repair/phase4.c +++ b/repair/phase4.c @@ -303,6 +303,7 @@ phase4(xfs_mount_t *mp) _("unknown block state, ag %d, blocks %u-%u\n"), i, j, j + blen - 1); fallthrough; + case XR_E_METADATA: case XR_E_UNKNOWN: case XR_E_FREE: case XR_E_INUSE: @@ -335,6 +336,7 @@ phase4(xfs_mount_t *mp) _("unknown rt extent state, extent %" PRIu64 "\n"), rtx); fallthrough; + case XR_E_METADATA: case XR_E_UNKNOWN: case XR_E_FREE1: case XR_E_FREE: diff --git a/repair/scan.c b/repair/scan.c index 8822f0f05fb..c52ace31c2d 100644 --- a/repair/scan.c +++ b/repair/scan.c @@ -227,6 +227,7 @@ scan_bmapbt( xfs_agnumber_t agno; xfs_agblock_t agbno; int state; + bool zap_metadata = priv != NULL; /* * unlike the ag freeblock btrees, if anything looks wrong @@ -352,7 +353,20 @@ _("bad back (left) sibling pointer (saw %llu should be NULL (0))\n" case XR_E_UNKNOWN: case XR_E_FREE1: case XR_E_FREE: - set_bmap(agno, agbno, XR_E_INUSE); + set_bmap(agno, agbno, zap_metadata ? XR_E_METADATA : + XR_E_INUSE); + break; + case XR_E_METADATA: + /* + * bmbt block already claimed by a metadata file. We + * always reconstruct the entire metadata tree, so if + * this is a regular file we mark it owned by the file. + */ + do_warn( +_("inode 0x%" PRIx64 "bmap block 0x%" PRIx64 " claimed by metadata file\n"), + ino, bno); + if (!zap_metadata) + set_bmap(agno, agbno, XR_E_INUSE); break; case XR_E_FS_MAP: case XR_E_INUSE: @@ -364,7 +378,8 @@ _("bad back (left) sibling pointer (saw %llu should be NULL (0))\n" * we made it here, the block probably * contains btree data. */ - set_bmap(agno, agbno, XR_E_MULT); + if (!zap_metadata) + set_bmap(agno, agbno, XR_E_MULT); do_warn( _("inode 0x%" PRIx64 "bmap block 0x%" PRIx64 " claimed, state is %d\n"), ino, bno, state); @@ -440,7 +455,8 @@ _("inode %" PRIu64 " bad # of bmap records (%" PRIu64 ", min - %u, max - %u)\n") if (check_dups == 0) { err = process_bmbt_reclist(mp, rp, &numrecs, type, ino, tot, blkmapp, &first_key, - &last_key, whichfork); + &last_key, whichfork, + zap_metadata); if (err) return 1; @@ -470,7 +486,7 @@ _("out-of-order bmap key (file offset) in inode %" PRIu64 ", %s fork, fsbno %" P return 0; } else { return scan_bmbt_reclist(mp, rp, &numrecs, type, ino, - tot, whichfork); + tot, whichfork, zap_metadata); } } if (numrecs > mp->m_bmap_dmxr[1] || (isroot == 0 && numrecs < @@ -860,6 +876,12 @@ process_rmap_rec( break; } break; + case XR_E_METADATA: + do_warn( +_("Metadata file block (%d,%d-%d) mismatch in %s tree, state - %d,%" PRIx64 "\n"), + agno, b, b + blen - 1, + name, state, owner); + break; case XR_E_INUSE_FS: if (owner == XFS_RMAP_OWN_FS || owner == XFS_RMAP_OWN_LOG) From patchwork Sun Dec 31 23:42:37 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13508172 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 07B4AC2C5 for ; Sun, 31 Dec 2023 23:42:38 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="euMzbnG3" Received: by smtp.kernel.org (Postfix) with ESMTPSA id CEDC5C433C7; Sun, 31 Dec 2023 23:42:37 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704066157; bh=gVE66MjBOl5jAYoXNtswRcMW4Tn1kwCUJj5jwAqeKSA=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=euMzbnG3HsmZQGUUhuT746u5aOqj8qRg34c8nEYMri5pYGLwlNA1ZKGjeixuvnofU uiP5Dcy7044yNM9MhW3qacAeYrn37TIwBd5NT6FNhaO4Z+EcvoMR3gHYJQRTnqBvsZ fg11cbKeQLG3Ujv8mPTzTFJlNFbgBNKLHmsOVzak6pWo+21XCR9NBxoWdr5ZE39+23 eWxRhyJvzBmyvK6awVJ8IKzbj8cAozRnFZgDHXJABWj1kj9b9FjNICeEixGqFG2IqR 6DqnHq9E0hKSTgUlL8ZpqKUKUkjl1A9F8KU//r9H2Wx9Ua3MJUP2wuCeBsjT4dcq0p ZhcP7PCKl6DFw== Date: Sun, 31 Dec 2023 15:42:37 -0800 Subject: [PATCH 50/58] xfs_repair: adjust keep_fsinos to handle metadata directories From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <170405010614.1809361.4904828130415486810.stgit@frogsfrogsfrogs> In-Reply-To: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> References: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong On a filesystem with metadata directories, we only want to automatically mark the two root directories present because those are the only two statically allocated inode numbers -- the rt summary inode is now just a regular file in a directory. Signed-off-by: Darrick J. Wong --- repair/phase5.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/repair/phase5.c b/repair/phase5.c index d7bacb18b84..983f2169228 100644 --- a/repair/phase5.c +++ b/repair/phase5.c @@ -421,13 +421,14 @@ static void keep_fsinos(xfs_mount_t *mp) { ino_tree_node_t *irec; - int i; irec = find_inode_rec(mp, XFS_INO_TO_AGNO(mp, mp->m_sb.sb_rootino), XFS_INO_TO_AGINO(mp, mp->m_sb.sb_rootino)); - for (i = 0; i < 3; i++) - set_inode_used(irec, i); + set_inode_used(irec, 0); /* root dir */ + set_inode_used(irec, 1); /* rt bitmap or metadata dir root */ + if (!xfs_has_metadir(mp)) + set_inode_used(irec, 2); /* rt summary */ } static void From patchwork Sun Dec 31 23:42:53 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13508173 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 F3283C2D4 for ; Sun, 31 Dec 2023 23:42:53 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="ilzUiF37" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 7C928C433C7; Sun, 31 Dec 2023 23:42:53 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704066173; bh=l7L2i5yKDV8jNMpvQyjAJ2/HuE75/90s4dlK+3uuvG4=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=ilzUiF37UFTeCtGeCKePLQLFfZd7WHiVHWXR51AffroWs3Wz9ok/31OM1cb3StuYo 7eZ7HMJqEZpeBNGTq1KTOD0AeHjPiX2ZzkvEyEev0wfIBIoO35UHcYwa+t1ZvY5a4y RZO/0GUvWH47lQJrK1a2ryHZLkwKQE10h6t88OOK1hFfjYiqIviUd2djQhprp5eBNn nVmWS6x97PadFOq5uSk+2t5TQb40bIKFiBA8dlvysMUkWOX7I3XQAJtGW8dEJMsOEG MHi5/AWI0PXveAqhJsigPqGyPGOU/lKQglze0NFrR4cGfei4EuGsHZi02EqcwfibN6 8kUmZRno8C3og== Date: Sun, 31 Dec 2023 15:42:53 -0800 Subject: [PATCH 51/58] xfs_repair: metadata dirs are never plausible root dirs From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <170405010627.1809361.195606095171584318.stgit@frogsfrogsfrogs> In-Reply-To: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> References: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Metadata directories are never candidates to be the root of the user-accessible directory tree. Update has_plausible_rootdir to ignore them all, as well as detecting the case where the superblock incorrectly thinks both trees have the same root. Signed-off-by: Darrick J. Wong --- repair/xfs_repair.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/repair/xfs_repair.c b/repair/xfs_repair.c index d881d5ec4ac..fe24f66ab98 100644 --- a/repair/xfs_repair.c +++ b/repair/xfs_repair.c @@ -541,9 +541,15 @@ has_plausible_rootdir( int error; bool ret = false; + if (xfs_has_metadir(mp) && + mp->m_sb.sb_rootino == mp->m_sb.sb_metadirino) + goto out; + error = -libxfs_iget(mp, NULL, mp->m_sb.sb_rootino, 0, &ip); if (error) goto out; + if (xfs_is_metadir_inode(ip)) + goto out_rele; if (!S_ISDIR(VFS_I(ip)->i_mode)) goto out_rele; From patchwork Sun Dec 31 23:43:08 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13508174 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 A9A78C2CC for ; Sun, 31 Dec 2023 23:43:09 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="NhZ8+nxb" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 2764CC433C7; Sun, 31 Dec 2023 23:43:09 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704066189; bh=k1rgXECzQHfkHVkFlzO7XLDT8g1tVTd4cn5atZb609k=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=NhZ8+nxbdgA7OEARDT6e4sLXHKAR19OpQbgCNw3ZnAWj1yhchAqtzx5mHN1lH3Vjf RzKymkS4j16Qk2OH1JBdZIlfDxaPXb0VDShnoiQ0Y47OEsxuz3aAmu8sYgTzGK0+qp TcuKcE+RetK9UxpbgXQoShVkY2JNc33UyHAGVJoDDKSqhaXw5TpVSJzmM3kseLNckW yrnTIsm1ycP6/T/ckHdZTxEPi0nNcL/c8/XNL1hTSxNiIhQ1jr+mMcRLLu31tPmbn4 sqGdjNjhnnW8jgGONxKrB02BrEuAhiZHfSRP9A5m0k+t9JYT5R/GvWibU6b7ySNJyZ oZ3YlAxeu7wxA== Date: Sun, 31 Dec 2023 15:43:08 -0800 Subject: [PATCH 52/58] xfs_repair: reattach quota inodes to metadata directory From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <170405010640.1809361.6877152924759110980.stgit@frogsfrogsfrogs> In-Reply-To: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> References: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 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 the quota inodes came through unscathed, we should attach them to the new metadata directory so that phase 7 can run quotacheck on them. Signed-off-by: Darrick J. Wong --- repair/phase6.c | 127 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) diff --git a/repair/phase6.c b/repair/phase6.c index 9ad586602cb..5eeffd5dce9 100644 --- a/repair/phase6.c +++ b/repair/phase6.c @@ -3633,6 +3633,131 @@ update_missing_dotdot_entries( } } +/* + * Re-link a quota inode into the metadata directory. We do not create quota + * inodes or abort repair if we cannot relink the inodes, because quota mount + * can recreate all the quota metadata. + */ +static int +reattach_quota_inode( + struct xfs_mount *mp, + xfs_ino_t *inop, + const struct xfs_imeta_path *path) +{ + struct xfs_imeta_update upd; + struct xfs_trans *tp; + struct xfs_inode *ip = NULL; + xfs_ino_t ino = *inop; + int error; + + error = ensure_imeta_dirpath(mp, path); + if (error) { + do_warn( + _("Couldn't create quota metadata directory, error %d\n"), error); + return error; + } + + error = -libxfs_trans_alloc_empty(mp, &tp); + if (error) + do_error( + _("failed to allocate trans to grab quota inode 0x%llx, error %d\n"), + (unsigned long long)ino, error); + error = -libxfs_imeta_iget(tp, ino, XFS_DIR3_FT_REG_FILE, &ip); + libxfs_trans_cancel(tp); + if (error) { + do_warn( + _("Couldn't grab quota inode 0x%llx, error %d\n"), + (unsigned long long)ino, error); + goto out_rele; + } + + /* + * Since we're reattaching this file to the metadata directory tree, + * try to remove all the parent pointers that might be attached. + */ + try_erase_parent_ptrs(ip); + + error = -libxfs_imeta_start_link(mp, path, ip, &upd); + if (error) { + do_warn( + _("Couldn't allocate transaction to attach quota inode 0x%llx, error %d\n"), + (unsigned long long)ino, error); + goto out_rele; + } + + /* Null out the superblock pointer and re-link this file into it. */ + *inop = NULLFSINO; + + error = -libxfs_imeta_link(&upd); + if (error) { + do_warn( + _("Couldn't link quota inode 0x%llx, error %d\n"), + (unsigned long long)ino, error); + goto out_cancel; + } + + /* Reset the link count to something sane. */ + set_nlink(VFS_I(ip), 1); + libxfs_trans_log_inode(upd.tp, ip, XFS_ILOG_CORE); + + error = -libxfs_imeta_commit_update(&upd); + if (error) { + do_warn( +_("Couldn't commit quota inode 0x%llx reattachment transaction, error %d\n"), + (unsigned long long)ino, error); + } + + goto out_rele; + +out_cancel: + libxfs_imeta_cancel_update(&upd, error); +out_rele: + if (ip) + libxfs_irele(ip); + return error; +} + +/* + * Reattach quota inodes to the metadata directory if we rebuilt the metadata + * directory tree. + */ +static inline void +reattach_metadir_quota_inodes( + struct xfs_mount *mp) +{ + int error; + + if (!xfs_has_metadir(mp) || no_modify) + return; + + if (mp->m_sb.sb_uquotino != NULLFSINO) { + error = reattach_quota_inode(mp, &mp->m_sb.sb_uquotino, + &XFS_IMETA_USRQUOTA); + if (error) { + mp->m_sb.sb_uquotino = NULLFSINO; + lost_uquotino = 1; + } + } + + if (mp->m_sb.sb_gquotino != NULLFSINO) { + error = reattach_quota_inode(mp, &mp->m_sb.sb_gquotino, + &XFS_IMETA_GRPQUOTA); + if (error) { + mp->m_sb.sb_gquotino = NULLFSINO; + lost_gquotino = 1; + } + } + + if (mp->m_sb.sb_pquotino != NULLFSINO) { + error = reattach_quota_inode(mp, &mp->m_sb.sb_pquotino, + &XFS_IMETA_PRJQUOTA); + if (error) { + mp->m_sb.sb_pquotino = NULLFSINO; + lost_pquotino = 1; + } + } +} + static void traverse_ags( struct xfs_mount *mp) @@ -3718,6 +3843,8 @@ _(" - resetting contents of realtime bitmap and summary inodes\n")); } } + reattach_metadir_quota_inodes(mp); + mark_standalone_inodes(mp); do_log(_(" - traversing filesystem ...\n")); From patchwork Sun Dec 31 23:43:24 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13508175 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 E3DF7C2CC for ; Sun, 31 Dec 2023 23:43:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="HGsvkbgw" Received: by smtp.kernel.org (Postfix) with ESMTPSA id AD6E0C433C7; Sun, 31 Dec 2023 23:43:24 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704066204; bh=nhyKsGAAMZUEeVIXej5cxLAmx8IIMcUiPECiRex1NaE=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=HGsvkbgwUd2PxnBSH1ICJFvSoGIORJTjJpnR5LMOO18LcbEZH7XSGeNLlFmq3Rrjh PxpJiFg+t1h+cLW1jZeGqyyN2doJ5Brj6KqQOlz1npnhzKoUaRrmaWD78rS2wsX3WR T6GnhtAYBSH85JhCA4LJim8hXR5TXJUYGzsRz4oJ2xWTQsABgfFbI2vga5TRP/PSjA 4MbVmUsOpPL4NMnxPsjiHuZfqJ8k4eQfJ/TFk45NHvR7N+KoBjbvr/yM9q9c9lwFeB 9XGXEwLZj3DIBZCzS6pTjnbBwixmitjAu9OWuYb3GMGKa44ZFyu7eDRgAtJkMkOaJm cvYUQ1VgM+cWA== Date: Sun, 31 Dec 2023 15:43:24 -0800 Subject: [PATCH 53/58] xfs_repair: drop all the metadata directory files during pass 4 From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <170405010653.1809361.5737330654597011552.stgit@frogsfrogsfrogs> In-Reply-To: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> References: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Drop the entire metadata directory tree during pass 4 so that we can reinitialize the entire tree in phase 6. The existing metadata files (rtbitmap, rtsummary, quotas) will be reattached to the newly rebuilt directory tree. Signed-off-by: Darrick J. Wong --- repair/dino_chunks.c | 9 +++++++++ repair/dinode.c | 14 +++++++++++++- repair/phase6.c | 21 +++++++++++---------- repair/scan.c | 2 +- 4 files changed, 34 insertions(+), 12 deletions(-) diff --git a/repair/dino_chunks.c b/repair/dino_chunks.c index 7e18991a3d5..a7f9ea70ca7 100644 --- a/repair/dino_chunks.c +++ b/repair/dino_chunks.c @@ -950,6 +950,15 @@ process_inode_chunk( clear_inode_isadir(ino_rec, irec_offset); } + /* + * We always reinitialize the rt bitmap and summary inodes if + * the metadata directory feature is enabled. + */ + if (xfs_has_metadir(mp) && !no_modify) { + need_rbmino = -1; + need_rsumino = -1; + } + if (status) { if (mp->m_sb.sb_rootino == ino) { need_root_inode = 1; diff --git a/repair/dinode.c b/repair/dinode.c index 52830a85a6f..5c9101fa0b0 100644 --- a/repair/dinode.c +++ b/repair/dinode.c @@ -656,7 +656,7 @@ _("illegal state %d in block map %" PRIu64 "\n"), break; } } - if (collect_rmaps) /* && !check_dups */ + if (collect_rmaps && !zap_metadata) /* && !check_dups */ rmap_add_rec(mp, ino, whichfork, &irec); *tot += irec.br_blockcount; } @@ -3084,6 +3084,18 @@ _("Bad CoW extent size %u on inode %" PRIu64 ", "), */ *dirty += process_check_inode_nlink_version(dino, lino); + /* + * The entire metadata directory tree will be rebuilt during phase 6. + * Therefore, if we're at the end of phase 4 and this is a metadata + * file, zero the ondisk inode and the incore state. + */ + if (check_dups && zap_metadata && !no_modify) { + clear_dinode(mp, dino, lino); + *dirty += 1; + *used = is_free; + *isa_dir = 0; + } + return retval; clear_bad_out: diff --git a/repair/phase6.c b/repair/phase6.c index 5eeffd5dce9..c7cfc371ac2 100644 --- a/repair/phase6.c +++ b/repair/phase6.c @@ -3798,20 +3798,20 @@ phase6(xfs_mount_t *mp) } } - if (need_metadir_inode) { - if (!no_modify) { + if (!no_modify && xfs_has_metadir(mp)) { + if (need_metadir_inode) do_warn(_("reinitializing metadata root directory\n")); - mk_metadir(mp); - need_metadir_inode = false; - need_metadir_dotdot = 0; - } else { - do_warn(_("would reinitialize metadata root directory\n")); - } + mk_metadir(mp); + need_metadir_inode = false; + need_metadir_dotdot = 0; + } else if (need_metadir_inode) { + do_warn(_("would reinitialize metadata root directory\n")); } if (need_rbmino) { if (!no_modify) { - do_warn(_("reinitializing realtime bitmap inode\n")); + if (need_rbmino > 0) + do_warn(_("reinitializing realtime bitmap inode\n")); mk_rbmino(mp); need_rbmino = 0; } else { @@ -3821,7 +3821,8 @@ phase6(xfs_mount_t *mp) if (need_rsumino) { if (!no_modify) { - do_warn(_("reinitializing realtime summary inode\n")); + if (need_rsumino > 0) + do_warn(_("reinitializing realtime summary inode\n")); mk_rsumino(mp); need_rsumino = 0; } else { diff --git a/repair/scan.c b/repair/scan.c index c52ace31c2d..3857593b165 100644 --- a/repair/scan.c +++ b/repair/scan.c @@ -429,7 +429,7 @@ _("bad state %d, inode %" PRIu64 " bmap block 0x%" PRIx64 "\n"), numrecs = be16_to_cpu(block->bb_numrecs); /* Record BMBT blocks in the reverse-mapping data. */ - if (check_dups && collect_rmaps) { + if (check_dups && collect_rmaps && !zap_metadata) { agno = XFS_FSB_TO_AGNO(mp, bno); pthread_mutex_lock(&ag_locks[agno].lock); rmap_add_bmbt_rec(mp, ino, whichfork, bno); From patchwork Sun Dec 31 23:43:39 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13508176 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 8BD0CC2C0 for ; Sun, 31 Dec 2023 23:43:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="QeDCsquW" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 59656C433C7; Sun, 31 Dec 2023 23:43:40 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704066220; bh=X6tgdC5ODeXmt3P3R1uhRCi8QKXDbbLcJaELMaj1G/Q=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=QeDCsquWDch6/FS+KMVlGSZH3i2wHryzsboo2pP6BZj80EMwAmj7AybTpqL/F/qnl lYRbHxH/niahwbC6rLo8nup5FOoa2t2NeTln7mpyQXr30ZPEcfDMwmIEiuHLia2nvO KwOmVYr/WTNEsNxWqbkvbiv3+skiB7oApWH52MJyb3hjp9+VdR5AN5R7QlvHmB9bmO Z8DQTV9mTmQpiKAt5CJ9tRZT0udrniI0s9+iqWg+5oNbVX3NKjO/YkTEk95ExxqZrV fkB+L3JxnLghTKtgZR6OmdcF9fb/CPyU4ArrtiJzUR4pe+ZUFQzI8SQRg7TcLrWr4N WzRLMMD4voMNw== Date: Sun, 31 Dec 2023 15:43:39 -0800 Subject: [PATCH 54/58] xfs_repair: truncate and unmark orphaned metadata inodes From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <170405010667.1809361.3276857935166080301.stgit@frogsfrogsfrogs> In-Reply-To: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> References: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 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 an inode claims to be a metadata inode but wasn't linked in either directory tree, remove the attr fork and reset the data fork if the contents weren't regular extent mappings before moving the inode to the lost+found. We don't ifree the inode, because it's possible that the inode was not actually a metadata inode but simply got corrupted due to bitflips or something, and we'd rather let the sysadmin examine what's left of the file instead of photorec'ing it. Signed-off-by: Darrick J. Wong --- repair/phase6.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/repair/phase6.c b/repair/phase6.c index c7cfc371ac2..a99793b4d90 100644 --- a/repair/phase6.c +++ b/repair/phase6.c @@ -1273,6 +1273,53 @@ mk_orphanage( return(ino); } +/* Don't let metadata inode contents leak to lost+found. */ +static void +trunc_metadata_inode( + struct xfs_inode *ip) +{ + struct xfs_trans *tp; + struct xfs_mount *mp = ip->i_mount; + int err; + + err = -libxfs_trans_alloc(mp, &M_RES(mp)->tr_ichange, 0, 0, 0, &tp); + if (err) + do_error( + _("space reservation failed (%d), filesystem may be out of space\n"), + err); + + libxfs_trans_ijoin(tp, ip, 0); + ip->i_diflags2 &= ~XFS_DIFLAG2_METADIR; + + switch (VFS_I(ip)->i_mode & S_IFMT) { + case S_IFIFO: + case S_IFCHR: + case S_IFBLK: + case S_IFSOCK: + ip->i_df.if_format = XFS_DINODE_FMT_DEV; + break; + case S_IFREG: + switch (ip->i_df.if_format) { + case XFS_DINODE_FMT_EXTENTS: + case XFS_DINODE_FMT_BTREE: + break; + default: + ip->i_df.if_format = XFS_DINODE_FMT_EXTENTS; + ip->i_df.if_nextents = 0; + break; + } + break; + } + + libxfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); + + err = -libxfs_trans_commit(tp); + if (err) + do_error( + _("truncation of metadata inode 0x%llx failed, err=%d\n"), + (unsigned long long)ip->i_ino, err); +} + /* * Add a parent pointer back to the orphanage for any file we're moving into * the orphanage, being careful not to trip over any existing parent pointer. @@ -1362,6 +1409,9 @@ mv_orphanage( if (err) do_error(_("%d - couldn't iget disconnected inode\n"), err); + if (xfs_is_metadir_inode(ino_p)) + trunc_metadata_inode(ino_p); + xname.type = libxfs_mode_to_ftype(VFS_I(ino_p)->i_mode); if (isa_dir) { From patchwork Sun Dec 31 23:43:55 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13508177 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 366A8C2C5 for ; Sun, 31 Dec 2023 23:43:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="lZkC9H91" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 04C74C433C8; Sun, 31 Dec 2023 23:43:55 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704066236; bh=PqFLHJZw0n12ubY0klFraY7iT/nxAHjnQWbfUiY00Y8=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=lZkC9H91/G1+3GXqx1RGzUrjHXtSShV2X4ndGe/rDQlmD0cWSSmgAC4TS/ULhKh8B nBuVm6yT8+uvxpwhqD5GbSbLKyJtHTvcqZH5dqIM1eBENkMIonwbMgA46eng2pMbhT wa+5cpcLgBvy7vweSTX+QwuUS96Ky+KkvB/sUwyWk02WWxwiimzzKnin5eGPiWws30 5eO2dV1gRkqZ2oWRzx50CeqVwYKZYywpIc5nKbcs2UaNFCrosuCW5jaVPMXnYm0Nqm vSEc0qDocMztLr7AcCHYI3jnTNwezkeFXi9dkaJmJdUA7U7hDeXPGlAKles15YsJjI gfTWJEYUkQIsA== Date: Sun, 31 Dec 2023 15:43:55 -0800 Subject: [PATCH 55/58] xfs_repair: do not count metadata directory files when doing quotacheck From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <170405010680.1809361.14560654946710868594.stgit@frogsfrogsfrogs> In-Reply-To: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> References: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Previously, we stated that files in the metadata directory tree are not counted in the dquot information. Fix the offline quotacheck code in xfs_repair and xfs_check to reflect this. Signed-off-by: Darrick J. Wong --- db/check.c | 4 ++++ repair/quotacheck.c | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/db/check.c b/db/check.c index ae527471161..190565074b6 100644 --- a/db/check.c +++ b/db/check.c @@ -3018,6 +3018,10 @@ process_inode( default: break; } + /* Metadata directory files are not counted in quotas. */ + if (dip->di_version >= 3 && + (dip->di_flags2 & cpu_to_be64(XFS_DIFLAG2_METADIR))) + ic = 0; if (ic) quota_add(&prid, &gid, &uid, 0, bc, ic, rc); } diff --git a/repair/quotacheck.c b/repair/quotacheck.c index 4cb38db3ddd..3abcd8ae9a0 100644 --- a/repair/quotacheck.c +++ b/repair/quotacheck.c @@ -217,6 +217,10 @@ quotacheck_adjust( return; } + /* Metadata directory files aren't counted in quota. */ + if (xfs_is_metadir_inode(ip)) + goto out_rele; + /* Count the file's blocks. */ if (XFS_IS_REALTIME_INODE(ip)) rtblks = qc_count_rtblocks(ip); @@ -229,6 +233,7 @@ quotacheck_adjust( if (proj_dquots) qc_adjust(proj_dquots, ip->i_projid, blocks, rtblks); +out_rele: libxfs_irele(ip); } From patchwork Sun Dec 31 23:44:11 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13508178 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 4A8BFC2C0 for ; Sun, 31 Dec 2023 23:44:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="gfnjkpws" Received: by smtp.kernel.org (Postfix) with ESMTPSA id ABD9DC433C7; Sun, 31 Dec 2023 23:44:11 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704066251; bh=naFiO2vNv4eV9q40+NcPsxOXkvHeZjEkR8Wd4jwYU7Q=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=gfnjkpwsaiv+seJiDnf3oivYH4gVZASPm6vVDKrZE14ZuhhtMK55VdvmiFDTnBFCq id5u8MdE4gvziqhhMVd1RIOfKTE5FRyWFu3qpIQ3mYDWRr+72GimlI2IBM0HYMflmz lugnXia3kC6glV2fQzG/FTaKIhZIEGXvx/G/KZXVxN+3bVNb5kUq04a7EKYa3+Doic 4TSf57VqajOPWcKHXCKjJWVUC912DtkbQdAAyiUuc/0BBrQNKz7GDfNN49cyFW+FnL K6RbVjl1SE0pw2qSoMD7QVEmRoxl6snpzGo4TItBOe5qBVbZFo61X9rEYU6j4lggOs S/kSKUBt2xOSQ== Date: Sun, 31 Dec 2023 15:44:11 -0800 Subject: [PATCH 56/58] xfs_repair: allow sysadmins to add metadata directories From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <170405010694.1809361.8213815600295286861.stgit@frogsfrogsfrogs> In-Reply-To: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> References: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Allow the sysadmin to use xfs_repair to upgrade an existing filesystem to support metadata directories. This will be needed to upgrade filesystems to support realtime rmap and reflink. Signed-off-by: Darrick J. Wong --- man/man8/xfs_admin.8 | 8 ++++++ repair/dino_chunks.c | 6 ++++ repair/dinode.c | 5 +++- repair/globals.c | 1 + repair/globals.h | 1 + repair/phase2.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++ repair/phase4.c | 5 +++- repair/protos.h | 6 ++++ repair/xfs_repair.c | 11 ++++++++ 9 files changed, 109 insertions(+), 3 deletions(-) diff --git a/man/man8/xfs_admin.8 b/man/man8/xfs_admin.8 index 28f28b6dd8f..68b4bf62427 100644 --- a/man/man8/xfs_admin.8 +++ b/man/man8/xfs_admin.8 @@ -184,6 +184,14 @@ This enables much stronger cross-referencing and online repairs of the directory tree. The filesystem cannot be downgraded after this feature is enabled. This upgrade can fail if the filesystem has less than 25% free space remaining. +.TP 0.4i +.B metadir +Create a directory tree of metadata inodes instead of storing them all in the +superblock. +This is required for reverse mapping btrees and reflink support on the realtime +device. +The filesystem cannot be downgraded after this feature is enabled. +This upgrade can fail if any AG has less than 5% free space remaining. This feature is not upstream yet. .RE .TP diff --git a/repair/dino_chunks.c b/repair/dino_chunks.c index a7f9ea70ca7..d132556d9dc 100644 --- a/repair/dino_chunks.c +++ b/repair/dino_chunks.c @@ -960,7 +960,11 @@ process_inode_chunk( } if (status) { - if (mp->m_sb.sb_rootino == ino) { + if (wipe_pre_metadir_file(ino)) { + if (!ino_discovery) + do_warn( + _("wiping pre-metadir metadata inode %"PRIu64".\n"), ino); + } else if (mp->m_sb.sb_rootino == ino) { need_root_inode = 1; if (!no_modify) { diff --git a/repair/dinode.c b/repair/dinode.c index 5c9101fa0b0..5a57069c29e 100644 --- a/repair/dinode.c +++ b/repair/dinode.c @@ -2422,6 +2422,9 @@ process_dinode_int( ASSERT(uncertain == 0 || verify_mode != 0); ASSERT(ino_bpp != NULL || verify_mode != 0); + if (wipe_pre_metadir_file(lino)) + goto clear_bad_out; + /* * This is the only valid point to check the CRC; after this we may have * made changes which invalidate it, and the CRC is only updated again @@ -2631,7 +2634,7 @@ _("bad (negative) size %" PRId64 " on inode %" PRIu64 "\n"), if (flags & XFS_DIFLAG_NEWRTBM) { /* must be a rt bitmap inode */ if (lino != mp->m_sb.sb_rbmino) { - if (!uncertain) { + if (!uncertain && !add_metadir) { do_warn( _("inode %" PRIu64 " not rt bitmap\n"), lino); diff --git a/repair/globals.c b/repair/globals.c index 22cb096c6a4..e3b2697127f 100644 --- a/repair/globals.c +++ b/repair/globals.c @@ -56,6 +56,7 @@ bool add_finobt; /* add free inode btrees */ bool add_reflink; /* add reference count btrees */ bool add_rmapbt; /* add reverse mapping btrees */ bool add_parent; /* add parent pointers */ +bool add_metadir; /* add metadata directory tree */ /* misc status variables */ diff --git a/repair/globals.h b/repair/globals.h index c3709f11874..1c24e313b89 100644 --- a/repair/globals.h +++ b/repair/globals.h @@ -97,6 +97,7 @@ extern bool add_finobt; /* add free inode btrees */ extern bool add_reflink; /* add reference count btrees */ extern bool add_rmapbt; /* add reverse mapping btrees */ extern bool add_parent; /* add parent pointers */ +extern bool add_metadir; /* add metadata directory tree */ /* misc status variables */ diff --git a/repair/phase2.c b/repair/phase2.c index 5a08cbc31c6..cc7ddad8240 100644 --- a/repair/phase2.c +++ b/repair/phase2.c @@ -14,6 +14,7 @@ #include "incore.h" #include "progress.h" #include "scan.h" +#include "quotacheck.h" /* workaround craziness in the xlog routines */ int xlog_recover_do_trans(struct xlog *log, struct xlog_recover *t, int p) @@ -287,6 +288,70 @@ set_parent( return true; } +static xfs_ino_t doomed_rbmino = NULLFSINO; +static xfs_ino_t doomed_rsumino = NULLFSINO; +static xfs_ino_t doomed_uquotino = NULLFSINO; +static xfs_ino_t doomed_gquotino = NULLFSINO; +static xfs_ino_t doomed_pquotino = NULLFSINO; + +bool +wipe_pre_metadir_file( + xfs_ino_t ino) +{ + if (ino == doomed_rbmino || + ino == doomed_rsumino || + ino == doomed_uquotino || + ino == doomed_gquotino || + ino == doomed_pquotino) + return true; + return false; +} + +static bool +set_metadir( + struct xfs_mount *mp, + struct xfs_sb *new_sb) +{ + if (xfs_has_metadir(mp)) { + printf(_("Filesystem already supports metadata directory trees.\n")); + exit(0); + } + + if (!xfs_has_crc(mp)) { + printf( + _("Metadata directory trees only supported on V5 filesystems.\n")); + exit(0); + } + + printf(_("Adding metadata directory trees to filesystem.\n")); + new_sb->sb_features_incompat |= (XFS_SB_FEAT_INCOMPAT_METADIR | + XFS_SB_FEAT_INCOMPAT_NEEDSREPAIR); + + /* Blow out all the old metadata inodes; we'll rebuild in phase6. */ + new_sb->sb_metadirino = new_sb->sb_rootino + 1; + doomed_rbmino = mp->m_sb.sb_rbmino; + doomed_rsumino = mp->m_sb.sb_rsumino; + doomed_uquotino = mp->m_sb.sb_uquotino; + doomed_gquotino = mp->m_sb.sb_gquotino; + doomed_pquotino = mp->m_sb.sb_pquotino; + + new_sb->sb_rbmino = NULLFSINO; + new_sb->sb_rsumino = NULLFSINO; + new_sb->sb_uquotino = NULLFSINO; + new_sb->sb_gquotino = NULLFSINO; + new_sb->sb_pquotino = NULLFSINO; + + /* Indicate that we need a rebuild. */ + need_metadir_inode = 1; + need_rbmino = 1; + need_rsumino = 1; + have_uquotino = 0; + have_gquotino = 0; + have_pquotino = 0; + quotacheck_skip(); + return true; +} + struct check_state { struct xfs_sb sb; uint64_t features; @@ -475,6 +540,8 @@ need_check_fs_free_space( return true; if (xfs_has_parent(mp) && !(old->features & XFS_FEAT_PARENT)) return true; + if (xfs_has_metadir(mp) && !(old->features & XFS_FEAT_METADIR)) + return true; return false; } @@ -558,6 +625,8 @@ upgrade_filesystem( dirty |= set_rmapbt(mp, &new_sb); if (add_parent) dirty |= set_parent(mp, &new_sb); + if (add_metadir) + dirty |= set_metadir(mp, &new_sb); if (!dirty) return; diff --git a/repair/phase4.c b/repair/phase4.c index e8bd5982147..cfdea1460e5 100644 --- a/repair/phase4.c +++ b/repair/phase4.c @@ -272,7 +272,10 @@ phase4(xfs_mount_t *mp) if (xfs_has_metadir(mp) && (is_inode_free(irec, 1) || !inode_isadir(irec, 1))) { need_metadir_inode = true; - if (no_modify) + if (add_metadir) + do_warn( + _("metadata directory root inode needs to be initialized\n")); + else if (no_modify) do_warn( _("metadata directory root inode would be lost\n")); else diff --git a/repair/protos.h b/repair/protos.h index e2f39f1d6e8..ce171f3dd87 100644 --- a/repair/protos.h +++ b/repair/protos.h @@ -3,6 +3,8 @@ * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. */ +#ifndef __XFS_REPAIR_PROTOS_H__ +#define __XFS_REPAIR_PROTOS_H__ void xfs_init(struct libxfs_init *args); @@ -45,3 +47,7 @@ void phase7(struct xfs_mount *, int); int verify_set_agheader(struct xfs_mount *, struct xfs_buf *, struct xfs_sb *, struct xfs_agf *, struct xfs_agi *, xfs_agnumber_t); + +bool wipe_pre_metadir_file(xfs_ino_t ino); + +#endif /* __XFS_REPAIR_PROTOS_H__ */ diff --git a/repair/xfs_repair.c b/repair/xfs_repair.c index fe24f66ab98..bab8aa70f7a 100644 --- a/repair/xfs_repair.c +++ b/repair/xfs_repair.c @@ -73,6 +73,7 @@ enum c_opt_nums { CONVERT_REFLINK, CONVERT_RMAPBT, CONVERT_PARENT, + CONVERT_METADIR, C_MAX_OPTS, }; @@ -85,6 +86,7 @@ static char *c_opts[] = { [CONVERT_REFLINK] = "reflink", [CONVERT_RMAPBT] = "rmapbt", [CONVERT_PARENT] = "parent", + [CONVERT_METADIR] = "metadir", [C_MAX_OPTS] = NULL, }; @@ -380,6 +382,15 @@ process_args(int argc, char **argv) _("-c parent only supports upgrades\n")); add_parent = true; break; + case CONVERT_METADIR: + if (!val) + do_abort( + _("-c metadir requires a parameter\n")); + if (strtol(val, NULL, 0) != 1) + do_abort( + _("-c metadir only supports upgrades\n")); + add_metadir = true; + break; default: unknown('c', val); break; From patchwork Sun Dec 31 23:44:26 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13508179 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 CE668C2C0 for ; Sun, 31 Dec 2023 23:44:27 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Z81CHwT6" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 4F785C433C8; Sun, 31 Dec 2023 23:44:27 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704066267; bh=VhGAopvSxHO4gE/CE8g5BKgLRD+xPr6Tv54K1A/9E1s=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=Z81CHwT68QrkHmpv9CieUxwNmJQ9DD55tF0PyjflHXoUratAplJeugjLzejWyebvq w5nJiLXp97PhvRFd6tEzupmESVAvdN5FXYhB8NqYfffDuOUSWqMES+B/J2jot4zIGf Gj2LUCtJNEanO87BjiqxuJf3XqqUqie697d90c6b2jbDqm1zqgUmQVk+jqGqm3+qjZ emGvelV8u+D4A6xkroVLgL0S4T9jdZxTq0jzcnX/PcyA4Ul97Mgco3Jx+eCYrBiKOP NZ+TCqmLj2oLIWtE2xa8fl8ji1rfQX8mhgQFcPFk/RZAb0vaL7wxZR2ElW+p5WVOCd Nk93hLzzEaZ0g== Date: Sun, 31 Dec 2023 15:44:26 -0800 Subject: [PATCH 57/58] mkfs.xfs: enable metadata directories From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <170405010707.1809361.800003234594178428.stgit@frogsfrogsfrogs> In-Reply-To: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> References: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 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 formatting filesystems with metadata directories. Signed-off-by: Darrick J. Wong --- libxfs/xfs_format.h | 3 ++- man/man8/mkfs.xfs.8.in | 11 +++++++++++ mkfs/lts_4.19.conf | 1 + mkfs/lts_5.10.conf | 1 + mkfs/lts_5.15.conf | 1 + mkfs/proto.c | 45 ++++++++++++++++++++++++++++++++++++++++++++- mkfs/xfs_mkfs.c | 24 +++++++++++++++++++++++- 7 files changed, 83 insertions(+), 3 deletions(-) diff --git a/libxfs/xfs_format.h b/libxfs/xfs_format.h index 7596b928698..0636ca97622 100644 --- a/libxfs/xfs_format.h +++ b/libxfs/xfs_format.h @@ -398,7 +398,8 @@ xfs_sb_has_ro_compat_feature( XFS_SB_FEAT_INCOMPAT_BIGTIME| \ XFS_SB_FEAT_INCOMPAT_NEEDSREPAIR| \ XFS_SB_FEAT_INCOMPAT_NREXT64| \ - XFS_SB_FEAT_INCOMPAT_PARENT) + XFS_SB_FEAT_INCOMPAT_PARENT | \ + XFS_SB_FEAT_INCOMPAT_METADIR) #define XFS_SB_FEAT_INCOMPAT_UNKNOWN ~XFS_SB_FEAT_INCOMPAT_ALL static inline bool diff --git a/man/man8/mkfs.xfs.8.in b/man/man8/mkfs.xfs.8.in index 8060d342c2a..587754ff95b 100644 --- a/man/man8/mkfs.xfs.8.in +++ b/man/man8/mkfs.xfs.8.in @@ -271,6 +271,17 @@ option set. When the option .B \-m finobt=0 is used, the inode btree counter feature is not supported and is disabled. +.TP +.BI metadir= value +This option creates an internal directory tree to store filesystem metadata. +.IP +By default, +.B mkfs.xfs +will not enable this feature. +If the option +.B \-m crc=0 +is used, the metadata directory feature is not supported and is disabled. + .TP .BI uuid= value Use the given value as the filesystem UUID for the newly created filesystem. diff --git a/mkfs/lts_4.19.conf b/mkfs/lts_4.19.conf index 8b2bdd7a347..6ed71c75347 100644 --- a/mkfs/lts_4.19.conf +++ b/mkfs/lts_4.19.conf @@ -6,6 +6,7 @@ bigtime=0 crc=1 finobt=1 inobtcount=0 +metadir=0 reflink=0 rmapbt=0 diff --git a/mkfs/lts_5.10.conf b/mkfs/lts_5.10.conf index 40189310af2..6eb25d7d4b2 100644 --- a/mkfs/lts_5.10.conf +++ b/mkfs/lts_5.10.conf @@ -6,6 +6,7 @@ bigtime=0 crc=1 finobt=1 inobtcount=0 +metadir=0 reflink=1 rmapbt=0 diff --git a/mkfs/lts_5.15.conf b/mkfs/lts_5.15.conf index aeecc035567..445719f6013 100644 --- a/mkfs/lts_5.15.conf +++ b/mkfs/lts_5.15.conf @@ -6,6 +6,7 @@ bigtime=1 crc=1 finobt=1 inobtcount=1 +metadir=0 reflink=1 rmapbt=0 diff --git a/mkfs/proto.c b/mkfs/proto.c index 0103fe54a5d..33d454cffb2 100644 --- a/mkfs/proto.c +++ b/mkfs/proto.c @@ -17,6 +17,7 @@ static void fail(char *msg, int i); static struct xfs_trans * getres(struct xfs_mount *mp, uint blocks); static void rsvfile(xfs_mount_t *mp, xfs_inode_t *ip, long long len); static char *newregfile(char **pp, int *len); +static int metadir_create(struct xfs_mount *mp); static void rtinit(xfs_mount_t *mp); static void rtfreesp_init(struct xfs_mount *mp); static long filesize(int fd); @@ -705,8 +706,15 @@ parseproto( * RT initialization. Do this here to ensure that * the RT inodes get placed after the root inode. */ - if (isroot) + if (isroot) { + error = metadir_create(mp); + if (error) + fail( + _("Creation of the metadata directory inode failed"), + error); + rtinit(mp); + } tp = NULL; for (;;) { name = getdirentname(pp); @@ -744,6 +752,41 @@ parse_proto( parseproto(mp, NULL, fsx, pp, NULL); } +/* Create a new metadata root directory. */ +static int +metadir_create( + struct xfs_mount *mp) +{ + struct xfs_imeta_update upd; + struct xfs_inode *ip = NULL; + int error; + + if (!xfs_has_metadir(mp)) + return 0; + + error = -libxfs_imeta_start_create(mp, &XFS_IMETA_METADIR, &upd); + if (error) + return error; + + error = -libxfs_imeta_create(&upd, S_IFDIR, &ip); + if (error) + goto out_cancel; + + error = -libxfs_imeta_commit_update(&upd); + if (error) + goto out_rele; + + mp->m_metadirip = ip; + return 0; + +out_cancel: + libxfs_imeta_cancel_update(&upd, error); +out_rele: + if (ip) + libxfs_irele(ip); + return error; +} + /* Create the realtime bitmap inode. */ static void rtbitmap_create( diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c index 15be7e0fb60..de4d1b25c26 100644 --- a/mkfs/xfs_mkfs.c +++ b/mkfs/xfs_mkfs.c @@ -147,6 +147,7 @@ enum { M_REFLINK, M_INOBTCNT, M_BIGTIME, + M_METADIR, M_MAX_OPTS, }; @@ -801,6 +802,7 @@ static struct opt_params mopts = { [M_REFLINK] = "reflink", [M_INOBTCNT] = "inobtcount", [M_BIGTIME] = "bigtime", + [M_METADIR] = "metadir", [M_MAX_OPTS] = NULL, }, .subopt_params = { @@ -844,6 +846,12 @@ static struct opt_params mopts = { .maxval = 1, .defaultval = 1, }, + { .index = M_METADIR, + .conflicts = { { NULL, LAST_CONFLICT } }, + .minval = 0, + .maxval = 1, + .defaultval = 1, + }, }, }; @@ -896,6 +904,7 @@ struct sb_feat_args { bool reflink; /* XFS_SB_FEAT_RO_COMPAT_REFLINK */ bool inobtcnt; /* XFS_SB_FEAT_RO_COMPAT_INOBTCNT */ bool bigtime; /* XFS_SB_FEAT_INCOMPAT_BIGTIME */ + bool metadir; /* XFS_SB_FEAT_INCOMPAT_METADIR */ bool nodalign; bool nortalign; bool nrext64; @@ -1028,7 +1037,7 @@ usage( void ) /* blocksize */ [-b size=num]\n\ /* config file */ [-c options=xxx]\n\ /* metadata */ [-m crc=0|1,finobt=0|1,uuid=xxx,rmapbt=0|1,reflink=0|1,\n\ - inobtcount=0|1,bigtime=0|1]\n\ + inobtcount=0|1,bigtime=0|1,metadir=0|1]\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\ @@ -1845,6 +1854,9 @@ meta_opts_parser( case M_BIGTIME: cli->sb_feat.bigtime = getnum(value, opts, subopt); break; + case M_METADIR: + cli->sb_feat.metadir = getnum(value, opts, subopt); + break; default: return -EINVAL; } @@ -2384,6 +2396,13 @@ _("64 bit extent count not supported without CRC support\n")); usage(); } cli->sb_feat.nrext64 = false; + + if (cli->sb_feat.metadir) { + fprintf(stderr, +_("metadata directory not supported without CRC support\n")); + usage(); + } + cli->sb_feat.metadir = false; } if (!cli->sb_feat.finobt) { @@ -3508,6 +3527,8 @@ sb_set_features( sbp->sb_features_incompat |= XFS_SB_FEAT_INCOMPAT_PARENT; sbp->sb_versionnum |= XFS_SB_VERSION_ATTRBIT; } + if (fp->metadir) + sbp->sb_features_incompat |= XFS_SB_FEAT_INCOMPAT_METADIR; /* * Sparse inode chunk support has two main inode alignment requirements. @@ -3957,6 +3978,7 @@ finish_superblock_setup( platform_uuid_copy(&sbp->sb_meta_uuid, &cfg->uuid); sbp->sb_logstart = cfg->logstart; sbp->sb_rootino = sbp->sb_rbmino = sbp->sb_rsumino = NULLFSINO; + sbp->sb_metadirino = NULLFSINO; sbp->sb_agcount = (xfs_agnumber_t)cfg->agcount; sbp->sb_rbmblocks = cfg->rtbmblocks; sbp->sb_logblocks = (xfs_extlen_t)cfg->logblocks; From patchwork Sun Dec 31 23:44:42 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13508180 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 67B03C2C0 for ; Sun, 31 Dec 2023 23:44:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="QHylGRy/" Received: by smtp.kernel.org (Postfix) with ESMTPSA id D9A41C433C7; Sun, 31 Dec 2023 23:44:42 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704066282; bh=zogi8EgxjOMbCLcmrgQkMVuIvbCpsUlqH7qRhFWSVZs=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=QHylGRy/VFXGSydY+j5hd95+bCYpzv3RuVUxaTl+MOr9H/ps29fqk5LBEmXgcybXG TL1YDsuZUFhQdax64BiYapuN4aaUNUh3VL8bico2w9G4UF0+l5OoXy69PpnjgtXC2/ ql64GkZaIsjxVaOoietvIr+R4YYHDalKmJ8ixH1Jst4F1KBbcP1Xx/mmW9fUA8C4IF BHwDEOV5J+8TWlWz+pB5O4XyOS71W6dt3kR0QeN1FppgYluJPRgzq/ItYkNXVKQLRr hCm8DkranfxCn6HWtehvWuz0LsmNu6SJxCw5gmGscb2N7hqPvuGKS9ls1rL5OYEP3O G9q8I5mHXybFA== Date: Sun, 31 Dec 2023 15:44:42 -0800 Subject: [PATCH 58/58] mkfs: add a utility to generate protofiles From: "Darrick J. Wong" To: cem@kernel.org, djwong@kernel.org Cc: linux-xfs@vger.kernel.org Message-ID: <170405010721.1809361.5709410894088659453.stgit@frogsfrogsfrogs> In-Reply-To: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> References: <170405009903.1809361.17191356040741566208.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Add a new utility to generate mkfs protofiles from a directory tree. Signed-off-by: Darrick J. Wong --- man/man8/xfs_protofile.8 | 33 ++++++++++ mkfs/Makefile | 10 +++ mkfs/xfs_protofile.in | 152 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 194 insertions(+), 1 deletion(-) create mode 100644 man/man8/xfs_protofile.8 create mode 100644 mkfs/xfs_protofile.in diff --git a/man/man8/xfs_protofile.8 b/man/man8/xfs_protofile.8 new file mode 100644 index 00000000000..75090c138f3 --- /dev/null +++ b/man/man8/xfs_protofile.8 @@ -0,0 +1,33 @@ +.TH xfs_protofile 8 +.SH NAME +xfs_protofile \- create a protofile for use with mkfs.xfs +.SH SYNOPSIS +.B xfs_protofile +.I path +[ +.I paths... +] +.br +.B xfs_protofile \-V +.SH DESCRIPTION +.B xfs_protofile +walks a directory tree to generate a protofile. +The protofile format is specified in the +.BR mkfs.xfs (8) +manual page and is derived from 3rd edition Unix. +.SH OPTIONS +.TP 1.0i +.I path +Create protofile directives to copy this path into the root directory. +If the path is a directory, protofile directives will be emitted to +replicate the entire subtree as a subtree of the root directory. +If the path is a not a directory, protofile directives will be emitted +to create the file as an entry in the root directory. +The first path must resolve to a directory. + +.SH BUGS +Filenames cannot contain spaces. +Extended attributes are not copied into the filesystem. + +.PD +.RE diff --git a/mkfs/Makefile b/mkfs/Makefile index a0c168e3815..e42a5618302 100644 --- a/mkfs/Makefile +++ b/mkfs/Makefile @@ -6,6 +6,7 @@ TOPDIR = .. include $(TOPDIR)/include/builddefs LTCOMMAND = mkfs.xfs +XFS_PROTOFILE = xfs_protofile HFILES = CFILES = proto.c xfs_mkfs.c @@ -22,17 +23,24 @@ LLDLIBS += $(LIBXFS) $(LIBXCMD) $(LIBFROG) $(LIBRT) $(LIBBLKID) \ $(LIBUUID) $(LIBINIH) $(LIBURCU) $(LIBPTHREAD) LTDEPENDENCIES += $(LIBXFS) $(LIBXCMD) $(LIBFROG) LLDFLAGS = -static-libtool-libs +DIRT = $(XFS_PROTOFILE) -default: depend $(LTCOMMAND) $(CFGFILES) +default: depend $(LTCOMMAND) $(CFGFILES) $(XFS_PROTOFILE) include $(BUILDRULES) install: default $(INSTALL) -m 755 -d $(PKG_ROOT_SBIN_DIR) $(LTINSTALL) -m 755 $(LTCOMMAND) $(PKG_ROOT_SBIN_DIR) + $(INSTALL) -m 755 $(XFS_PROTOFILE) $(PKG_ROOT_SBIN_DIR) $(INSTALL) -m 755 -d $(MKFS_CFG_DIR) $(INSTALL) -m 644 $(CFGFILES) $(MKFS_CFG_DIR) install-dev: +$(XFS_PROTOFILE): $(XFS_PROTOFILE).in + @echo " [SED] $@" + $(Q)$(SED) -e "s|@pkg_version@|$(PKG_VERSION)|g" < $< > $@ + $(Q)chmod a+x $@ + -include .dep diff --git a/mkfs/xfs_protofile.in b/mkfs/xfs_protofile.in new file mode 100644 index 00000000000..9aee4336888 --- /dev/null +++ b/mkfs/xfs_protofile.in @@ -0,0 +1,152 @@ +#!/usr/bin/python3 + +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2018-2024 Oracle. All rights reserved. +# +# Author: Darrick J. Wong + +# Walk a filesystem tree to generate a protofile for mkfs. + +import os +import argparse +import sys +import stat + +def emit_proto_header(): + '''Emit the protofile header.''' + print('/') + print('0 0') + +def stat_to_str(statbuf): + '''Convert a stat buffer to a proto string.''' + + if stat.S_ISREG(statbuf.st_mode): + type = '-' + elif stat.S_ISCHR(statbuf.st_mode): + type = 'c' + elif stat.S_ISBLK(statbuf.st_mode): + type = 'b' + elif stat.S_ISFIFO(statbuf.st_mode): + type = 'p' + elif stat.S_ISDIR(statbuf.st_mode): + type = 'd' + elif stat.S_ISLNK(statbuf.st_mode): + type = 'l' + + if statbuf.st_mode & stat.S_ISUID: + suid = 'u' + else: + suid = '-' + + if statbuf.st_mode & stat.S_ISGID: + sgid = 'g' + else: + sgid = '-' + + perms = stat.S_IMODE(statbuf.st_mode) + + return '%s%s%s%o %d %d' % (type, suid, sgid, perms, statbuf.st_uid, \ + statbuf.st_gid) + +def stat_to_extra(statbuf, fullpath): + '''Compute the extras column for a protofile.''' + + if stat.S_ISREG(statbuf.st_mode): + return ' %s' % fullpath + elif stat.S_ISCHR(statbuf.st_mode) or stat.S_ISBLK(statbuf.st_mode): + return ' %d %d' % (statbuf.st_rdev, statbuf.st_rdev) + elif stat.S_ISLNK(statbuf.st_mode): + return ' %s' % os.readlink(fullpath) + return '' + +def max_fname_len(s1): + '''Return the length of the longest string in s1.''' + ret = 0 + for s in s1: + if len(s) > ret: + ret = len(s) + return ret + +def walk_tree(path, depth): + '''Walk the directory tree rooted by path.''' + dirs = [] + files = [] + + for fname in os.listdir(path): + fullpath = os.path.join(path, fname) + sb = os.lstat(fullpath) + + if stat.S_ISDIR(sb.st_mode): + dirs.append(fname) + continue + elif stat.S_ISSOCK(sb.st_mode): + continue + else: + files.append(fname) + + for fname in files: + if ' ' in fname: + raise ValueError( \ + f'{fname}: Spaces not allowed in file names.') + for fname in dirs: + if ' ' in fname: + raise Exception( \ + f'{fname}: Spaces not allowed in file names.') + + fname_width = max_fname_len(files) + for fname in files: + fullpath = os.path.join(path, fname) + sb = os.lstat(fullpath) + extra = stat_to_extra(sb, fullpath) + print('%*s%-*s %s%s' % (depth, ' ', fname_width, fname, \ + stat_to_str(sb), extra)) + + for fname in dirs: + fullpath = os.path.join(path, fname) + sb = os.lstat(fullpath) + extra = stat_to_extra(sb, fullpath) + print('%*s%s %s' % (depth, ' ', fname, \ + stat_to_str(sb))) + walk_tree(fullpath, depth + 1) + + if depth > 1: + print('%*s$' % (depth - 1, ' ')) + +def main(): + parser = argparse.ArgumentParser( \ + description = "Generate mkfs.xfs protofile for a directory tree.") + parser.add_argument('paths', metavar = 'paths', type = str, \ + nargs = '*', help = 'Directory paths to walk.') + parser.add_argument("-V", help = "Report version and exit.", \ + action = "store_true") + args = parser.parse_args() + + if args.V: + print("xfs_protofile version @pkg_version@") + sys.exit(0) + + emit_proto_header() + if len(args.paths) == 0: + print('d--755 0 0') + print('$') + else: + # Copy the first argument's stat to the rootdir + statbuf = os.stat(args.paths[0]) + if not stat.S_ISDIR(statbuf.st_mode): + raise NotADirectoryError(path) + print(stat_to_str(statbuf)) + + # All files under each path go in the root dir, recursively + for path in args.paths: + print(': Descending path %s' % path) + try: + walk_tree(path, 1) + except Exception as e: + print(e, file = sys.stderr) + return 1 + + print('$') + return 0 + +if __name__ == '__main__': + sys.exit(main())