From patchwork Sun Dec 31 23:05: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: 13508024 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 E411EBA45 for ; Sun, 31 Dec 2023 23:05:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="ubF44yS+" Received: by smtp.kernel.org (Postfix) with ESMTPSA id B16FEC433C7; Sun, 31 Dec 2023 23:05:22 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704063922; bh=xvu1csgTYZkhpjsNQhsIDg77pinD2q4DwmcYh3QiFGY=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=ubF44yS+jgC9lybPAQPmBxFW7zquoc+ASi3SYhYRWPvHTZZWi9/vdAdNShF4qHYF4 3SW8gYmeDizbrizdiHsqunWILZ79zwHocmiHDQbVLE740L7sPS+7qt5jJeXaMS5o9W s/GUTMWY319yxCcujxx+5oZvKJgVc62xxFnnZATiSDTzCxw8fWli7u1PK9hFjjIx6d MJT/4wXVzBqTYLEdRN5rXsbfjUmp4h3+KEFm2Czn3mrIgOvVJrjM/xO2z86CLXNvrn TxOkaMUDEtRXfhYPJfX4sDPYFeDz369UtuSxvBW6ey92oUzCKTwyeE+QRyzMLCTF0E Ui+UG2pgMjjhw== Date: Sun, 31 Dec 2023 15:05:22 -0800 Subject: [PATCH 01/32] xfs: add parent pointer support to attribute code From: "Darrick J. Wong" To: djwong@kernel.org, cem@kernel.org Cc: Mark Tinguely , Dave Chinner , Allison Henderson , catherine.hoang@oracle.com, linux-xfs@vger.kernel.org, allison.henderson@oracle.com Message-ID: <170405006115.1804688.9089283147822973903.stgit@frogsfrogsfrogs> In-Reply-To: <170405006077.1804688.8762482665401724622.stgit@frogsfrogsfrogs> References: <170405006077.1804688.8762482665401724622.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: Allison Henderson Add the new parent attribute type. XFS_ATTR_PARENT is used only for parent pointer entries; it uses reserved blocks like XFS_ATTR_ROOT. Signed-off-by: Mark Tinguely Signed-off-by: Dave Chinner Signed-off-by: Allison Henderson Reviewed-by: Darrick J. Wong Signed-off-by: Darrick J. Wong --- libxfs/xfs_attr.c | 3 ++- libxfs/xfs_da_format.h | 5 ++++- libxfs/xfs_log_format.h | 1 + 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/libxfs/xfs_attr.c b/libxfs/xfs_attr.c index 3fe9041ae2c..78884485c08 100644 --- a/libxfs/xfs_attr.c +++ b/libxfs/xfs_attr.c @@ -943,7 +943,8 @@ xfs_attr_set( struct xfs_inode *dp = args->dp; struct xfs_mount *mp = dp->i_mount; struct xfs_trans_res tres; - bool rsvd = (args->attr_filter & XFS_ATTR_ROOT); + bool rsvd = (args->attr_filter & (XFS_ATTR_ROOT | + XFS_ATTR_PARENT)); bool is_remove = args->op_flags & XFS_DA_OP_REMOVE; int error, local; int rmt_blks = 0; diff --git a/libxfs/xfs_da_format.h b/libxfs/xfs_da_format.h index 0e1ada44f21..6b5971ee680 100644 --- a/libxfs/xfs_da_format.h +++ b/libxfs/xfs_da_format.h @@ -709,12 +709,15 @@ struct xfs_attr3_leafblock { #define XFS_ATTR_LOCAL_BIT 0 /* attr is stored locally */ #define XFS_ATTR_ROOT_BIT 1 /* limit access to trusted attrs */ #define XFS_ATTR_SECURE_BIT 2 /* limit access to secure attrs */ +#define XFS_ATTR_PARENT_BIT 3 /* parent pointer attrs */ #define XFS_ATTR_INCOMPLETE_BIT 7 /* attr in middle of create/delete */ #define XFS_ATTR_LOCAL (1u << XFS_ATTR_LOCAL_BIT) #define XFS_ATTR_ROOT (1u << XFS_ATTR_ROOT_BIT) #define XFS_ATTR_SECURE (1u << XFS_ATTR_SECURE_BIT) +#define XFS_ATTR_PARENT (1u << XFS_ATTR_PARENT_BIT) #define XFS_ATTR_INCOMPLETE (1u << XFS_ATTR_INCOMPLETE_BIT) -#define XFS_ATTR_NSP_ONDISK_MASK (XFS_ATTR_ROOT | XFS_ATTR_SECURE) +#define XFS_ATTR_NSP_ONDISK_MASK \ + (XFS_ATTR_ROOT | XFS_ATTR_SECURE | XFS_ATTR_PARENT) #define XFS_ATTR_NAMESPACE_STR \ { XFS_ATTR_LOCAL, "local" }, \ diff --git a/libxfs/xfs_log_format.h b/libxfs/xfs_log_format.h index 285a0a089df..bded03634e5 100644 --- a/libxfs/xfs_log_format.h +++ b/libxfs/xfs_log_format.h @@ -1056,6 +1056,7 @@ struct xfs_icreate_log { */ #define XFS_ATTRI_FILTER_MASK (XFS_ATTR_ROOT | \ XFS_ATTR_SECURE | \ + XFS_ATTR_PARENT | \ XFS_ATTR_INCOMPLETE) /* From patchwork Sun Dec 31 23:05: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: 13508025 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 B713EC140 for ; Sun, 31 Dec 2023 23:05:38 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="gPJrW2LJ" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 46C3EC433C7; Sun, 31 Dec 2023 23:05:38 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704063938; bh=qDc+hMSCd6o2NNzcCp003YS8n++k7bOizBl0rdk/O48=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=gPJrW2LJ8dPFZhfUKqJhKioucYfuEk9/2Ohb2Xk47FJF+TszXkPkA8uSiUZCM/4mh +LlvlzfRZqqnoNmk56wgFJLQSegeVtvorSrQmet7rBWUubLnt5pd+5jqr1HkTqVeb9 4bjngXCdfdSj992s1K7GK5PE/SYUgjf18gvRahGeXRpEt1FT4HJkXT4eRwCXsnvDvh dSEfVYE1Vxi2BwY2NyFRVIuUmJibbsMl93wfAotr6KTASsBXLPwF2N2dz2MhqNGZvO lNuFAEPOahAdwxHG+iJrI+WFkc+5jWnnQX7Tgfwn61G2GqnnomgNvGeCacF5s1jNbP 59VkYsErnrkHQ== Date: Sun, 31 Dec 2023 15:05:37 -0800 Subject: [PATCH 02/32] xfs: define parent pointer ondisk extended attribute format From: "Darrick J. Wong" To: djwong@kernel.org, cem@kernel.org Cc: Dave Chinner , Allison Henderson , catherine.hoang@oracle.com, linux-xfs@vger.kernel.org, allison.henderson@oracle.com Message-ID: <170405006129.1804688.7377562468344948804.stgit@frogsfrogsfrogs> In-Reply-To: <170405006077.1804688.8762482665401724622.stgit@frogsfrogsfrogs> References: <170405006077.1804688.8762482665401724622.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: Allison Henderson We need to define the parent pointer attribute format before we start adding support for it into all the code that needs to use it. The EA format we will use encodes the following information: name={parent inode #, parent inode generation, dirent namehash} value={dirent name} The inode/gen gives all the information we need to reliably identify the parent without requiring child->parent lock ordering, and allows userspace to do pathname component level reconstruction without the kernel ever needing to verify the parent itself as part of ioctl calls. Storing the dirent name hash in the key reduces hash collisions if a file is hardlinked multiple times in the same directory. By using the NVLOOKUP mode in the extended attribute code to match parent pointers using both the xattr name and value, we can identify the exact parent pointer EA we need to modify/remove in rename/unlink operations without searching the entire EA space. By storing the dirent name, we have enough information to be able to validate and reconstruct damaged directory trees. Earlier iterations of this patchset encoded the directory offset in the parent pointer key, but this format required repair to keep that in sync across directory rebuilds, which is unnecessary complexity. Signed-off-by: Dave Chinner Signed-off-by: Allison Henderson Reviewed-by: Darrick J. Wong [djwong: replace diroffset with the namehash in the pptr key] Signed-off-by: Darrick J. Wong --- libxfs/xfs_da_format.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/libxfs/xfs_da_format.h b/libxfs/xfs_da_format.h index 6b5971ee680..edbd901d906 100644 --- a/libxfs/xfs_da_format.h +++ b/libxfs/xfs_da_format.h @@ -878,4 +878,24 @@ static inline unsigned int xfs_dir2_dirblock_bytes(struct xfs_sb *sbp) xfs_failaddr_t xfs_da3_blkinfo_verify(struct xfs_buf *bp, struct xfs_da3_blkinfo *hdr3); +/* + * Parent pointer attribute format definition + * + * The xattr name encodes the parent inode number, generation and the crc32c + * hash of the dirent name. + * + * The xattr value contains the dirent name. + */ +struct xfs_parent_name_rec { + __be64 p_ino; + __be32 p_gen; + __be32 p_namehash; +}; + +/* + * Maximum size of the dirent name that can be stored in a parent pointer. + * This matches the maximum dirent name length. + */ +#define XFS_PARENT_DIRENT_NAME_MAX_SIZE (MAXNAMELEN - 1) + #endif /* __XFS_DA_FORMAT_H__ */ From patchwork Sun Dec 31 23:05: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: 13508026 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 11670C147 for ; Sun, 31 Dec 2023 23:05:54 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="cJ55YpMr" Received: by smtp.kernel.org (Postfix) with ESMTPSA id CC97AC433C8; Sun, 31 Dec 2023 23:05:53 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704063953; bh=Nv9UgbWwUVzaXuBtiJaiee+HLUDfgH/HYL7zyLUAecU=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=cJ55YpMr71Ay7IIi3RwziSyPoF5cWT4h2Fb3tJJlCTHtDj8PMV9HCsLygJHly6uqP nngGeZlSJxMUvnQuPgKojHLugcLOYzdAxDSCGIyJojGTIjyXz2+gaTEjxJhQV6Wgaj WLMZ2mhWrxtuWIEw+Nj3+PhJ7xAmZEPhyCVXvBuZECGgU17os8oi4MgddEl9Pu2wmQ wwMavL9Q8mARORGw5OaSJbdzvC/KCWZ5d1ozq0n0coTjvMXaAsoUj9Xbjg4B7iBjAU S0BKBMPQ50UVfOpcy2VjZYmtrgorH6a5VltQ3HRfYfCt1W8xjOhjm6eSWNbP39dwIe QLfeEZr46Lxcg== Date: Sun, 31 Dec 2023 15:05:53 -0800 Subject: [PATCH 03/32] xfs: add parent pointer validator functions From: "Darrick J. Wong" To: djwong@kernel.org, cem@kernel.org Cc: Allison Henderson , catherine.hoang@oracle.com, linux-xfs@vger.kernel.org, allison.henderson@oracle.com Message-ID: <170405006142.1804688.593744446205743406.stgit@frogsfrogsfrogs> In-Reply-To: <170405006077.1804688.8762482665401724622.stgit@frogsfrogsfrogs> References: <170405006077.1804688.8762482665401724622.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: Allison Henderson Attribute names of parent pointers are not strings. So we need to modify attr_namecheck to verify parent pointer records when the XFS_ATTR_PARENT flag is set. At the same time, we need to validate attr values during log recovery if the xattr is really a parent pointer. Signed-off-by: Allison Henderson Reviewed-by: Darrick J. Wong [djwong: move functions to xfs_parent.c, adjust for new disk format] Signed-off-by: Darrick J. Wong --- libxfs/Makefile | 2 + libxfs/xfs_attr.c | 10 +++- libxfs/xfs_attr.h | 3 + libxfs/xfs_da_format.h | 8 +++ libxfs/xfs_parent.c | 114 ++++++++++++++++++++++++++++++++++++++++++++++++ libxfs/xfs_parent.h | 19 ++++++++ repair/attr_repair.c | 19 +++++--- 7 files changed, 165 insertions(+), 10 deletions(-) create mode 100644 libxfs/xfs_parent.c create mode 100644 libxfs/xfs_parent.h diff --git a/libxfs/Makefile b/libxfs/Makefile index 0fb8f7b39bc..38594965882 100644 --- a/libxfs/Makefile +++ b/libxfs/Makefile @@ -50,6 +50,7 @@ HFILES = \ xfs_ialloc_btree.h \ xfs_inode_buf.h \ xfs_inode_fork.h \ + xfs_parent.h \ xfs_quota_defs.h \ xfs_refcount.h \ xfs_refcount_btree.h \ @@ -101,6 +102,7 @@ CFILES = cache.c \ xfs_inode_fork.c \ xfs_ialloc_btree.c \ xfs_log_rlimit.c \ + xfs_parent.c \ xfs_refcount.c \ xfs_refcount_btree.c \ xfs_rmap.c \ diff --git a/libxfs/xfs_attr.c b/libxfs/xfs_attr.c index 78884485c08..04561f0318a 100644 --- a/libxfs/xfs_attr.c +++ b/libxfs/xfs_attr.c @@ -24,6 +24,7 @@ #include "xfs_quota_defs.h" #include "xfs_trans_space.h" #include "xfs_trace.h" +#include "xfs_parent.h" struct kmem_cache *xfs_attr_intent_cache; @@ -1543,9 +1544,14 @@ xfs_attr_node_get( /* Returns true if the attribute entry name is valid. */ bool xfs_attr_namecheck( - const void *name, - size_t length) + struct xfs_mount *mp, + const void *name, + size_t length, + unsigned int flags) { + if (flags & XFS_ATTR_PARENT) + return xfs_parent_namecheck(mp, name, length, flags); + /* * MAXNAMELEN includes the trailing null, but (name/length) leave it * out, so use >= for the length check. diff --git a/libxfs/xfs_attr.h b/libxfs/xfs_attr.h index b4e8ecee3e0..5b3a0d4b158 100644 --- a/libxfs/xfs_attr.h +++ b/libxfs/xfs_attr.h @@ -552,7 +552,8 @@ int xfs_attr_get(struct xfs_da_args *args); int xfs_attr_set(struct xfs_da_args *args); int xfs_attr_set_iter(struct xfs_attr_intent *attr); int xfs_attr_remove_iter(struct xfs_attr_intent *attr); -bool xfs_attr_namecheck(const void *name, size_t length); +bool xfs_attr_namecheck(struct xfs_mount *mp, const void *name, size_t length, + unsigned int flags); int xfs_attr_calc_size(struct xfs_da_args *args, int *local); void xfs_init_attr_trans(struct xfs_da_args *args, struct xfs_trans_res *tres, unsigned int *total); diff --git a/libxfs/xfs_da_format.h b/libxfs/xfs_da_format.h index edbd901d906..a63387796a2 100644 --- a/libxfs/xfs_da_format.h +++ b/libxfs/xfs_da_format.h @@ -757,6 +757,14 @@ xfs_attr3_leaf_name(xfs_attr_leafblock_t *leafp, int idx) return &((char *)leafp)[be16_to_cpu(entries[idx].nameidx)]; } +static inline int +xfs_attr3_leaf_flags(xfs_attr_leafblock_t *leafp, int idx) +{ + struct xfs_attr_leaf_entry *entries = xfs_attr3_leaf_entryp(leafp); + + return entries[idx].flags; +} + static inline xfs_attr_leaf_name_remote_t * xfs_attr3_leaf_name_remote(xfs_attr_leafblock_t *leafp, int idx) { diff --git a/libxfs/xfs_parent.c b/libxfs/xfs_parent.c new file mode 100644 index 00000000000..6874d8afe23 --- /dev/null +++ b/libxfs/xfs_parent.c @@ -0,0 +1,114 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2022-2024 Oracle. + * All rights reserved. + */ +#include "libxfs_priv.h" +#include "xfs_shared.h" +#include "xfs_format.h" +#include "xfs_log_format.h" +#include "xfs_trans_resv.h" +#include "xfs_mount.h" +#include "xfs_inode.h" +#include "xfs_trans_resv.h" +#include "xfs_mount.h" +#include "xfs_trace.h" +#include "xfs.h" +#include "xfs_fs.h" +#include "xfs_da_format.h" +#include "xfs_bmap_btree.h" +#include "xfs_trans.h" +#include "xfs_da_btree.h" +#include "xfs_attr.h" +#include "xfs_dir2.h" +#include "xfs_dir2_priv.h" +#include "xfs_attr_sf.h" +#include "xfs_bmap.h" +#include "xfs_parent.h" +#include "xfs_da_format.h" +#include "xfs_format.h" +#include "xfs_trans_space.h" + +/* + * Parent pointer attribute handling. + * + * Because the attribute value is a filename component, it will never be longer + * than 255 bytes. This means the attribute will always be a local format + * attribute as it is xfs_attr_leaf_entsize_local_max() for v5 filesystems will + * always be larger than this (max is 75% of block size). + * + * Creating a new parent attribute will always create a new attribute - there + * should never, ever be an existing attribute in the tree for a new inode. + * ENOSPC behavior is problematic - creating the inode without the parent + * pointer is effectively a corruption, so we allow parent attribute creation + * to dip into the reserve block pool to avoid unexpected ENOSPC errors from + * occurring. + */ + +/* Return true if parent pointer EA name is valid. */ +bool +xfs_parent_namecheck( + struct xfs_mount *mp, + const struct xfs_parent_name_rec *rec, + size_t reclen, + unsigned int attr_flags) +{ + if (!(attr_flags & XFS_ATTR_PARENT)) + return false; + + /* pptr updates use logged xattrs, so we should never see this flag */ + if (attr_flags & XFS_ATTR_INCOMPLETE) + return false; + + if (reclen != sizeof(struct xfs_parent_name_rec)) + return false; + + /* Only one namespace bit allowed. */ + if (hweight32(attr_flags & XFS_ATTR_NSP_ONDISK_MASK) > 1) + return false; + + return true; +} + +/* Return true if parent pointer EA value is valid. */ +bool +xfs_parent_valuecheck( + struct xfs_mount *mp, + const void *value, + size_t valuelen) +{ + if (valuelen == 0 || valuelen > XFS_PARENT_DIRENT_NAME_MAX_SIZE) + return false; + + if (value == NULL) + return false; + + return true; +} + +/* Return true if the ondisk parent pointer is consistent. */ +bool +xfs_parent_hashcheck( + struct xfs_mount *mp, + const struct xfs_parent_name_rec *rec, + const void *value, + size_t valuelen) +{ + struct xfs_name dname = { + .name = value, + .len = valuelen, + }; + xfs_ino_t p_ino; + + /* Valid dirent name? */ + if (!xfs_dir2_namecheck(value, valuelen)) + return false; + + /* Valid inode number? */ + p_ino = be64_to_cpu(rec->p_ino); + if (!xfs_verify_dir_ino(mp, p_ino)) + return false; + + /* Namehash matches name? */ + return be32_to_cpu(rec->p_namehash) == xfs_dir2_hashname(mp, &dname); +} diff --git a/libxfs/xfs_parent.h b/libxfs/xfs_parent.h new file mode 100644 index 00000000000..fcfeddb645f --- /dev/null +++ b/libxfs/xfs_parent.h @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2022-2024 Oracle. + * All Rights Reserved. + */ +#ifndef __XFS_PARENT_H__ +#define __XFS_PARENT_H__ + +/* Metadata validators */ +bool xfs_parent_namecheck(struct xfs_mount *mp, + const struct xfs_parent_name_rec *rec, size_t reclen, + unsigned int attr_flags); +bool xfs_parent_valuecheck(struct xfs_mount *mp, const void *value, + size_t valuelen); +bool xfs_parent_hashcheck(struct xfs_mount *mp, + const struct xfs_parent_name_rec *rec, const void *value, + size_t valuelen); + +#endif /* __XFS_PARENT_H__ */ diff --git a/repair/attr_repair.c b/repair/attr_repair.c index b7ebf103dd6..314a9cb4d6e 100644 --- a/repair/attr_repair.c +++ b/repair/attr_repair.c @@ -294,8 +294,9 @@ process_shortform_attr( } /* namecheck checks for null chars in attr names. */ - if (!libxfs_attr_namecheck(currententry->nameval, - currententry->namelen)) { + if (!libxfs_attr_namecheck(mp, currententry->nameval, + currententry->namelen, + currententry->flags)) { do_warn( _("entry contains illegal character in shortform attribute name\n")); junkit = 1; @@ -471,12 +472,14 @@ process_leaf_attr_local( xfs_dablk_t da_bno, xfs_ino_t ino) { - xfs_attr_leaf_name_local_t *local; + xfs_attr_leaf_name_local_t *local; + int flags; local = xfs_attr3_leaf_name_local(leaf, i); + flags = xfs_attr3_leaf_flags(leaf, i); if (local->namelen == 0 || - !libxfs_attr_namecheck(local->nameval, - local->namelen)) { + !libxfs_attr_namecheck(mp, local->nameval, + local->namelen, flags)) { do_warn( _("attribute entry %d in attr block %u, inode %" PRIu64 " has bad name (namelen = %d)\n"), i, da_bno, ino, local->namelen); @@ -527,12 +530,14 @@ process_leaf_attr_remote( { xfs_attr_leaf_name_remote_t *remotep; char* value; + int flags; remotep = xfs_attr3_leaf_name_remote(leaf, i); + flags = xfs_attr3_leaf_flags(leaf, i); if (remotep->namelen == 0 || - !libxfs_attr_namecheck(remotep->name, - remotep->namelen) || + !libxfs_attr_namecheck(mp, remotep->name, + remotep->namelen, flags) || be32_to_cpu(entry->hashval) != libxfs_da_hashname((unsigned char *)&remotep->name[0], remotep->namelen) || From patchwork Sun Dec 31 23:06: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: 13508027 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 EFDDFC147 for ; Sun, 31 Dec 2023 23:06:09 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="gMLhwRpF" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 6DDADC433C7; Sun, 31 Dec 2023 23:06:09 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704063969; bh=mHTqY4xvC+uGASpQrf7Ks06dp3uoGtTgRPKgoeUdp3Y=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=gMLhwRpFD4L1bjdio9wx/QVNytfuZYUzvwwCHi5Zg9AvgQs0p3EVVBAWEox3IX0gR tgyZtmZVLTDoc6e+ZqQ2NDBCrLqKLl25rTBy5jHUo3YIwvHAg2zlMw/iohR2JoAUJ7 zNpbsNozjc2JBVni7T+F0jhFP+tXbsgb2eoR0YejNuJad47oUKmPN1tvqwf6t0CIPY qBtxeyt2au4qp7vexehEZ4rcZilS2t9E6BYNty9foLXMBshgM2PXx0oG9GQLetDX9J hcIWVe4zRkgeRqS9bmQNnBxv4vzUbIqvffSdH4BfLktxZj49hcCOqCzpGuHw/cT4Yg zlYRKZs4yML1Q== Date: Sun, 31 Dec 2023 15:06:09 -0800 Subject: [PATCH 04/32] xfs: extend transaction reservations for parent attributes From: "Darrick J. Wong" To: djwong@kernel.org, cem@kernel.org Cc: Dave Chinner , Allison Henderson , catherine.hoang@oracle.com, linux-xfs@vger.kernel.org, allison.henderson@oracle.com Message-ID: <170405006155.1804688.1663180920993382787.stgit@frogsfrogsfrogs> In-Reply-To: <170405006077.1804688.8762482665401724622.stgit@frogsfrogsfrogs> References: <170405006077.1804688.8762482665401724622.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: Allison Henderson We need to add, remove or modify parent pointer attributes during create/link/unlink/rename operations atomically with the dirents in the parent directories being modified. This means they need to be modified in the same transaction as the parent directories, and so we need to add the required space for the attribute modifications to the transaction reservations. Signed-off-by: Dave Chinner Signed-off-by: Allison Henderson Reviewed-by: Darrick J. Wong [djwong: fix indenting errors, adjust for new log format] Signed-off-by: Darrick J. Wong --- libxfs/libxfs_priv.h | 1 libxfs/xfs_trans_resv.c | 324 +++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 273 insertions(+), 52 deletions(-) diff --git a/libxfs/libxfs_priv.h b/libxfs/libxfs_priv.h index 45cfe4408a9..411c33b3956 100644 --- a/libxfs/libxfs_priv.h +++ b/libxfs/libxfs_priv.h @@ -483,6 +483,7 @@ static inline int retzero(void) { return 0; } #define xfs_icreate_log(tp, agno, agbno, cnt, isize, len, gen) ((void) 0) #define xfs_sb_validate_fsb_count(sbp, nblks) (0) +#define xlog_calc_iovec_len(len) roundup(len, sizeof(uint32_t)) /* * Prototypes for kernel static functions that are aren't in their diff --git a/libxfs/xfs_trans_resv.c b/libxfs/xfs_trans_resv.c index 82b3d1522b6..78e7a575baa 100644 --- a/libxfs/xfs_trans_resv.c +++ b/libxfs/xfs_trans_resv.c @@ -19,6 +19,7 @@ #include "xfs_trans_space.h" #include "xfs_quota_defs.h" #include "xfs_rtbitmap.h" +#include "xfs_da_format.h" #define _ALLOC true #define _FREE false @@ -421,29 +422,110 @@ xfs_calc_itruncate_reservation_minlogsize( return xfs_calc_itruncate_reservation(mp, true); } +static inline unsigned int xfs_calc_pptr_link_overhead(void) +{ + return sizeof(struct xfs_attri_log_format) + + xlog_calc_iovec_len(sizeof(struct xfs_parent_name_rec)) + + xlog_calc_iovec_len(XFS_PARENT_DIRENT_NAME_MAX_SIZE); +} +static inline unsigned int xfs_calc_pptr_unlink_overhead(void) +{ + return sizeof(struct xfs_attri_log_format) + + xlog_calc_iovec_len(sizeof(struct xfs_parent_name_rec)) + + xlog_calc_iovec_len(XFS_PARENT_DIRENT_NAME_MAX_SIZE); +} +static inline unsigned int xfs_calc_pptr_replace_overhead(void) +{ + return sizeof(struct xfs_attri_log_format) + + xlog_calc_iovec_len(sizeof(struct xfs_parent_name_rec)) + + xlog_calc_iovec_len(XFS_PARENT_DIRENT_NAME_MAX_SIZE) + + xlog_calc_iovec_len(sizeof(struct xfs_parent_name_rec)) + + xlog_calc_iovec_len(XFS_PARENT_DIRENT_NAME_MAX_SIZE); +} + /* * In renaming a files we can modify: * the five inodes involved: 5 * inode size * the two directory btrees: 2 * (max depth + v2) * dir block size * the two directory bmap btrees: 2 * max depth * block size * And the bmap_finish transaction can free dir and bmap blocks (two sets - * of bmap blocks) giving: + * of bmap blocks) giving (t2): * the agf for the ags in which the blocks live: 3 * sector size * the agfl for the ags in which the blocks live: 3 * sector size * the superblock for the free block count: sector size * the allocation btrees: 3 exts * 2 trees * (2 * max depth - 1) * block size + * If parent pointers are enabled (t3), then each transaction in the chain + * must be capable of setting or removing the extended attribute + * containing the parent information. It must also be able to handle + * the three xattr intent items that track the progress of the parent + * pointer update. */ STATIC uint xfs_calc_rename_reservation( struct xfs_mount *mp) { - return XFS_DQUOT_LOGRES(mp) + - max((xfs_calc_inode_res(mp, 5) + - xfs_calc_buf_res(2 * XFS_DIROP_LOG_COUNT(mp), - XFS_FSB_TO_B(mp, 1))), - (xfs_calc_buf_res(7, mp->m_sb.sb_sectsize) + - xfs_calc_buf_res(xfs_allocfree_block_count(mp, 3), - XFS_FSB_TO_B(mp, 1)))); + unsigned int overhead = XFS_DQUOT_LOGRES(mp); + struct xfs_trans_resv *resp = M_RES(mp); + unsigned int t1, t2, t3 = 0; + + t1 = xfs_calc_inode_res(mp, 5) + + xfs_calc_buf_res(2 * XFS_DIROP_LOG_COUNT(mp), + XFS_FSB_TO_B(mp, 1)); + + t2 = xfs_calc_buf_res(7, mp->m_sb.sb_sectsize) + + xfs_calc_buf_res(xfs_allocfree_block_count(mp, 3), + XFS_FSB_TO_B(mp, 1)); + + if (xfs_has_parent(mp)) { + unsigned int rename_overhead, exchange_overhead; + + t3 = max(resp->tr_attrsetm.tr_logres, + resp->tr_attrrm.tr_logres); + + /* + * For a standard rename, the three xattr intent log items + * are (1) replacing the pptr for the source file; (2) + * removing the pptr on the dest file; and (3) adding a + * pptr for the whiteout file in the src dir. + * + * For an RENAME_EXCHANGE, there are two xattr intent + * items to replace the pptr for both src and dest + * files. Link counts don't change and there is no + * whiteout. + * + * In the worst case we can end up relogging all log + * intent items to allow the log tail to move ahead, so + * they become overhead added to each transaction in a + * processing chain. + */ + rename_overhead = xfs_calc_pptr_replace_overhead() + + xfs_calc_pptr_unlink_overhead() + + xfs_calc_pptr_link_overhead(); + exchange_overhead = 2 * xfs_calc_pptr_replace_overhead(); + + overhead += max(rename_overhead, exchange_overhead); + } + + return overhead + max3(t1, t2, t3); +} + +static inline unsigned int +xfs_rename_log_count( + struct xfs_mount *mp, + struct xfs_trans_resv *resp) +{ + /* One for the rename, one more for freeing blocks */ + unsigned int ret = XFS_RENAME_LOG_COUNT; + + /* + * Pre-reserve enough log reservation to handle the transaction + * rolling needed to remove or add one parent pointer. + */ + if (xfs_has_parent(mp)) + ret += max(resp->tr_attrsetm.tr_logcount, + resp->tr_attrrm.tr_logcount); + + return ret; } /* @@ -460,6 +542,23 @@ xfs_calc_iunlink_remove_reservation( 2 * M_IGEO(mp)->inode_cluster_size; } +static inline unsigned int +xfs_link_log_count( + struct xfs_mount *mp, + struct xfs_trans_resv *resp) +{ + unsigned int ret = XFS_LINK_LOG_COUNT; + + /* + * Pre-reserve enough log reservation to handle the transaction + * rolling needed to add one parent pointer. + */ + if (xfs_has_parent(mp)) + ret += resp->tr_attrsetm.tr_logcount; + + return ret; +} + /* * For creating a link to an inode: * the parent directory inode: inode size @@ -476,14 +575,23 @@ STATIC uint xfs_calc_link_reservation( struct xfs_mount *mp) { - return XFS_DQUOT_LOGRES(mp) + - xfs_calc_iunlink_remove_reservation(mp) + - max((xfs_calc_inode_res(mp, 2) + - xfs_calc_buf_res(XFS_DIROP_LOG_COUNT(mp), - XFS_FSB_TO_B(mp, 1))), - (xfs_calc_buf_res(3, mp->m_sb.sb_sectsize) + - xfs_calc_buf_res(xfs_allocfree_block_count(mp, 1), - XFS_FSB_TO_B(mp, 1)))); + unsigned int overhead = XFS_DQUOT_LOGRES(mp); + struct xfs_trans_resv *resp = M_RES(mp); + unsigned int t1, t2, t3 = 0; + + overhead += xfs_calc_iunlink_remove_reservation(mp); + t1 = xfs_calc_inode_res(mp, 2) + + xfs_calc_buf_res(XFS_DIROP_LOG_COUNT(mp), XFS_FSB_TO_B(mp, 1)); + t2 = xfs_calc_buf_res(3, mp->m_sb.sb_sectsize) + + xfs_calc_buf_res(xfs_allocfree_block_count(mp, 1), + XFS_FSB_TO_B(mp, 1)); + + if (xfs_has_parent(mp)) { + t3 = resp->tr_attrsetm.tr_logres; + overhead += xfs_calc_pptr_link_overhead(); + } + + return overhead + max3(t1, t2, t3); } /* @@ -498,6 +606,23 @@ xfs_calc_iunlink_add_reservation(xfs_mount_t *mp) M_IGEO(mp)->inode_cluster_size; } +static inline unsigned int +xfs_remove_log_count( + struct xfs_mount *mp, + struct xfs_trans_resv *resp) +{ + unsigned int ret = XFS_REMOVE_LOG_COUNT; + + /* + * Pre-reserve enough log reservation to handle the transaction + * rolling needed to add one parent pointer. + */ + if (xfs_has_parent(mp)) + ret += resp->tr_attrrm.tr_logcount; + + return ret; +} + /* * For removing a directory entry we can modify: * the parent directory inode: inode size @@ -514,14 +639,24 @@ STATIC uint xfs_calc_remove_reservation( struct xfs_mount *mp) { - return XFS_DQUOT_LOGRES(mp) + - xfs_calc_iunlink_add_reservation(mp) + - max((xfs_calc_inode_res(mp, 2) + - xfs_calc_buf_res(XFS_DIROP_LOG_COUNT(mp), - XFS_FSB_TO_B(mp, 1))), - (xfs_calc_buf_res(4, mp->m_sb.sb_sectsize) + - xfs_calc_buf_res(xfs_allocfree_block_count(mp, 2), - XFS_FSB_TO_B(mp, 1)))); + unsigned int overhead = XFS_DQUOT_LOGRES(mp); + struct xfs_trans_resv *resp = M_RES(mp); + unsigned int t1, t2, t3 = 0; + + overhead += xfs_calc_iunlink_add_reservation(mp); + + t1 = xfs_calc_inode_res(mp, 2) + + xfs_calc_buf_res(XFS_DIROP_LOG_COUNT(mp), XFS_FSB_TO_B(mp, 1)); + t2 = xfs_calc_buf_res(4, mp->m_sb.sb_sectsize) + + xfs_calc_buf_res(xfs_allocfree_block_count(mp, 2), + XFS_FSB_TO_B(mp, 1)); + + if (xfs_has_parent(mp)) { + t3 = resp->tr_attrrm.tr_logres; + overhead += xfs_calc_pptr_unlink_overhead(); + } + + return overhead + max3(t1, t2, t3); } /* @@ -570,12 +705,40 @@ xfs_calc_icreate_resv_alloc( xfs_calc_finobt_res(mp); } +static inline unsigned int +xfs_icreate_log_count( + struct xfs_mount *mp, + struct xfs_trans_resv *resp) +{ + unsigned int ret = XFS_CREATE_LOG_COUNT; + + /* + * Pre-reserve enough log reservation to handle the transaction + * rolling needed to add one parent pointer. + */ + if (xfs_has_parent(mp)) + ret += resp->tr_attrsetm.tr_logcount; + + return ret; +} + STATIC uint -xfs_calc_icreate_reservation(xfs_mount_t *mp) +xfs_calc_icreate_reservation( + struct xfs_mount *mp) { - return XFS_DQUOT_LOGRES(mp) + - max(xfs_calc_icreate_resv_alloc(mp), - xfs_calc_create_resv_modify(mp)); + struct xfs_trans_resv *resp = M_RES(mp); + unsigned int overhead = XFS_DQUOT_LOGRES(mp); + unsigned int t1, t2, t3 = 0; + + t1 = xfs_calc_icreate_resv_alloc(mp); + t2 = xfs_calc_create_resv_modify(mp); + + if (xfs_has_parent(mp)) { + t3 = resp->tr_attrsetm.tr_logres; + overhead += xfs_calc_pptr_link_overhead(); + } + + return overhead + max3(t1, t2, t3); } STATIC uint @@ -588,6 +751,23 @@ xfs_calc_create_tmpfile_reservation( return res + xfs_calc_iunlink_add_reservation(mp); } +static inline unsigned int +xfs_mkdir_log_count( + struct xfs_mount *mp, + struct xfs_trans_resv *resp) +{ + unsigned int ret = XFS_MKDIR_LOG_COUNT; + + /* + * Pre-reserve enough log reservation to handle the transaction + * rolling needed to add one parent pointer. + */ + if (xfs_has_parent(mp)) + ret += resp->tr_attrsetm.tr_logcount; + + return ret; +} + /* * Making a new directory is the same as creating a new file. */ @@ -598,6 +778,22 @@ xfs_calc_mkdir_reservation( return xfs_calc_icreate_reservation(mp); } +static inline unsigned int +xfs_symlink_log_count( + struct xfs_mount *mp, + struct xfs_trans_resv *resp) +{ + unsigned int ret = XFS_SYMLINK_LOG_COUNT; + + /* + * Pre-reserve enough log reservation to handle the transaction + * rolling needed to add one parent pointer. + */ + if (xfs_has_parent(mp)) + ret += resp->tr_attrsetm.tr_logcount; + + return ret; +} /* * Making a new symplink is the same as creating a new file, but @@ -910,6 +1106,52 @@ xfs_calc_sb_reservation( return xfs_calc_buf_res(1, mp->m_sb.sb_sectsize); } +/* + * Namespace reservations. + * + * These get tricky when parent pointers are enabled as we have attribute + * modifications occurring from within these transactions. Rather than confuse + * each of these reservation calculations with the conditional attribute + * reservations, add them here in a clear and concise manner. This requires that + * the attribute reservations have already been calculated. + * + * Note that we only include the static attribute reservation here; the runtime + * reservation will have to be modified by the size of the attributes being + * added/removed/modified. See the comments on the attribute reservation + * calculations for more details. + */ +STATIC void +xfs_calc_namespace_reservations( + struct xfs_mount *mp, + struct xfs_trans_resv *resp) +{ + ASSERT(resp->tr_attrsetm.tr_logres > 0); + + resp->tr_rename.tr_logres = xfs_calc_rename_reservation(mp); + resp->tr_rename.tr_logcount = xfs_rename_log_count(mp, resp); + resp->tr_rename.tr_logflags |= XFS_TRANS_PERM_LOG_RES; + + resp->tr_link.tr_logres = xfs_calc_link_reservation(mp); + resp->tr_link.tr_logcount = xfs_link_log_count(mp, resp); + resp->tr_link.tr_logflags |= XFS_TRANS_PERM_LOG_RES; + + resp->tr_remove.tr_logres = xfs_calc_remove_reservation(mp); + resp->tr_remove.tr_logcount = xfs_remove_log_count(mp, resp); + resp->tr_remove.tr_logflags |= XFS_TRANS_PERM_LOG_RES; + + resp->tr_symlink.tr_logres = xfs_calc_symlink_reservation(mp); + resp->tr_symlink.tr_logcount = xfs_symlink_log_count(mp, resp); + resp->tr_symlink.tr_logflags |= XFS_TRANS_PERM_LOG_RES; + + resp->tr_create.tr_logres = xfs_calc_icreate_reservation(mp); + resp->tr_create.tr_logcount = xfs_icreate_log_count(mp, resp); + resp->tr_create.tr_logflags |= XFS_TRANS_PERM_LOG_RES; + + resp->tr_mkdir.tr_logres = xfs_calc_mkdir_reservation(mp); + resp->tr_mkdir.tr_logcount = xfs_mkdir_log_count(mp, resp); + resp->tr_mkdir.tr_logflags |= XFS_TRANS_PERM_LOG_RES; +} + void xfs_trans_resv_calc( struct xfs_mount *mp, @@ -929,35 +1171,11 @@ xfs_trans_resv_calc( resp->tr_itruncate.tr_logcount = XFS_ITRUNCATE_LOG_COUNT; resp->tr_itruncate.tr_logflags |= XFS_TRANS_PERM_LOG_RES; - resp->tr_rename.tr_logres = xfs_calc_rename_reservation(mp); - resp->tr_rename.tr_logcount = XFS_RENAME_LOG_COUNT; - resp->tr_rename.tr_logflags |= XFS_TRANS_PERM_LOG_RES; - - resp->tr_link.tr_logres = xfs_calc_link_reservation(mp); - resp->tr_link.tr_logcount = XFS_LINK_LOG_COUNT; - resp->tr_link.tr_logflags |= XFS_TRANS_PERM_LOG_RES; - - resp->tr_remove.tr_logres = xfs_calc_remove_reservation(mp); - resp->tr_remove.tr_logcount = XFS_REMOVE_LOG_COUNT; - resp->tr_remove.tr_logflags |= XFS_TRANS_PERM_LOG_RES; - - resp->tr_symlink.tr_logres = xfs_calc_symlink_reservation(mp); - resp->tr_symlink.tr_logcount = XFS_SYMLINK_LOG_COUNT; - resp->tr_symlink.tr_logflags |= XFS_TRANS_PERM_LOG_RES; - - resp->tr_create.tr_logres = xfs_calc_icreate_reservation(mp); - resp->tr_create.tr_logcount = XFS_CREATE_LOG_COUNT; - resp->tr_create.tr_logflags |= XFS_TRANS_PERM_LOG_RES; - resp->tr_create_tmpfile.tr_logres = xfs_calc_create_tmpfile_reservation(mp); resp->tr_create_tmpfile.tr_logcount = XFS_CREATE_TMPFILE_LOG_COUNT; resp->tr_create_tmpfile.tr_logflags |= XFS_TRANS_PERM_LOG_RES; - resp->tr_mkdir.tr_logres = xfs_calc_mkdir_reservation(mp); - resp->tr_mkdir.tr_logcount = XFS_MKDIR_LOG_COUNT; - resp->tr_mkdir.tr_logflags |= XFS_TRANS_PERM_LOG_RES; - resp->tr_ifree.tr_logres = xfs_calc_ifree_reservation(mp); resp->tr_ifree.tr_logcount = XFS_INACTIVE_LOG_COUNT; resp->tr_ifree.tr_logflags |= XFS_TRANS_PERM_LOG_RES; @@ -987,6 +1205,8 @@ xfs_trans_resv_calc( resp->tr_qm_dqalloc.tr_logcount = XFS_WRITE_LOG_COUNT; resp->tr_qm_dqalloc.tr_logflags |= XFS_TRANS_PERM_LOG_RES; + xfs_calc_namespace_reservations(mp, resp); + /* * The following transactions are logged in logical format with * a default log count. From patchwork Sun Dec 31 23:06: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: 13508028 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 444CBC147 for ; Sun, 31 Dec 2023 23:06:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="QgrZCqIh" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 146B2C433C8; Sun, 31 Dec 2023 23:06:25 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704063985; bh=Bt62LoT0gz4tWR1Iru05CGvHuJjuN0ykkvlQRrsUaos=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=QgrZCqIhS78YTC87JTssVQyUSLwgWOHt7CbIpDoJWbqirnHvjARUXqutdKOvYfBsI OFcfTTS7u+yO+GZrZPkR2xMGPaZe+wMo6f9f6T9uoy1t85fUq1saSrklkNpeBXxufr OsA/BRRhAps6EjLyhLpX75WKUZxPJ/OvBxSiD5ALtF1428sb7hNZmYCuFc0d/pN72g JSzehnfCRpyYF0Yy0edDlmM1HCJQHbRCBF5XS/jskDqT1RFsaboFJrRuiKkqisH+Pd V7vfEHz57HKf//HtJmPNXkQn0dczLBYJsMaJd///avo+UMteugzk0/VOPoktJAkWSC 5Tl3FtFlaF6wg== Date: Sun, 31 Dec 2023 15:06:24 -0800 Subject: [PATCH 05/32] xfs: parent pointer attribute creation From: "Darrick J. Wong" To: djwong@kernel.org, cem@kernel.org Cc: Dave Chinner , Allison Henderson , catherine.hoang@oracle.com, linux-xfs@vger.kernel.org, allison.henderson@oracle.com Message-ID: <170405006169.1804688.18130227675090082383.stgit@frogsfrogsfrogs> In-Reply-To: <170405006077.1804688.8762482665401724622.stgit@frogsfrogsfrogs> References: <170405006077.1804688.8762482665401724622.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: Allison Henderson Add parent pointer attribute during xfs_create, and subroutines to initialize attributes Signed-off-by: Dave Chinner Signed-off-by: Allison Henderson Reviewed-by: Darrick J. Wong [djwong: shorten names, adjust to new format, set init_xattrs for parent pointers] Signed-off-by: Darrick J. Wong --- include/libxfs.h | 1 + include/xfs_inode.h | 6 +++ libxfs/Makefile | 1 + libxfs/init.c | 3 ++ libxfs/libxfs_api_defs.h | 2 + libxfs/libxfs_priv.h | 5 ++- libxfs/xfs_attr.c | 2 + libxfs/xfs_attr.h | 2 + libxfs/xfs_parent.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++ libxfs/xfs_parent.h | 77 ++++++++++++++++++++++++++++++++++++++- libxfs/xfs_trans_space.c | 52 ++++++++++++++++++++++++++ libxfs/xfs_trans_space.h | 9 +++-- repair/phase6.c | 8 ++-- 13 files changed, 246 insertions(+), 13 deletions(-) create mode 100644 libxfs/xfs_trans_space.c diff --git a/include/libxfs.h b/include/libxfs.h index 77ecfda4bc7..425112b0693 100644 --- a/include/libxfs.h +++ b/include/libxfs.h @@ -87,6 +87,7 @@ struct iomap; #include "xfs_rtbitmap.h" #include "xfs_symlink_remote.h" #include "xfs_ag_resv.h" +#include "xfs_parent.h" #ifndef ARRAY_SIZE #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) diff --git a/include/xfs_inode.h b/include/xfs_inode.h index 47959314811..088a6b34f04 100644 --- a/include/xfs_inode.h +++ b/include/xfs_inode.h @@ -268,6 +268,12 @@ static inline struct inode *VFS_I(struct xfs_inode *ip) return &ip->i_vnode; } +/* convert from const xfs inode to const vfs inode */ +static inline const struct inode *VFS_IC(const struct xfs_inode *ip) +{ + return &ip->i_vnode; +} + /* We only have i_size in the xfs inode in userspace */ static inline loff_t i_size_read(struct inode *inode) { diff --git a/libxfs/Makefile b/libxfs/Makefile index 38594965882..e0bdaefb209 100644 --- a/libxfs/Makefile +++ b/libxfs/Makefile @@ -113,6 +113,7 @@ CFILES = cache.c \ xfs_symlink_remote.c \ xfs_trans_inode.c \ xfs_trans_resv.c \ + xfs_trans_space.c \ xfs_types.c # diff --git a/libxfs/init.c b/libxfs/init.c index 2e59ba0d0a2..b6b1282201c 100644 --- a/libxfs/init.c +++ b/libxfs/init.c @@ -213,6 +213,8 @@ init_caches(void) "xfs_extfree_item"); xfs_trans_cache = kmem_cache_init( sizeof(struct xfs_trans), "xfs_trans"); + xfs_parent_args_cache = kmem_cache_init( + sizeof(struct xfs_parent_args), "xfs_parent_args"); } static int @@ -230,6 +232,7 @@ destroy_caches(void) xfs_btree_destroy_cur_caches(); leaked += kmem_cache_destroy(xfs_extfree_item_cache); leaked += kmem_cache_destroy(xfs_trans_cache); + leaked += kmem_cache_destroy(xfs_parent_args_cache); return leaked; } diff --git a/libxfs/libxfs_api_defs.h b/libxfs/libxfs_api_defs.h index eba9a8386d2..6ab10be3ad6 100644 --- a/libxfs/libxfs_api_defs.h +++ b/libxfs/libxfs_api_defs.h @@ -89,6 +89,7 @@ #define xfs_bwrite libxfs_bwrite #define xfs_calc_dquots_per_chunk libxfs_calc_dquots_per_chunk #define xfs_compute_rextslog libxfs_compute_rextslog +#define xfs_create_space_res libxfs_create_space_res #define xfs_da3_node_hdr_from_disk libxfs_da3_node_hdr_from_disk #define xfs_da_get_buf libxfs_da_get_buf #define xfs_da_hashname libxfs_da_hashname @@ -175,6 +176,7 @@ #define xfs_log_get_max_trans_res libxfs_log_get_max_trans_res #define xfs_log_sb libxfs_log_sb #define xfs_mode_to_ftype libxfs_mode_to_ftype +#define xfs_mkdir_space_res libxfs_mkdir_space_res #define xfs_perag_get libxfs_perag_get #define xfs_perag_hold libxfs_perag_hold #define xfs_perag_put libxfs_perag_put diff --git a/libxfs/libxfs_priv.h b/libxfs/libxfs_priv.h index 411c33b3956..123e25d2f5e 100644 --- a/libxfs/libxfs_priv.h +++ b/libxfs/libxfs_priv.h @@ -562,8 +562,9 @@ struct xfs_item_ops; bool xfs_log_check_lsn(struct xfs_mount *, xfs_lsn_t); void xfs_log_item_init(struct xfs_mount *mp, struct xfs_log_item *lip, int type, const struct xfs_item_ops *ops); -#define xfs_attr_use_log_assist(mp) (0) -#define xlog_drop_incompat_feat(log) do { } while (0) +#define xfs_attr_grab_log_assist(mp) (0) +#define xfs_attr_rele_log_assist(mp) ((void) 0) +#define xlog_drop_incompat_feat(log,w) do { } while (0) #define xfs_log_in_recovery(mp) (false) /* xfs_icache.c */ diff --git a/libxfs/xfs_attr.c b/libxfs/xfs_attr.c index 04561f0318a..c4f543db474 100644 --- a/libxfs/xfs_attr.c +++ b/libxfs/xfs_attr.c @@ -893,7 +893,7 @@ xfs_attr_lookup( return error; } -static void +void xfs_attr_defer_add( struct xfs_da_args *args, unsigned int op_flags) diff --git a/libxfs/xfs_attr.h b/libxfs/xfs_attr.h index 5b3a0d4b158..4a4d45a96dd 100644 --- a/libxfs/xfs_attr.h +++ b/libxfs/xfs_attr.h @@ -549,6 +549,7 @@ int xfs_inode_hasattr(struct xfs_inode *ip); bool xfs_attr_is_leaf(struct xfs_inode *ip); int xfs_attr_get_ilocked(struct xfs_da_args *args); int xfs_attr_get(struct xfs_da_args *args); +void xfs_attr_defer_add(struct xfs_da_args *args, unsigned int op_flags); int xfs_attr_set(struct xfs_da_args *args); int xfs_attr_set_iter(struct xfs_attr_intent *attr); int xfs_attr_remove_iter(struct xfs_attr_intent *attr); @@ -557,7 +558,6 @@ bool xfs_attr_namecheck(struct xfs_mount *mp, const void *name, size_t length, int xfs_attr_calc_size(struct xfs_da_args *args, int *local); void xfs_init_attr_trans(struct xfs_da_args *args, struct xfs_trans_res *tres, unsigned int *total); - /* * Check to see if the attr should be upgraded from non-existent or shortform to * single-leaf-block attribute list. diff --git a/libxfs/xfs_parent.c b/libxfs/xfs_parent.c index 6874d8afe23..32e1d1f62ec 100644 --- a/libxfs/xfs_parent.c +++ b/libxfs/xfs_parent.c @@ -29,6 +29,8 @@ #include "xfs_format.h" #include "xfs_trans_space.h" +struct kmem_cache *xfs_parent_args_cache; + /* * Parent pointer attribute handling. * @@ -112,3 +114,92 @@ xfs_parent_hashcheck( /* Namehash matches name? */ return be32_to_cpu(rec->p_namehash) == xfs_dir2_hashname(mp, &dname); } + +/* Initializes a xfs_parent_name_rec to be stored as an attribute name. */ +static inline void +xfs_init_parent_name_rec( + struct xfs_parent_name_rec *rec, + const struct xfs_inode *dp, + const struct xfs_name *name, + struct xfs_inode *ip) +{ + rec->p_ino = cpu_to_be64(dp->i_ino); + rec->p_gen = cpu_to_be32(VFS_IC(dp)->i_generation); + rec->p_namehash = cpu_to_be32(xfs_dir2_hashname(dp->i_mount, name)); +} + +/* Point the da args value fields at the non-key parts of a parent pointer. */ +static inline void +xfs_init_parent_davalue( + struct xfs_da_args *args, + const struct xfs_name *name) +{ + args->valuelen = name->len; + args->value = (void *)name->name; +} + +/* + * Allocate memory to control a logged parent pointer update as part of a + * dirent operation. + */ +int +xfs_parent_args_alloc( + struct xfs_mount *mp, + struct xfs_parent_args **ppargsp) +{ + struct xfs_parent_args *ppargs; + + ppargs = kmem_cache_zalloc(xfs_parent_args_cache, GFP_KERNEL); + if (!ppargs) + return -ENOMEM; + + xfs_parent_args_init(mp, ppargs); + *ppargsp = ppargs; + return 0; +} + +static inline xfs_dahash_t +xfs_parent_hashname( + struct xfs_inode *ip, + const struct xfs_parent_args *ppargs) +{ + return xfs_da_hashname((const void *)&ppargs->rec, + sizeof(struct xfs_parent_name_rec)); +} + +/* Add a parent pointer to reflect a dirent addition. */ +int +xfs_parent_addname( + struct xfs_trans *tp, + struct xfs_parent_args *ppargs, + struct xfs_inode *dp, + const struct xfs_name *parent_name, + struct xfs_inode *child) +{ + struct xfs_da_args *args = &ppargs->args; + + if (XFS_IS_CORRUPT(tp->t_mountp, + !xfs_parent_valuecheck(tp->t_mountp, parent_name->name, + parent_name->len))) + return -EFSCORRUPTED; + + xfs_init_parent_name_rec(&ppargs->rec, dp, parent_name, child); + args->hashval = xfs_parent_hashname(dp, ppargs); + + args->trans = tp; + args->dp = child; + + xfs_init_parent_davalue(&ppargs->args, parent_name); + + xfs_attr_defer_add(args, XFS_ATTRI_OP_FLAGS_SET); + return 0; +} + +/* Free a parent pointer context object. */ +void +xfs_parent_args_free( + struct xfs_mount *mp, + struct xfs_parent_args *ppargs) +{ + kmem_cache_free(xfs_parent_args_cache, ppargs); +} diff --git a/libxfs/xfs_parent.h b/libxfs/xfs_parent.h index fcfeddb645f..e2115a2b964 100644 --- a/libxfs/xfs_parent.h +++ b/libxfs/xfs_parent.h @@ -16,4 +16,79 @@ bool xfs_parent_hashcheck(struct xfs_mount *mp, const struct xfs_parent_name_rec *rec, const void *value, size_t valuelen); -#endif /* __XFS_PARENT_H__ */ +extern struct kmem_cache *xfs_parent_args_cache; + +/* + * Dynamically allocd structure used to wrap the needed data to pass around + * the defer ops machinery + */ +struct xfs_parent_args { + struct xfs_parent_name_rec rec; + struct xfs_da_args args; +}; + +int xfs_parent_args_alloc(struct xfs_mount *mp, + struct xfs_parent_args **ppargsp); + +/* + * Initialize the parent pointer arguments structure. Caller must have zeroed + * the contents. + */ +static inline void +xfs_parent_args_init( + struct xfs_mount *mp, + struct xfs_parent_args *ppargs) +{ + ppargs->args.geo = mp->m_attr_geo; + ppargs->args.whichfork = XFS_ATTR_FORK; + ppargs->args.attr_filter = XFS_ATTR_PARENT; + ppargs->args.op_flags = XFS_DA_OP_OKNOENT | XFS_DA_OP_LOGGED | + XFS_DA_OP_NVLOOKUP; + ppargs->args.name = (const uint8_t *)&ppargs->rec; + ppargs->args.namelen = sizeof(struct xfs_parent_name_rec); +} + +/* + * Start a parent pointer update by allocating the context object we need to + * perform a parent pointer update. + */ +static inline int +xfs_parent_start( + struct xfs_mount *mp, + struct xfs_parent_args **ppargsp) +{ + *ppargsp = NULL; + + if (xfs_has_parent(mp)) + return xfs_parent_args_alloc(mp, ppargsp); + return 0; +} + +int xfs_parent_addname(struct xfs_trans *tp, struct xfs_parent_args *ppargs, + struct xfs_inode *dp, const struct xfs_name *parent_name, + struct xfs_inode *child); + +/* Schedule a parent pointer addition. */ +static inline int +xfs_parent_add(struct xfs_trans *tp, struct xfs_parent_args *ppargs, + struct xfs_inode *dp, const struct xfs_name *parent_name, + struct xfs_inode *child) +{ + if (ppargs) + return xfs_parent_addname(tp, ppargs, dp, parent_name, child); + return 0; +} + +void xfs_parent_args_free(struct xfs_mount *mp, struct xfs_parent_args *ppargs); + +/* Finish a parent pointer update by freeing the context object. */ +static inline void +xfs_parent_finish( + struct xfs_mount *mp, + struct xfs_parent_args *ppargs) +{ + if (ppargs) + xfs_parent_args_free(mp, ppargs); +} + +#endif /* __XFS_PARENT_H__ */ diff --git a/libxfs/xfs_trans_space.c b/libxfs/xfs_trans_space.c new file mode 100644 index 00000000000..3408e700f01 --- /dev/null +++ b/libxfs/xfs_trans_space.c @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2000,2005 Silicon Graphics, Inc. + * All Rights Reserved. + */ +#include "libxfs_priv.h" +#include "xfs_fs.h" +#include "xfs_shared.h" +#include "xfs_format.h" +#include "xfs_da_format.h" +#include "xfs_log_format.h" +#include "xfs_trans_resv.h" +#include "xfs_mount.h" +#include "xfs_da_btree.h" +#include "xfs_bmap_btree.h" +#include "xfs_trans_space.h" + +/* Calculate the disk space required to add a parent pointer. */ +unsigned int +xfs_parent_calc_space_res( + struct xfs_mount *mp, + unsigned int namelen) +{ + /* + * Parent pointers are always the first attr in an attr tree, and never + * larger than a block + */ + return XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK) + + XFS_NEXTENTADD_SPACE_RES(mp, namelen, XFS_ATTR_FORK); +} + +unsigned int +xfs_create_space_res( + struct xfs_mount *mp, + unsigned int namelen) +{ + unsigned int ret; + + ret = XFS_IALLOC_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp, namelen); + if (xfs_has_parent(mp)) + ret += xfs_parent_calc_space_res(mp, namelen); + + return ret; +} + +unsigned int +xfs_mkdir_space_res( + struct xfs_mount *mp, + unsigned int namelen) +{ + return xfs_create_space_res(mp, namelen); +} diff --git a/libxfs/xfs_trans_space.h b/libxfs/xfs_trans_space.h index 9640fc232c1..6cda87153b3 100644 --- a/libxfs/xfs_trans_space.h +++ b/libxfs/xfs_trans_space.h @@ -80,8 +80,6 @@ /* This macro is not used - see inline code in xfs_attr_set */ #define XFS_ATTRSET_SPACE_RES(mp, v) \ (XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK) + XFS_B_TO_FSB(mp, v)) -#define XFS_CREATE_SPACE_RES(mp,nl) \ - (XFS_IALLOC_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp,nl)) #define XFS_DIOSTRAT_SPACE_RES(mp, v) \ (XFS_EXTENTADD_SPACE_RES(mp, XFS_DATA_FORK) + (v)) #define XFS_GROWFS_SPACE_RES(mp) \ @@ -90,8 +88,6 @@ ((b) + XFS_EXTENTADD_SPACE_RES(mp, XFS_DATA_FORK)) #define XFS_LINK_SPACE_RES(mp,nl) \ XFS_DIRENTER_SPACE_RES(mp,nl) -#define XFS_MKDIR_SPACE_RES(mp,nl) \ - (XFS_IALLOC_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp,nl)) #define XFS_QM_DQALLOC_SPACE_RES(mp) \ (XFS_EXTENTADD_SPACE_RES(mp, XFS_DATA_FORK) + \ XFS_DQUOT_CLUSTER_SIZE_FSB) @@ -106,5 +102,10 @@ #define XFS_IFREE_SPACE_RES(mp) \ (xfs_has_finobt(mp) ? M_IGEO(mp)->inobt_maxlevels : 0) +unsigned int xfs_parent_calc_space_res(struct xfs_mount *mp, + unsigned int namelen); + +unsigned int xfs_create_space_res(struct xfs_mount *mp, unsigned int namelen); +unsigned int xfs_mkdir_space_res(struct xfs_mount *mp, unsigned int namelen); #endif /* __XFS_TRANS_SPACE_H__ */ diff --git a/repair/phase6.c b/repair/phase6.c index 75391378291..825f0cf3956 100644 --- a/repair/phase6.c +++ b/repair/phase6.c @@ -924,7 +924,7 @@ mk_orphanage(xfs_mount_t *mp) /* * could not be found, create it */ - nres = XFS_MKDIR_SPACE_RES(mp, xname.len); + nres = libxfs_mkdir_space_res(mp, xname.len); i = -libxfs_trans_alloc(mp, &M_RES(mp)->tr_mkdir, nres, 0, 0, &tp); if (i) res_failed(i); @@ -1335,7 +1335,7 @@ longform_dir2_rebuild( p->name.name[1] == '.')))) continue; - nres = XFS_CREATE_SPACE_RES(mp, p->name.len); + nres = libxfs_create_space_res(mp, p->name.len); error = -libxfs_trans_alloc(mp, &M_RES(mp)->tr_create, nres, 0, 0, &tp); if (error) @@ -2947,7 +2947,7 @@ _("error %d fixing shortform directory %llu\n"), do_warn(_("recreating root directory .. entry\n")); - nres = XFS_MKDIR_SPACE_RES(mp, 2); + nres = libxfs_mkdir_space_res(mp, 2); error = -libxfs_trans_alloc(mp, &M_RES(mp)->tr_mkdir, nres, 0, 0, &tp); if (error) @@ -3002,7 +3002,7 @@ _("error %d fixing shortform directory %llu\n"), do_warn( _("creating missing \".\" entry in dir ino %" PRIu64 "\n"), ino); - nres = XFS_MKDIR_SPACE_RES(mp, 1); + nres = libxfs_mkdir_space_res(mp, 1); error = -libxfs_trans_alloc(mp, &M_RES(mp)->tr_mkdir, nres, 0, 0, &tp); if (error) From patchwork Sun Dec 31 23:06: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: 13508029 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 D827EC140 for ; Sun, 31 Dec 2023 23:06:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Nyy4EZBi" Received: by smtp.kernel.org (Postfix) with ESMTPSA id A5A1BC433C8; Sun, 31 Dec 2023 23:06:40 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704064000; bh=9eL7XeYB9EP5CDIDx8VdAXpj6a90rLRSXvxKmQ0tQn4=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=Nyy4EZBi4Cclka1Sb2OMSRtN+hbcx903zTLdHNcUc7v0FShY3Q0m/781UA/DyyKpT DtcNzyDmlhduPE5H3eHzlI0+0VD7FmJPzfFVNbAOD9dVpKKdqIaTljIZ7urrktArxd LP4a8qX2e9rMKL++Hkxe13NEBMyZK4DVaTXO7NGRFp/bzJja0I+xKP9sLoEjo5PmDW xwLbPYPxbuoZUCz6HuHVpO1TBaWs1KUN+buIaN255e6ln5acEHzq7k3yU2orR3Y4dZ NKw9MYT9xuog62nH6367EgPU7xUMS5CHhi+1gyMRfCvvy/fZj91PnN0xxYgGqGpWp9 6cw6DqR3yLzNQ== Date: Sun, 31 Dec 2023 15:06:40 -0800 Subject: [PATCH 06/32] xfs: add parent attributes to link From: "Darrick J. Wong" To: djwong@kernel.org, cem@kernel.org Cc: Dave Chinner , Allison Henderson , catherine.hoang@oracle.com, linux-xfs@vger.kernel.org, allison.henderson@oracle.com Message-ID: <170405006183.1804688.237715546796664157.stgit@frogsfrogsfrogs> In-Reply-To: <170405006077.1804688.8762482665401724622.stgit@frogsfrogsfrogs> References: <170405006077.1804688.8762482665401724622.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: Allison Henderson This patch modifies xfs_link to add a parent pointer to the inode. Signed-off-by: Dave Chinner Signed-off-by: Allison Henderson Reviewed-by: Darrick J. Wong [djwong: minor rebase fixes] Signed-off-by: Darrick J. Wong --- libxfs/xfs_trans_space.c | 14 ++++++++++++++ libxfs/xfs_trans_space.h | 3 +-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/libxfs/xfs_trans_space.c b/libxfs/xfs_trans_space.c index 3408e700f01..039bbd91e87 100644 --- a/libxfs/xfs_trans_space.c +++ b/libxfs/xfs_trans_space.c @@ -50,3 +50,17 @@ xfs_mkdir_space_res( { return xfs_create_space_res(mp, namelen); } + +unsigned int +xfs_link_space_res( + struct xfs_mount *mp, + unsigned int namelen) +{ + unsigned int ret; + + ret = XFS_DIRENTER_SPACE_RES(mp, namelen); + if (xfs_has_parent(mp)) + ret += xfs_parent_calc_space_res(mp, namelen); + + return ret; +} diff --git a/libxfs/xfs_trans_space.h b/libxfs/xfs_trans_space.h index 6cda87153b3..5539634009f 100644 --- a/libxfs/xfs_trans_space.h +++ b/libxfs/xfs_trans_space.h @@ -86,8 +86,6 @@ (2 * (mp)->m_alloc_maxlevels) #define XFS_GROWFSRT_SPACE_RES(mp,b) \ ((b) + XFS_EXTENTADD_SPACE_RES(mp, XFS_DATA_FORK)) -#define XFS_LINK_SPACE_RES(mp,nl) \ - XFS_DIRENTER_SPACE_RES(mp,nl) #define XFS_QM_DQALLOC_SPACE_RES(mp) \ (XFS_EXTENTADD_SPACE_RES(mp, XFS_DATA_FORK) + \ XFS_DQUOT_CLUSTER_SIZE_FSB) @@ -107,5 +105,6 @@ unsigned int xfs_parent_calc_space_res(struct xfs_mount *mp, unsigned int xfs_create_space_res(struct xfs_mount *mp, unsigned int namelen); unsigned int xfs_mkdir_space_res(struct xfs_mount *mp, unsigned int namelen); +unsigned int xfs_link_space_res(struct xfs_mount *mp, unsigned int namelen); #endif /* __XFS_TRANS_SPACE_H__ */ From patchwork Sun Dec 31 23:06: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: 13508030 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 CF1BCC140 for ; Sun, 31 Dec 2023 23:06:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="hvNL1rNF" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 45A4AC433C7; Sun, 31 Dec 2023 23:06:56 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704064016; bh=p88oZmSqUksJDYfpTyDUx4i/fqc4ihdpJMqTePIY0xg=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=hvNL1rNFjVtsXKMnPvdz3BebfPpNj5eyhvAiqxbB7gOr+1AIbLbz+V34FEzVTiFPu 8DAvfQiSUsgv48gfd48FSlx6hcOlPsnWxRyxLcsG4EeEF/YR6Z6VeFk7LgWCWP8auE NJqXmsoN0qkg/xdRm33LBn+YSb8QJTWr6sU2daKRjCSF6BKaJTMuN3DRHOmSJ07UYy LYODaop7OkYlFNqE/ywgrNT+eM1GbYA8vR1kTDzmVD6U4ss6msG7EjcMov6zbQUoUA GDszMRvOr/gXSfVo12ccB/MZfqc4pm5C/i2aXt8YY1UHGTdRrZPFXf5rzAVZDNgaig byt/867qAblXw== Date: Sun, 31 Dec 2023 15:06:55 -0800 Subject: [PATCH 07/32] xfs: add parent attributes to symlink From: "Darrick J. Wong" To: djwong@kernel.org, cem@kernel.org Cc: Allison Henderson , catherine.hoang@oracle.com, linux-xfs@vger.kernel.org, allison.henderson@oracle.com Message-ID: <170405006196.1804688.9033901414797404924.stgit@frogsfrogsfrogs> In-Reply-To: <170405006077.1804688.8762482665401724622.stgit@frogsfrogsfrogs> References: <170405006077.1804688.8762482665401724622.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: Allison Henderson This patch modifies xfs_symlink to add a parent pointer to the inode. Signed-off-by: Allison Henderson Reviewed-by: Darrick J. Wong [djwong: minor rebase fixups] Signed-off-by: Darrick J. Wong --- libxfs/xfs_trans_space.c | 17 +++++++++++++++++ libxfs/xfs_trans_space.h | 4 ++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/libxfs/xfs_trans_space.c b/libxfs/xfs_trans_space.c index 039bbd91e87..bf4a41492c2 100644 --- a/libxfs/xfs_trans_space.c +++ b/libxfs/xfs_trans_space.c @@ -64,3 +64,20 @@ xfs_link_space_res( return ret; } + +unsigned int +xfs_symlink_space_res( + struct xfs_mount *mp, + unsigned int namelen, + unsigned int fsblocks) +{ + unsigned int ret; + + ret = XFS_IALLOC_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp, namelen) + + fsblocks; + + if (xfs_has_parent(mp)) + ret += xfs_parent_calc_space_res(mp, namelen); + + return ret; +} diff --git a/libxfs/xfs_trans_space.h b/libxfs/xfs_trans_space.h index 5539634009f..354ad1d6e18 100644 --- a/libxfs/xfs_trans_space.h +++ b/libxfs/xfs_trans_space.h @@ -95,8 +95,6 @@ XFS_DIRREMOVE_SPACE_RES(mp) #define XFS_RENAME_SPACE_RES(mp,nl) \ (XFS_DIRREMOVE_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp,nl)) -#define XFS_SYMLINK_SPACE_RES(mp,nl,b) \ - (XFS_IALLOC_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp,nl) + (b)) #define XFS_IFREE_SPACE_RES(mp) \ (xfs_has_finobt(mp) ? M_IGEO(mp)->inobt_maxlevels : 0) @@ -106,5 +104,7 @@ unsigned int xfs_parent_calc_space_res(struct xfs_mount *mp, unsigned int xfs_create_space_res(struct xfs_mount *mp, unsigned int namelen); unsigned int xfs_mkdir_space_res(struct xfs_mount *mp, unsigned int namelen); unsigned int xfs_link_space_res(struct xfs_mount *mp, unsigned int namelen); +unsigned int xfs_symlink_space_res(struct xfs_mount *mp, unsigned int namelen, + unsigned int fsblocks); #endif /* __XFS_TRANS_SPACE_H__ */ From patchwork Sun Dec 31 23:07: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: 13508031 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 132ABC140 for ; Sun, 31 Dec 2023 23:07:12 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="uK3OjmgI" Received: by smtp.kernel.org (Postfix) with ESMTPSA id D3827C433C7; Sun, 31 Dec 2023 23:07:11 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704064031; bh=38lNuDWKAG2sCld47fUKAsuzqljZk3BpEdVGEbIz0tk=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=uK3OjmgIs6/d/wG8bJ9d/6MjuhyotIHHbBEc/oJ4cRHH63v89S2u47Gh/lHJW5u8E k7B+HYsv5p8Vi49pBUFtlSK5vGB7nIztcoIxc78ZSnFeiFdz9F22YDa2jRIBfbXOxO Yh0MuCHX6FzfMrRZ4JLx3w8hrKLWVcpXtTTHdoi/F1CSSk+K2fmtfO/7riFn6/ebwX Cg6JZ2Mjh7nCSciZENwPf8aEd8Yxqr32GFY6u0z0KVsi2/BM7Os3+yd6vz1BaJAi/N qrwmJm1mdAt9jzza2l4HXWLzYOyNJCzAGaeheYwVw1ii6XtiCQnhGvKVRNUGhYM718 PL29H0iqepimA== Date: Sun, 31 Dec 2023 15:07:11 -0800 Subject: [PATCH 08/32] xfs: remove parent pointers in unlink From: "Darrick J. Wong" To: djwong@kernel.org, cem@kernel.org Cc: Dave Chinner , Allison Henderson , catherine.hoang@oracle.com, linux-xfs@vger.kernel.org, allison.henderson@oracle.com Message-ID: <170405006209.1804688.10673477133013884075.stgit@frogsfrogsfrogs> In-Reply-To: <170405006077.1804688.8762482665401724622.stgit@frogsfrogsfrogs> References: <170405006077.1804688.8762482665401724622.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: Allison Henderson This patch removes the parent pointer attribute during unlink Signed-off-by: Dave Chinner Signed-off-by: Allison Henderson Reviewed-by: Darrick J. Wong [djwong: adjust to new ondisk format, minor rebase fixes] Signed-off-by: Darrick J. Wong --- libxfs/libxfs_api_defs.h | 1 + libxfs/xfs_parent.c | 39 +++++++++++++++++++++++++++++++++++++++ libxfs/xfs_parent.h | 16 ++++++++++++++++ libxfs/xfs_trans_space.c | 13 +++++++++++++ libxfs/xfs_trans_space.h | 3 +-- repair/phase6.c | 6 +++--- 6 files changed, 73 insertions(+), 5 deletions(-) diff --git a/libxfs/libxfs_api_defs.h b/libxfs/libxfs_api_defs.h index 6ab10be3ad6..1b69124767c 100644 --- a/libxfs/libxfs_api_defs.h +++ b/libxfs/libxfs_api_defs.h @@ -193,6 +193,7 @@ #define xfs_refcountbt_stage_cursor libxfs_refcountbt_stage_cursor #define xfs_refcount_get_rec libxfs_refcount_get_rec #define xfs_refcount_lookup_le libxfs_refcount_lookup_le +#define xfs_remove_space_res libxfs_remove_space_res #define xfs_rmap_alloc libxfs_rmap_alloc #define xfs_rmapbt_calc_reserves libxfs_rmapbt_calc_reserves diff --git a/libxfs/xfs_parent.c b/libxfs/xfs_parent.c index 32e1d1f62ec..b3004af9161 100644 --- a/libxfs/xfs_parent.c +++ b/libxfs/xfs_parent.c @@ -28,6 +28,7 @@ #include "xfs_da_format.h" #include "xfs_format.h" #include "xfs_trans_space.h" +#include "xfs_health.h" struct kmem_cache *xfs_parent_args_cache; @@ -195,6 +196,44 @@ xfs_parent_addname( return 0; } +/* Remove a parent pointer to reflect a dirent removal. */ +int +xfs_parent_removename( + struct xfs_trans *tp, + struct xfs_parent_args *ppargs, + struct xfs_inode *dp, + const struct xfs_name *parent_name, + struct xfs_inode *child) +{ + struct xfs_da_args *args = &ppargs->args; + + if (XFS_IS_CORRUPT(tp->t_mountp, + !xfs_parent_valuecheck(tp->t_mountp, parent_name->name, + parent_name->len))) + return -EFSCORRUPTED; + + /* + * For regular attrs, removing an attr from a !hasattr inode is a nop. + * For parent pointers, we require that the pointer must exist if the + * caller wants us to remove the pointer. + */ + if (XFS_IS_CORRUPT(child->i_mount, !xfs_inode_hasattr(child))) { + xfs_inode_mark_sick(child, XFS_SICK_INO_PARENT); + return -EFSCORRUPTED; + } + + xfs_init_parent_name_rec(&ppargs->rec, dp, parent_name, child); + args->hashval = xfs_parent_hashname(dp, ppargs); + + args->trans = tp; + args->dp = child; + + xfs_init_parent_davalue(&ppargs->args, parent_name); + + xfs_attr_defer_add(args, XFS_ATTRI_OP_FLAGS_REMOVE); + return 0; +} + /* Free a parent pointer context object. */ void xfs_parent_args_free( diff --git a/libxfs/xfs_parent.h b/libxfs/xfs_parent.h index e2115a2b964..31349130a33 100644 --- a/libxfs/xfs_parent.h +++ b/libxfs/xfs_parent.h @@ -79,6 +79,22 @@ xfs_parent_add(struct xfs_trans *tp, struct xfs_parent_args *ppargs, return 0; } +int xfs_parent_removename(struct xfs_trans *tp, struct xfs_parent_args *ppargs, + struct xfs_inode *dp, const struct xfs_name *parent_name, + struct xfs_inode *child); + +/* Schedule a parent pointer removal. */ +static inline int +xfs_parent_remove(struct xfs_trans *tp, struct xfs_parent_args *ppargs, + struct xfs_inode *dp, const struct xfs_name *parent_name, + struct xfs_inode *child) +{ + if (ppargs) + return xfs_parent_removename(tp, ppargs, dp, parent_name, + child); + return 0; +} + void xfs_parent_args_free(struct xfs_mount *mp, struct xfs_parent_args *ppargs); /* Finish a parent pointer update by freeing the context object. */ diff --git a/libxfs/xfs_trans_space.c b/libxfs/xfs_trans_space.c index bf4a41492c2..86a91a3a844 100644 --- a/libxfs/xfs_trans_space.c +++ b/libxfs/xfs_trans_space.c @@ -81,3 +81,16 @@ xfs_symlink_space_res( return ret; } + +unsigned int +xfs_remove_space_res( + struct xfs_mount *mp, + unsigned int namelen) +{ + unsigned int ret = XFS_DIRREMOVE_SPACE_RES(mp); + + if (xfs_has_parent(mp)) + ret += xfs_parent_calc_space_res(mp, namelen); + + return ret; +} diff --git a/libxfs/xfs_trans_space.h b/libxfs/xfs_trans_space.h index 354ad1d6e18..a4490813c56 100644 --- a/libxfs/xfs_trans_space.h +++ b/libxfs/xfs_trans_space.h @@ -91,8 +91,6 @@ XFS_DQUOT_CLUSTER_SIZE_FSB) #define XFS_QM_QINOCREATE_SPACE_RES(mp) \ XFS_IALLOC_SPACE_RES(mp) -#define XFS_REMOVE_SPACE_RES(mp) \ - XFS_DIRREMOVE_SPACE_RES(mp) #define XFS_RENAME_SPACE_RES(mp,nl) \ (XFS_DIRREMOVE_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp,nl)) #define XFS_IFREE_SPACE_RES(mp) \ @@ -106,5 +104,6 @@ unsigned int xfs_mkdir_space_res(struct xfs_mount *mp, unsigned int namelen); unsigned int xfs_link_space_res(struct xfs_mount *mp, unsigned int namelen); unsigned int xfs_symlink_space_res(struct xfs_mount *mp, unsigned int namelen, unsigned int fsblocks); +unsigned int xfs_remove_space_res(struct xfs_mount *mp, unsigned int namelen); #endif /* __XFS_TRANS_SPACE_H__ */ diff --git a/repair/phase6.c b/repair/phase6.c index 825f0cf3956..9b43e58b3d3 100644 --- a/repair/phase6.c +++ b/repair/phase6.c @@ -1275,7 +1275,7 @@ longform_dir2_rebuild( libxfs_dir_ino_validate(mp, pip.i_ino)) pip.i_ino = mp->m_sb.sb_rootino; - nres = XFS_REMOVE_SPACE_RES(mp); + nres = libxfs_remove_space_res(mp, 0); error = -libxfs_trans_alloc(mp, &M_RES(mp)->tr_remove, nres, 0, 0, &tp); if (error) res_failed(error); @@ -1381,7 +1381,7 @@ dir2_kill_block( int nres; xfs_trans_t *tp; - nres = XFS_REMOVE_SPACE_RES(mp); + nres = libxfs_remove_space_res(mp, 0); error = -libxfs_trans_alloc(mp, &M_RES(mp)->tr_remove, nres, 0, 0, &tp); if (error) res_failed(error); @@ -2900,7 +2900,7 @@ process_dir_inode( * inode but it's easier than wedging a * new define in ourselves. */ - nres = no_modify ? 0 : XFS_REMOVE_SPACE_RES(mp); + nres = no_modify ? 0 : libxfs_remove_space_res(mp, 0); error = -libxfs_trans_alloc(mp, &M_RES(mp)->tr_remove, nres, 0, 0, &tp); if (error) From patchwork Sun Dec 31 23:07: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: 13508032 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 AAA27C14C for ; Sun, 31 Dec 2023 23:07:27 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="met0VqJs" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 7CB1FC433C7; Sun, 31 Dec 2023 23:07:27 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704064047; bh=shsT6C0cUp9KcEDqqJvrINMy6s613FXmqu/2QcLNm5E=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=met0VqJsF8sUV7iN95R9UyMlDxFAgcXFslMxVkBUsyXSU+lYXT+g5HDMWBknJhDmW GDHKyfiQaiDf9CEo9B2ML/s2cBqcINIMnKiTn2eN9Ius9rV+qKEuX67Zx5ybM+PaVD dwSenmNEVe8gSujJuRKlugkk8/1laVCfcXhfTKYCr+PGTxooQ17/SFT0KtCUaz7NVr IZ55F15ndKYTbD8P5yvAs4nFrpL52m7yKX753pFemg6oRRoQFqEwywt/ZbVq5KViqN +6f3LqTXJTV4aJdANXBL4T7vj+jS1h3TYHFcAiHNa0+29MPxVmH57CslhCyG8puXKe xvR7YQhmKSVyA== Date: Sun, 31 Dec 2023 15:07:27 -0800 Subject: [PATCH 09/32] xfs: Add parent pointers to rename From: "Darrick J. Wong" To: djwong@kernel.org, cem@kernel.org Cc: Allison Henderson , catherine.hoang@oracle.com, linux-xfs@vger.kernel.org, allison.henderson@oracle.com Message-ID: <170405006222.1804688.15929628504320931898.stgit@frogsfrogsfrogs> In-Reply-To: <170405006077.1804688.8762482665401724622.stgit@frogsfrogsfrogs> References: <170405006077.1804688.8762482665401724622.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: Allison Henderson This patch removes the old parent pointer attribute during the rename operation, and re-adds the updated parent pointer. Signed-off-by: Allison Henderson Reviewed-by: Darrick J. Wong [djwong: adjust to new ondisk format] Signed-off-by: Darrick J. Wong --- libxfs/xfs_parent.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++ libxfs/xfs_parent.h | 20 +++++++++++++++ libxfs/xfs_trans_space.c | 25 ++++++++++++++++++ libxfs/xfs_trans_space.h | 6 +++- 4 files changed, 112 insertions(+), 2 deletions(-) diff --git a/libxfs/xfs_parent.c b/libxfs/xfs_parent.c index b3004af9161..6c98f95f274 100644 --- a/libxfs/xfs_parent.c +++ b/libxfs/xfs_parent.c @@ -139,6 +139,19 @@ xfs_init_parent_davalue( args->value = (void *)name->name; } +/* + * Point the da args new value fields at the non-key parts of a replacement + * parent pointer. + */ +static inline void +xfs_init_parent_danewvalue( + struct xfs_da_args *args, + const struct xfs_name *name) +{ + args->new_valuelen = name->len; + args->new_value = (void *)name->name; +} + /* * Allocate memory to control a logged parent pointer update as part of a * dirent operation. @@ -234,6 +247,56 @@ xfs_parent_removename( return 0; } +/* Replace one parent pointer with another to reflect a rename. */ +int +xfs_parent_replacename( + struct xfs_trans *tp, + struct xfs_parent_args *ppargs, + struct xfs_inode *old_dp, + const struct xfs_name *old_name, + struct xfs_inode *new_dp, + const struct xfs_name *new_name, + struct xfs_inode *child) +{ + struct xfs_da_args *args = &ppargs->args; + + if (XFS_IS_CORRUPT(tp->t_mountp, + !xfs_parent_valuecheck(tp->t_mountp, old_name->name, + old_name->len))) + return -EFSCORRUPTED; + + if (XFS_IS_CORRUPT(tp->t_mountp, + !xfs_parent_valuecheck(tp->t_mountp, new_name->name, + new_name->len))) + return -EFSCORRUPTED; + + /* + * For regular attrs, replacing an attr from a !hasattr inode becomes + * an attr-set operation. For replacing a parent pointer, however, we + * require that the old pointer must exist. + */ + if (XFS_IS_CORRUPT(child->i_mount, !xfs_inode_hasattr(child))) { + xfs_inode_mark_sick(child, XFS_SICK_INO_PARENT); + return -EFSCORRUPTED; + } + + xfs_init_parent_name_rec(&ppargs->rec, old_dp, old_name, child); + args->hashval = xfs_parent_hashname(old_dp, ppargs); + + xfs_init_parent_name_rec(&ppargs->new_rec, new_dp, new_name, child); + args->new_name = (const uint8_t *)&ppargs->new_rec; + args->new_namelen = sizeof(struct xfs_parent_name_rec); + + args->trans = tp; + args->dp = child; + + xfs_init_parent_davalue(&ppargs->args, old_name); + xfs_init_parent_danewvalue(&ppargs->args, new_name); + + xfs_attr_defer_add(args, XFS_ATTRI_OP_FLAGS_REPLACE); + return 0; +} + /* Free a parent pointer context object. */ void xfs_parent_args_free( diff --git a/libxfs/xfs_parent.h b/libxfs/xfs_parent.h index 31349130a33..c68c501388e 100644 --- a/libxfs/xfs_parent.h +++ b/libxfs/xfs_parent.h @@ -24,6 +24,7 @@ extern struct kmem_cache *xfs_parent_args_cache; */ struct xfs_parent_args { struct xfs_parent_name_rec rec; + struct xfs_parent_name_rec new_rec; struct xfs_da_args args; }; @@ -95,6 +96,25 @@ xfs_parent_remove(struct xfs_trans *tp, struct xfs_parent_args *ppargs, return 0; } +int xfs_parent_replacename(struct xfs_trans *tp, + struct xfs_parent_args *ppargs, + struct xfs_inode *old_dp, const struct xfs_name *old_name, + struct xfs_inode *new_dp, const struct xfs_name *new_name, + struct xfs_inode *child); + +/* Schedule a parent pointer replacement. */ +static inline int +xfs_parent_replace(struct xfs_trans *tp, struct xfs_parent_args *ppargs, + struct xfs_inode *old_dp, const struct xfs_name *old_name, + struct xfs_inode *new_dp, const struct xfs_name *new_name, + struct xfs_inode *child) +{ + if (ppargs) + return xfs_parent_replacename(tp, ppargs, old_dp, old_name, + new_dp, new_name, child); + return 0; +} + void xfs_parent_args_free(struct xfs_mount *mp, struct xfs_parent_args *ppargs); /* Finish a parent pointer update by freeing the context object. */ diff --git a/libxfs/xfs_trans_space.c b/libxfs/xfs_trans_space.c index 86a91a3a844..373f5cc2497 100644 --- a/libxfs/xfs_trans_space.c +++ b/libxfs/xfs_trans_space.c @@ -94,3 +94,28 @@ xfs_remove_space_res( return ret; } + +unsigned int +xfs_rename_space_res( + struct xfs_mount *mp, + unsigned int src_namelen, + bool target_exists, + unsigned int target_namelen, + bool has_whiteout) +{ + unsigned int ret; + + ret = XFS_DIRREMOVE_SPACE_RES(mp) + + XFS_DIRENTER_SPACE_RES(mp, target_namelen); + + if (xfs_has_parent(mp)) { + if (has_whiteout) + ret += xfs_parent_calc_space_res(mp, src_namelen); + ret += 2 * xfs_parent_calc_space_res(mp, target_namelen); + } + + if (target_exists) + ret += xfs_parent_calc_space_res(mp, target_namelen); + + return ret; +} diff --git a/libxfs/xfs_trans_space.h b/libxfs/xfs_trans_space.h index a4490813c56..1155ff2d37e 100644 --- a/libxfs/xfs_trans_space.h +++ b/libxfs/xfs_trans_space.h @@ -91,8 +91,6 @@ XFS_DQUOT_CLUSTER_SIZE_FSB) #define XFS_QM_QINOCREATE_SPACE_RES(mp) \ XFS_IALLOC_SPACE_RES(mp) -#define XFS_RENAME_SPACE_RES(mp,nl) \ - (XFS_DIRREMOVE_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp,nl)) #define XFS_IFREE_SPACE_RES(mp) \ (xfs_has_finobt(mp) ? M_IGEO(mp)->inobt_maxlevels : 0) @@ -106,4 +104,8 @@ unsigned int xfs_symlink_space_res(struct xfs_mount *mp, unsigned int namelen, unsigned int fsblocks); unsigned int xfs_remove_space_res(struct xfs_mount *mp, unsigned int namelen); +unsigned int xfs_rename_space_res(struct xfs_mount *mp, + unsigned int src_namelen, bool target_exists, + unsigned int target_namelen, bool has_whiteout); + #endif /* __XFS_TRANS_SPACE_H__ */ From patchwork Sun Dec 31 23:07: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: 13508033 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 ABC02C147 for ; Sun, 31 Dec 2023 23:07:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="nZ48XxSY" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 22B94C433C7; Sun, 31 Dec 2023 23:07:43 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704064063; bh=QJ3Y0j53gKPFV9Fl7UmlOxaUtJFBjIcj9V0+qaakKOs=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=nZ48XxSYEsUCElWiL9+4vPKPr3Y48LZsQDgOXOKxd27KM5GqHlcUyTTY+Gi1z4397 haRWWVcL1MlC5UojxOdIMsVi+xGsPsJywGhRfL5QIdDicaUO9O7CXSQk52RgeMEyBx 3tK8XTSY/JWu371qCjIYEDqaszV9Mz7ygBQEe3FoHFF7pxk+zVORI3tw+ZkBMqckN2 EVOKPFACqiaL5+OJ6Rm+Ha6plTn7KpJ7gkom0c3pvJqDZqgxKEe6D+3bUDHvkNWW5N 2LHpSrf58D6VickNZk9IMLbwbiLAMhzdAFpZd0ZhewVYTFTtYKCA877UstsLWduRm9 PGakFHMI0bwnw== Date: Sun, 31 Dec 2023 15:07:42 -0800 Subject: [PATCH 10/32] xfs: pass the attr value to put_listent when possible From: "Darrick J. Wong" To: djwong@kernel.org, cem@kernel.org Cc: Allison Henderson , catherine.hoang@oracle.com, linux-xfs@vger.kernel.org, allison.henderson@oracle.com Message-ID: <170405006236.1804688.15967255303269704822.stgit@frogsfrogsfrogs> In-Reply-To: <170405006077.1804688.8762482665401724622.stgit@frogsfrogsfrogs> References: <170405006077.1804688.8762482665401724622.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: Allison Henderson Pass the attr value to put_listent when we have local xattrs or shortform xattrs. Signed-off-by: Allison Henderson Reviewed-by: Darrick J. Wong Signed-off-by: Darrick J. Wong --- libxfs/xfs_attr.h | 5 +++-- libxfs/xfs_attr_sf.h | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/libxfs/xfs_attr.h b/libxfs/xfs_attr.h index 4a4d45a96dd..0204f62298c 100644 --- a/libxfs/xfs_attr.h +++ b/libxfs/xfs_attr.h @@ -47,8 +47,9 @@ struct xfs_attrlist_cursor_kern { /* void; state communicated via *context */ -typedef void (*put_listent_func_t)(struct xfs_attr_list_context *, int, - unsigned char *, int, int); +typedef void (*put_listent_func_t)(struct xfs_attr_list_context *context, + int flags, unsigned char *name, int namelen, void *value, + int valuelen); struct xfs_attr_list_context { struct xfs_trans *tp; diff --git a/libxfs/xfs_attr_sf.h b/libxfs/xfs_attr_sf.h index 37578b369d9..c6e259791bc 100644 --- a/libxfs/xfs_attr_sf.h +++ b/libxfs/xfs_attr_sf.h @@ -24,6 +24,7 @@ typedef struct xfs_attr_sf_sort { uint8_t flags; /* flags bits (see xfs_attr_leaf.h) */ xfs_dahash_t hash; /* this entry's hash value */ unsigned char *name; /* name value, pointer into buffer */ + void *value; } xfs_attr_sf_sort_t; #define XFS_ATTR_SF_ENTSIZE_MAX /* max space for name&value */ \ From patchwork Sun Dec 31 23:07: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: 13508034 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 EA4DEC147 for ; Sun, 31 Dec 2023 23:07:58 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="NjlvPDIJ" Received: by smtp.kernel.org (Postfix) with ESMTPSA id B4424C433C8; Sun, 31 Dec 2023 23:07:58 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704064078; bh=RflnodAJshQ2Xv6LlzKhiCVA/0SKTkLBzuj8LUf0y9M=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=NjlvPDIJnK2DahzTi74iRySsrQTpyhu5d7zGFJyPKdLew95e3VRv7kIuAheoqFAB1 pPy3OJdu5O+ar8KRvu1dLDdIX0+9c5srWADsNKlFfI3deWzYL/iTxfS9wyGCiOyDPB sn+2iFWpptxDarnYkJ85ZqGxXBE7cnh35V1nZp/CaOrv2vTqJDvh9SYeJciKxcVeRh 5A4OC+6dMtSaoC8dh5clJMDbtS4oEldyqH7C0Gc00KcJqLW+Vtz3IdxhzvvPBDh3me AVIN7x1ztfNJ42NkToaD5lzXeG1ea3NMxu7TOTk+I5l9t60iCB8lVsPOXhBIkvDQ8I nMG6ZSWlYczpw== Date: Sun, 31 Dec 2023 15:07:58 -0800 Subject: [PATCH 11/32] xfs: Add parent pointer ioctl From: "Darrick J. Wong" To: djwong@kernel.org, cem@kernel.org Cc: Allison Henderson , catherine.hoang@oracle.com, linux-xfs@vger.kernel.org, allison.henderson@oracle.com Message-ID: <170405006249.1804688.11477606075426879369.stgit@frogsfrogsfrogs> In-Reply-To: <170405006077.1804688.8762482665401724622.stgit@frogsfrogsfrogs> References: <170405006077.1804688.8762482665401724622.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: Allison Henderson This patch adds a new file ioctl to retrieve the parent pointer of a given inode Signed-off-by: Allison Henderson Reviewed-by: Darrick J. Wong [djwong: move new ioctl to xfs_fs_staging.h, adjust to new ondisk format] Signed-off-by: Darrick J. Wong --- libxfs/xfs_fs.h | 1 libxfs/xfs_fs_staging.h | 66 +++++++++++ libxfs/xfs_ondisk.h | 4 + libxfs/xfs_parent.c | 62 +++++++++++ libxfs/xfs_parent.h | 25 ++++ man/man2/ioctl_xfs_getparents.2 | 227 +++++++++++++++++++++++++++++++++++++++ 6 files changed, 385 insertions(+) create mode 100644 man/man2/ioctl_xfs_getparents.2 diff --git a/libxfs/xfs_fs.h b/libxfs/xfs_fs.h index 63a145e5035..e92b6a9612a 100644 --- a/libxfs/xfs_fs.h +++ b/libxfs/xfs_fs.h @@ -811,6 +811,7 @@ struct xfs_scrub_metadata { /* XFS_IOC_GETFSMAP ------ hoisted 59 */ #define XFS_IOC_SCRUB_METADATA _IOWR('X', 60, struct xfs_scrub_metadata) #define XFS_IOC_AG_GEOMETRY _IOWR('X', 61, struct xfs_ag_geometry) +/* XFS_IOC_GETPARENTS ---- staging 62 */ /* * ioctl commands that replace IRIX syssgi()'s diff --git a/libxfs/xfs_fs_staging.h b/libxfs/xfs_fs_staging.h index e3d9f3b32b0..e0650af0558 100644 --- a/libxfs/xfs_fs_staging.h +++ b/libxfs/xfs_fs_staging.h @@ -104,4 +104,70 @@ struct xfs_exch_range { #define XFS_IOC_EXCHANGE_RANGE _IOWR('X', 129, struct xfs_exch_range) +/* Iterating parent pointers of files. */ + +/* return parents of the handle, not the open fd */ +#define XFS_GETPARENTS_IFLAG_HANDLE (1U << 0) + +/* target was the root directory */ +#define XFS_GETPARENTS_OFLAG_ROOT (1U << 1) + +/* Cursor is done iterating pptrs */ +#define XFS_GETPARENTS_OFLAG_DONE (1U << 2) + +#define XFS_GETPARENTS_FLAG_ALL (XFS_GETPARENTS_IFLAG_HANDLE | \ + XFS_GETPARENTS_OFLAG_ROOT | \ + XFS_GETPARENTS_OFLAG_DONE) + +/* Get an inode parent pointer through ioctl */ +struct xfs_getparents_rec { + __u64 gpr_ino; /* Inode number */ + __u32 gpr_gen; /* Inode generation */ + __u32 gpr_pad; /* Reserved */ + __u64 gpr_rsvd; /* Reserved */ + __u8 gpr_name[]; /* File name and null terminator */ +}; + +/* Iterate through an inodes parent pointers */ +struct xfs_getparents { + /* File handle, if XFS_GETPARENTS_IFLAG_HANDLE is set */ + struct xfs_handle gp_handle; + + /* + * Structure to track progress in iterating the parent pointers. + * Must be initialized to zeroes before the first ioctl call, and + * not touched by callers after that. + */ + struct xfs_attrlist_cursor gp_cursor; + + /* Operational flags: XFS_GETPARENTS_*FLAG* */ + __u32 gp_flags; + + /* Must be set to zero */ + __u32 gp_reserved; + + /* Size of the buffer in bytes, including this header */ + __u32 gp_bufsize; + + /* # of entries filled in (output) */ + __u32 gp_count; + + /* Must be set to zero */ + __u64 gp_reserved2[5]; + + /* Byte offset of each record within the buffer */ + __u32 gp_offsets[]; +}; + +static inline struct xfs_getparents_rec* +xfs_getparents_rec( + struct xfs_getparents *info, + unsigned int idx) +{ + return (struct xfs_getparents_rec *)((char *)info + + info->gp_offsets[idx]); +} + +#define XFS_IOC_GETPARENTS _IOWR('X', 62, struct xfs_getparents) + #endif /* __XFS_FS_STAGING_H__ */ diff --git a/libxfs/xfs_ondisk.h b/libxfs/xfs_ondisk.h index d9c988c5ad6..bffd39242d4 100644 --- a/libxfs/xfs_ondisk.h +++ b/libxfs/xfs_ondisk.h @@ -155,6 +155,10 @@ xfs_check_ondisk_structs(void) XFS_CHECK_OFFSET(struct xfs_efi_log_format_32, efi_extents, 16); XFS_CHECK_OFFSET(struct xfs_efi_log_format_64, efi_extents, 16); + /* parent pointer ioctls */ + XFS_CHECK_STRUCT_SIZE(struct xfs_getparents_rec, 24); + XFS_CHECK_STRUCT_SIZE(struct xfs_getparents, 96); + /* * The v5 superblock format extended several v4 header structures with * additional data. While new fields are only accessible on v5 diff --git a/libxfs/xfs_parent.c b/libxfs/xfs_parent.c index 6c98f95f274..92b541737cb 100644 --- a/libxfs/xfs_parent.c +++ b/libxfs/xfs_parent.c @@ -305,3 +305,65 @@ xfs_parent_args_free( { kmem_cache_free(xfs_parent_args_cache, ppargs); } + +/* Convert an ondisk parent pointer to the incore format. */ +void +xfs_parent_irec_from_disk( + struct xfs_parent_name_irec *irec, + const struct xfs_parent_name_rec *rec, + const void *value, + unsigned int valuelen) +{ + irec->p_ino = be64_to_cpu(rec->p_ino); + irec->p_gen = be32_to_cpu(rec->p_gen); + irec->p_namehash = be32_to_cpu(rec->p_namehash); + irec->p_namelen = valuelen; + memcpy(irec->p_name, value, valuelen); +} + +/* Convert an incore parent pointer to the ondisk attr name format. */ +void +xfs_parent_irec_to_disk( + struct xfs_parent_name_rec *rec, + const struct xfs_parent_name_irec *irec) +{ + rec->p_ino = cpu_to_be64(irec->p_ino); + rec->p_gen = cpu_to_be32(irec->p_gen); + rec->p_namehash = cpu_to_be32(irec->p_namehash); +} + +/* Is this a valid incore parent pointer? */ +bool +xfs_parent_verify_irec( + struct xfs_mount *mp, + const struct xfs_parent_name_irec *irec) +{ + struct xfs_name dname = { + .name = irec->p_name, + .len = irec->p_namelen, + }; + + if (!xfs_verify_dir_ino(mp, irec->p_ino)) + return false; + if (!xfs_parent_valuecheck(mp, irec->p_name, irec->p_namelen)) + return false; + if (!xfs_dir2_namecheck(irec->p_name, irec->p_namelen)) + return false; + if (irec->p_namehash != xfs_dir2_hashname(mp, &dname)) + return false; + return true; +} + +/* Compute p_namehash for the this parent pointer. */ +void +xfs_parent_irec_hashname( + struct xfs_mount *mp, + struct xfs_parent_name_irec *irec) +{ + struct xfs_name dname = { + .name = irec->p_name, + .len = irec->p_namelen, + }; + + irec->p_namehash = xfs_dir2_hashname(mp, &dname); +} diff --git a/libxfs/xfs_parent.h b/libxfs/xfs_parent.h index c68c501388e..e43ae5a7df8 100644 --- a/libxfs/xfs_parent.h +++ b/libxfs/xfs_parent.h @@ -127,4 +127,29 @@ xfs_parent_finish( xfs_parent_args_free(mp, ppargs); } +/* + * Incore version of a parent pointer, also contains dirent name so callers + * can pass/obtain all the parent pointer information in a single structure + */ +struct xfs_parent_name_irec { + /* Parent pointer attribute name fields */ + xfs_ino_t p_ino; + uint32_t p_gen; + xfs_dahash_t p_namehash; + + /* Parent pointer attribute value fields */ + uint8_t p_namelen; + unsigned char p_name[MAXNAMELEN]; +}; + +void xfs_parent_irec_from_disk(struct xfs_parent_name_irec *irec, + const struct xfs_parent_name_rec *rec, const void *value, + unsigned int valuelen); +void xfs_parent_irec_to_disk(struct xfs_parent_name_rec *rec, + const struct xfs_parent_name_irec *irec); +void xfs_parent_irec_hashname(struct xfs_mount *mp, + struct xfs_parent_name_irec *irec); +bool xfs_parent_verify_irec(struct xfs_mount *mp, + const struct xfs_parent_name_irec *irec); + #endif /* __XFS_PARENT_H__ */ diff --git a/man/man2/ioctl_xfs_getparents.2 b/man/man2/ioctl_xfs_getparents.2 new file mode 100644 index 00000000000..d6987979e85 --- /dev/null +++ b/man/man2/ioctl_xfs_getparents.2 @@ -0,0 +1,227 @@ +.\" Copyright (c) 2019-2024 Oracle. All rights reserved. +.\" +.\" %%%LICENSE_START(GPLv2+_DOC_FULL) +.\" SPDX-License-Identifier: GPL-2.0-or-later +.\" %%%LICENSE_END +.TH IOCTL-XFS-GETPARENTS 2 2023-08-18 "XFS" +.SH NAME +ioctl_xfs_getparents \- query XFS directory parent information +.SH SYNOPSIS +.br +.B #include +.br +.B #include +.PP +.BI "int ioctl(int " fd ", XFS_IOC_GETPARENTS, struct xfs_getparents *" arg ); +.SH DESCRIPTION +This command is used to get a file's parent pointers. +Parent pointers point upwards in the directory tree from a child file towards a +parent directories. +Each entry in a parent directory must have a corresponding parent pointer in +the child. + +Calling programs should allocate a large memory buffer and initialize the +beginning of the buffer to a header of the following form: +.PP +.in +4n +.nf +struct xfs_getparents { + struct xfs_handle gp_handle; + struct xfs_attrlist_cursor gp_cursor; + __u32 gp_flags; + __u32 gp_reserved; + __u32 gp_bufsize; + __u32 gp_count; + __u64 gp_reserved2[5]; + __u32 gp_offsets[]; +}; +.fi +.in + +.PP +If the flag +.B XFS_GETPARENTS_IFLAG_HANDLE +is set, +the field +.I gp_handle +will be interpreted as if it contains file handle information. +If the file handle is not stale, the file represented by the handle will be the +target of the query. +If the flag is not set, the file represented by +.I fd +will be queried instead. + +.PP +The field +.I gp_cursor +tracks the progress of iterating through the parent pointers. +Calling programs must initialize this to zero before the first system call +and must not touch it after that. + +.PP +The field +.I gp_flags +control the behavior of the query operation and provide more information +about the outcome of the operation. +.RS 0.4i +.TP +.B XFS_GETPARENTS_IFLAG_HANDLE +If the caller sets this flag, the kernel driver will interpret the +.I gp_handle +field as if it were a file handle. +If the handle maps to an allocated file, that file will be queried for +parents instead of the open file descriptor. +.TP +.B XFS_GETPARENTS_OFLAG_ROOT +The file queried was the root directory. +.TP +.B XFS_GETPARENTS_OFLAG_DONE +There are no more parent pointers to query. +.RE + +.PP +The fields +.I gp_reserved +and +.I gp_reserved2 +must be zero. + +.PP +The field +.I gp_bufsize +should be set to the size of the buffer, in bytes. + +.PP +The field +.I gp_count +will be set to the number of parent pointer records returned. + +.PP +Each element of the array +.I gp_offsets +will be set to the byte offset within the buffer of each parent record. + +Parent pointer records are returned in the following form: +.PP +.in +4n +.nf + +struct xfs_getparents_rec { + __u64 gpr_ino; + __u32 gpr_gen; + __u32 gpr_pad; + __u64 gpr_rsvd; + __u8 gpr_name[]; +}; +.fi +.in + +.PP +The field +.I gpr_ino +and +.I gpr_gen +will be set to the inode number and generation number of the parent. + +.PP +The fields +.I gpr_pad +and +.I gpr_rsvd +will be set to zero. + +.PP +The array +.I gpr_name +will be set to a NULL-terminated byte sequence representing the filename +stored in the parent pointer. + +.SH SAMPLE PROGRAM +Calling programs should allocate a large memory buffer, initialize the head +structure to zeroes, set gp_bufsize to the size of the buffer, and call the +ioctl. +The kernel will fill out the gp_offsets array with integer offsets to +struct xfs_getparents_rec objects that are written within the provided memory +buffer. +The size of the gp_offsets array is given by gp_count. +The XFS_GETPARENTS_OFLAG_DONE flag will be set in gp_flags when there are no +more parent pointers to be read. +The below code is an example of XFS_IOC_GETPARENTS usage: + +.nf +#include +#include +#include +#include +#include +#include +#include +#include + +int main() { + struct xfs_getparents *pi; + struct xfs_getparents_rec *p; + int i, error, fd, nr_ptrs = 4; + + error = malloc(65536); + if (!error) { + perror("malloc"); + return 1; + } + + memset(pi, 0, sizeof(*pi)); + pi->gp_bufsize = 65536; + + fd = open("/mnt/test/foo.txt", O_RDONLY | O_CREAT); + if (fd == -1) + return errno; + + do { + error = ioctl(fd, XFS_IOC_GETPARENTS, pi); + if (error) + return error; + + for (i = 0; i < pi->gp_count; i++) { + p = xfs_getparents_rec(pi, i); + printf("inode = %llu\\n", (unsigned long long)p->gpr_ino); + printf("generation = %u\\n", (unsigned int)p->gpr_gen); + printf("name = \\"%s\\"\\n\\n", (char *)p->gpr_name); + } + } while (!(pi->gp_flags & XFS_GETPARENTS_OFLAG_DONE)); + + return 0; +} +.fi + +.SH RETURN VALUE +On error, \-1 is returned, and +.I errno +is set to indicate the error. +.PP +.SH ERRORS +Error codes can be one of, but are not limited to, the following: +.TP +.B EFSBADCRC +Metadata checksum validation failed while performing the query. +.TP +.B EFSCORRUPTED +Metadata corruption was encountered while performing the query. +.TP +.B EINVAL +One or more of the arguments specified is invalid. +.TP +.B EOPNOTSUPP +Repairs of the requested metadata object are not supported. +.TP +.B EROFS +Filesystem is read-only and a repair was requested. +.TP +.B ESHUTDOWN +Filesystem is shut down due to previous errors. +.TP +.B EIO +An I/O error was encountered while performing the query. +.SH CONFORMING TO +This API is specific to XFS filesystem on the Linux kernel. +.SH SEE ALSO +.BR ioctl (2) From patchwork Sun Dec 31 23:08: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: 13508035 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 E5660C147 for ; Sun, 31 Dec 2023 23:08:14 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="JxxHmsAg" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 67AD2C433C7; Sun, 31 Dec 2023 23:08:14 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704064094; bh=8K82lil0r2LjkDvnxEZqN0WYLdGXb9APGxeBQIKKmts=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=JxxHmsAgtfmGh2LI5/lPqeazRYRKpCp7t99X4SA35hPKdwWLCRd1yobnUpw6SGnxk qBgFzOneucLIn5X6dpH707IlrIX1oEcEMegyS3y9pQ8Mx2lVaYa/ECCer/nWFiUgxV urLVHpgLEkBNi98Pw45Gmqp+QKw73A0wRh3/tIpje59TnzeFvepaLyzGd1xckPQyZ4 ovj4onAczc4uIRno1b/Wju/27rkeMX1PpM+PcVBof/EG3vHROwljKXzaBUBQ4+NkWE gxYxbrsSP7fmsKw7NTGvLnFLtBaU/EjTKYlq4+wnPd2LtmAUzJgSrUMehA9I5GT+6e VQqA2TodQ02qg== Date: Sun, 31 Dec 2023 15:08:13 -0800 Subject: [PATCH 12/32] xfs: fix unit conversion error in xfs_log_calc_max_attrsetm_res From: "Darrick J. Wong" To: djwong@kernel.org, cem@kernel.org Cc: Allison Henderson , catherine.hoang@oracle.com, linux-xfs@vger.kernel.org, allison.henderson@oracle.com Message-ID: <170405006263.1804688.4745717652618524511.stgit@frogsfrogsfrogs> In-Reply-To: <170405006077.1804688.8762482665401724622.stgit@frogsfrogsfrogs> References: <170405006077.1804688.8762482665401724622.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 Dave and I were discussing some recent test regressions as a result of me turning on nrext64=1 on realtime filesystems, when we noticed that the minimum log size of a 32M filesystem jumped from 954 blocks to 4287 blocks. Digging through xfs_log_calc_max_attrsetm_res, Dave noticed that @size contains the maximum estimated amount of space needed for a local format xattr, in bytes, but we feed this quantity to XFS_NEXTENTADD_SPACE_RES, which requires units of blocks. This has resulted in an overestimation of the minimum log size over the years. We should nominally correct this, but there's a backwards compatibility problem -- if we enable it now, the minimum log size will decrease. If a corrected mkfs formats a filesystem with this new smaller log size, a user will encounter mount failures on an uncorrected kernel due to the larger minimum log size computations there. However, the large extent counters feature is still EXPERIMENTAL, so we can gate the correction on that feature (or any features that get added after that) being enabled. Any filesystem with nrext64 or any of the as-yet-undefined feature bits turned on will be rejected by old uncorrected kernels, so this should be safe even in the upgrade case. Signed-off-by: Darrick J. Wong Reviewed-by: Allison Henderson --- libxfs/xfs_log_rlimit.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/libxfs/xfs_log_rlimit.c b/libxfs/xfs_log_rlimit.c index cba24493f86..096e3ee4b6a 100644 --- a/libxfs/xfs_log_rlimit.c +++ b/libxfs/xfs_log_rlimit.c @@ -16,6 +16,29 @@ #include "xfs_bmap_btree.h" #include "xfs_trace.h" +/* + * Decide if the filesystem has the parent pointer feature or any feature + * added after that. If so, we can improve the accuracy of the transaction + * reservation computations that should lead to more efficient log grant use. + */ +static inline bool +xfs_has_parent_or_newer_feature( + struct xfs_mount *mp) +{ + if (!xfs_sb_is_v5(&mp->m_sb)) + return false; + + if (xfs_sb_has_incompat_feature(&mp->m_sb, + ~(XFS_SB_FEAT_INCOMPAT_FTYPE | + XFS_SB_FEAT_INCOMPAT_SPINODES | + XFS_SB_FEAT_INCOMPAT_META_UUID | + XFS_SB_FEAT_INCOMPAT_BIGTIME | + XFS_SB_FEAT_INCOMPAT_NREXT64))) + return true; + + return false; +} + /* * Calculate the maximum length in bytes that would be required for a local * attribute value as large attributes out of line are not logged. @@ -31,6 +54,16 @@ xfs_log_calc_max_attrsetm_res( MAXNAMELEN - 1; nblks = XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK); nblks += XFS_B_TO_FSB(mp, size); + + /* + * Starting with the parent pointer feature, every new fs feature + * corrects a unit conversion error in the xattr transaction + * reservation code that resulted in oversized minimum log size + * computations. + */ + if (xfs_has_parent_or_newer_feature(mp)) + size = XFS_B_TO_FSB(mp, size); + nblks += XFS_NEXTENTADD_SPACE_RES(mp, size, XFS_ATTR_FORK); return M_RES(mp)->tr_attrsetm.tr_logres + From patchwork Sun Dec 31 23:08: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: 13508036 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 49874C154 for ; Sun, 31 Dec 2023 23:08:30 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="k6EflWdx" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 18B63C433C7; Sun, 31 Dec 2023 23:08:30 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704064110; bh=H4fKnseCpgsoOL3dW+9IVo2l0KfXyfTkXYDD7xISvoQ=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=k6EflWdxY5nxT65S34dy88FqJwyDQ3ntcOQt57XeF0CPMV5igacft5wHcxa1CrGlv a8PJh3y6rOuUXRFqM9LYugXQZH+xJ+MzDrj/cfEeCBfRRQTrlEvzeA9oGeksR13mtG y5+u70gmB6CJdrjLaLsPJRb2SRWoYA580cOHUercJqXo2FSochF23OeIC1ESzh4Hjd BZO8HfjiS2TVZxcT+X4gHMgrBWs17dTkkRyJ7Xx3gESMOnusycJM35krYcOC72XAHw EjXclExymKS1eAkjjBz6TAmD8NQhzxQ32vOnvaQSlTHvOeTRxq+38vKHzPOMO2tY1g sL+1obNms4IMw== Date: Sun, 31 Dec 2023 15:08:29 -0800 Subject: [PATCH 13/32] xfs: drop compatibility minimum log size computations for reflink From: "Darrick J. Wong" To: djwong@kernel.org, cem@kernel.org Cc: Allison Henderson , catherine.hoang@oracle.com, linux-xfs@vger.kernel.org, allison.henderson@oracle.com Message-ID: <170405006276.1804688.17164442662917384498.stgit@frogsfrogsfrogs> In-Reply-To: <170405006077.1804688.8762482665401724622.stgit@frogsfrogsfrogs> References: <170405006077.1804688.8762482665401724622.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 Having established that we can reduce the minimum log size computation for filesystems with parent pointers or any newer feature, we should also drop the compat minlogsize code that we added when we reduced the transaction reservation size for rmap and reflink. Signed-off-by: Darrick J. Wong Reviewed-by: Allison Henderson --- libxfs/xfs_log_rlimit.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/libxfs/xfs_log_rlimit.c b/libxfs/xfs_log_rlimit.c index 096e3ee4b6a..2a5fa3334c8 100644 --- a/libxfs/xfs_log_rlimit.c +++ b/libxfs/xfs_log_rlimit.c @@ -81,6 +81,16 @@ xfs_log_calc_trans_resv_for_minlogblocks( { unsigned int rmap_maxlevels = mp->m_rmap_maxlevels; + /* + * Starting with the parent pointer feature, every new fs feature + * drops the oversized minimum log size computation introduced by the + * original reflink code. + */ + if (xfs_has_parent_or_newer_feature(mp)) { + xfs_trans_resv_calc(mp, resv); + return; + } + /* * In the early days of rmap+reflink, we always set the rmap maxlevels * to 9 even if the AG was small enough that it would never grow to From patchwork Sun Dec 31 23:08: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: 13508037 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 DD4CFC147 for ; Sun, 31 Dec 2023 23:08:45 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="kYjZ3Og+" Received: by smtp.kernel.org (Postfix) with ESMTPSA id B193DC433C7; Sun, 31 Dec 2023 23:08:45 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704064125; bh=uMyWrEmX6MVpKen9Wrl1wizEEKtghbMK9DdJxy2/olM=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=kYjZ3Og+ac8KmO3G2gv6CMYt/ciXdxFGNFfoTrDpUTWvVt4eRAAKoGx2XG1aA4EKw TSgxK1pyrEZUrYyrHJolAexMb6q7WU3EYuQ5t6bbKoN5Zj/j3e4WNM0ctbbPjxkwi6 2rkObo7JXGFEUYhfaF50cc13lM8HoNwB16+aZap5mM6oiPCfOusR/SV17g8/y4ahtJ VaK0+k09yh/21S1D0z4xoaZ2uojHdbtcRnik+LD5Aq4eIQN0KG8bQUY4v7/IKyvOLX 1MqeF1duX+Jm5b4/vJfrhc7aOtMZiv2HXw2oQRA6qqhgHdz2OqHfhQ+mYS1NnKBhWL jQwW//rrK0sPw== Date: Sun, 31 Dec 2023 15:08:45 -0800 Subject: [PATCH 14/32] xfs: don't remove the attr fork when parent pointers are enabled From: "Darrick J. Wong" To: djwong@kernel.org, cem@kernel.org Cc: Allison Henderson , catherine.hoang@oracle.com, linux-xfs@vger.kernel.org, allison.henderson@oracle.com Message-ID: <170405006288.1804688.10218847227092680339.stgit@frogsfrogsfrogs> In-Reply-To: <170405006077.1804688.8762482665401724622.stgit@frogsfrogsfrogs> References: <170405006077.1804688.8762482665401724622.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: Allison Henderson When an inode is removed, it may also cause the attribute fork to be removed if it is the last attribute. This transaction gets flushed to the log, but if the system goes down before we could inactivate the symlink, the log recovery tries to inactivate this inode (since it is on the unlinked list) but the verifier trips over the remote value and leaks it. Hence we ended up with a file in this odd state on a "clean" mount. The "obvious" fix is to prohibit erasure of the attr fork to avoid tripping over the verifiers when pptrs are enabled. Signed-off-by: Allison Henderson Reviewed-by: Darrick J. Wong Signed-off-by: Darrick J. Wong --- libxfs/xfs_attr_leaf.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libxfs/xfs_attr_leaf.c b/libxfs/xfs_attr_leaf.c index c0fc3c10dc4..14020c09146 100644 --- a/libxfs/xfs_attr_leaf.c +++ b/libxfs/xfs_attr_leaf.c @@ -910,7 +910,8 @@ xfs_attr_sf_removename( totsize -= size; if (totsize == sizeof(xfs_attr_sf_hdr_t) && xfs_has_attr2(mp) && (dp->i_df.if_format != XFS_DINODE_FMT_BTREE) && - !(args->op_flags & (XFS_DA_OP_ADDNAME | XFS_DA_OP_REPLACE))) { + !(args->op_flags & (XFS_DA_OP_ADDNAME | XFS_DA_OP_REPLACE)) && + !xfs_has_parent(mp)) { xfs_attr_fork_remove(dp, args->trans); } else { xfs_idata_realloc(dp, -size, XFS_ATTR_FORK); @@ -919,7 +920,8 @@ xfs_attr_sf_removename( ASSERT(totsize > sizeof(xfs_attr_sf_hdr_t) || (args->op_flags & XFS_DA_OP_ADDNAME) || !xfs_has_attr2(mp) || - dp->i_df.if_format == XFS_DINODE_FMT_BTREE); + dp->i_df.if_format == XFS_DINODE_FMT_BTREE || + xfs_has_parent(mp)); xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_ADATA); } From patchwork Sun Dec 31 23:09: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: 13508038 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 81518C140 for ; Sun, 31 Dec 2023 23:09:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Ii7sxgAz" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 563FBC433C8; Sun, 31 Dec 2023 23:09:01 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704064141; bh=I1MJR2U1yZLpcfcsDThFsKXry8DkaQVKn1yUUjuNwDw=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=Ii7sxgAzhQe82983p94RsrYJ10QmqCcmke+aF1d4paC8yFoXwqVwYvChi0/eZDCHf xossCtN8v0wo3XLXOGjkC3kRjcGE2PcTT0pXXAzPl8YCAuHrQRmmKskb2F0u8mshdg xSFpKvrWzVJp4or3QBkrteq/J9JYWGpdXpkyD+oOXgvY79ZFxExkhlKQKzpfd0D9wo 8xOydJFkpHe9B/Z6daqYN5xKyQTBbLKNqBXvKDvy3QrZiL+qfZD0Kc2brkRq0Xorlg jau0bi4HtC7zjRwsvGoX1bgG/ZzzjCQing6XSO3kYRKeffKaHl8F8B3Cx+D1MOuBKo a8caTHfi0SMIw== Date: Sun, 31 Dec 2023 15:09:00 -0800 Subject: [PATCH 15/32] xfs: Add the parent pointer support to the superblock version 5. From: "Darrick J. Wong" To: djwong@kernel.org, cem@kernel.org Cc: Mark Tinguely , Dave Chinner , Allison Henderson , "Darrick J. Wong" , catherine.hoang@oracle.com, linux-xfs@vger.kernel.org, allison.henderson@oracle.com Message-ID: <170405006302.1804688.5942768186018194393.stgit@frogsfrogsfrogs> In-Reply-To: <170405006077.1804688.8762482665401724622.stgit@frogsfrogsfrogs> References: <170405006077.1804688.8762482665401724622.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: Allison Henderson Add the parent pointer superblock flag so that we can actually mount filesystems with this feature enabled. Signed-off-by: Mark Tinguely Signed-off-by: Dave Chinner Signed-off-by: Allison Henderson Reviewed-by: Darrick J. Wong Reviewed-by: Darrick J. Wong Signed-off-by: Darrick J. Wong --- libfrog/fsgeom.c | 6 ++++-- libxfs/xfs_format.h | 4 +++- libxfs/xfs_fs.h | 1 + libxfs/xfs_sb.c | 4 ++++ 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/libfrog/fsgeom.c b/libfrog/fsgeom.c index 6980d3ffab6..061995fa2c7 100644 --- a/libfrog/fsgeom.c +++ b/libfrog/fsgeom.c @@ -31,6 +31,7 @@ xfs_report_geom( int bigtime_enabled; int inobtcount; int nrext64; + int parent; isint = geo->logstart > 0; lazycount = geo->flags & XFS_FSOP_GEOM_FLAGS_LAZYSB ? 1 : 0; @@ -49,6 +50,7 @@ xfs_report_geom( bigtime_enabled = geo->flags & XFS_FSOP_GEOM_FLAGS_BIGTIME ? 1 : 0; 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; printf(_( "meta-data=%-22s isize=%-6d agcount=%u, agsize=%u blks\n" @@ -57,7 +59,7 @@ xfs_report_geom( " =%-22s reflink=%-4u bigtime=%u inobtcount=%u nrext64=%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\n" +"naming =version %-14u bsize=%-6u ascii-ci=%d, ftype=%d, parent=%d\n" "log =%-22s bsize=%-6d blocks=%u, version=%d\n" " =%-22s sectsz=%-5u sunit=%d blks, lazy-count=%d\n" "realtime =%-22s extsz=%-6d blocks=%lld, rtextents=%lld\n"), @@ -68,7 +70,7 @@ xfs_report_geom( "", geo->blocksize, (unsigned long long)geo->datablocks, geo->imaxpct, "", geo->sunit, geo->swidth, - dirversion, geo->dirblocksize, cimode, ftype_enabled, + dirversion, geo->dirblocksize, cimode, ftype_enabled, parent, isint ? _("internal log") : logname ? logname : _("external"), geo->blocksize, geo->logblocks, logversion, "", geo->logsectsize, geo->logsunit / geo->blocksize, lazycount, diff --git a/libxfs/xfs_format.h b/libxfs/xfs_format.h index 8b952909ce1..b0aaa825539 100644 --- a/libxfs/xfs_format.h +++ b/libxfs/xfs_format.h @@ -373,13 +373,15 @@ xfs_sb_has_ro_compat_feature( #define XFS_SB_FEAT_INCOMPAT_BIGTIME (1 << 3) /* large timestamps */ #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_ALL \ (XFS_SB_FEAT_INCOMPAT_FTYPE| \ XFS_SB_FEAT_INCOMPAT_SPINODES| \ XFS_SB_FEAT_INCOMPAT_META_UUID| \ XFS_SB_FEAT_INCOMPAT_BIGTIME| \ XFS_SB_FEAT_INCOMPAT_NEEDSREPAIR| \ - XFS_SB_FEAT_INCOMPAT_NREXT64) + XFS_SB_FEAT_INCOMPAT_NREXT64| \ + XFS_SB_FEAT_INCOMPAT_PARENT) #define XFS_SB_FEAT_INCOMPAT_UNKNOWN ~XFS_SB_FEAT_INCOMPAT_ALL static inline bool diff --git a/libxfs/xfs_fs.h b/libxfs/xfs_fs.h index e92b6a9612a..efa68a2d82a 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_PARENT (1U << 30) /* parent pointers */ /* atomic file extent swap available to userspace */ #define XFS_FSOP_GEOM_FLAGS_ATOMIC_SWAP (1U << 31) diff --git a/libxfs/xfs_sb.c b/libxfs/xfs_sb.c index fd017d18cda..d150170d87b 100644 --- a/libxfs/xfs_sb.c +++ b/libxfs/xfs_sb.c @@ -174,6 +174,8 @@ xfs_sb_version_to_features( features |= XFS_FEAT_NEEDSREPAIR; if (sbp->sb_features_incompat & XFS_SB_FEAT_INCOMPAT_NREXT64) features |= XFS_FEAT_NREXT64; + if (sbp->sb_features_incompat & XFS_SB_FEAT_INCOMPAT_PARENT) + features |= XFS_FEAT_PARENT; return features; } @@ -1249,6 +1251,8 @@ xfs_fs_geometry( geo->flags |= XFS_FSOP_GEOM_FLAGS_BIGTIME; if (xfs_has_inobtcounts(mp)) geo->flags |= XFS_FSOP_GEOM_FLAGS_INOBTCNT; + if (xfs_has_parent(mp)) + geo->flags |= XFS_FSOP_GEOM_FLAGS_PARENT; if (xfs_has_sector(mp)) { geo->flags |= XFS_FSOP_GEOM_FLAGS_SECTOR; geo->logsectsize = sbp->sb_logsectsize; From patchwork Sun Dec 31 23:09: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: 13508039 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 42E93C147 for ; Sun, 31 Dec 2023 23:09:17 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="gFxAknJE" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 0C13CC433C8; Sun, 31 Dec 2023 23:09:17 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704064157; bh=2NIrejcvRGkUT0mu3Rf6/Xf6CMXy+qgiLzAgfrRbtGg=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=gFxAknJEA6t8AJ3ZPnL+u+nl0RpCC2cQZ6oXSsiO6/u+0uSISps6fr4J0LH1vY0QA C6KPQH5hQ+eo2zTAKxRMe4xGDiR34/1U80gsd3Ts83DT+NTzGZzpMvWnbIAGH8anTG P2UgzH+A1my/TOFsyLo9V6Sae3/ezO0UbYg6dMvNCJSDq7kR/5Y/LmisrWwO8pCXR0 PKflOdW5TXrSrz7h+XoMOBk/GR4+fwyH2j7euXnKixJv88ze2WzMFgtY4cfP14NV+L nw4/0BOSXRUY3pj5GxvVFUTXLspJUV96DStDgtVIAFUCQWJKZ9GrejaemZuQ1bseqD 0XS6yEHnkZDEA== Date: Sun, 31 Dec 2023 15:09:16 -0800 Subject: [PATCH 16/32] libfrog: add parent pointer support code From: "Darrick J. Wong" To: djwong@kernel.org, cem@kernel.org Cc: Allison Henderson , catherine.hoang@oracle.com, linux-xfs@vger.kernel.org, allison.henderson@oracle.com Message-ID: <170405006315.1804688.18073267977833660387.stgit@frogsfrogsfrogs> In-Reply-To: <170405006077.1804688.8762482665401724622.stgit@frogsfrogsfrogs> References: <170405006077.1804688.8762482665401724622.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 some support code to libfrog so that client programs can walk file descriptors and handles upwards through the directory tree; and obtain a reasonable file path from a file descriptor/handle. This code will be used in xfsprogs utilities. Signed-off-by: Darrick J. Wong Reviewed-by: Allison Henderson --- include/handle.h | 1 libfrog/Makefile | 2 libfrog/getparents.c | 345 ++++++++++++++++++++++++++++++++++++++++++++++++++ libfrog/getparents.h | 36 +++++ libfrog/paths.c | 167 ++++++++++++++++++++++++ libfrog/paths.h | 25 ++++ libhandle/handle.c | 7 + 7 files changed, 580 insertions(+), 3 deletions(-) create mode 100644 libfrog/getparents.c create mode 100644 libfrog/getparents.h diff --git a/include/handle.h b/include/handle.h index 34246f3854d..ba06500516c 100644 --- a/include/handle.h +++ b/include/handle.h @@ -17,6 +17,7 @@ struct parent; extern int path_to_handle (char *__path, void **__hanp, size_t *__hlen); extern int path_to_fshandle (char *__path, void **__fshanp, size_t *__fshlen); extern int fd_to_handle (int fd, void **hanp, size_t *hlen); +extern int handle_to_fsfd(void *, char **); extern int handle_to_fshandle (void *__hanp, size_t __hlen, void **__fshanp, size_t *__fshlen); extern void free_handle (void *__hanp, size_t __hlen); diff --git a/libfrog/Makefile b/libfrog/Makefile index bbc5b887cd3..8c2d040bc29 100644 --- a/libfrog/Makefile +++ b/libfrog/Makefile @@ -20,6 +20,7 @@ convert.c \ crc32.c \ file_exchange.c \ fsgeom.c \ +getparents.c \ histogram.c \ list_sort.c \ linux.c \ @@ -46,6 +47,7 @@ dahashselftest.h \ div64.h \ file_exchange.h \ fsgeom.h \ +getparents.h \ histogram.h \ logging.h \ paths.h \ diff --git a/libfrog/getparents.c b/libfrog/getparents.c new file mode 100644 index 00000000000..016fe3f026d --- /dev/null +++ b/libfrog/getparents.c @@ -0,0 +1,345 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2017-2024 Oracle. All Rights Reserved. + * Author: Darrick J. Wong + */ +#include "platform_defs.h" +#include "xfs.h" +#include "xfs_arch.h" +#include "list.h" +#include "libfrog/paths.h" +#include "handle.h" +#include "libfrog/getparents.h" + +/* Allocate a buffer large enough for some parent pointer records. */ +static inline struct xfs_getparents * +alloc_pptr_buf( + size_t bufsize) +{ + struct xfs_getparents *pi; + + pi = calloc(bufsize, 1); + if (!pi) + return NULL; + pi->gp_bufsize = bufsize; + return pi; +} + +/* + * Walk all parents of the given file handle. Returns 0 on success or positive + * errno. + */ +static int +call_getparents( + int fd, + struct xfs_handle *handle, + walk_parent_fn fn, + void *arg) +{ + struct xfs_getparents *pi; + struct xfs_getparents_rec *p; + unsigned int i; + ssize_t ret = -1; + + pi = alloc_pptr_buf(XFS_XATTR_LIST_MAX); + if (!pi) + return errno; + + if (handle) { + memcpy(&pi->gp_handle, handle, sizeof(struct xfs_handle)); + pi->gp_flags = XFS_GETPARENTS_IFLAG_HANDLE; + } + + ret = ioctl(fd, XFS_IOC_GETPARENTS, pi); + while (!ret) { + if (pi->gp_flags & XFS_GETPARENTS_OFLAG_ROOT) { + struct parent_rec rec = { + .p_flags = PARENT_IS_ROOT, + }; + + ret = fn(&rec, arg); + goto out_pi; + } + + for (i = 0; i < pi->gp_count; i++) { + struct parent_rec rec = { 0 }; + + p = xfs_getparents_rec(pi, i); + rec.p_ino = p->gpr_ino; + rec.p_gen = p->gpr_gen; + strncpy((char *)rec.p_name, (char *)p->gpr_name, + MAXNAMELEN - 1); + + ret = fn(&rec, arg); + if (ret) + goto out_pi; + } + + if (pi->gp_flags & XFS_GETPARENTS_OFLAG_DONE) + break; + + ret = ioctl(fd, XFS_IOC_GETPARENTS, pi); + } + if (ret) + ret = errno; + +out_pi: + free(pi); + return ret; +} + +/* Walk all parent pointers of this handle. Returns 0 or positive errno. */ +int +handle_walk_parents( + void *hanp, + size_t hlen, + walk_parent_fn fn, + void *arg) +{ + char *mntpt; + int fd; + + if (hlen != sizeof(struct xfs_handle)) + return EINVAL; + + fd = handle_to_fsfd(hanp, &mntpt); + if (fd < 0) + return errno; + + return call_getparents(fd, hanp, fn, arg); +} + +/* Walk all parent pointers of this fd. Returns 0 or positive errno. */ +int +fd_walk_parents( + int fd, + walk_parent_fn fn, + void *arg) +{ + return call_getparents(fd, NULL, fn, arg); +} + +struct walk_ppaths_info { + walk_path_fn fn; + void *arg; + char *mntpt; + struct path_list *path; + int fd; +}; + +struct walk_ppath_level_info { + struct xfs_handle newhandle; + struct path_component *pc; + struct walk_ppaths_info *wpi; +}; + +static int handle_walk_ppath(struct walk_ppaths_info *wpi, + struct xfs_handle *handle); + +static int +handle_walk_ppath_rec( + const struct parent_rec *rec, + void *arg) +{ + struct walk_ppath_level_info *wpli = arg; + struct walk_ppaths_info *wpi = wpli->wpi; + int ret = 0; + + if (rec->p_flags & PARENT_IS_ROOT) + return wpi->fn(wpi->mntpt, wpi->path, wpi->arg); + + ret = path_component_change(wpli->pc, rec->p_name, + strlen((char *)rec->p_name), rec->p_ino); + if (ret) + return ret; + + wpli->newhandle.ha_fid.fid_ino = rec->p_ino; + wpli->newhandle.ha_fid.fid_gen = rec->p_gen; + + path_list_add_parent_component(wpi->path, wpli->pc); + ret = handle_walk_ppath(wpi, &wpli->newhandle); + path_list_del_component(wpi->path, wpli->pc); + + return ret; +} + +/* + * Recursively walk all parents of the given file handle; if we hit the + * fs root then we call the associated function with the constructed path. + * Returns 0 for success or positive errno. + */ +static int +handle_walk_ppath( + struct walk_ppaths_info *wpi, + struct xfs_handle *handle) +{ + struct walk_ppath_level_info *wpli; + int ret; + + wpli = malloc(sizeof(struct walk_ppath_level_info)); + if (!wpli) + return errno; + wpli->pc = path_component_init("", 0); + if (!wpli->pc) { + ret = errno; + free(wpli); + return ret; + } + wpli->wpi = wpi; + memcpy(&wpli->newhandle, handle, sizeof(struct xfs_handle)); + + ret = call_getparents(wpi->fd, handle, handle_walk_ppath_rec, wpli); + + path_component_free(wpli->pc); + free(wpli); + return ret; +} + +/* + * Call the given function on all known paths from the vfs root to the inode + * described in the handle. Returns 0 for success or positive errno. + */ +int +handle_walk_parent_paths( + void *hanp, + size_t hlen, + walk_path_fn fn, + void *arg) +{ + struct walk_ppaths_info wpi; + ssize_t ret; + + if (hlen != sizeof(struct xfs_handle)) + return EINVAL; + + wpi.fd = handle_to_fsfd(hanp, &wpi.mntpt); + if (wpi.fd < 0) + return errno; + wpi.path = path_list_init(); + if (!wpi.path) + return errno; + wpi.fn = fn; + wpi.arg = arg; + + ret = handle_walk_ppath(&wpi, hanp); + path_list_free(wpi.path); + + return ret; +} + +/* + * Call the given function on all known paths from the vfs root to the inode + * referred to by the file description. Returns 0 or positive errno. + */ +int +fd_walk_parent_paths( + int fd, + walk_path_fn fn, + void *arg) +{ + struct walk_ppaths_info wpi; + void *hanp; + size_t hlen; + int fsfd; + int ret; + + ret = fd_to_handle(fd, &hanp, &hlen); + if (ret) + return errno; + + fsfd = handle_to_fsfd(hanp, &wpi.mntpt); + if (fsfd < 0) + return errno; + wpi.fd = fd; + wpi.path = path_list_init(); + if (!wpi.path) + return errno; + wpi.fn = fn; + wpi.arg = arg; + + ret = handle_walk_ppath(&wpi, hanp); + path_list_free(wpi.path); + + return ret; +} + +struct path_walk_info { + char *buf; + size_t len; + size_t written; +}; + +/* Helper that stringifies the first full path that we find. */ +static int +handle_to_path_walk( + const char *mntpt, + const struct path_list *path, + void *arg) +{ + struct path_walk_info *pwi = arg; + int mntpt_len = strlen(mntpt); + int ret; + + /* Trim trailing slashes from the mountpoint */ + while (mntpt_len > 0 && mntpt[mntpt_len - 1] == '/') + mntpt_len--; + + ret = snprintf(pwi->buf, pwi->len, "%.*s", mntpt_len, mntpt); + if (ret != mntpt_len) + return ENAMETOOLONG; + pwi->written += ret; + + ret = path_list_to_string(path, pwi->buf + ret, pwi->len - ret); + if (ret < 0) + return ENAMETOOLONG; + + pwi->written += ret; + return ECANCELED; +} + +/* + * Return any eligible path to this file handle. Returns 0 for success or + * positive errno. + */ +int +handle_to_path( + void *hanp, + size_t hlen, + char *path, + size_t pathlen) +{ + struct path_walk_info pwi = { .buf = path, .len = pathlen }; + int ret; + + ret = handle_walk_parent_paths(hanp, hlen, handle_to_path_walk, &pwi); + if (ret && ret != ECANCELED) + return ret; + if (!pwi.written) + return ENODATA; + + path[pwi.written] = 0; + return 0; +} + +/* + * Return any eligible path to this file description. Returns 0 for success + * or positive errno. + */ +int +fd_to_path( + int fd, + char *path, + size_t pathlen) +{ + struct path_walk_info pwi = { .buf = path, .len = pathlen }; + int ret; + + ret = fd_walk_parent_paths(fd, handle_to_path_walk, &pwi); + if (ret && ret != ECANCELED) + return ret; + if (!pwi.written) + return ENODATA; + + path[pwi.written] = 0; + return ret; +} diff --git a/libfrog/getparents.h b/libfrog/getparents.h new file mode 100644 index 00000000000..41beb4ce3be --- /dev/null +++ b/libfrog/getparents.h @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2023-2024 Oracle. All Rights Reserved. + * Author: Darrick J. Wong + */ +#ifndef __LIBFROG_GETPARENTS_H_ +#define __LIBFROG_GETPARENTS_H_ + +struct path_list; + +struct parent_rec { + uint64_t p_ino; + uint32_t p_gen; + uint32_t p_flags; + unsigned char p_name[MAXNAMELEN]; +}; + +/* This is the root directory. */ +#define PARENT_IS_ROOT (1U << 0) + +typedef int (*walk_parent_fn)(const struct parent_rec *rec, void *arg); +typedef int (*walk_path_fn)(const char *mntpt, const struct path_list *path, + void *arg); + +int fd_walk_parents(int fd, walk_parent_fn fn, void *arg); +int handle_walk_parents(void *hanp, size_t hanlen, walk_parent_fn fn, + void *arg); + +int fd_walk_parent_paths(int fd, walk_path_fn fn, void *arg); +int handle_walk_parent_paths(void *hanp, size_t hanlen, walk_path_fn fn, + void *arg); + +int fd_to_path(int fd, char *path, size_t pathlen); +int handle_to_path(void *hanp, size_t hlen, char *path, size_t pathlen); + +#endif /* __LIBFROG_GETPARENTS_H_ */ diff --git a/libfrog/paths.c b/libfrog/paths.c index d8c42163a7b..b3c5236990e 100644 --- a/libfrog/paths.c +++ b/libfrog/paths.c @@ -15,6 +15,7 @@ #include "paths.h" #include "input.h" #include "projects.h" +#include "list.h" #include extern char *progname; @@ -567,3 +568,169 @@ fs_table_insert_project_path( return error; } + +/* Structured path components. */ + +struct path_list { + struct list_head p_head; +}; + +struct path_component { + struct list_head pc_list; + uint64_t pc_ino; + char *pc_fname; +}; + +/* Initialize a path component with a given name. */ +struct path_component * +path_component_init( + const char *name, + uint64_t ino) +{ + struct path_component *pc; + + pc = malloc(sizeof(struct path_component)); + if (!pc) + return NULL; + INIT_LIST_HEAD(&pc->pc_list); + pc->pc_fname = strdup(name); + if (!pc->pc_fname) { + free(pc); + return NULL; + } + pc->pc_ino = ino; + return pc; +} + +/* Free a path component. */ +void +path_component_free( + struct path_component *pc) +{ + free(pc->pc_fname); + free(pc); +} + +/* Change a path component's filename or returns positive errno. */ +int +path_component_change( + struct path_component *pc, + const void *name, + size_t namelen, + uint64_t ino) +{ + void *p; + + p = realloc(pc->pc_fname, namelen + 1); + if (!p) + return errno; + pc->pc_fname = p; + memcpy(pc->pc_fname, name, namelen); + pc->pc_fname[namelen] = 0; + pc->pc_ino = ino; + return 0; +} + +/* Initialize a pathname or returns positive errno. */ +struct path_list * +path_list_init(void) +{ + struct path_list *path; + + path = malloc(sizeof(struct path_list)); + if (!path) + return NULL; + INIT_LIST_HEAD(&path->p_head); + return path; +} + +/* Empty out a pathname. */ +void +path_list_free( + struct path_list *path) +{ + struct path_component *pos; + struct path_component *n; + + list_for_each_entry_safe(pos, n, &path->p_head, pc_list) { + path_list_del_component(path, pos); + path_component_free(pos); + } + free(path); +} + +/* Add a parent component to a pathname. */ +void +path_list_add_parent_component( + struct path_list *path, + struct path_component *pc) +{ + list_add(&pc->pc_list, &path->p_head); +} + +/* Add a component to a pathname. */ +void +path_list_add_component( + struct path_list *path, + struct path_component *pc) +{ + list_add_tail(&pc->pc_list, &path->p_head); +} + +/* Remove a component from a pathname. */ +void +path_list_del_component( + struct path_list *path, + struct path_component *pc) +{ + list_del_init(&pc->pc_list); +} + +/* + * Convert a pathname into a string or returns -1 if the buffer isn't long + * enough. + */ +ssize_t +path_list_to_string( + const struct path_list *path, + char *buf, + size_t buflen) +{ + struct path_component *pos; + char *buf_end = buf + buflen; + ssize_t bytes = 0; + int ret; + + list_for_each_entry(pos, &path->p_head, pc_list) { + if (buf >= buf_end) + return -1; + + ret = snprintf(buf, buflen, "/%s", pos->pc_fname); + if (ret < 0 || ret >= buflen) + return -1; + + bytes += ret; + buf += ret; + buflen -= ret; + } + return bytes; +} + +/* Walk each component of a path. */ +int +path_walk_components( + const struct path_list *path, + path_walk_fn_t fn, + void *arg) +{ + struct path_component *pos; + int ret; + + list_for_each_entry(pos, &path->p_head, pc_list) { + ret = fn(pos->pc_fname, pos->pc_ino, arg); + if (ret) + return ret; + } + + return 0; +} diff --git a/libfrog/paths.h b/libfrog/paths.h index f20a2c3ef58..6be74c42b07 100644 --- a/libfrog/paths.h +++ b/libfrog/paths.h @@ -58,4 +58,29 @@ typedef struct fs_cursor { extern void fs_cursor_initialise(char *__dir, uint __flags, fs_cursor_t *__cp); extern fs_path_t *fs_cursor_next_entry(fs_cursor_t *__cp); +/* Path information. */ + +struct path_list; +struct path_component; + +struct path_component *path_component_init(const char *name, uint64_t ino); +void path_component_free(struct path_component *pc); +int path_component_change(struct path_component *pc, const void *name, + size_t namelen, uint64_t ino); + +struct path_list *path_list_init(void); +void path_list_free(struct path_list *path); +void path_list_add_parent_component(struct path_list *path, + struct path_component *pc); +void path_list_add_component(struct path_list *path, struct path_component *pc); +void path_list_del_component(struct path_list *path, struct path_component *pc); + +ssize_t path_list_to_string(const struct path_list *path, char *buf, + size_t buflen); + +typedef int (*path_walk_fn_t)(const char *name, uint64_t ino, void *arg); + +int path_walk_components(const struct path_list *path, path_walk_fn_t fn, + void *arg); + #endif /* __LIBFROG_PATH_H__ */ diff --git a/libhandle/handle.c b/libhandle/handle.c index 333c2190900..1e8fe9ac5f1 100644 --- a/libhandle/handle.c +++ b/libhandle/handle.c @@ -29,7 +29,6 @@ typedef union { } comarg_t; static int obj_to_handle(char *, int, unsigned int, comarg_t, void**, size_t*); -static int handle_to_fsfd(void *, char **); static char *path_to_fspath(char *path); @@ -203,8 +202,10 @@ handle_to_fshandle( return 0; } -static int -handle_to_fsfd(void *hanp, char **path) +int +handle_to_fsfd( + void *hanp, + char **path) { struct fdhash *fdhp; From patchwork Sun Dec 31 23:09: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: 13508040 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 26D76C140 for ; Sun, 31 Dec 2023 23:09:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="CkmV6BLl" Received: by smtp.kernel.org (Postfix) with ESMTPSA id A8A0AC433C7; Sun, 31 Dec 2023 23:09:32 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704064172; bh=eD6hId5iVU7eKY6ieu3rVkUF4f+CTaSLVtQrswWg7bY=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=CkmV6BLl0+g/xP0Ow8flLfBIGZFBCMn2iAeWhoUWemKuMi33wOLWha7ptk/by6uXb e+0hThsFtNGHu+qFlOGJtitAKKDnqSOFQ3a6JK2E8M+J+Nj8CXtXxqQ1H1I9u3RS2o /25XIjHK9EvmwxDCQVuJOiUKPIGmS23itLr9PXETffXFjfFSVzmySnSWGdZbvtdNyd XxcB8x2JhGTLrkwV0YXahEYTYR5unU3SIlh+Ohw9Rd46ovY2lYZZzu0xYARMEJaNgq khj/Tv+j/S+N73lvhlptbWmisQL1mhuDLwo0TeI/K5IpPJIhSEckUnRh8XaKLsJiLQ 5cEr3aeYD3ESw== Date: Sun, 31 Dec 2023 15:09:32 -0800 Subject: [PATCH 17/32] libfrog: detect looping paths when walking directory parent pointers From: "Darrick J. Wong" To: djwong@kernel.org, cem@kernel.org Cc: catherine.hoang@oracle.com, linux-xfs@vger.kernel.org, allison.henderson@oracle.com Message-ID: <170405006328.1804688.14864529372800053315.stgit@frogsfrogsfrogs> In-Reply-To: <170405006077.1804688.8762482665401724622.stgit@frogsfrogsfrogs> References: <170405006077.1804688.8762482665401724622.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 Detect loops when we're walking directory parent pointers so that we don't loop infinitely. Signed-off-by: Darrick J. Wong --- libfrog/getparents.c | 3 +++ libfrog/paths.c | 16 ++++++++++++++++ libfrog/paths.h | 2 ++ 3 files changed, 21 insertions(+) diff --git a/libfrog/getparents.c b/libfrog/getparents.c index 016fe3f026d..fa4e4a1c9c0 100644 --- a/libfrog/getparents.c +++ b/libfrog/getparents.c @@ -148,6 +148,9 @@ handle_walk_ppath_rec( if (rec->p_flags & PARENT_IS_ROOT) return wpi->fn(wpi->mntpt, wpi->path, wpi->arg); + if (path_will_loop(wpi->path, rec->p_ino)) + return 0; + ret = path_component_change(wpli->pc, rec->p_name, strlen((char *)rec->p_name), rec->p_ino); if (ret) diff --git a/libfrog/paths.c b/libfrog/paths.c index b3c5236990e..9ba2a2f313b 100644 --- a/libfrog/paths.c +++ b/libfrog/paths.c @@ -734,3 +734,19 @@ path_walk_components( return 0; } + +/* Will this path contain a loop if we add this inode? */ +bool +path_will_loop( + const struct path_list *path_list, + uint64_t ino) +{ + struct path_component *pc; + + list_for_each_entry(pc, &path_list->p_head, pc_list) { + if (pc->pc_ino == ino) + return true; + } + + return false; +} diff --git a/libfrog/paths.h b/libfrog/paths.h index 6be74c42b07..895171aa342 100644 --- a/libfrog/paths.h +++ b/libfrog/paths.h @@ -83,4 +83,6 @@ typedef int (*path_walk_fn_t)(const char *name, uint64_t ino, void *arg); int path_walk_components(const struct path_list *path, path_walk_fn_t fn, void *arg); +bool path_will_loop(const struct path_list *path, uint64_t ino); + #endif /* __LIBFROG_PATH_H__ */ From patchwork Sun Dec 31 23:09: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: 13508041 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 6B06AC147 for ; Sun, 31 Dec 2023 23:09:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="e8dkopc4" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 3616BC433C7; Sun, 31 Dec 2023 23:09:48 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704064188; bh=kmTZOYBq94czzAuxLymgJJOHMHwYA5F5eqzj34WJ79U=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=e8dkopc4NH6pz//wXm3IsClistNXyqiwBMMysi0fKDMYbS4+f/Au3IRmEwoM5eTDg OCpUc8whJ0ZS7NRwzR6TCq/ifUKHtC0zQIqt4xC2sT4/KCt1JJ3DbFWk1rDzFxBU0F +NVKB4SDmaXkDJT2BxHfCD4uKfTt8nJAdf9YdnP0P6OhuMyCc2X1b4WkQi7oRuuMRX r4458BV4llrsoFizjjnBsYDxLhLceUUgmW7O8vvL3jixgQjpb/RK/xY7XWV3uETkTf 2ujpQOJ+NjmoahyObP5kCNzv5MqvuioE2apQOzdsXUXJmAApZK/kbUe8A2Qen8eAFG 6ZgNv48iUi4ow== Date: Sun, 31 Dec 2023 15:09:47 -0800 Subject: [PATCH 18/32] xfs_io: adapt parent command to new parent pointer ioctls From: "Darrick J. Wong" To: djwong@kernel.org, cem@kernel.org Cc: Allison Henderson , catherine.hoang@oracle.com, linux-xfs@vger.kernel.org, allison.henderson@oracle.com Message-ID: <170405006341.1804688.11009892277015794783.stgit@frogsfrogsfrogs> In-Reply-To: <170405006077.1804688.8762482665401724622.stgit@frogsfrogsfrogs> References: <170405006077.1804688.8762482665401724622.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 ages, xfs_io has had a totally useless 'parent' command that enabled callers to walk the parents or print the directory tree path of an open file. This code used the ioctl interface presented by SGI's version of parent pointers that was never merged. Rework the code in here to use the new ioctl interfaces that we've settled upon. Get rid of the old parent pointer checking code since xfs_repair/xfs_scrub will take care of that. (This originally was in the "xfsprogs: implement the upper half of parent pointers" megapatch.) Signed-off-by: Darrick J. Wong Reviewed-by: Allison Henderson --- io/parent.c | 470 ++++++++++++++--------------------------------------- man/man8/xfs_io.8 | 21 +- 2 files changed, 133 insertions(+), 358 deletions(-) diff --git a/io/parent.c b/io/parent.c index 8f63607ffec..65fd892bffc 100644 --- a/io/parent.c +++ b/io/parent.c @@ -7,365 +7,112 @@ #include "command.h" #include "input.h" #include "libfrog/paths.h" -#include "parent.h" +#include "libfrog/getparents.h" #include "handle.h" -#include "jdm.h" #include "init.h" #include "io.h" -#define PARENTBUF_SZ 16384 -#define BSTATBUF_SZ 16384 - static cmdinfo_t parent_cmd; -static int verbose_flag; -static int err_status; -static __u64 inodes_checked; static char *mntpt; -/* - * check out a parent entry to see if the values seem valid - */ -static void -check_parent_entry(struct xfs_bstat *bstatp, parent_t *parent) +static int +pptr_print( + const struct parent_rec *rec, + void *arg) { - int sts; - char fullpath[PATH_MAX]; - struct stat statbuf; - char *str; - - sprintf(fullpath, _("%s%s"), mntpt, parent->p_name); - - sts = lstat(fullpath, &statbuf); - if (sts != 0) { - fprintf(stderr, - _("inode-path for inode: %llu is incorrect - path \"%s\" non-existent\n"), - (unsigned long long) bstatp->bs_ino, fullpath); - if (verbose_flag) { - fprintf(stderr, - _("path \"%s\" does not stat for inode: %llu; err = %s\n"), - fullpath, - (unsigned long long) bstatp->bs_ino, - strerror(errno)); - } - err_status++; - return; - } else { - if (verbose_flag > 1) { - printf(_("path \"%s\" found\n"), fullpath); - } - } - - if (statbuf.st_ino != bstatp->bs_ino) { - fprintf(stderr, - _("inode-path for inode: %llu is incorrect - wrong inode#\n"), - (unsigned long long) bstatp->bs_ino); - if (verbose_flag) { - fprintf(stderr, - _("ino mismatch for path \"%s\" %llu vs %llu\n"), - fullpath, - (unsigned long long)statbuf.st_ino, - (unsigned long long)bstatp->bs_ino); - } - err_status++; - return; - } else if (verbose_flag > 1) { - printf(_("inode number match: %llu\n"), - (unsigned long long)statbuf.st_ino); - } + const char *name = (char *)rec->p_name; + unsigned int namelen; - /* get parent path */ - str = strrchr(fullpath, '/'); - *str = '\0'; - sts = stat(fullpath, &statbuf); - if (sts != 0) { - fprintf(stderr, - _("parent path \"%s\" does not stat: %s\n"), - fullpath, - strerror(errno)); - err_status++; - return; - } else { - if (parent->p_ino != statbuf.st_ino) { - fprintf(stderr, - _("inode-path for inode: %llu is incorrect - wrong parent inode#\n"), - (unsigned long long) bstatp->bs_ino); - if (verbose_flag) { - fprintf(stderr, - _("ino mismatch for path \"%s\" %llu vs %llu\n"), - fullpath, - (unsigned long long)parent->p_ino, - (unsigned long long)statbuf.st_ino); - } - err_status++; - return; - } else { - if (verbose_flag > 1) { - printf(_("parent ino match for %llu\n"), - (unsigned long long) parent->p_ino); - } - } + if (rec->p_flags & PARENT_IS_ROOT) { + printf(_("Root directory.\n")); + return 0; } -} - -static void -check_parents(parent_t *parentbuf, size_t *parentbuf_size, - jdm_fshandle_t *fshandlep, struct xfs_bstat *statp) -{ - int error, i; - __u32 count; - parent_t *entryp; - - do { - error = jdm_parentpaths(fshandlep, statp, parentbuf, *parentbuf_size, &count); - - if (error == ERANGE) { - *parentbuf_size *= 2; - parentbuf = (parent_t *)realloc(parentbuf, *parentbuf_size); - } else if (error) { - fprintf(stderr, _("parentpaths failed for ino %llu: %s\n"), - (unsigned long long) statp->bs_ino, - strerror(errno)); - err_status++; - break; - } - } while (error == ERANGE); - - if (count == 0) { - /* no links for inode - something wrong here */ - fprintf(stderr, _("inode-path for inode: %llu is missing\n"), - (unsigned long long) statp->bs_ino); - err_status++; - } + namelen = strlen(name); + printf(_("p_ino = %llu\n"), (unsigned long long)rec->p_ino); + printf(_("p_gen = %u\n"), (unsigned int)rec->p_gen); + printf(_("p_namelen = %u\n"), namelen); + printf(_("p_name = \"%s\"\n\n"), rec->p_name); - entryp = parentbuf; - for (i = 0; i < count; i++) { - check_parent_entry(statp, entryp); - entryp = (parent_t*) (((char*)entryp) + entryp->p_reclen); - } + return 0; } static int -do_bulkstat(parent_t *parentbuf, size_t *parentbuf_size, - struct xfs_bstat *bstatbuf, int fsfd, jdm_fshandle_t *fshandlep) +print_parents( + struct xfs_handle *handle) { - __s32 buflenout; - __u64 lastino = 0; - struct xfs_bstat *p; - struct xfs_bstat *endp; - struct xfs_fsop_bulkreq bulkreq; - struct stat mntstat; - - if (stat(mntpt, &mntstat)) { - fprintf(stderr, _("can't stat mount point \"%s\": %s\n"), - mntpt, strerror(errno)); - return 1; - } - - bulkreq.lastip = &lastino; - bulkreq.icount = BSTATBUF_SZ; - bulkreq.ubuffer = (void *)bstatbuf; - bulkreq.ocount = &buflenout; - - while (xfsctl(mntpt, fsfd, XFS_IOC_FSBULKSTAT, &bulkreq) == 0) { - if (*(bulkreq.ocount) == 0) { - return 0; - } - for (p = bstatbuf, endp = bstatbuf + *bulkreq.ocount; p < endp; p++) { - - /* inode being modified, get synced data with iget */ - if ( (!p->bs_nlink || !p->bs_mode) && p->bs_ino != 0 ) { - - if (xfsctl(mntpt, fsfd, XFS_IOC_FSBULKSTAT_SINGLE, &bulkreq) < 0) { - fprintf(stderr, - _("failed to get bulkstat information for inode %llu\n"), - (unsigned long long) p->bs_ino); - continue; - } - if (!p->bs_nlink || !p->bs_mode || !p->bs_ino) { - fprintf(stderr, - _("failed to get valid bulkstat information for inode %llu\n"), - (unsigned long long) p->bs_ino); - continue; - } - } - - /* skip root */ - if (p->bs_ino == mntstat.st_ino) { - continue; - } - - if (verbose_flag > 1) { - printf(_("checking inode %llu\n"), - (unsigned long long) p->bs_ino); - } - - /* print dotted progress */ - if ((inodes_checked % 100) == 0 && verbose_flag == 1) { - printf("."); fflush(stdout); - } - inodes_checked++; - - check_parents(parentbuf, parentbuf_size, fshandlep, p); - } + int ret; - }/*while*/ + if (handle) + ret = handle_walk_parents(handle, sizeof(*handle), pptr_print, + NULL); + else + ret = fd_walk_parents(file->fd, pptr_print, NULL); + if (ret) + fprintf(stderr, "%s: %s\n", file->name, strerror(ret)); - fprintf(stderr, _("syssgi bulkstat failed: %s\n"), strerror(errno)); - return 1; + return 0; } static int -parent_check(void) +path_print( + const char *mntpt, + const struct path_list *path, + void *arg) { - int fsfd; - jdm_fshandle_t *fshandlep; - parent_t *parentbuf; - size_t parentbuf_size = PARENTBUF_SZ; - struct xfs_bstat *bstatbuf; - - err_status = 0; - inodes_checked = 0; - - sync(); - - fsfd = file->fd; - - fshandlep = jdm_getfshandle(mntpt); - if (fshandlep == NULL) { - fprintf(stderr, _("unable to open \"%s\" for jdm: %s\n"), - mntpt, - strerror(errno)); - return 1; - } + char buf[PATH_MAX]; + size_t len = PATH_MAX; + int mntpt_len = strlen(mntpt); + int ret; - /* allocate buffers */ - bstatbuf = (struct xfs_bstat *)calloc(BSTATBUF_SZ, sizeof(struct xfs_bstat)); - parentbuf = (parent_t *)malloc(parentbuf_size); - if (!bstatbuf || !parentbuf) { - fprintf(stderr, _("unable to allocate buffers: %s\n"), - strerror(errno)); - err_status = 1; - goto out; - } - - if (do_bulkstat(parentbuf, &parentbuf_size, bstatbuf, fsfd, fshandlep) != 0) - err_status++; + /* Trim trailing slashes from the mountpoint */ + while (mntpt_len > 0 && mntpt[mntpt_len - 1] == '/') + mntpt_len--; - if (err_status > 0) - fprintf(stderr, _("num errors: %d\n"), err_status); - else - printf(_("succeeded checking %llu inodes\n"), - (unsigned long long) inodes_checked); + ret = snprintf(buf, len, "%.*s", mntpt_len, mntpt); + if (ret != mntpt_len) + return ENAMETOOLONG; -out: - free(bstatbuf); - free(parentbuf); - free(fshandlep); - return err_status; -} + ret = path_list_to_string(path, buf + ret, len - ret); + if (ret < 0) + return ENAMETOOLONG; -static void -print_parent_entry(parent_t *parent, int fullpath) -{ - printf(_("p_ino = %llu\n"), (unsigned long long) parent->p_ino); - printf(_("p_gen = %u\n"), parent->p_gen); - printf(_("p_reclen = %u\n"), parent->p_reclen); - if (fullpath) - printf(_("p_name = \"%s%s\"\n"), mntpt, parent->p_name); - else - printf(_("p_name = \"%s\"\n"), parent->p_name); + printf("%s\n", buf); + return 0; } static int -parent_list(int fullpath) +print_paths( + struct xfs_handle *handle) { - void *handlep = NULL; - size_t handlen; - int error, i; - int retval = 1; - __u32 count; - parent_t *entryp; - parent_t *parentbuf = NULL; - char *path = file->name; - int pb_size = PARENTBUF_SZ; + int ret; - /* XXXX for linux libhandle version - to set libhandle fsfd cache */ - { - void *fshandle; - size_t fshlen; - - if (path_to_fshandle(mntpt, &fshandle, &fshlen) != 0) { - fprintf(stderr, _("%s: failed path_to_fshandle \"%s\": %s\n"), - progname, path, strerror(errno)); - goto error; - } - free_handle(fshandle, fshlen); - } - - if (path_to_handle(path, &handlep, &handlen) != 0) { - fprintf(stderr, _("%s: path_to_handle failed for \"%s\"\n"), progname, path); - goto error; - } - - do { - parentbuf = (parent_t *)realloc(parentbuf, pb_size); - if (!parentbuf) { - fprintf(stderr, _("%s: unable to allocate parent buffer: %s\n"), - progname, strerror(errno)); - goto error; - } - - if (fullpath) { - error = parentpaths_by_handle(handlep, - handlen, - parentbuf, - pb_size, - &count); - } else { - error = parents_by_handle(handlep, - handlen, - parentbuf, - pb_size, - &count); - } - if (error == ERANGE) { - pb_size *= 2; - } else if (error) { - fprintf(stderr, _("%s: %s call failed for \"%s\": %s\n"), - progname, fullpath ? "parentpaths" : "parents", - path, strerror(errno)); - goto error; - } - } while (error == ERANGE); - - if (count == 0) { - /* no links for inode - something wrong here */ - fprintf(stderr, _("%s: inode-path is missing\n"), progname); - goto error; - } - - entryp = parentbuf; - for (i = 0; i < count; i++) { - print_parent_entry(entryp, fullpath); - entryp = (parent_t*) (((char*)entryp) + entryp->p_reclen); - } - - retval = 0; -error: - free(handlep); - free(parentbuf); - return retval; + if (handle) + ret = handle_walk_parent_paths(handle, sizeof(*handle), + path_print, NULL); + else + ret = fd_walk_parent_paths(file->fd, path_print, NULL); + if (ret) + fprintf(stderr, "%s: %s\n", file->name, strerror(ret)); + return 0; } static int -parent_f(int argc, char **argv) +parent_f( + int argc, + char **argv) { - int c; - int listpath_flag = 0; - int check_flag = 0; - fs_path_t *fs; - static int tab_init; + struct xfs_handle handle; + void *hanp = NULL; + size_t hlen; + struct fs_path *fs; + char *p; + uint64_t ino = 0; + uint32_t gen = 0; + int c; + int listpath_flag = 0; + int ret; + static int tab_init; if (!tab_init) { tab_init = 1; @@ -380,46 +127,74 @@ parent_f(int argc, char **argv) } mntpt = fs->fs_dir; - verbose_flag = 0; - - while ((c = getopt(argc, argv, "cpv")) != EOF) { + while ((c = getopt(argc, argv, "p")) != EOF) { switch (c) { - case 'c': - check_flag = 1; - break; case 'p': listpath_flag = 1; break; - case 'v': - verbose_flag++; - break; default: return command_usage(&parent_cmd); } } - if (!check_flag && !listpath_flag) /* default case */ - exitcode = parent_list(listpath_flag); - else { - if (listpath_flag) - exitcode = parent_list(listpath_flag); - if (check_flag) - exitcode = parent_check(); + /* + * Always initialize the fshandle table because we need it for + * the ppaths functions to work. + */ + ret = path_to_fshandle((char *)mntpt, &hanp, &hlen); + if (ret) { + perror(mntpt); + return 0; } + if (optind + 2 == argc) { + ino = strtoull(argv[optind], &p, 0); + if (*p != '\0' || ino == 0) { + fprintf(stderr, + _("Bad inode number '%s'.\n"), + argv[optind]); + return 0; + } + gen = strtoul(argv[optind + 1], &p, 0); + if (*p != '\0') { + fprintf(stderr, + _("Bad generation number '%s'.\n"), + argv[optind + 1]); + return 0; + } + + memcpy(&handle, hanp, sizeof(handle)); + handle.ha_fid.fid_len = sizeof(xfs_fid_t) - + sizeof(handle.ha_fid.fid_len); + handle.ha_fid.fid_pad = 0; + handle.ha_fid.fid_ino = ino; + handle.ha_fid.fid_gen = gen; + + } else if (optind != argc) { + return command_usage(&parent_cmd); + } + + if (listpath_flag) + exitcode = print_paths(ino ? &handle : NULL); + else + exitcode = print_parents(ino ? &handle : NULL); + + if (hanp) + free_handle(hanp, hlen); + return 0; } static void parent_help(void) { - printf(_( +printf(_( "\n" " list the current file's parents and their filenames\n" "\n" -" -c -- check the current file's file system for parent consistency\n" -" -p -- list the current file's parents and their full paths\n" -" -v -- verbose mode\n" +" -p -- list the current file's paths up to the root\n" +"\n" +"If ino and gen are supplied, use them instead.\n" "\n")); } @@ -430,11 +205,10 @@ parent_init(void) parent_cmd.cfunc = parent_f; parent_cmd.argmin = 0; parent_cmd.argmax = -1; - parent_cmd.args = _("[-cpv]"); + parent_cmd.args = _("[-p] [ino gen]"); parent_cmd.flags = CMD_NOMAP_OK; - parent_cmd.oneline = _("print or check parent inodes"); + parent_cmd.oneline = _("print parent inodes"); parent_cmd.help = parent_help; - if (expert) - add_command(&parent_cmd); + add_command(&parent_cmd); } diff --git a/man/man8/xfs_io.8 b/man/man8/xfs_io.8 index 6ebb479a344..4eda47c2772 100644 --- a/man/man8/xfs_io.8 +++ b/man/man8/xfs_io.8 @@ -1016,25 +1016,26 @@ and options behave as described above, in .B chproj. .TP -.BR parent " [ " \-cpv " ]" +.BR parent " [ " \-p " ] [" " ino gen " "]" By default this command prints out the parent inode numbers, inode generation numbers and basenames of all the hardlinks which point to the inode of the current file. + +If the optional +.B ino +and +.B gen +parameters are provided, they will be used to create a file handle on the same +filesystem as the open file. +The parents of the file represented by the handle will be reported instead of +the open file. + .RS 1.0i .PD 0 .TP 0.4i .B \-p the output is similar to the default output except pathnames up to the mount-point are printed out instead of the component name. -.TP -.B \-c -the file's filesystem will check all the parent attributes for consistency. -.TP -.B \-v -verbose output will be printed. -.RE -.IP -.B [NOTE: Not currently operational on Linux.] .RE .PD .TP From patchwork Sun Dec 31 23:10: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: 13508042 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 201ECC147 for ; Sun, 31 Dec 2023 23:10:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="iNMJ4lOQ" Received: by smtp.kernel.org (Postfix) with ESMTPSA id E7326C433C8; Sun, 31 Dec 2023 23:10:03 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704064203; bh=WqYsdYFO2aJe9nirGx9Eg324mJN/X9vrvMPI3PO79HU=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=iNMJ4lOQCNo2t+kfp2eGYUqa9Mc2lVCNBI48zSYyqCUIwC8g1AqhES7jCzGEnSvqp kUS2+3c5rUYq0vk21uN7dOftskKEFX44DuNgUUQi+T5wRIuaseSwmSdvX/kj0d5mAL Wox/sytZ0WGzUj7xuZwyKxPy9hy33xB2eOU1IhdrJo8YzbFcyKYJnqE0QlU6bhgLST co8aPwISi0oY4o11e/FEvBNG/HABVX5VpTGbSUKSJQH6nt48AE/QiLseIHmdSPSC9k SaOXd9NBk4OFl2YND40wS7d2eSZklEI/lq7veAIrdJP3jioPiLipvHQCexPG3BIDTE ulVw3NKmy17/w== Date: Sun, 31 Dec 2023 15:10:03 -0800 Subject: [PATCH 19/32] xfs_io: Add i, n and f flags to parent command From: "Darrick J. Wong" To: djwong@kernel.org, cem@kernel.org Cc: Allison Henderson , catherine.hoang@oracle.com, linux-xfs@vger.kernel.org, allison.henderson@oracle.com Message-ID: <170405006355.1804688.5667520525117208449.stgit@frogsfrogsfrogs> In-Reply-To: <170405006077.1804688.8762482665401724622.stgit@frogsfrogsfrogs> References: <170405006077.1804688.8762482665401724622.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: Allison Henderson This patch adds the flags i, n, and f to the parent command. These flags add filtering options that are used by the new parent pointer tests in xfstests, and help to improve the test run time. The flags are: -i: Only show parent pointer records containing the given inode -n: Only show parent pointer records containing the given filename -f: Print records in short format: ino/gen/namelen/name Signed-off-by: Allison Henderson Reviewed-by: Darrick J. Wong [djwong: adapt to new getparents ioctl] Signed-off-by: Darrick J. Wong --- io/parent.c | 89 +++++++++++++++++++++++++++++++++++++++++++++++------ man/man8/xfs_io.8 | 11 ++++++- 2 files changed, 89 insertions(+), 11 deletions(-) diff --git a/io/parent.c b/io/parent.c index 65fd892bffc..6bb7571e1bd 100644 --- a/io/parent.c +++ b/io/parent.c @@ -15,11 +15,18 @@ static cmdinfo_t parent_cmd; static char *mntpt; +struct pptr_args { + uint64_t filter_ino; + char *filter_name; + bool shortformat; +}; + static int pptr_print( const struct parent_rec *rec, void *arg) { + struct pptr_args *args = arg; const char *name = (char *)rec->p_name; unsigned int namelen; @@ -28,7 +35,22 @@ pptr_print( return 0; } + if (args->filter_ino && rec->p_ino != args->filter_ino) + return 0; + if (args->filter_name && strcmp(args->filter_name, name)) + return 0; + namelen = strlen(name); + + if (args->shortformat) { + printf("%llu/%u/%u/%s\n", + (unsigned long long)rec->p_ino, + (unsigned int)rec->p_gen, + namelen, + rec->p_name); + return 0; + } + printf(_("p_ino = %llu\n"), (unsigned long long)rec->p_ino); printf(_("p_gen = %u\n"), (unsigned int)rec->p_gen); printf(_("p_namelen = %u\n"), namelen); @@ -39,32 +61,55 @@ pptr_print( static int print_parents( - struct xfs_handle *handle) + struct xfs_handle *handle, + struct pptr_args *args) { int ret; if (handle) ret = handle_walk_parents(handle, sizeof(*handle), pptr_print, - NULL); + args); else - ret = fd_walk_parents(file->fd, pptr_print, NULL); + ret = fd_walk_parents(file->fd, pptr_print, args); if (ret) fprintf(stderr, "%s: %s\n", file->name, strerror(ret)); return 0; } +static int +filter_path_components( + const char *name, + uint64_t ino, + void *arg) +{ + struct pptr_args *args = arg; + + if (args->filter_ino && ino == args->filter_ino) + return ECANCELED; + if (args->filter_name && !strcmp(args->filter_name, name)) + return ECANCELED; + return 0; +} + static int path_print( const char *mntpt, const struct path_list *path, void *arg) { + struct pptr_args *args = arg; char buf[PATH_MAX]; size_t len = PATH_MAX; int mntpt_len = strlen(mntpt); int ret; + if (args->filter_ino || args->filter_name) { + ret = path_walk_components(path, filter_path_components, args); + if (ret != ECANCELED) + return 0; + } + /* Trim trailing slashes from the mountpoint */ while (mntpt_len > 0 && mntpt[mntpt_len - 1] == '/') mntpt_len--; @@ -83,15 +128,16 @@ path_print( static int print_paths( - struct xfs_handle *handle) + struct xfs_handle *handle, + struct pptr_args *args) { int ret; if (handle) ret = handle_walk_parent_paths(handle, sizeof(*handle), - path_print, NULL); + path_print, args); else - ret = fd_walk_parent_paths(file->fd, path_print, NULL); + ret = fd_walk_parent_paths(file->fd, path_print, args); if (ret) fprintf(stderr, "%s: %s\n", file->name, strerror(ret)); return 0; @@ -103,6 +149,7 @@ parent_f( char **argv) { struct xfs_handle handle; + struct pptr_args args = { 0 }; void *hanp = NULL; size_t hlen; struct fs_path *fs; @@ -127,11 +174,27 @@ parent_f( } mntpt = fs->fs_dir; - while ((c = getopt(argc, argv, "p")) != EOF) { + while ((c = getopt(argc, argv, "pfi:n:")) != EOF) { switch (c) { case 'p': listpath_flag = 1; break; + case 'i': + args.filter_ino = strtoull(optarg, &p, 0); + if (*p != '\0' || args.filter_ino == 0) { + fprintf(stderr, + _("Bad inode number '%s'.\n"), + optarg); + return 0; + } + + break; + case 'n': + args.filter_name = optarg; + break; + case 'f': + args.shortformat = true; + break; default: return command_usage(&parent_cmd); } @@ -175,9 +238,9 @@ parent_f( } if (listpath_flag) - exitcode = print_paths(ino ? &handle : NULL); + exitcode = print_paths(ino ? &handle : NULL, &args); else - exitcode = print_parents(ino ? &handle : NULL); + exitcode = print_parents(ino ? &handle : NULL, &args); if (hanp) free_handle(hanp, hlen); @@ -195,6 +258,12 @@ printf(_( " -p -- list the current file's paths up to the root\n" "\n" "If ino and gen are supplied, use them instead.\n" +"\n" +" -i -- Only show parent pointer records containing the given inode\n" +"\n" +" -n -- Only show parent pointer records containing the given filename\n" +"\n" +" -f -- Print records in short format: ino/gen/namelen/filename\n" "\n")); } @@ -205,7 +274,7 @@ parent_init(void) parent_cmd.cfunc = parent_f; parent_cmd.argmin = 0; parent_cmd.argmax = -1; - parent_cmd.args = _("[-p] [ino gen]"); + parent_cmd.args = _("[-p] [ino gen] [-i ino] [-n name] [-f]"); parent_cmd.flags = CMD_NOMAP_OK; parent_cmd.oneline = _("print parent inodes"); parent_cmd.help = parent_help; diff --git a/man/man8/xfs_io.8 b/man/man8/xfs_io.8 index 4eda47c2772..aa9907c1e5e 100644 --- a/man/man8/xfs_io.8 +++ b/man/man8/xfs_io.8 @@ -1016,7 +1016,7 @@ and options behave as described above, in .B chproj. .TP -.BR parent " [ " \-p " ] [" " ino gen " "]" +.BR parent " [ " \-fp " ] [-i " ino "] [-n " name "] [" " ino gen " "]" By default this command prints out the parent inode numbers, inode generation numbers and basenames of all the hardlinks which point to the inode of the current file. @@ -1033,6 +1033,15 @@ the open file. .RS 1.0i .PD 0 .TP 0.4i +.B \-f +Print records in short format: ino/gen/namelen/name +.TP 0.4i +.B \-i +Only show parent pointer records containing this inode number. +.TP 0.4i +.B \-n +Only show parent pointer records containing this directory entry name. +.TP 0.4i .B \-p the output is similar to the default output except pathnames up to the mount-point are printed out instead of the component name. From patchwork Sun Dec 31 23:10: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: 13508043 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 AFE2DC154 for ; Sun, 31 Dec 2023 23:10:19 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="IQj6T4kd" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 7F6C4C433C8; Sun, 31 Dec 2023 23:10:19 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704064219; bh=IvoEZEncoNCSumIANu5vGkmZUDvZMskNk21AEZcm0CA=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=IQj6T4kdEmzYGUMYuFMkwOMisxDSP+jw+TTfjYSXhHPGUpW5/SY+/Xcpj/B4SoxFE gd3SRjnlsqFepcZ5fCEBlb7XdyhOcH/aYCLH9qLlaDbUkQXKSJ18w06SMr6beGu4RY oiDcJwqegdgJFcH775thHsUDpwquMtHSXjZ3y4qwwW5FkuBcaRb55c+dSrGVcWtvKW SeFGtyVMTJ+4775v4kLIVlm4dlCWY6q00BmcRDY3UafQrvgaxgzLrqkFeA3hlDoNs9 91AsiJcyq1fXIthNyQ17j/R/QpPmrj1fO9Ri9OXv9ZTsWl9RUtYVcIdCjNYDcbXHZs OqoY/T0RSdumw== Date: Sun, 31 Dec 2023 15:10:19 -0800 Subject: [PATCH 20/32] xfs_logprint: decode parent pointers in ATTRI items fully From: "Darrick J. Wong" To: djwong@kernel.org, cem@kernel.org Cc: Allison Henderson , catherine.hoang@oracle.com, linux-xfs@vger.kernel.org, allison.henderson@oracle.com Message-ID: <170405006368.1804688.13069374496914124680.stgit@frogsfrogsfrogs> In-Reply-To: <170405006077.1804688.8762482665401724622.stgit@frogsfrogsfrogs> References: <170405006077.1804688.8762482665401724622.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: Allison Henderson This patch modifies the ATTRI print routines to look for the parent pointer flag, and decode logged parent pointers fully when dumping log contents. Between the existing ATTRI: printouts and the new ones introduced here, we can figure out what was stored in each log iovec, as well as the higher level parent pointer that was logged. Signed-off-by: Allison Henderson Reviewed-by: Darrick J. Wong [djwong: adjust to new ondisk format] Signed-off-by: Darrick J. Wong --- libxfs/libxfs_api_defs.h | 4 ++ logprint/log_redo.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+) diff --git a/libxfs/libxfs_api_defs.h b/libxfs/libxfs_api_defs.h index 1b69124767c..c94972fb84b 100644 --- a/libxfs/libxfs_api_defs.h +++ b/libxfs/libxfs_api_defs.h @@ -177,6 +177,10 @@ #define xfs_log_sb libxfs_log_sb #define xfs_mode_to_ftype libxfs_mode_to_ftype #define xfs_mkdir_space_res libxfs_mkdir_space_res +#define xfs_parent_add libxfs_parent_add +#define xfs_parent_finish libxfs_parent_finish +#define xfs_parent_irec_from_disk libxfs_parent_irec_from_disk +#define xfs_parent_start libxfs_parent_start #define xfs_perag_get libxfs_perag_get #define xfs_perag_hold libxfs_perag_hold #define xfs_perag_put libxfs_perag_put diff --git a/logprint/log_redo.c b/logprint/log_redo.c index e6401bb293e..948924d5bcb 100644 --- a/logprint/log_redo.c +++ b/logprint/log_redo.c @@ -674,6 +674,59 @@ xfs_attri_copy_log_format( return 1; } +static void +dump_pptr( + const char *tag, + const void *name_ptr, + unsigned int name_len, + const void *value_ptr, + unsigned int value_len) +{ + struct xfs_parent_name_irec irec; + + if (name_len < sizeof(struct xfs_parent_name_rec)) { + printf("PPTR: %s CORRUPT\n", tag); + return; + } + + libxfs_parent_irec_from_disk(&irec, name_ptr, value_ptr, value_len); + + printf("PPTR: %s attr_namelen %u attr_valuelen %u\n", tag, name_len, value_len); + printf("PPTR: %s parent_ino %llu parent_gen %u namehash 0x%x namelen %u name '%.*s'\n", + tag, + (unsigned long long)irec.p_ino, + irec.p_gen, + irec.p_namehash, + irec.p_namelen, + irec.p_namelen, + irec.p_name); +} + +static void +dump_pptr_update( + const void *name_ptr, + unsigned int name_len, + const void *new_name_ptr, + unsigned int new_name_len, + const void *value_ptr, + unsigned int value_len, + const void *new_value_ptr, + unsigned int new_value_len) +{ + if (new_name_ptr && name_ptr) { + dump_pptr("OLDNAME", name_ptr, name_len, value_ptr, value_len); + dump_pptr("NEWNAME", new_name_ptr, new_name_len, new_value_ptr, + new_value_len); + return; + } + + if (name_ptr) + dump_pptr("NAME", name_ptr, name_len, value_ptr, value_len); + if (new_name_ptr) + dump_pptr("NEWNAME", new_name_ptr, new_name_len, new_value_ptr, + new_value_len); +} + static inline unsigned int xfs_attr_log_item_op(const struct xfs_attri_log_format *attrp) { @@ -688,6 +741,10 @@ xlog_print_trans_attri( { struct xfs_attri_log_format *src_f = NULL; xlog_op_header_t *head = NULL; + void *name_ptr = NULL; + void *new_name_ptr = NULL; + void *value_ptr = NULL; + void *new_value_ptr = NULL; uint dst_len; unsigned int name_len = 0; unsigned int new_name_len = 0; @@ -741,6 +798,7 @@ xlog_print_trans_attri( (*i)++; head = (xlog_op_header_t *)*ptr; xlog_print_op_header(head, *i, ptr); + name_ptr = *ptr; error = xlog_print_trans_attri_name(ptr, be32_to_cpu(head->oh_len), "name"); if (error) @@ -752,6 +810,7 @@ xlog_print_trans_attri( (*i)++; head = (xlog_op_header_t *)*ptr; xlog_print_op_header(head, *i, ptr); + new_name_ptr = *ptr; error = xlog_print_trans_attri_name(ptr, be32_to_cpu(head->oh_len), "newname"); if (error) @@ -763,6 +822,7 @@ xlog_print_trans_attri( (*i)++; head = (xlog_op_header_t *)*ptr; xlog_print_op_header(head, *i, ptr); + value_ptr = *ptr; error = xlog_print_trans_attri_value(ptr, be32_to_cpu(head->oh_len), value_len, "value"); if (error) @@ -774,12 +834,19 @@ xlog_print_trans_attri( (*i)++; head = (xlog_op_header_t *)*ptr; xlog_print_op_header(head, *i, ptr); + new_value_ptr = *ptr; error = xlog_print_trans_attri_value(ptr, be32_to_cpu(head->oh_len), new_value_len, "newvalue"); if (error) goto error; } + + if (src_f->alfi_attr_filter & XFS_ATTR_PARENT) + dump_pptr_update(name_ptr, name_len, + new_name_ptr, new_name_len, + value_ptr, value_len, + new_value_ptr, new_value_len); error: free(src_f); @@ -822,6 +889,10 @@ xlog_recover_print_attri( struct xlog_recover_item *item) { struct xfs_attri_log_format *f, *src_f = NULL; + void *name_ptr = NULL; + void *new_name_ptr = NULL; + void *value_ptr = NULL; + void *new_value_ptr = NULL; uint src_len, dst_len; unsigned int name_len = 0; unsigned int new_name_len = 0; @@ -872,6 +943,7 @@ xlog_recover_print_attri( printf(_("ATTRI: name len:%u\n"), name_len); print_or_dump((char *)item->ri_buf[region].i_addr, name_len); + name_ptr = item->ri_buf[region].i_addr; } if (new_name_len > 0) { @@ -879,6 +951,7 @@ xlog_recover_print_attri( printf(_("ATTRI: newname len:%u\n"), new_name_len); print_or_dump((char *)item->ri_buf[region].i_addr, new_name_len); + new_name_ptr = item->ri_buf[region].i_addr; } if (value_len > 0) { @@ -887,6 +960,7 @@ xlog_recover_print_attri( region++; printf(_("ATTRI: value len:%u\n"), value_len); print_or_dump((char *)item->ri_buf[region].i_addr, len); + value_ptr = item->ri_buf[region].i_addr; } if (new_value_len > 0) { @@ -895,8 +969,15 @@ xlog_recover_print_attri( region++; printf(_("ATTRI: newvalue len:%u\n"), new_value_len); print_or_dump((char *)item->ri_buf[region].i_addr, len); + new_value_ptr = item->ri_buf[region].i_addr; } + if (src_f->alfi_attr_filter & XFS_ATTR_PARENT) + dump_pptr_update(name_ptr, name_len, + new_name_ptr, new_name_len, + value_ptr, value_len, + new_value_ptr, new_value_len); + out: free(f); From patchwork Sun Dec 31 23:10: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: 13508044 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 54928C2D4 for ; Sun, 31 Dec 2023 23:10:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="UPr94Wty" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 23CCAC433C8; Sun, 31 Dec 2023 23:10:35 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704064235; bh=U7z4y8T9+1Rw1IMDc5zOon910TJ8rIpcBRVdZFBHi7w=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=UPr94WtylMmFH2PLAI+Gmf42B3A2fwMncEkUDrCxzwBZGUso80L/uh8Dsm8gL5npU Mi/tz0THNZBKdp8Ed+DX/SaN9lA4lxgOkP+nIjn5dYDevYM4IAlnWQ//wP2OOOlPn3 J9o2xJ9EQYB0tHPyY3FFeXcb5WSOsW33B4cW8fPxcjXjWNTsoEur6sdgbYrFOUcMOP GZkDufuyWIL19VyKfAUOpnm3+p8390UVucy20miCZmNqarPA0gJ73sxqiatSscyFlq TgUBGvoCj4kxZRKtFfvoe6JXizhdtSv/xESBD1Qg31c6UEAieZUWHK4B6t2NPIfjbP WDGYt5ZyVoKaQ== Date: Sun, 31 Dec 2023 15:10:34 -0800 Subject: [PATCH 21/32] xfs_spaceman: report file paths From: "Darrick J. Wong" To: djwong@kernel.org, cem@kernel.org Cc: catherine.hoang@oracle.com, linux-xfs@vger.kernel.org, allison.henderson@oracle.com Message-ID: <170405006381.1804688.3715768524309031421.stgit@frogsfrogsfrogs> In-Reply-To: <170405006077.1804688.8762482665401724622.stgit@frogsfrogsfrogs> References: <170405006077.1804688.8762482665401724622.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 health command to report file paths when possible. Signed-off-by: Darrick J. Wong --- man/man8/xfs_spaceman.8 | 7 +++++- spaceman/Makefile | 4 ++-- spaceman/file.c | 7 ++++++ spaceman/health.c | 53 ++++++++++++++++++++++++++++++++++++++--------- spaceman/space.h | 3 +++ 5 files changed, 61 insertions(+), 13 deletions(-) diff --git a/man/man8/xfs_spaceman.8 b/man/man8/xfs_spaceman.8 index ece840d7300..0d299132a78 100644 --- a/man/man8/xfs_spaceman.8 +++ b/man/man8/xfs_spaceman.8 @@ -91,7 +91,7 @@ The output will have the same format that .BR "xfs_info" "(8)" prints when querying a filesystem. .TP -.BI "health [ \-a agno] [ \-c ] [ \-f ] [ \-i inum ] [ \-q ] [ paths ]" +.BI "health [ \-a agno] [ \-c ] [ \-f ] [ \-i inum ] [ \-n ] [ \-q ] [ paths ]" Reports the health of the given group of filesystem metadata. .RS 1.0i .PD 0 @@ -111,6 +111,11 @@ Report on the health of metadata that affect the entire filesystem. .B \-i inum Report on the health of a specific inode. .TP +.B \-n +When reporting on the health of a file, try to report the full file path, +if possible. +This option is disabled by default to minimize runtime. +.TP .B \-q Report only unhealthy metadata. .TP diff --git a/spaceman/Makefile b/spaceman/Makefile index 1f048d54a4d..d6fccc361cf 100644 --- a/spaceman/Makefile +++ b/spaceman/Makefile @@ -10,8 +10,8 @@ HFILES = init.h space.h CFILES = info.c init.c file.c health.c prealloc.c trim.c LSRCFILES = xfs_info.sh -LLDLIBS = $(LIBXCMD) $(LIBFROG) -LTDEPENDENCIES = $(LIBXCMD) $(LIBFROG) +LLDLIBS = $(LIBHANDLE) $(LIBXCMD) $(LIBFROG) +LTDEPENDENCIES = $(LIBHANDLE) $(LIBXCMD) $(LIBFROG) LLDFLAGS = -static ifeq ($(ENABLE_EDITLINE),yes) diff --git a/spaceman/file.c b/spaceman/file.c index eec7ee9f4ba..850688ace15 100644 --- a/spaceman/file.c +++ b/spaceman/file.c @@ -14,6 +14,7 @@ #include "libfrog/paths.h" #include "libfrog/fsgeom.h" #include "space.h" +#include "handle.h" static cmdinfo_t print_cmd; @@ -106,6 +107,12 @@ addfile( file->name = filename; memcpy(&file->xfd, xfd, sizeof(struct xfs_fd)); memcpy(&file->fs_path, fs_path, sizeof(file->fs_path)); + + /* Try to capture a fs handle for reporting paths. */ + file->fshandle = NULL; + file->fshandle_len = 0; + path_to_fshandle(filename, &file->fshandle, &file->fshandle_len); + return 0; } diff --git a/spaceman/health.c b/spaceman/health.c index 12fb67bab28..ab5bc074988 100644 --- a/spaceman/health.c +++ b/spaceman/health.c @@ -13,11 +13,13 @@ #include "libfrog/fsgeom.h" #include "libfrog/bulkstat.h" #include "space.h" +#include "libfrog/getparents.h" static cmdinfo_t health_cmd; static unsigned long long reported; static bool comprehensive; static bool quiet; +static bool report_paths; static bool has_realtime(const struct xfs_fsop_geom *g) { @@ -269,6 +271,38 @@ report_file_health( #define BULKSTAT_NR (128) +static void +report_inode( + const struct xfs_bulkstat *bs) +{ + char descr[PATH_MAX]; + int ret; + + if (report_paths && file->fshandle && + (file->xfd.fsgeom.flags & XFS_FSOP_GEOM_FLAGS_PARENT)) { + struct xfs_handle handle; + + memcpy(&handle.ha_fsid, file->fshandle, sizeof(handle.ha_fsid)); + handle.ha_fid.fid_len = sizeof(xfs_fid_t) - + sizeof(handle.ha_fid.fid_len); + handle.ha_fid.fid_pad = 0; + handle.ha_fid.fid_ino = bs->bs_ino; + handle.ha_fid.fid_gen = bs->bs_gen; + + ret = handle_to_path(&handle, sizeof(struct xfs_handle), descr, + sizeof(descr) - 1); + if (ret) + goto report_inum; + + goto report_status; + } + +report_inum: + snprintf(descr, sizeof(descr) - 1, _("inode %"PRIu64), bs->bs_ino); +report_status: + report_sick(descr, inode_flags, bs->bs_sick, bs->bs_checked); +} + /* * Report on all files' health for a given @agno. If @agno is NULLAGNUMBER, * report on all files in the filesystem. @@ -278,7 +312,6 @@ report_bulkstat_health( xfs_agnumber_t agno) { struct xfs_bulkstat_req *breq; - char descr[256]; uint32_t i; int error; @@ -296,13 +329,8 @@ report_bulkstat_health( error = -xfrog_bulkstat(&file->xfd, breq); if (error) break; - for (i = 0; i < breq->hdr.ocount; i++) { - snprintf(descr, sizeof(descr) - 1, _("inode %"PRIu64), - breq->bulkstat[i].bs_ino); - report_sick(descr, inode_flags, - breq->bulkstat[i].bs_sick, - breq->bulkstat[i].bs_checked); - } + for (i = 0; i < breq->hdr.ocount; i++) + report_inode(&breq->bulkstat[i]); } while (breq->hdr.ocount > 0); if (error) @@ -312,7 +340,7 @@ report_bulkstat_health( return error; } -#define OPT_STRING ("a:cfi:q") +#define OPT_STRING ("a:cfi:nq") /* Report on health problems in XFS filesystem. */ static int @@ -327,6 +355,7 @@ health_f( int ret; reported = 0; + report_paths = false; if (file->xfd.fsgeom.version != XFS_FSOP_GEOM_VERSION_V5) { perror("health"); @@ -362,6 +391,9 @@ health_f( return 1; } break; + case 'n': + report_paths = true; + break; case 'q': quiet = true; break; @@ -449,6 +481,7 @@ health_help(void) " -c -- Report on the health of all inodes.\n" " -f -- Report health of the overall filesystem.\n" " -i inum -- Report health of a given inode number.\n" +" -n -- Try to report file names.\n" " -q -- Only report unhealthy metadata.\n" " paths -- Report health of the given file path.\n" "\n")); @@ -460,7 +493,7 @@ static cmdinfo_t health_cmd = { .cfunc = health_f, .argmin = 0, .argmax = -1, - .args = "[-a agno] [-c] [-f] [-i inum] [-q] [paths]", + .args = "[-a agno] [-c] [-f] [-i inum] [-n] [-q] [paths]", .flags = CMD_FLAG_ONESHOT, .help = health_help, }; diff --git a/spaceman/space.h b/spaceman/space.h index 723209edd99..28fa35a3047 100644 --- a/spaceman/space.h +++ b/spaceman/space.h @@ -10,6 +10,9 @@ struct fileio { struct xfs_fd xfd; /* XFS runtime support context */ struct fs_path fs_path; /* XFS path information */ char *name; /* file name at time of open */ + + void *fshandle; + size_t fshandle_len; }; extern struct fileio *filetable; /* open file table */ From patchwork Sun Dec 31 23:10: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: 13508045 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 0B721C2CC for ; Sun, 31 Dec 2023 23:10:51 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="ga65hIQu" Received: by smtp.kernel.org (Postfix) with ESMTPSA id CFFA9C433C8; Sun, 31 Dec 2023 23:10:50 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704064250; bh=ONKqpcv+oQlR7yVDHoU17xVpTj9B0y3wwUvTkGaSEx0=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=ga65hIQuXJGhJvvpue31/dP362+WQ2k0lvBmX0AQvXDRlOiSddShDaRxulAiJ73ij VvcwHVOPgYbpo4yBayO+D1wQQSAV8ovMZ8tKzJHEvlwoMAi5W9bq//eBh6jpTH/Pe2 of8g5wRdh3zLm77MBxMSuZlPnSUIPw3IHAHtqaLjFd7rpPUB+0oC766TRkSHKMmswy YAGf5Putbelbh21nKtlMECb0AiWfMXJVHKc7y4VvNlju3X3sEy4oxYrJYYUDs+AC52 E/bZTAyOeroBkcOJTpRApGM+5dZz4HcoCnd0+A2weXvgljE7f/TB+ENX9IKoQv+cl7 hdJJlAx2Y17Qg== Date: Sun, 31 Dec 2023 15:10:50 -0800 Subject: [PATCH 22/32] xfs_scrub: use parent pointers when possible to report file operations From: "Darrick J. Wong" To: djwong@kernel.org, cem@kernel.org Cc: catherine.hoang@oracle.com, linux-xfs@vger.kernel.org, allison.henderson@oracle.com Message-ID: <170405006394.1804688.6501111294241060516.stgit@frogsfrogsfrogs> In-Reply-To: <170405006077.1804688.8762482665401724622.stgit@frogsfrogsfrogs> References: <170405006077.1804688.8762482665401724622.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 parent pointers are available, use them to supply file paths when doing things to files, instead of merely printing the inode number. Signed-off-by: Darrick J. Wong --- scrub/common.c | 41 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/scrub/common.c b/scrub/common.c index aca59648711..248a33ef324 100644 --- a/scrub/common.c +++ b/scrub/common.c @@ -9,6 +9,7 @@ #include #include "platform_defs.h" #include "libfrog/paths.h" +#include "libfrog/getparents.h" #include "xfs_scrub.h" #include "common.h" #include "progress.h" @@ -405,19 +406,55 @@ scrub_render_ino_descr( ...) { va_list args; + size_t pathlen = 0; uint32_t agno; uint32_t agino; int ret; + if (ctx->mnt.fsgeom.flags & XFS_FSOP_GEOM_FLAGS_PARENT) { + struct xfs_handle handle; + + memcpy(&handle.ha_fsid, ctx->fshandle, sizeof(handle.ha_fsid)); + handle.ha_fid.fid_len = sizeof(xfs_fid_t) - + sizeof(handle.ha_fid.fid_len); + handle.ha_fid.fid_pad = 0; + handle.ha_fid.fid_ino = ino; + handle.ha_fid.fid_gen = gen; + + ret = handle_to_path(&handle, sizeof(struct xfs_handle), buf, + buflen); + if (ret) + goto report_inum; + + /* + * Leave at least 16 bytes for the description of what went + * wrong. If we can't do that, we'll use the inode number. + */ + pathlen = strlen(buf); + if (pathlen >= buflen - 16) + goto report_inum; + + if (format) { + buf[pathlen] = ' '; + buf[pathlen + 1] = 0; + pathlen++; + } + + goto report_format; + } + +report_inum: agno = cvt_ino_to_agno(&ctx->mnt, ino); agino = cvt_ino_to_agino(&ctx->mnt, ino); ret = snprintf(buf, buflen, _("inode %"PRIu64" (%"PRIu32"/%"PRIu32")%s"), ino, agno, agino, format ? " " : ""); if (ret < 0 || ret >= buflen || format == NULL) return ret; + pathlen = ret; +report_format: va_start(args, format); - ret += vsnprintf(buf + ret, buflen - ret, format, args); + pathlen += vsnprintf(buf + pathlen, buflen - pathlen, format, args); va_end(args); - return ret; + return pathlen; } From patchwork Sun Dec 31 23:11: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: 13508046 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 AE138C2C0 for ; Sun, 31 Dec 2023 23:11:06 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="oskycXsk" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 7BFF3C433C8; Sun, 31 Dec 2023 23:11:06 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704064266; bh=dVwKmVNoo0qK223xgHvWXZ0sKwR0hCL+I7iWS0zz+sE=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=oskycXskezLy1dL3IOPbRIOQwqyl1u1jJgEIidrw2lsG/KolGaQnk3DGuAqBGIShD 0WDzfBPz0v5NubwcDMgnwR2Gen0dtBxuZ8+pagAseB9NzURG1BNjXZovQv31keO2Od q42F38+IputpDk8I2kh7/LXuyk5Os0gG5NHq8oqVQgPCyCSY3HCLjJ3vHspfOu1tjY rrIXvJtKSjSAqiVGS9RPeHOR1Km6OC53grHGCjlMuu4hj65/IhwGxv0vvuHvj+aSia hmObE9R8a7nuOaZAKhzcEp7N9wXb5B11fOEzuRRZYDYj7t0OoWdRnnWbwbX7V3A+4H 16H+bqXYVBuLg== Date: Sun, 31 Dec 2023 15:11:06 -0800 Subject: [PATCH 23/32] xfs_db: report parent pointers in version command From: "Darrick J. Wong" To: djwong@kernel.org, cem@kernel.org Cc: catherine.hoang@oracle.com, linux-xfs@vger.kernel.org, allison.henderson@oracle.com Message-ID: <170405006407.1804688.3081180575836582476.stgit@frogsfrogsfrogs> In-Reply-To: <170405006077.1804688.8762482665401724622.stgit@frogsfrogsfrogs> References: <170405006077.1804688.8762482665401724622.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 presents of PARENT pointers from the version subcommand. Signed-off-by: Darrick J. Wong --- db/sb.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/db/sb.c b/db/sb.c index b48767f47fe..9a5d665dfbd 100644 --- a/db/sb.c +++ b/db/sb.c @@ -706,6 +706,8 @@ version_string( strcat(s, ",NEEDSREPAIR"); if (xfs_has_large_extent_counts(mp)) strcat(s, ",NREXT64"); + if (xfs_has_parent(mp)) + strcat(s, ",PARENT"); return s; } From patchwork Sun Dec 31 23:11: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: 13508047 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 411CBC2C5 for ; Sun, 31 Dec 2023 23:11:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="reAw1QLw" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 15E75C433C7; Sun, 31 Dec 2023 23:11:22 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704064282; bh=6fLNIenh/+izzgOksenA4UfhR4GURe07oqoTTNmox+c=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=reAw1QLwrDz3js2H8BFz2jYwk6weuM2R2aAxVOz7YRdtO6nn6U9PiI44zPeCS2ZN2 C1y6Q0bBsRlGnLuZSnmE3Y5X5OyojaMQdKbUloY4L/GaZKMbXV7IoUJMgoZ8nIneb6 /ppngYvMuPh3kEiyRmdFMez2BdcgT/o3z63xvpoT/8UKdgajvrllG92bmmJ0KSWpu+ P6wysbg/USI4MfjhRZWXb0E2a1bvIW1PQBfNPjFeLeEanLX1jASOFBJpc1OZUAXwRY JzhUKOdT8xnq5rzfx0wlvVFL3bLYocb3BYnk8wFSKKhjUiLlLdj6VXwoq4FxTeMqPx tMuwqRYb4QR5A== Date: Sun, 31 Dec 2023 15:11:21 -0800 Subject: [PATCH 24/32] xfs_db: report parent bit on xattrs From: "Darrick J. Wong" To: djwong@kernel.org, cem@kernel.org Cc: Allison Henderson , catherine.hoang@oracle.com, linux-xfs@vger.kernel.org, allison.henderson@oracle.com Message-ID: <170405006421.1804688.16782016668028500385.stgit@frogsfrogsfrogs> In-Reply-To: <170405006077.1804688.8762482665401724622.stgit@frogsfrogsfrogs> References: <170405006077.1804688.8762482665401724622.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 Display the parent bit on xattr keys Signed-off-by: Darrick J. Wong Reviewed-by: Allison Henderson --- db/attr.c | 3 +++ db/attrshort.c | 3 +++ 2 files changed, 6 insertions(+) diff --git a/db/attr.c b/db/attr.c index ba722e146e2..f29e4a54454 100644 --- a/db/attr.c +++ b/db/attr.c @@ -82,6 +82,9 @@ const field_t attr_leaf_entry_flds[] = { { "local", FLDT_UINT1, OI(LEOFF(flags) + bitsz(uint8_t) - XFS_ATTR_LOCAL_BIT - 1), C1, 0, TYP_NONE }, + { "parent", FLDT_UINT1, + OI(LEOFF(flags) + bitsz(uint8_t) - XFS_ATTR_PARENT_BIT - 1), C1, 0, + TYP_NONE }, { "pad2", FLDT_UINT8X, OI(LEOFF(pad2)), C1, FLD_SKIPALL, TYP_NONE }, { NULL } }; diff --git a/db/attrshort.c b/db/attrshort.c index e234fbd8365..872d771d5ed 100644 --- a/db/attrshort.c +++ b/db/attrshort.c @@ -44,6 +44,9 @@ const field_t attr_sf_entry_flds[] = { { "secure", FLDT_UINT1, OI(EOFF(flags) + bitsz(uint8_t) - XFS_ATTR_SECURE_BIT - 1), C1, 0, TYP_NONE }, + { "parent", FLDT_UINT1, + OI(EOFF(flags) + bitsz(uint8_t) - XFS_ATTR_PARENT_BIT - 1), C1, 0, + TYP_NONE }, { "name", FLDT_CHARNS, OI(EOFF(nameval)), attr_sf_entry_name_count, FLD_COUNT, TYP_NONE }, { "value", FLDT_CHARNS, attr_sf_entry_value_offset, From patchwork Sun Dec 31 23:11: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: 13508048 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 DFE92C2C5 for ; Sun, 31 Dec 2023 23:11:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="YD4yEgYA" Received: by smtp.kernel.org (Postfix) with ESMTPSA id B0D00C433C8; Sun, 31 Dec 2023 23:11:37 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704064297; bh=MEZDtEHAaTzBfu3pxZnYFoYz7wdnlbra0j+KO0FNyc0=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=YD4yEgYAJNkE3DkCfQZ0s+CKAvGgUk/XwFWsdJTu8igoxe+iG4GtAyqrdCr7cxIhg q/SfBeGnUiLI5fBIzXftBhasLx9C+NILBHdAjsoeJJrXzlySiqasW1GJEfKMU67Hxb iFlGq5ST+aKq6REwbg0JcVx7YjN9+h361dTitvuckGIWT7j96ZmoWjC2KEQUv+TSqr wQ79dDSDNkpmrjyAYerv+PZeJ/m2MajOmVwq0XeXLtjuvGHXwPKOIKwYqyH6vuJkYK x+KPswUzPGSq/TFzHl4ay/7y62xTeLlFKLdHWV2cok+fj9e8AELsPjxddNDlyuv1DZ dnQuLSJ9/R8oQ== Date: Sun, 31 Dec 2023 15:11:37 -0800 Subject: [PATCH 25/32] xfs_db: report parent pointers embedded in xattrs From: "Darrick J. Wong" To: djwong@kernel.org, cem@kernel.org Cc: catherine.hoang@oracle.com, linux-xfs@vger.kernel.org, allison.henderson@oracle.com Message-ID: <170405006434.1804688.3757235808372242607.stgit@frogsfrogsfrogs> In-Reply-To: <170405006077.1804688.8762482665401724622.stgit@frogsfrogsfrogs> References: <170405006077.1804688.8762482665401724622.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 Decode the parent pointer inode, generation, namehash, and name fields if the parent pointer passes basic validation checks. Signed-off-by: Darrick J. Wong --- db/attr.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ db/attrshort.c | 48 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 110 insertions(+) diff --git a/db/attr.c b/db/attr.c index f29e4a54454..9e7bbd164df 100644 --- a/db/attr.c +++ b/db/attr.c @@ -19,6 +19,8 @@ static int attr_leaf_entries_count(void *obj, int startoff); static int attr_leaf_hdr_count(void *obj, int startoff); static int attr_leaf_name_local_count(void *obj, int startoff); static int attr_leaf_name_local_name_count(void *obj, int startoff); +static int attr_leaf_name_pptr_count(void *obj, int startoff); +static int attr_leaf_name_pptr_namelen(void *obj, int startoff); static int attr_leaf_name_local_value_count(void *obj, int startoff); static int attr_leaf_name_local_value_offset(void *obj, int startoff, int idx); @@ -111,6 +113,8 @@ const field_t attr_leaf_map_flds[] = { #define LNOFF(f) bitize(offsetof(xfs_attr_leaf_name_local_t, f)) #define LVOFF(f) bitize(offsetof(xfs_attr_leaf_name_remote_t, f)) +#define PPOFF(f) bitize(offsetof(xfs_attr_leaf_name_local_t, nameval) + \ + offsetof(struct xfs_parent_name_rec, f)) const field_t attr_leaf_name_flds[] = { { "valuelen", FLDT_UINT16D, OI(LNOFF(valuelen)), attr_leaf_name_local_count, FLD_COUNT, TYP_NONE }, @@ -118,6 +122,14 @@ const field_t attr_leaf_name_flds[] = { attr_leaf_name_local_count, FLD_COUNT, TYP_NONE }, { "name", FLDT_CHARNS, OI(LNOFF(nameval)), attr_leaf_name_local_name_count, FLD_COUNT, TYP_NONE }, + { "parent_ino", FLDT_INO, OI(PPOFF(p_ino)), + attr_leaf_name_pptr_count, FLD_COUNT, TYP_INODE }, + { "parent_gen", FLDT_UINT32D, OI(PPOFF(p_gen)), + attr_leaf_name_pptr_count, FLD_COUNT, TYP_NONE }, + { "parent_namehash", FLDT_UINT32X, OI(PPOFF(p_namehash)), + attr_leaf_name_pptr_count, FLD_COUNT, TYP_NONE }, + { "parent_name", FLDT_CHARNS, attr_leaf_name_local_value_offset, + attr_leaf_name_pptr_namelen, FLD_COUNT|FLD_OFFSET, TYP_NONE }, { "value", FLDT_CHARNS, attr_leaf_name_local_value_offset, attr_leaf_name_local_value_count, FLD_COUNT|FLD_OFFSET, TYP_NONE }, { "valueblk", FLDT_UINT32X, OI(LVOFF(valueblk)), @@ -273,6 +285,26 @@ attr_leaf_name_local_count( __attr_leaf_name_local_count); } +static int +__attr_leaf_name_pptr_count( + struct xfs_attr_leafblock *leaf, + struct xfs_attr_leaf_entry *e, + int i) +{ + if ((e->flags & XFS_ATTR_NSP_ONDISK_MASK) == XFS_ATTR_PARENT) + return 1; + return 0; +} + +static int +attr_leaf_name_pptr_count( + void *obj, + int startoff) +{ + return attr_leaf_entry_walk(obj, startoff, + __attr_leaf_name_pptr_count); +} + static int __attr_leaf_name_local_name_count( struct xfs_attr_leafblock *leaf, @@ -283,6 +315,8 @@ __attr_leaf_name_local_name_count( if (!(e->flags & XFS_ATTR_LOCAL)) return 0; + if ((e->flags & XFS_ATTR_NSP_ONDISK_MASK) == XFS_ATTR_PARENT) + return 0; l = xfs_attr3_leaf_name_local(leaf, i); return l->namelen; @@ -297,6 +331,32 @@ attr_leaf_name_local_name_count( __attr_leaf_name_local_name_count); } +static int +__attr_leaf_name_pptr_namelen( + struct xfs_attr_leafblock *leaf, + struct xfs_attr_leaf_entry *e, + int i) +{ + struct xfs_attr_leaf_name_local *l; + + if (!(e->flags & XFS_ATTR_LOCAL)) + return 0; + if ((e->flags & XFS_ATTR_NSP_ONDISK_MASK) != XFS_ATTR_PARENT) + return 0; + + l = xfs_attr3_leaf_name_local(leaf, i); + return be16_to_cpu(l->valuelen); +} + +static int +attr_leaf_name_pptr_namelen( + void *obj, + int startoff) +{ + return attr_leaf_entry_walk(obj, startoff, + __attr_leaf_name_pptr_namelen); +} + static int __attr_leaf_name_local_value_count( struct xfs_attr_leafblock *leaf, @@ -307,6 +367,8 @@ __attr_leaf_name_local_value_count( if (!(e->flags & XFS_ATTR_LOCAL)) return 0; + if ((e->flags & XFS_ATTR_NSP_ONDISK_MASK) == XFS_ATTR_PARENT) + return 0; l = xfs_attr3_leaf_name_local(leaf, i); return be16_to_cpu(l->valuelen); diff --git a/db/attrshort.c b/db/attrshort.c index 872d771d5ed..9cd3411bee4 100644 --- a/db/attrshort.c +++ b/db/attrshort.c @@ -13,6 +13,8 @@ #include "attrshort.h" static int attr_sf_entry_name_count(void *obj, int startoff); +static int attr_sf_entry_pptr_count(void *obj, int startoff); +static int attr_sf_entry_pptr_namelen(void *obj, int startoff); static int attr_sf_entry_value_count(void *obj, int startoff); static int attr_sf_entry_value_offset(void *obj, int startoff, int idx); static int attr_shortform_list_count(void *obj, int startoff); @@ -34,6 +36,8 @@ const field_t attr_sf_hdr_flds[] = { }; #define EOFF(f) bitize(offsetof(struct xfs_attr_sf_entry, f)) +#define PPOFF(f) bitize(offsetof(struct xfs_attr_sf_entry, nameval) + \ + offsetof(struct xfs_parent_name_rec, f)) const field_t attr_sf_entry_flds[] = { { "namelen", FLDT_UINT8D, OI(EOFF(namelen)), C1, 0, TYP_NONE }, { "valuelen", FLDT_UINT8D, OI(EOFF(valuelen)), C1, 0, TYP_NONE }, @@ -49,11 +53,33 @@ const field_t attr_sf_entry_flds[] = { TYP_NONE }, { "name", FLDT_CHARNS, OI(EOFF(nameval)), attr_sf_entry_name_count, FLD_COUNT, TYP_NONE }, + { "parent_ino", FLDT_INO, OI(PPOFF(p_ino)), attr_sf_entry_pptr_count, + FLD_COUNT, TYP_INODE }, + { "parent_gen", FLDT_UINT32D, OI(PPOFF(p_gen)), attr_sf_entry_pptr_count, + FLD_COUNT, TYP_NONE }, + { "parent_namehash", FLDT_UINT32X, OI(PPOFF(p_namehash)), + attr_sf_entry_pptr_count, FLD_COUNT, TYP_NONE }, + { "parent_name", FLDT_CHARNS, attr_sf_entry_value_offset, + attr_sf_entry_pptr_namelen, FLD_COUNT|FLD_OFFSET, TYP_NONE }, { "value", FLDT_CHARNS, attr_sf_entry_value_offset, attr_sf_entry_value_count, FLD_COUNT|FLD_OFFSET, TYP_NONE }, { NULL } }; +static int +attr_sf_entry_pptr_count( + void *obj, + int startoff) +{ + struct xfs_attr_sf_entry *e; + + ASSERT(bitoffs(startoff) == 0); + e = (struct xfs_attr_sf_entry *)((char *)obj + byteize(startoff)); + if ((e->flags & XFS_ATTR_NSP_ONDISK_MASK) == XFS_ATTR_PARENT) + return 1; + return 0; +} + static int attr_sf_entry_name_count( void *obj, @@ -63,6 +89,8 @@ attr_sf_entry_name_count( ASSERT(bitoffs(startoff) == 0); e = (struct xfs_attr_sf_entry *)((char *)obj + byteize(startoff)); + if ((e->flags & XFS_ATTR_NSP_ONDISK_MASK) == XFS_ATTR_PARENT) + return 0; return e->namelen; } @@ -84,6 +112,22 @@ attr_sf_entry_size( return bitize((int)xfs_attr_sf_entsize(e)); } +static int +attr_sf_entry_pptr_namelen( + void *obj, + int startoff) +{ + struct xfs_attr_sf_entry *e; + + ASSERT(bitoffs(startoff) == 0); + e = (struct xfs_attr_sf_entry *)((char *)obj + byteize(startoff)); + + if ((e->flags & XFS_ATTR_NSP_ONDISK_MASK) != XFS_ATTR_PARENT) + return 0; + + return e->valuelen; +} + static int attr_sf_entry_value_count( void *obj, @@ -93,6 +137,10 @@ attr_sf_entry_value_count( ASSERT(bitoffs(startoff) == 0); e = (struct xfs_attr_sf_entry *)((char *)obj + byteize(startoff)); + + if ((e->flags & XFS_ATTR_NSP_ONDISK_MASK) == XFS_ATTR_PARENT) + return 0; + return e->valuelen; } From patchwork Sun Dec 31 23:11:52 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: 13508049 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 139F1C2D4 for ; Sun, 31 Dec 2023 23:11:53 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="k8BUPgw0" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 5C2F9C433C8; Sun, 31 Dec 2023 23:11:53 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704064313; bh=7hu7ay1OfnErAY4VBjZzwRC0RkJ43kBPgU7hbbikRQI=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=k8BUPgw0i9d0WiicxleDsQ9Y/932iSWWY8Sv7vvnBLcGeXrPBh1lzDb/nd7+sAIKI m9mpVNzNFiMdT0LxsCuDrV03qAcko7kvWB2DEZ5Vw+ecsxVytpvb1lHIPAa5+DXVST eHb+ala0vUAtNGOoC5SrB9x3wo/+irI1tMZRVXk5/RNpzpaOjdkQtCayZtjsqnPlGn 2R4uz2VS7m6OJ9OW2ZXY3/f/RVAX8m6VUzDMTZFdqdcmLSSZTEyVCaU+aoSUUPn3yU 9inQrm1RRtnvYSuJfLUKR1GtvyQLEsuEgxuRA1HUQLNkHkUEZa5M9TAr/cgPVaJzvR wvs+sB8J7ykDg== Date: Sun, 31 Dec 2023 15:11:52 -0800 Subject: [PATCH 26/32] xfs_db: obfuscate dirent and parent pointer names consistently From: "Darrick J. Wong" To: djwong@kernel.org, cem@kernel.org Cc: catherine.hoang@oracle.com, linux-xfs@vger.kernel.org, allison.henderson@oracle.com Message-ID: <170405006447.1804688.9641059864417586912.stgit@frogsfrogsfrogs> In-Reply-To: <170405006077.1804688.8762482665401724622.stgit@frogsfrogsfrogs> References: <170405006077.1804688.8762482665401724622.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 someone wants to perform an obfuscated metadump of a filesystem where parent pointers are enabled, we have to use the *exact* same obfuscated name for both the directory entry and the parent pointer. Create a name remapping table so that when we obfuscate a dirent name or a parent pointer name, we can apply the same obfuscation when we find the corresponding parent pointer or dirent. Signed-off-by: Darrick J. Wong --- db/metadump.c | 323 ++++++++++++++++++++++++++++++++++++++++++++-- libxfs/libxfs_api_defs.h | 3 2 files changed, 315 insertions(+), 11 deletions(-) diff --git a/db/metadump.c b/db/metadump.c index bac35b9cc68..5f5a33335b0 100644 --- a/db/metadump.c +++ b/db/metadump.c @@ -21,6 +21,14 @@ #include "dir2.h" #include "obfuscate.h" +#undef REMAP_DEBUG + +#ifdef REMAP_DEBUG +# define remap_debug printf +#else +# define remap_debug(...) ((void)0) +#endif + #define DEFAULT_MAX_EXT_SIZE XFS_MAX_BMBT_EXTLEN /* copy all metadata structures to/from a file */ @@ -719,6 +727,111 @@ nametable_add(xfs_dahash_t hash, int namelen, unsigned char *name) return ent; } +/* + * Obfuscated name remapping table for parent pointer-enabled filesystems. + * When this feature is enabled, we have to maintain consistency between the + * names that appears in the dirent and the corresponding parent pointer. + */ + +struct remap_ent { + struct remap_ent *next; + xfs_ino_t dir_ino; + xfs_dahash_t namehash; + uint8_t namelen; + + uint8_t names[]; +}; + +static inline uint8_t *remap_ent_before(struct remap_ent *ent) +{ + return &ent->names[0]; +} + +static inline uint8_t *remap_ent_after(struct remap_ent *ent) +{ + return &ent->names[ent->namelen]; +} + +#define REMAP_TABLE_SIZE 4096 + +static struct remap_ent *remaptable[REMAP_TABLE_SIZE]; + +static void +remaptable_clear(void) +{ + int i; + struct remap_ent *ent, *next; + + for (i = 0; i < REMAP_TABLE_SIZE; i++) { + ent = remaptable[i]; + + while (ent) { + next = ent->next; + free(ent); + ent = next; + } + } +} + +/* Try to find a remapping table entry. */ +static struct remap_ent * +remaptable_find( + xfs_ino_t dir_ino, + xfs_dahash_t namehash, + const unsigned char *name, + unsigned int namelen) +{ + struct remap_ent *ent = remaptable[namehash % REMAP_TABLE_SIZE]; + + remap_debug("REMAP FIND: 0x%lx hash 0x%x '%.*s'\n", + dir_ino, namehash, namelen, name); + + while (ent) { + remap_debug("REMAP ENT: 0x%lx hash 0x%x '%.*s'\n", + ent->dir_ino, ent->namehash, ent->namelen, + remap_ent_before(ent)); + + if (ent->dir_ino == dir_ino && + ent->namehash == namehash && + ent->namelen == namelen && + !memcmp(remap_ent_before(ent), name, namelen)) + return ent; + ent = ent->next; + } + + return NULL; +} + +/* Remember the remapping for a particular dirent that we obfuscated. */ +static struct remap_ent * +remaptable_add( + xfs_ino_t dir_ino, + xfs_dahash_t namehash, + const unsigned char *old_name, + unsigned int namelen, + const unsigned char *new_name) +{ + struct remap_ent *ent; + + ent = malloc(sizeof(struct remap_ent) + (namelen * 2)); + if (!ent) + return NULL; + + ent->dir_ino = dir_ino; + ent->namehash = namehash; + ent->namelen = namelen; + memcpy(remap_ent_before(ent), old_name, namelen); + memcpy(remap_ent_after(ent), new_name, namelen); + ent->next = remaptable[namehash % REMAP_TABLE_SIZE]; + + remaptable[namehash % REMAP_TABLE_SIZE] = ent; + + remap_debug("REMAP ADD: 0x%lx hash 0x%x '%.*s' -> '%.*s'\n", + dir_ino, namehash, namelen, old_name, namelen, + new_name); + return ent; +} + #define ORPHANAGE "lost+found" #define ORPHANAGE_LEN (sizeof (ORPHANAGE) - 1) @@ -844,6 +957,7 @@ generate_obfuscated_name( int namelen, unsigned char *name) { + unsigned char *orig_name = NULL; xfs_dahash_t hash; /* @@ -865,8 +979,37 @@ generate_obfuscated_name( name++; /* Obfuscate the name (if possible) */ - hash = dirattr_hashname(ino != 0, name, namelen); + + /* + * If we're obfuscating a dirent name on a pptrs filesystem, see if we + * already processed the parent pointer and use the same name. + */ + if (xfs_has_parent(mp) && ino) { + struct remap_ent *remap; + + remap = remaptable_find(metadump.cur_ino, hash, name, namelen); + if (remap) { + remap_debug("found obfuscated dir 0x%lx '%.*s' -> 0x%lx -> '%.*s' \n", + cur_ino, namelen, + remap_ent_before(remap), ino, namelen, + remap_ent_after(remap)); + memcpy(name, remap_ent_after(remap), namelen); + return; + } + + /* + * If we haven't procesed this dirent name before, save the + * old name for a remap table entry. Obfuscate the name. + */ + orig_name = malloc(namelen); + if (!orig_name) { + orig_name = name; + goto add_remap; + } + memcpy(orig_name, name, namelen); + } + obfuscate_name(hash, namelen, name, ino != 0); ASSERT(hash == dirattr_hashname(ino != 0, name, namelen)); @@ -891,6 +1034,26 @@ generate_obfuscated_name( "in dir inode %llu\n", (unsigned long long) ino, (unsigned long long) metadump.cur_ino); + + /* + * We've obfuscated a name in the directory entry. Remember this + * remapping for when we come across the parent pointer later. + */ + if (!orig_name) + return; + +add_remap: + remap_debug("obfuscating dir 0x%lx '%.*s' -> 0x%lx -> '%.*s' \n", + metadump.cur_ino, namelen, orig_name, ino, namelen, + name); + + if (!remaptable_add(metadump.cur_ino, hash, orig_name, namelen, name)) + print_warning("unable to record remapped dirent name for inode %llu " + "in dir inode %llu\n", + (unsigned long long) ino, + (unsigned long long) metadump.cur_ino); + if (orig_name && orig_name != name) + free(orig_name); } static void @@ -1026,6 +1189,125 @@ process_sf_symlink( memset(&buf[len], 0, XFS_DFORK_DSIZE(dip, mp) - len); } +static inline bool +want_obfuscate_pptr( + unsigned int nsp_flags, + const void *name, + unsigned int namelen, + const void *value, + unsigned int valuelen) +{ + if (!metadump.obfuscate) + return false; + + /* Ignore if parent pointers aren't enabled. */ + if (!xfs_has_parent(mp)) + return false; + + /* Ignore anything not claiming to be a parent pointer. */ + if (!(nsp_flags & XFS_ATTR_PARENT)) + return false; + + /* Obfuscate this parent pointer if it passes basic checks. */ + if (libxfs_parent_namecheck(mp, name, namelen, nsp_flags) && + libxfs_parent_valuecheck(mp, value, valuelen) && + libxfs_parent_hashcheck(mp, name, value, valuelen)) + return true; + + /* Ignore otherwise. */ + return false; +} + +static void +obfuscate_parent_pointer( + const struct xfs_parent_name_rec *rec, + unsigned char *value, + unsigned int valuelen) +{ + struct xfs_parent_name_irec irec; + struct remap_ent *remap; + char *old_name = irec.p_name; + xfs_dahash_t hash; + xfs_ino_t child_ino = metadump.cur_ino; + + libxfs_parent_irec_from_disk(&irec, rec, value, valuelen); + + /* + * We don't obfuscate "lost+found" or any orphan files + * therein. If When the name table is used for extended + * attributes, the inode number provided is 0, in which + * case we don't need to make this check. + */ + metadump.cur_ino = irec.p_ino; + if (in_lost_found(child_ino, valuelen, value)) { + metadump.cur_ino = child_ino; + return; + } + metadump.cur_ino = child_ino; + + /* + * If the name starts with a slash, just skip over it. It isn't + * included in the hash and we don't record it in the name table. + */ + if (*value == '/') { + old_name++; + value++; + valuelen--; + } + + hash = libxfs_da_hashname(value, valuelen); + + /* + * If we already processed the dirent, use the same name for the parent + * pointer. + */ + remap = remaptable_find(irec.p_ino, hash, value, valuelen); + if (remap) { + remap_debug("found obfuscated pptr 0x%lx '%.*s' -> 0x%lx -> '%.*s' \n", + irec.p_ino, valuelen, remap_ent_before(remap), + metadump.cur_ino, valuelen, + remap_ent_after(remap)); + memcpy(value, remap_ent_after(remap), valuelen); + return; + } + + /* + * Obfuscate the parent pointer name and remember this for later + * in case we encounter the dirent and need to reuse the name there. + */ + obfuscate_name(hash, valuelen, value, true); + + remap_debug("obfuscated pptr 0x%lx '%.*s' -> 0x%lx -> '%.*s'\n", + irec.p_ino, valuelen, old_name, metadump.cur_ino, + valuelen, value); + if (!remaptable_add(irec.p_ino, hash, old_name, valuelen, value)) + print_warning("unable to record remapped pptr name for inode %llu " + "in dir inode %llu\n", + (unsigned long long) metadump.cur_ino, + (unsigned long long) irec.p_ino); +} + +static inline bool +want_obfuscate_attr( + unsigned int nsp_flags, + const void *name, + unsigned int namelen, + const void *value, + unsigned int valuelen) +{ + if (!metadump.obfuscate) + return false; + + /* + * If we didn't already obfuscate the parent pointer, it's probably + * corrupt. Leave it intact for analysis. + */ + if (nsp_flags & XFS_ATTR_PARENT) + return false; + + return true; +} + static void process_sf_attr( struct xfs_dinode *dip) @@ -1055,7 +1337,7 @@ process_sf_attr( asfep = &asfp->list[0]; for (i = 0; (i < asfp->hdr.count) && ((char *)asfep - (char *)asfp < ino_attr_size); i++) { - + void *name, *value; int namelen = asfep->namelen; if (namelen == 0) { @@ -1072,11 +1354,16 @@ process_sf_attr( break; } - if (metadump.obfuscate) { - generate_obfuscated_name(0, asfep->namelen, - &asfep->nameval[0]); - memset(&asfep->nameval[asfep->namelen], 'v', - asfep->valuelen); + name = &asfep->nameval[0]; + value = &asfep->nameval[asfep->namelen]; + + if (want_obfuscate_pptr(asfep->flags, name, namelen, value, + asfep->valuelen)) { + obfuscate_parent_pointer(name, value, asfep->valuelen); + } else if (want_obfuscate_attr(asfep->flags, name, namelen, + value, asfep->valuelen)) { + generate_obfuscated_name(0, asfep->namelen, name); + memset(value, 'v', asfep->valuelen); } asfep = (struct xfs_attr_sf_entry *)((char *)asfep + @@ -1445,6 +1732,9 @@ process_attr_block( break; } if (entry->flags & XFS_ATTR_LOCAL) { + void *name, *value; + unsigned int valuelen; + local = xfs_attr3_leaf_name_local(leaf, i); if (local->namelen == 0) { if (metadump.show_warnings) @@ -1453,11 +1743,21 @@ process_attr_block( (long long)metadump.cur_ino); break; } - if (metadump.obfuscate) { + + name = &local->nameval[0]; + value = &local->nameval[local->namelen]; + valuelen = be16_to_cpu(local->valuelen); + + if (want_obfuscate_pptr(entry->flags, name, + local->namelen, value, + valuelen)) { + obfuscate_parent_pointer(name, value, valuelen); + } else if (want_obfuscate_attr(entry->flags, name, + local->namelen, value, + valuelen)) { generate_obfuscated_name(0, local->namelen, - &local->nameval[0]); - memset(&local->nameval[local->namelen], 'v', - be16_to_cpu(local->valuelen)); + name); + memset(value, 'v', valuelen); } /* zero from end of nameval[] to next name start */ nlen = local->namelen; @@ -3046,5 +3346,6 @@ metadump_f( metadump.mdops->release(); out: + remaptable_clear(); return 0; } diff --git a/libxfs/libxfs_api_defs.h b/libxfs/libxfs_api_defs.h index c94972fb84b..a6b561b5b40 100644 --- a/libxfs/libxfs_api_defs.h +++ b/libxfs/libxfs_api_defs.h @@ -181,6 +181,9 @@ #define xfs_parent_finish libxfs_parent_finish #define xfs_parent_irec_from_disk libxfs_parent_irec_from_disk #define xfs_parent_start libxfs_parent_start +#define xfs_parent_hashcheck libxfs_parent_hashcheck +#define xfs_parent_namecheck libxfs_parent_namecheck +#define xfs_parent_valuecheck libxfs_parent_valuecheck #define xfs_perag_get libxfs_perag_get #define xfs_perag_hold libxfs_perag_hold #define xfs_perag_put libxfs_perag_put From patchwork Sun Dec 31 23:12: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: 13508050 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 A08B5C2C0 for ; Sun, 31 Dec 2023 23:12:09 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="O0xtbnKo" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 0F104C433C8; Sun, 31 Dec 2023 23:12:09 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704064329; bh=Phe7FxD7STkHY5TjHf4voB6bCmpPTq7ktKtJn7fqX/s=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=O0xtbnKoaIRiK/G1IK7diDH9J/ZH6DIJdxr3vsqG4neD1n17M8euJX8Hxvr4eGpBb Dz5/Ph2pblCAQAX+zBj9wEUA/YZdSYwBdaA9u+p7mcTygWNmoxMU5/n98baAIzqJDD /FXAoDKC5H/CwPr3/+y+vlYO1v4dD2Hzi3rerbRVSWRQZBFemeH/9ZENq5iLw3emS8 3nvvrfykALUNMMGv72VZGETYw7+BkBZVaEdi/QAZGqMIoppl1NfLIJOy4uXUUg9iN2 NuDLE6vhd85lk7ihTsBDJpRTg7s5B5mTmMATha4mwV+2WYoIzbjXxZb3gDfxiJvSam QEgKkvjsyAzSg== Date: Sun, 31 Dec 2023 15:12:08 -0800 Subject: [PATCH 27/32] libxfs: export attr3_leaf_hdr_from_disk via libxfs_api_defs.h From: "Darrick J. Wong" To: djwong@kernel.org, cem@kernel.org Cc: catherine.hoang@oracle.com, linux-xfs@vger.kernel.org, allison.henderson@oracle.com Message-ID: <170405006461.1804688.5728263139637208432.stgit@frogsfrogsfrogs> In-Reply-To: <170405006077.1804688.8762482665401724622.stgit@frogsfrogsfrogs> References: <170405006077.1804688.8762482665401724622.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 Do the xfs -> libxfs switcheroo and cleanups separately so the next patch doesn't become an even larger mess. Signed-off-by: Darrick J. Wong --- db/attr.c | 2 +- db/metadump.c | 2 +- libxfs/libxfs_api_defs.h | 5 +++++ repair/attr_repair.c | 6 +++--- 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/db/attr.c b/db/attr.c index 9e7bbd164df..95969d115d4 100644 --- a/db/attr.c +++ b/db/attr.c @@ -256,7 +256,7 @@ attr_leaf_entry_walk( return 0; off = byteize(startoff); - xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &leafhdr, leaf); + libxfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &leafhdr, leaf); entries = xfs_attr3_leaf_entryp(leaf); for (i = 0; i < leafhdr.count; i++) { diff --git a/db/metadump.c b/db/metadump.c index 5f5a33335b0..f5b930d51d2 100644 --- a/db/metadump.c +++ b/db/metadump.c @@ -1701,7 +1701,7 @@ process_attr_block( } /* Ok, it's a leaf - get header; accounts for crc & non-crc */ - xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &hdr, leaf); + libxfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &hdr, leaf); nentries = hdr.count; if (nentries == 0 || diff --git a/libxfs/libxfs_api_defs.h b/libxfs/libxfs_api_defs.h index a6b561b5b40..22e4c569170 100644 --- a/libxfs/libxfs_api_defs.h +++ b/libxfs/libxfs_api_defs.h @@ -36,7 +36,10 @@ #define xfs_ascii_ci_hashname libxfs_ascii_ci_hashname +#define xfs_attr3_leaf_hdr_from_disk libxfs_attr3_leaf_hdr_from_disk +#define xfs_attr3_leaf_read libxfs_attr3_leaf_read #define xfs_attr_get libxfs_attr_get +#define xfs_attr_is_leaf libxfs_attr_is_leaf #define xfs_attr_leaf_newentsize libxfs_attr_leaf_newentsize #define xfs_attr_namecheck libxfs_attr_namecheck #define xfs_attr_set libxfs_attr_set @@ -91,6 +94,7 @@ #define xfs_compute_rextslog libxfs_compute_rextslog #define xfs_create_space_res libxfs_create_space_res #define xfs_da3_node_hdr_from_disk libxfs_da3_node_hdr_from_disk +#define xfs_da3_node_read libxfs_da3_node_read #define xfs_da_get_buf libxfs_da_get_buf #define xfs_da_hashname libxfs_da_hashname #define xfs_da_read_buf libxfs_da_read_buf @@ -164,6 +168,7 @@ #define xfs_inobt_stage_cursor libxfs_inobt_stage_cursor #define xfs_inode_from_disk libxfs_inode_from_disk #define xfs_inode_from_disk_ts libxfs_inode_from_disk_ts +#define xfs_inode_hasattr libxfs_inode_hasattr #define xfs_inode_to_disk libxfs_inode_to_disk #define xfs_inode_validate_cowextsize libxfs_inode_validate_cowextsize #define xfs_inode_validate_extsize libxfs_inode_validate_extsize diff --git a/repair/attr_repair.c b/repair/attr_repair.c index 314a9cb4d6e..b0f6ee11ae4 100644 --- a/repair/attr_repair.c +++ b/repair/attr_repair.c @@ -596,7 +596,7 @@ process_leaf_attr_block( da_freemap_t *attr_freemap; struct xfs_attr3_icleaf_hdr leafhdr; - xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &leafhdr, leaf); + libxfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &leafhdr, leaf); clearit = usedbs = 0; firstb = mp->m_sb.sb_blocksize; stop = xfs_attr3_leaf_hdr_size(leaf); @@ -819,7 +819,7 @@ process_leaf_attr_level(xfs_mount_t *mp, } leaf = bp->b_addr; - xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &leafhdr, leaf); + libxfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &leafhdr, leaf); /* check magic number for leaf directory btree block */ if (!(leafhdr.magic == XFS_ATTR_LEAF_MAGIC || @@ -1017,7 +1017,7 @@ process_longform_leaf_root( * check sibling pointers in leaf block or root block 0 before * we have to release the btree block */ - xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &leafhdr, bp->b_addr); + libxfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &leafhdr, bp->b_addr); if (leafhdr.forw != 0 || leafhdr.back != 0) { if (!no_modify) { do_warn( From patchwork Sun Dec 31 23:12: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: 13508051 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 E76A9C2C5 for ; Sun, 31 Dec 2023 23:12:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="jVvSlolq" Received: by smtp.kernel.org (Postfix) with ESMTPSA id B768FC433C7; Sun, 31 Dec 2023 23:12:24 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704064344; bh=mXYcodJ52vnINEs0pgcJWnY9HUGUuMQeBih6NSdzMh0=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=jVvSlolqK5VdVbxZYfwh0N9iyHQlRGRCSKZAML1X+MCN+C1vaMvZAHxxejueDBupD h0OJUhnhsbhe+IHpHLRTq7QSU1nCwmpNuLy/mw/NoaJdKX6Ia3mccsuJCUx/H8/LzM tkDmWeBfO2jLFV7MJBdqQL+HjmY15v9ioS649x+vjmXCZSAGrwv/gkDtuJ3MoakHZW MKD3WzhV+f0zGz29nms8jPZDkoXR945i1Lgx3SOxtRqgPlTJuqWoOl9ji2FT0jaJIq J+H+XJriW2i9U5fB9Tg+j7AdVVVhwoKxvc/0+nKzUGxZ6SEu44nht9HS7H67NGYldt 8jj9eLYcaRwEA== Date: Sun, 31 Dec 2023 15:12:24 -0800 Subject: [PATCH 28/32] xfs_db: add a parents command to list the parents of a file From: "Darrick J. Wong" To: djwong@kernel.org, cem@kernel.org Cc: catherine.hoang@oracle.com, linux-xfs@vger.kernel.org, allison.henderson@oracle.com Message-ID: <170405006474.1804688.8496939238290408650.stgit@frogsfrogsfrogs> In-Reply-To: <170405006077.1804688.8762482665401724622.stgit@frogsfrogsfrogs> References: <170405006077.1804688.8762482665401724622.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 command to dump the parents of a file. Signed-off-by: Darrick J. Wong --- db/namei.c | 335 ++++++++++++++++++++++++++++++++++++++++++++++ libxfs/libxfs_api_defs.h | 1 man/man8/xfs_db.8 | 9 + 3 files changed, 345 insertions(+) diff --git a/db/namei.c b/db/namei.c index a8577b97222..fb7f63fda07 100644 --- a/db/namei.c +++ b/db/namei.c @@ -598,6 +598,338 @@ static struct cmdinfo ls_cmd = { .help = ls_help, }; +static void +pptr_emit( + struct xfs_mount *mp, + const struct xfs_parent_name_irec *irec) +{ + struct xfs_name xname = { + .name = irec->p_name, + .len = irec->p_namelen, + }; + xfs_dahash_t hash; + bool good; + + hash = libxfs_dir2_hashname(mp, &xname); + good = libxfs_parent_verify_irec(mp, irec); + + dbprintf("%18llu:0x%08x 0x%08x:0x%08x %3d %.*s %s\n", + irec->p_ino, irec->p_gen, irec->p_namehash, hash, + xname.len, xname.len, xname.name, + good ? _("(good)") : _("(corrupt)")); +} + +static int +list_sf_pptrs( + struct xfs_inode *ip) +{ + struct xfs_parent_name_irec irec; + struct xfs_attr_shortform *sf; + struct xfs_attr_sf_entry *sfe; + unsigned int i; + + sf = (struct xfs_attr_shortform *)ip->i_af.if_u1.if_data; + for (i = 0, sfe = &sf->list[0]; i < sf->hdr.count; i++) { + void *name = sfe->nameval; + void *value = &sfe->nameval[sfe->namelen]; + + if ((sfe->flags & XFS_ATTR_PARENT) && + libxfs_parent_namecheck(mp, name, sfe->namelen, sfe->flags) && + libxfs_parent_valuecheck(mp, value, sfe->valuelen)) { + libxfs_parent_irec_from_disk(&irec, name, value, + sfe->valuelen); + pptr_emit(mp, &irec); + } + + sfe = xfs_attr_sf_nextentry(sfe); + } + + return 0; +} + +static void +list_leaf_pptr_entries( + struct xfs_inode *ip, + struct xfs_buf *bp) +{ + struct xfs_parent_name_irec irec; + struct xfs_attr3_icleaf_hdr ichdr; + struct xfs_mount *mp = ip->i_mount; + struct xfs_attr_leafblock *leaf = bp->b_addr; + struct xfs_attr_leaf_entry *entry; + unsigned int i; + + libxfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &ichdr, leaf); + entry = xfs_attr3_leaf_entryp(leaf); + + for (i = 0; i < ichdr.count; entry++, i++) { + struct xfs_attr_leaf_name_local *name_loc; + void *value; + void *name; + unsigned int namelen, valuelen; + + if (!(entry->flags & XFS_ATTR_LOCAL) || + !(entry->flags & XFS_ATTR_PARENT)) + continue; + + name_loc = xfs_attr3_leaf_name_local(leaf, i); + name = name_loc->nameval; + namelen = name_loc->namelen; + value = &name_loc->nameval[name_loc->namelen]; + valuelen = be16_to_cpu(name_loc->valuelen); + + if (libxfs_parent_namecheck(mp, name, namelen, entry->flags) && + libxfs_parent_valuecheck(mp, value, valuelen)) { + libxfs_parent_irec_from_disk(&irec, name, value, + valuelen); + pptr_emit(mp, &irec); + } + } +} + +static int +list_leaf_pptrs( + struct xfs_inode *ip) +{ + struct xfs_buf *leaf_bp; + int error; + + error = -libxfs_attr3_leaf_read(NULL, ip, ip->i_ino, 0, &leaf_bp); + if (error) + return error; + + list_leaf_pptr_entries(ip, leaf_bp); + libxfs_trans_brelse(NULL, leaf_bp); + return 0; +} + +static int +find_leftmost_attr_leaf( + struct xfs_inode *ip, + struct xfs_buf **leaf_bpp) +{ + struct xfs_da3_icnode_hdr nodehdr; + struct xfs_mount *mp = ip->i_mount; + struct xfs_da_intnode *node; + struct xfs_da_node_entry *btree; + struct xfs_buf *bp; + xfs_dablk_t blkno = 0; + unsigned int expected_level = 0; + int error; + + for (;;) { + uint16_t magic; + + error = -libxfs_da3_node_read(NULL, ip, blkno, &bp, + XFS_ATTR_FORK); + if (error) + return error; + + node = bp->b_addr; + magic = be16_to_cpu(node->hdr.info.magic); + if (magic == XFS_ATTR_LEAF_MAGIC || + magic == XFS_ATTR3_LEAF_MAGIC) + break; + + error = EFSCORRUPTED; + if (magic != XFS_DA_NODE_MAGIC && + magic != XFS_DA3_NODE_MAGIC) + goto out_buf; + + libxfs_da3_node_hdr_from_disk(mp, &nodehdr, node); + + if (nodehdr.count == 0 || nodehdr.level >= XFS_DA_NODE_MAXDEPTH) + goto out_buf; + + /* Check the level from the root node. */ + if (blkno == 0) + expected_level = nodehdr.level - 1; + else if (expected_level != nodehdr.level) + goto out_buf; + else + expected_level--; + + /* Find the next level towards the leaves of the dabtree. */ + btree = nodehdr.btree; + blkno = be32_to_cpu(btree->before); + libxfs_trans_brelse(NULL, bp); + } + + error = EFSCORRUPTED; + if (expected_level != 0) + goto out_buf; + + *leaf_bpp = bp; + return 0; + +out_buf: + libxfs_trans_brelse(NULL, bp); + return error; +} + +static int +list_node_pptrs( + struct xfs_inode *ip) +{ + struct xfs_attr3_icleaf_hdr leafhdr; + struct xfs_mount *mp = ip->i_mount; + struct xfs_attr_leafblock *leaf; + struct xfs_buf *leaf_bp; + int error; + + error = find_leftmost_attr_leaf(ip, &leaf_bp); + if (error) + return error; + + for (;;) { + list_leaf_pptr_entries(ip, leaf_bp); + + /* Find the right sibling of this leaf block. */ + leaf = leaf_bp->b_addr; + libxfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &leafhdr, leaf); + if (leafhdr.forw == 0) + goto out_leaf; + + libxfs_trans_brelse(NULL, leaf_bp); + + error = -libxfs_attr3_leaf_read(NULL, ip, ip->i_ino, + leafhdr.forw, &leaf_bp); + if (error) + return error; + } + +out_leaf: + libxfs_trans_brelse(NULL, leaf_bp); + return error; +} + +static int +list_pptrs( + struct xfs_inode *ip) +{ + int error; + + if (!libxfs_inode_hasattr(ip)) + return 0; + + if (ip->i_af.if_format == XFS_DINODE_FMT_LOCAL) + return list_sf_pptrs(ip); + + /* attr functions require that the attr fork is loaded */ + error = -libxfs_iread_extents(NULL, ip, XFS_ATTR_FORK); + if (error) + return error; + + if (libxfs_attr_is_leaf(ip)) + return list_leaf_pptrs(ip); + + return list_node_pptrs(ip); +} + +/* If the io cursor points to a file, list its parents. */ +static int +parent_cur( + char *tag) +{ + struct xfs_inode *ip; + int error = 0; + + if (!xfs_has_parent(mp)) + return 0; + + if (iocur_top->typ != &typtab[TYP_INODE]) + return ENOTDIR; + + error = -libxfs_iget(mp, NULL, iocur_top->ino, 0, &ip); + if (error) + return error; + + /* List the parents of a file. */ + if (tag) + dbprintf(_("%s:\n"), tag); + + error = list_pptrs(ip); + if (error) + goto rele; + +rele: + libxfs_irele(ip); + return error; +} + +static void +parent_help(void) +{ + dbprintf(_( +"\n" +" List the parents of the currently selected file.\n" +"\n" +" Parent pointers will be listed in the format:\n" +" inode_number:inode_gen ondisk_namehash:namehash name_length name\n" + )); +} + +static int +parent_f( + int argc, + char **argv) +{ + int c; + int error = 0; + + while ((c = getopt(argc, argv, "")) != -1) { + switch (c) { + default: + ls_help(); + return 0; + } + } + + if (optind == argc) { + error = parent_cur(NULL); + if (error) { + dbprintf("%s\n", strerror(error)); + exitcode = 1; + } + + return 0; + } + + for (c = optind; c < argc; c++) { + push_cur(); + + error = path_walk(argv[c]); + if (error) + goto err_cur; + + error = parent_cur(argv[c]); + if (error) + goto err_cur; + + pop_cur(); + } + + return 0; +err_cur: + pop_cur(); + if (error) { + dbprintf("%s: %s\n", argv[c], strerror(error)); + exitcode = 1; + } + return 0; +} + +static struct cmdinfo parent_cmd = { + .name = "parent", + .altname = "pptr", + .cfunc = parent_f, + .argmin = 0, + .argmax = -1, + .canpush = 0, + .args = "[paths...]", + .help = parent_help, +}; + void namei_init(void) { @@ -606,4 +938,7 @@ namei_init(void) ls_cmd.oneline = _("list directory contents"); add_command(&ls_cmd); + + parent_cmd.oneline = _("list parent pointers"); + add_command(&parent_cmd); } diff --git a/libxfs/libxfs_api_defs.h b/libxfs/libxfs_api_defs.h index 22e4c569170..7ea7eebfbca 100644 --- a/libxfs/libxfs_api_defs.h +++ b/libxfs/libxfs_api_defs.h @@ -189,6 +189,7 @@ #define xfs_parent_hashcheck libxfs_parent_hashcheck #define xfs_parent_namecheck libxfs_parent_namecheck #define xfs_parent_valuecheck libxfs_parent_valuecheck +#define xfs_parent_verify_irec libxfs_parent_verify_irec #define xfs_perag_get libxfs_perag_get #define xfs_perag_hold libxfs_perag_hold #define xfs_perag_put libxfs_perag_put diff --git a/man/man8/xfs_db.8 b/man/man8/xfs_db.8 index a7f6d55ed8b..937b17e79a3 100644 --- a/man/man8/xfs_db.8 +++ b/man/man8/xfs_db.8 @@ -943,6 +943,15 @@ See the .B print command. .TP +.BI "parent [" 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 output format is: +inode number, inode generation, ondisk namehash, namehash, name length, name. +.TP .BI "path " dir_path Walk the directory tree to an inode using the supplied path. Absolute and relative paths are supported. From patchwork Sun Dec 31 23:12: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: 13508052 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 8FC6ED518 for ; Sun, 31 Dec 2023 23:12:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="ZZIK2Ql2" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 61AEEC433C8; Sun, 31 Dec 2023 23:12:40 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704064360; bh=GHPaI7DYe8ZMMq2rPXwpMHHLA8XeIzH9certDSh9zKY=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=ZZIK2Ql2jsQIDkS8nUXUMUacvqEDan2pTehyKDEDCWaxhuceQnbWsWsszo1n2Mr27 cc8vVGT/EtxECQUHPLr/A5XCUQVJsqUFgPfrPbLlbh0WEfXwfmSfJcyPwVTAcD6DYd p0sfuNYxTfAMq2XyP6CLGabKXKrL4UgWBag/C5qlzYKpwEcISmZ1/REt30NdxwVA2U glD7dHoyXG8vrfjC+8eW8l9MOV/jW/kAmxdNxfbBFfgfctHNPbDzFQ1qgr2GDJ4ZC8 c44WKHU0m5UlNDcQUHm6TSS0/1GQDnEQi26sXa9ocyE75JYJZ0hQNQj1g5eGXz2vMM oXaXbml0lREMw== Date: Sun, 31 Dec 2023 15:12:39 -0800 Subject: [PATCH 29/32] libxfs: create new files with attr forks if necessary From: "Darrick J. Wong" To: djwong@kernel.org, cem@kernel.org Cc: catherine.hoang@oracle.com, linux-xfs@vger.kernel.org, allison.henderson@oracle.com Message-ID: <170405006487.1804688.17023432522673020395.stgit@frogsfrogsfrogs> In-Reply-To: <170405006077.1804688.8762482665401724622.stgit@frogsfrogsfrogs> References: <170405006077.1804688.8762482665401724622.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 new files with attr forks if they're going to have parent pointers. In the next patch we'll fix mkfs to use the same parent creation functions as the kernel, so we're going to need this. Signed-off-by: Darrick J. Wong --- libxfs/init.c | 4 ++++ libxfs/util.c | 14 ++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/libxfs/init.c b/libxfs/init.c index b6b1282201c..397ce088d3a 100644 --- a/libxfs/init.c +++ b/libxfs/init.c @@ -655,14 +655,18 @@ void libxfs_compute_all_maxlevels( struct xfs_mount *mp) { + struct xfs_ino_geometry *igeo = M_IGEO(mp); + xfs_alloc_compute_maxlevels(mp); xfs_bmap_compute_maxlevels(mp, XFS_DATA_FORK); xfs_bmap_compute_maxlevels(mp, XFS_ATTR_FORK); + igeo->attr_fork_offset = xfs_bmap_compute_attr_offset(mp); xfs_ialloc_setup_geometry(mp); xfs_rmapbt_compute_maxlevels(mp); xfs_refcountbt_compute_maxlevels(mp); xfs_agbtree_compute_maxlevels(mp); + } /* diff --git a/libxfs/util.c b/libxfs/util.c index 03191ebcd08..5106a6433da 100644 --- a/libxfs/util.c +++ b/libxfs/util.c @@ -340,6 +340,20 @@ libxfs_init_new_inode( ASSERT(0); } + /* + * If we need to create attributes immediately after allocating the + * inode, initialise an empty attribute fork right now. We use the + * default fork offset for attributes here as we don't know exactly what + * size or how many attributes we might be adding. We can do this + * safely here because we know the data fork is completely empty and + * this saves us from needing to run a separate transaction to set the + * fork offset in the immediate future. + */ + if (xfs_has_parent(tp->t_mountp) && xfs_has_attr(tp->t_mountp)) { + ip->i_forkoff = xfs_default_attroffset(ip) >> 3; + xfs_ifork_init_attr(ip, XFS_DINODE_FMT_EXTENTS, 0); + } + /* * Log the new values stuffed into the inode. */ From patchwork Sun Dec 31 23:12: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: 13508053 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 96004D50B for ; Sun, 31 Dec 2023 23:12:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="ny9AuRi6" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 14761C433C8; Sun, 31 Dec 2023 23:12:56 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704064376; bh=IVHY0rDTAfNlDv/lHpXZIwFh0y72r7/eE+kQykGUfLY=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=ny9AuRi6bifONOEaC3JkdMxWpXFpY31WUjUjyUL4f84k9LdRU3h7RJXu7PZcGOEbR VTA/oS/y4ALfownOkxnXU9VTUUwTzgqAK95QdZxeQk/K8acp4jKvoY7lXC6TprDvWy Ns+Nte4ew+cnHa/m3V5fD3xtSpdlILch0kmAPg4VeKWDQPGEL5AGK2ZuQGYUKn8rwj 2sNxz3OaQ2yzPvuo0cMvC6FzILFfPVD7F4qcNHISyWI8/UPCOl9tSqP70s3cK9rcVs 4HXTeaPt5KjWcKOsnyWn9qINMVsJ8srwnV0v06eMNowrMO63u7TnJOdOsdlVt7xv0D 8lhqOmCcSQCig== Date: Sun, 31 Dec 2023 15:12:55 -0800 Subject: [PATCH 30/32] xfsprogs: Fix default superblock attr bits From: "Darrick J. Wong" To: djwong@kernel.org, cem@kernel.org Cc: Allison Henderson , catherine.hoang@oracle.com, linux-xfs@vger.kernel.org, allison.henderson@oracle.com Message-ID: <170405006500.1804688.11633053339413088287.stgit@frogsfrogsfrogs> In-Reply-To: <170405006077.1804688.8762482665401724622.stgit@frogsfrogsfrogs> References: <170405006077.1804688.8762482665401724622.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: Allison Henderson Recent parent pointer testing discovered that the default attr configuration has XFS_SB_VERSION2_ATTR2BIT enabled but XFS_SB_VERSION_ATTRBIT disabled. This is incorrect since XFS_SB_VERSION2_ATTR2BIT describes the format of the attr where as XFS_SB_VERSION_ATTRBIT enables or disables attrs. Fix this by enableing XFS_SB_VERSION_ATTRBIT for either attr version 1 or 2 Signed-off-by: Allison Henderson Reviewed-by: Darrick J. Wong Signed-off-by: Darrick J. Wong --- mkfs/xfs_mkfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c index 8b0fbe97ddc..cbfb89b6795 100644 --- a/mkfs/xfs_mkfs.c +++ b/mkfs/xfs_mkfs.c @@ -3424,7 +3424,7 @@ sb_set_features( sbp->sb_versionnum |= XFS_SB_VERSION_DALIGNBIT; if (fp->log_version == 2) sbp->sb_versionnum |= XFS_SB_VERSION_LOGV2BIT; - if (fp->attr_version == 1) + if (fp->attr_version >= 1) sbp->sb_versionnum |= XFS_SB_VERSION_ATTRBIT; if (fp->nci) sbp->sb_versionnum |= XFS_SB_VERSION_BORGBIT; From patchwork Sun Dec 31 23:13: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: 13508054 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 2C57CDF56 for ; Sun, 31 Dec 2023 23:13:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="jTJt9xNY" Received: by smtp.kernel.org (Postfix) with ESMTPSA id A7765C433C7; Sun, 31 Dec 2023 23:13:11 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704064391; bh=gLUJz5/0fcMTmExUdhG7SRgJDCO6pXjfqLnZgxYkXeI=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=jTJt9xNYienEdhRgfO7qzxSF5q7RShufLzDRNyeTTeUxP6j8/MEHUy5+SHvpJTc24 ypscNxjuBCE/EYXAl46yh+/xC6SRSf4MOw5pwmAU4DABz0tH+AlFTb8gD7tPQz21fa oZr1KCN8yK9j05LnN3j7vEX1yIskJbp4/zcxjshKzC/7upAgCL5KOJwfEag+EeAxzJ +J9uqMZjXurCIfUJwncKdzR5Jw+jtJYTm1eQlxc73CuDBv2WpvThCbtKz7kixsCyg9 9EkZA/91nK8ey0Jla7tMNLA8o6N+4EhuPewJSedMAmMArincCV2uD0nO5myG8nO6P5 V32zkMgyl7KCg== Date: Sun, 31 Dec 2023 15:13:11 -0800 Subject: [PATCH 31/32] mkfs: Add parent pointers during protofile creation From: "Darrick J. Wong" To: djwong@kernel.org, cem@kernel.org Cc: Allison Henderson , catherine.hoang@oracle.com, linux-xfs@vger.kernel.org, allison.henderson@oracle.com Message-ID: <170405006514.1804688.10799056762357845912.stgit@frogsfrogsfrogs> In-Reply-To: <170405006077.1804688.8762482665401724622.stgit@frogsfrogsfrogs> References: <170405006077.1804688.8762482665401724622.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: Allison Henderson Inodes created from protofile parsing will also need to add the appropriate parent pointers. Signed-off-by: Allison Henderson Reviewed-by: Darrick J. Wong [djwong: use xfs_parent_add from libxfs instead of open-coding xfs_attr_set] Signed-off-by: Darrick J. Wong --- mkfs/proto.c | 60 ++++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 46 insertions(+), 14 deletions(-) diff --git a/mkfs/proto.c b/mkfs/proto.c index 457899ac178..cc06bdfaf57 100644 --- a/mkfs/proto.c +++ b/mkfs/proto.c @@ -347,11 +347,12 @@ newregfile( static void newdirent( - xfs_mount_t *mp, - xfs_trans_t *tp, - xfs_inode_t *pip, - struct xfs_name *name, - xfs_ino_t inum) + struct xfs_mount *mp, + struct xfs_trans *tp, + struct xfs_inode *pip, + struct xfs_name *name, + struct xfs_inode *ip, + struct xfs_parent_args *ppargs) { int error; int rsv; @@ -364,9 +365,13 @@ newdirent( rsv = XFS_DIRENTER_SPACE_RES(mp, name->len); - error = -libxfs_dir_createname(tp, pip, name, inum, rsv); + error = -libxfs_dir_createname(tp, pip, name, ip->i_ino, rsv); if (error) fail(_("directory createname error"), error); + + error = -libxfs_parent_add(tp, ppargs, pip, name, ip); + if (error) + fail(_("committing parent pointers failed."), error); } static void @@ -383,6 +388,20 @@ newdirectory( fail(_("directory create error"), error); } +static struct xfs_parent_args * +newpptr( + struct xfs_mount *mp) +{ + struct xfs_parent_args *ret; + int error; + + error = -libxfs_parent_start(mp, &ret); + if (error) + fail(_("initializing parent pointer"), error); + + return ret; +} + static void parseproto( xfs_mount_t *mp, @@ -417,6 +436,7 @@ parseproto( struct cred creds; char *value; struct xfs_name xname; + struct xfs_parent_args *ppargs = NULL; memset(&creds, 0, sizeof(creds)); mstr = getstr(pp); @@ -491,6 +511,7 @@ parseproto( case IF_REGULAR: buf = newregfile(pp, &len); tp = getres(mp, XFS_B_TO_FSB(mp, len)); + ppargs = newpptr(mp); error = -libxfs_dir_ialloc(&tp, pip, mode|S_IFREG, 1, 0, &creds, fsxp, &ip); if (error) @@ -500,7 +521,7 @@ parseproto( free(buf); libxfs_trans_ijoin(tp, pip, 0); xname.type = XFS_DIR3_FT_REG_FILE; - newdirent(mp, tp, pip, &xname, ip->i_ino); + newdirent(mp, tp, pip, &xname, ip, ppargs); break; case IF_RESERVED: /* pre-allocated space only */ @@ -514,7 +535,7 @@ parseproto( exit(1); } tp = getres(mp, XFS_B_TO_FSB(mp, llen)); - + ppargs = newpptr(mp); error = -libxfs_dir_ialloc(&tp, pip, mode|S_IFREG, 1, 0, &creds, fsxp, &ip); if (error) @@ -523,17 +544,19 @@ parseproto( libxfs_trans_ijoin(tp, pip, 0); xname.type = XFS_DIR3_FT_REG_FILE; - newdirent(mp, tp, pip, &xname, ip->i_ino); + newdirent(mp, tp, pip, &xname, ip, ppargs); libxfs_trans_log_inode(tp, ip, flags); error = -libxfs_trans_commit(tp); if (error) fail(_("Space preallocation failed."), error); + libxfs_parent_finish(mp, ppargs); rsvfile(mp, ip, llen); libxfs_irele(ip); return; case IF_BLOCK: tp = getres(mp, 0); + ppargs = newpptr(mp); majdev = getnum(getstr(pp), 0, 0, false); mindev = getnum(getstr(pp), 0, 0, false); error = -libxfs_dir_ialloc(&tp, pip, mode|S_IFBLK, 1, @@ -543,12 +566,13 @@ parseproto( } libxfs_trans_ijoin(tp, pip, 0); xname.type = XFS_DIR3_FT_BLKDEV; - newdirent(mp, tp, pip, &xname, ip->i_ino); + newdirent(mp, tp, pip, &xname, ip, ppargs); flags |= XFS_ILOG_DEV; break; case IF_CHAR: tp = getres(mp, 0); + ppargs = newpptr(mp); majdev = getnum(getstr(pp), 0, 0, false); mindev = getnum(getstr(pp), 0, 0, false); error = -libxfs_dir_ialloc(&tp, pip, mode|S_IFCHR, 1, @@ -557,24 +581,26 @@ parseproto( fail(_("Inode allocation failed"), error); libxfs_trans_ijoin(tp, pip, 0); xname.type = XFS_DIR3_FT_CHRDEV; - newdirent(mp, tp, pip, &xname, ip->i_ino); + newdirent(mp, tp, pip, &xname, ip, ppargs); flags |= XFS_ILOG_DEV; break; case IF_FIFO: tp = getres(mp, 0); + ppargs = newpptr(mp); error = -libxfs_dir_ialloc(&tp, pip, mode|S_IFIFO, 1, 0, &creds, fsxp, &ip); if (error) fail(_("Inode allocation failed"), error); libxfs_trans_ijoin(tp, pip, 0); xname.type = XFS_DIR3_FT_FIFO; - newdirent(mp, tp, pip, &xname, ip->i_ino); + newdirent(mp, tp, pip, &xname, ip, ppargs); break; case IF_SYMLINK: buf = getstr(pp); len = (int)strlen(buf); tp = getres(mp, XFS_B_TO_FSB(mp, len)); + ppargs = newpptr(mp); error = -libxfs_dir_ialloc(&tp, pip, mode|S_IFLNK, 1, 0, &creds, fsxp, &ip); if (error) @@ -582,7 +608,7 @@ parseproto( writesymlink(tp, ip, buf, len); libxfs_trans_ijoin(tp, pip, 0); xname.type = XFS_DIR3_FT_SYMLINK; - newdirent(mp, tp, pip, &xname, ip->i_ino); + newdirent(mp, tp, pip, &xname, ip, ppargs); break; case IF_DIRECTORY: tp = getres(mp, 0); @@ -597,9 +623,10 @@ parseproto( libxfs_log_sb(tp); isroot = 1; } else { + ppargs = newpptr(mp); libxfs_trans_ijoin(tp, pip, 0); xname.type = XFS_DIR3_FT_DIR; - newdirent(mp, tp, pip, &xname, ip->i_ino); + newdirent(mp, tp, pip, &xname, ip, ppargs); libxfs_bumplink(tp, pip); libxfs_trans_log_inode(tp, pip, XFS_ILOG_CORE); } @@ -608,6 +635,9 @@ parseproto( error = -libxfs_trans_commit(tp); if (error) fail(_("Directory inode allocation failed."), error); + + libxfs_parent_finish(mp, ppargs); + /* * RT initialization. Do this here to ensure that * the RT inodes get placed after the root inode. @@ -635,6 +665,8 @@ parseproto( fail(_("Error encountered creating file from prototype file"), error); } + + libxfs_parent_finish(mp, ppargs); libxfs_irele(ip); } From patchwork Sun Dec 31 23:13: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: 13508055 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 7A1B3DF51 for ; Sun, 31 Dec 2023 23:13:27 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="a7ZbL+2d" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 482E5C433C7; Sun, 31 Dec 2023 23:13:27 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704064407; bh=0sUh9JPCtzjF5U222F5ebEV91YAMs/EEm5Ly7N+dzE0=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=a7ZbL+2djkyakghoWueljbNlSR1RNEqYEampMRMUD2Gm9gW9aefcguAST0PXylnfn IKDi6b2nDxlR9wnv8c+ggbC0k9T/+6fqWsR/0mVSz/0hAiN7DpB49LWKMpbEpIIhth bQBQVSjUGA/RSRPxjyMPYWIioyS16ndvS6vIEsOiGfiFmSIhOUeoc+WhvNjZXZNuZS EyxN3E+uyUYB8js74ETmpStDG8uKxEs8YSq3PQJyvjfbV+yzrE5Lxb75ugQxkzCN2m O0Bbs/udLIFP4c0neImHtjVyOM8OPLqfCdnEQRwb1BbTN83i9aKuHlRtcf8arPeBs5 cShh7hogseTvw== Date: Sun, 31 Dec 2023 15:13:26 -0800 Subject: [PATCH 32/32] mkfs: enable formatting with parent pointers From: "Darrick J. Wong" To: djwong@kernel.org, cem@kernel.org Cc: Allison Henderson , catherine.hoang@oracle.com, linux-xfs@vger.kernel.org, allison.henderson@oracle.com Message-ID: <170405006527.1804688.17342931533596284246.stgit@frogsfrogsfrogs> In-Reply-To: <170405006077.1804688.8762482665401724622.stgit@frogsfrogsfrogs> References: <170405006077.1804688.8762482665401724622.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: Allison Henderson Enable parent pointer support in mkfs via the '-n parent' parameter. Signed-off-by: Allison Henderson Reviewed-by: Darrick J. Wong Signed-off-by: Darrick J. Wong --- mkfs/xfs_mkfs.c | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c index cbfb89b6795..482275e0e0d 100644 --- a/mkfs/xfs_mkfs.c +++ b/mkfs/xfs_mkfs.c @@ -113,6 +113,7 @@ enum { N_SIZE = 0, N_VERSION, N_FTYPE, + N_PARENT, N_MAX_OPTS, }; @@ -648,6 +649,7 @@ static struct opt_params nopts = { [N_SIZE] = "size", [N_VERSION] = "version", [N_FTYPE] = "ftype", + [N_PARENT] = "parent", [N_MAX_OPTS] = NULL, }, .subopt_params = { @@ -671,6 +673,14 @@ static struct opt_params nopts = { .maxval = 1, .defaultval = 1, }, + { .index = N_PARENT, + .conflicts = { { NULL, LAST_CONFLICT } }, + .minval = 0, + .maxval = 1, + .defaultval = 1, + }, + + }, }; @@ -1030,7 +1040,7 @@ usage( void ) sunit=value|su=num,sectsize=num,lazy-count=0|1,\n\ concurrency=num]\n\ /* label */ [-L label (maximum 12 characters)]\n\ -/* naming */ [-n size=num,version=2|ci,ftype=0|1]\n\ +/* naming */ [-n size=num,version=2|ci,ftype=0|1,parent=0|1]]\n\ /* no-op info only */ [-N]\n\ /* prototype file */ [-p fname]\n\ /* quiet */ [-q]\n\ @@ -1865,6 +1875,9 @@ naming_opts_parser( case N_FTYPE: cli->sb_feat.dirftype = getnum(value, opts, subopt); break; + case N_PARENT: + cli->sb_feat.parent_pointers = getnum(value, &nopts, N_PARENT); + break; default: return -EINVAL; } @@ -2382,6 +2395,14 @@ _("inode btree counters not supported without finobt support\n")); cli->sb_feat.inobtcnt = false; } + if ((cli->sb_feat.parent_pointers) && + cli->sb_feat.dir_version == 4) { + fprintf(stderr, +_("parent pointers not supported on v4 filesystems\n")); + usage(); + cli->sb_feat.parent_pointers = false; + } + if (cli->xi->rt.name) { if (cli->sb_feat.reflink && cli_opt_set(&mopts, M_REFLINK)) { fprintf(stderr, @@ -3443,8 +3464,6 @@ sb_set_features( sbp->sb_features2 |= XFS_SB_VERSION2_LAZYSBCOUNTBIT; if (fp->projid32bit) sbp->sb_features2 |= XFS_SB_VERSION2_PROJID32BIT; - if (fp->parent_pointers) - sbp->sb_features2 |= XFS_SB_VERSION2_PARENTBIT; if (fp->crcs_enabled) sbp->sb_features2 |= XFS_SB_VERSION2_CRCBIT; if (fp->attr_version == 2) @@ -3485,6 +3504,10 @@ sb_set_features( sbp->sb_features_ro_compat |= XFS_SB_FEAT_RO_COMPAT_INOBTCNT; if (fp->bigtime) sbp->sb_features_incompat |= XFS_SB_FEAT_INCOMPAT_BIGTIME; + if (fp->parent_pointers) { + sbp->sb_features_incompat |= XFS_SB_FEAT_INCOMPAT_PARENT; + sbp->sb_versionnum |= XFS_SB_VERSION_ATTRBIT; + } /* * Sparse inode chunk support has two main inode alignment requirements.