From patchwork Sun Dec 31 20:48: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: 13507490 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 84B5FBA22 for ; Sun, 31 Dec 2023 20:48:46 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Dw1WlknS" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 06B72C433C7; Sun, 31 Dec 2023 20:48:45 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704055726; bh=x0+6qIR3pOHXhLqM/BZm7epT5k+S3eYMlGzwdfhoWnE=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=Dw1WlknSAB310sZlHooqxzTCKrRAA4jjqyceS+M+y6USxcMCZZKqKmP47ZSqx8y3/ o7FUWZKHl8TF3Z/sDXncgp5Bo6WxokaSjWvOOmF0+DSnvUz5XMBcDNYxcEEw97S+Hj BB9EPMdOol+XEFElEI4iTS9gPCaB7rFdqehIGaoedPPm0zVjXjy/RsQ2YytWfV9ILu beQZhRPCoeBfsg54eQwqHxIJblTV/RI8J+CrPELoD8lgPP5OzutHg2mStdUWORn3OW jsuGplpKfpQvzXhFfC6ho06RWZHFBbdIZunZWcC76+gx99P+y2ZjxtOj6qT0ja3kLW 144+1ZMshHi2w== Date: Sun, 31 Dec 2023 12:48:45 -0800 Subject: [PATCH 01/18] xfs: Expose init_xattrs in xfs_create_tmpfile From: "Darrick J. Wong" To: djwong@kernel.org Cc: Allison Henderson , catherine.hoang@oracle.com, allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <170404841053.1756905.7295680892065760737.stgit@frogsfrogsfrogs> In-Reply-To: <170404840995.1756905.18018727013229504371.stgit@frogsfrogsfrogs> References: <170404840995.1756905.18018727013229504371.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 Tmp files are used as part of rename operations and will need attr forks initialized for parent pointers. Expose the init_xattrs parameter to the calling function to initialize the fork. Signed-off-by: Allison Henderson Reviewed-by: Darrick J. Wong Signed-off-by: Darrick J. Wong --- fs/xfs/xfs_inode.c | 5 +++-- fs/xfs/xfs_inode.h | 2 +- fs/xfs/xfs_iops.c | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index 88e0e93ded2e4..f1f8f85f941eb 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -1197,6 +1197,7 @@ xfs_create_tmpfile( struct mnt_idmap *idmap, struct xfs_inode *dp, umode_t mode, + bool init_xattrs, struct xfs_inode **ipp) { struct xfs_mount *mp = dp->i_mount; @@ -1237,7 +1238,7 @@ xfs_create_tmpfile( error = xfs_dialloc(&tp, dp->i_ino, mode, &ino); if (!error) error = xfs_init_new_inode(idmap, tp, dp, ino, mode, - 0, 0, prid, false, &ip); + 0, 0, prid, init_xattrs, &ip); if (error) goto out_trans_cancel; @@ -3038,7 +3039,7 @@ xfs_rename_alloc_whiteout( int error; error = xfs_create_tmpfile(idmap, dp, S_IFCHR | WHITEOUT_MODE, - &tmpfile); + false, &tmpfile); if (error) return error; diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h index 4826155ad9147..14c6d9e7ab975 100644 --- a/fs/xfs/xfs_inode.h +++ b/fs/xfs/xfs_inode.h @@ -518,7 +518,7 @@ int xfs_create(struct mnt_idmap *idmap, umode_t mode, dev_t rdev, bool need_xattr, struct xfs_inode **ipp); int xfs_create_tmpfile(struct mnt_idmap *idmap, - struct xfs_inode *dp, umode_t mode, + struct xfs_inode *dp, umode_t mode, bool init_xattrs, struct xfs_inode **ipp); int xfs_remove(struct xfs_inode *dp, struct xfs_name *name, struct xfs_inode *ip); diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c index 037606e5eee40..d9277f7faf534 100644 --- a/fs/xfs/xfs_iops.c +++ b/fs/xfs/xfs_iops.c @@ -202,7 +202,7 @@ xfs_generic_create( xfs_create_need_xattr(dir, default_acl, acl), &ip); } else { - error = xfs_create_tmpfile(idmap, XFS_I(dir), mode, &ip); + error = xfs_create_tmpfile(idmap, XFS_I(dir), mode, false, &ip); } if (unlikely(error)) goto out_free_acl; From patchwork Sun Dec 31 20:49:01 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13507491 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 B50ECBA22 for ; Sun, 31 Dec 2023 20:49:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="iIWwh1pM" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 838E1C433C8; Sun, 31 Dec 2023 20:49:01 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704055741; bh=LQ2u1kkeBEMSKyZ4QHv8Poxi/3FDdjejC2OOTqSZBXI=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=iIWwh1pM5vTl8QAhpCL3wcwTXSftNt0WeqpQ3dCbB+E5kTDaO6kcXyzwHi1YID+J+ L/QnWACeC6e9SCeGkykLlnOvXIUn6zlerNIYh1j6XsfIH0G/s1Gs/eUL7NH+A1o6Ot V9P6sihmoDyHeGuD8yRxA3MxnBF5SQPnv3HdLk/VPpTDdI/3D/twqkmadiV7Jli6y6 HSmMjGkBVKbtqg27BblaVzI7Ai6yysfsV20zbcKjaA7U03a5Ur/cScDsB4HfReZZhT wRHg8qZzdnbK83X9S2ZYa+nykTUxl3ynTgufAlAwJj0iTmJxs1ON1DdiMeODAYnVZw N/1ZW4M+5nnVg== Date: Sun, 31 Dec 2023 12:49:01 -0800 Subject: [PATCH 02/18] xfs: add parent pointer support to attribute code From: "Darrick J. Wong" To: djwong@kernel.org Cc: Mark Tinguely , Dave Chinner , Allison Henderson , catherine.hoang@oracle.com, allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <170404841069.1756905.3898830797341643958.stgit@frogsfrogsfrogs> In-Reply-To: <170404840995.1756905.18018727013229504371.stgit@frogsfrogsfrogs> References: <170404840995.1756905.18018727013229504371.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 --- fs/xfs/libxfs/xfs_attr.c | 3 ++- fs/xfs/libxfs/xfs_da_format.h | 5 ++++- fs/xfs/libxfs/xfs_log_format.h | 1 + fs/xfs/scrub/attr.c | 2 +- fs/xfs/xfs_trace.h | 3 ++- 5 files changed, 10 insertions(+), 4 deletions(-) diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c index c6621af9554c2..579e63a1abf47 100644 --- a/fs/xfs/libxfs/xfs_attr.c +++ b/fs/xfs/libxfs/xfs_attr.c @@ -945,7 +945,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/fs/xfs/libxfs/xfs_da_format.h b/fs/xfs/libxfs/xfs_da_format.h index 0e1ada44f21ba..6b5971ee6804c 100644 --- a/fs/xfs/libxfs/xfs_da_format.h +++ b/fs/xfs/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/fs/xfs/libxfs/xfs_log_format.h b/fs/xfs/libxfs/xfs_log_format.h index 285a0a089df24..bded03634e53d 100644 --- a/fs/xfs/libxfs/xfs_log_format.h +++ b/fs/xfs/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) /* diff --git a/fs/xfs/scrub/attr.c b/fs/xfs/scrub/attr.c index ff83051c79818..247517f7e69bb 100644 --- a/fs/xfs/scrub/attr.c +++ b/fs/xfs/scrub/attr.c @@ -513,7 +513,7 @@ xchk_xattr_rec( /* Retrieve the entry and check it. */ hash = be32_to_cpu(ent->hashval); badflags = ~(XFS_ATTR_LOCAL | XFS_ATTR_ROOT | XFS_ATTR_SECURE | - XFS_ATTR_INCOMPLETE); + XFS_ATTR_INCOMPLETE | XFS_ATTR_PARENT); if ((ent->flags & badflags) != 0) xchk_da_set_corrupt(ds, level); if (ent->flags & XFS_ATTR_LOCAL) { diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h index 2c838b7471191..1dac853aa659e 100644 --- a/fs/xfs/xfs_trace.h +++ b/fs/xfs/xfs_trace.h @@ -87,7 +87,8 @@ struct xfs_swapext_req; #define XFS_ATTR_FILTER_FLAGS \ { XFS_ATTR_ROOT, "ROOT" }, \ { XFS_ATTR_SECURE, "SECURE" }, \ - { XFS_ATTR_INCOMPLETE, "INCOMPLETE" } + { XFS_ATTR_INCOMPLETE, "INCOMPLETE" }, \ + { XFS_ATTR_PARENT, "PARENT" } DECLARE_EVENT_CLASS(xfs_attr_list_class, TP_PROTO(struct xfs_attr_list_context *ctx), From patchwork Sun Dec 31 20:49: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: 13507492 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 623DABA22 for ; Sun, 31 Dec 2023 20:49:17 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Mcbe7ZxK" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 367E2C433C7; Sun, 31 Dec 2023 20:49:17 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704055757; bh=KhXlaEpYyx6H9NPZWVIv2dclEWGbre5AqbzRqLOgc7g=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=Mcbe7ZxKZSRLz4cvPVBzDTZvpQAe96fsnWMPG3j/Nb3HzB5RG1Sj1TylI4R2bgLki 9Y2ypmnmf/HKUgn7Pc6FWanM/i+vJD6lqaMgkTZiZm3yztLBqA83d0dzS80VDPBJio FThkEoFCQYQwHAK96vS3W0oGlVLpWrmj6UfkNGWEVmDOLIcwqsA60BRTzLdpGL+Cj9 yHLfMjnUc6ffugdCqXaRM2uqWERXlbbIKvL3nElJUlfGQJBafRGvDqKcFkc3dhPMHc 22GB7+RoqwNK/qKL3exjHzMnjH7nQUDGxRmpFRjyl3hzyGyG66/hN+gu+Spu2dBx7I Rqurd20EQwf+w== Date: Sun, 31 Dec 2023 12:49:16 -0800 Subject: [PATCH 03/18] xfs: define parent pointer ondisk extended attribute format From: "Darrick J. Wong" To: djwong@kernel.org Cc: Dave Chinner , Allison Henderson , catherine.hoang@oracle.com, allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <170404841086.1756905.16134755883883895795.stgit@frogsfrogsfrogs> In-Reply-To: <170404840995.1756905.18018727013229504371.stgit@frogsfrogsfrogs> References: <170404840995.1756905.18018727013229504371.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 --- fs/xfs/libxfs/xfs_da_format.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/fs/xfs/libxfs/xfs_da_format.h b/fs/xfs/libxfs/xfs_da_format.h index 6b5971ee6804c..edbd901d90659 100644 --- a/fs/xfs/libxfs/xfs_da_format.h +++ b/fs/xfs/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 20:49: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: 13507493 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 76F33BA30 for ; Sun, 31 Dec 2023 20:49:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="M++R73BM" Received: by smtp.kernel.org (Postfix) with ESMTPSA id E2EB3C433C8; Sun, 31 Dec 2023 20:49:32 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704055773; bh=HmIWa6hQv66+xUYQKW73AXW5aQjYsBoH8p3eSfadbKY=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=M++R73BMZiXT8Z66ssPzakfBQ7ilXxNyN0JpCOw7gsGKthsRuTC6RntWhrOvpiZwZ 56fVsKfqT3Y6pQQEydu5bIuKyfr9GhGqFuXlG0QY9AEkYkElAdNxPlKPt10NANStf5 wm+0TQGQTz7/xsdOHFHJzvGWBzdnu2jBztOUmGQJ2WtqW+vU3E/cvOK+lEEY3inZLe FMBFpiO1IvElwh18MxiOzZTa3lBSIsggVAYJ/K+VSQVPu1Hc8mosPVP+sGryDPnn2k v2G6/WpQKE4825ghbne2rWOHv+fo/AIpoBqCZTPHr3YmvRcv5by1hP6BZNx+pl1gfH fmZGClBK54pxg== Date: Sun, 31 Dec 2023 12:49:32 -0800 Subject: [PATCH 04/18] xfs: add parent pointer validator functions From: "Darrick J. Wong" To: djwong@kernel.org Cc: Allison Henderson , catherine.hoang@oracle.com, allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <170404841102.1756905.17706064794233084000.stgit@frogsfrogsfrogs> In-Reply-To: <170404840995.1756905.18018727013229504371.stgit@frogsfrogsfrogs> References: <170404840995.1756905.18018727013229504371.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 --- fs/xfs/Makefile | 1 fs/xfs/libxfs/xfs_attr.c | 10 +++- fs/xfs/libxfs/xfs_attr.h | 3 + fs/xfs/libxfs/xfs_da_format.h | 8 +++ fs/xfs/libxfs/xfs_parent.c | 113 +++++++++++++++++++++++++++++++++++++++++ fs/xfs/libxfs/xfs_parent.h | 19 +++++++ fs/xfs/scrub/attr.c | 2 - fs/xfs/xfs_attr_item.c | 42 ++++++++++++++- fs/xfs/xfs_attr_list.c | 17 ++++-- 9 files changed, 203 insertions(+), 12 deletions(-) create mode 100644 fs/xfs/libxfs/xfs_parent.c create mode 100644 fs/xfs/libxfs/xfs_parent.h diff --git a/fs/xfs/Makefile b/fs/xfs/Makefile index 09016465d4925..64ff5295d3fc9 100644 --- a/fs/xfs/Makefile +++ b/fs/xfs/Makefile @@ -41,6 +41,7 @@ xfs-y += $(addprefix libxfs/, \ xfs_inode_buf.o \ xfs_log_rlimit.o \ xfs_ag_resv.o \ + xfs_parent.o \ xfs_rmap.o \ xfs_rmap_btree.o \ xfs_refcount.o \ diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c index 579e63a1abf47..d513ed57177e1 100644 --- a/fs/xfs/libxfs/xfs_attr.c +++ b/fs/xfs/libxfs/xfs_attr.c @@ -26,6 +26,7 @@ #include "xfs_trace.h" #include "xfs_attr_item.h" #include "xfs_xattr.h" +#include "xfs_parent.h" struct kmem_cache *xfs_attr_intent_cache; @@ -1545,9 +1546,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/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h index b4e8ecee3e039..5b3a0d4b1583c 100644 --- a/fs/xfs/libxfs/xfs_attr.h +++ b/fs/xfs/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/fs/xfs/libxfs/xfs_da_format.h b/fs/xfs/libxfs/xfs_da_format.h index edbd901d90659..a63387796a246 100644 --- a/fs/xfs/libxfs/xfs_da_format.h +++ b/fs/xfs/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/fs/xfs/libxfs/xfs_parent.c b/fs/xfs/libxfs/xfs_parent.c new file mode 100644 index 0000000000000..1d45f926c13a6 --- /dev/null +++ b/fs/xfs/libxfs/xfs_parent.c @@ -0,0 +1,113 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2022-2024 Oracle. + * All rights reserved. + */ +#include "xfs.h" +#include "xfs_fs.h" +#include "xfs_format.h" +#include "xfs_da_format.h" +#include "xfs_log_format.h" +#include "xfs_shared.h" +#include "xfs_trans_resv.h" +#include "xfs_mount.h" +#include "xfs_bmap_btree.h" +#include "xfs_inode.h" +#include "xfs_error.h" +#include "xfs_trace.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_defer.h" +#include "xfs_log.h" +#include "xfs_xattr.h" +#include "xfs_parent.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/fs/xfs/libxfs/xfs_parent.h b/fs/xfs/libxfs/xfs_parent.h new file mode 100644 index 0000000000000..fcfeddb645f6d --- /dev/null +++ b/fs/xfs/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/fs/xfs/scrub/attr.c b/fs/xfs/scrub/attr.c index 247517f7e69bb..f213d745746fd 100644 --- a/fs/xfs/scrub/attr.c +++ b/fs/xfs/scrub/attr.c @@ -206,7 +206,7 @@ xchk_xattr_actor( } /* Does this name make sense? */ - if (!xfs_attr_namecheck(name, namelen)) { + if (!xfs_attr_namecheck(sc->mp, name, namelen, attr_flags)) { xchk_fblock_set_corrupt(sc, XFS_ATTR_FORK, args.blkno); return -ECANCELED; } diff --git a/fs/xfs/xfs_attr_item.c b/fs/xfs/xfs_attr_item.c index a1c8036310b21..96b8f58bc5770 100644 --- a/fs/xfs/xfs_attr_item.c +++ b/fs/xfs/xfs_attr_item.c @@ -27,6 +27,7 @@ #include "xfs_error.h" #include "xfs_log_priv.h" #include "xfs_log_recover.h" +#include "xfs_parent.h" struct kmem_cache *xfs_attri_cache; struct kmem_cache *xfs_attrd_cache; @@ -687,7 +688,8 @@ xfs_attr_recover_work( */ attrp = &attrip->attri_format; if (!xfs_attri_validate(mp, attrp) || - !xfs_attr_namecheck(nv->name.i_addr, nv->name.i_len)) + !xfs_attr_namecheck(mp, nv->name.i_addr, nv->name.i_len, + attrp->alfi_attr_filter)) return -EFSCORRUPTED; attr = xfs_attri_recover_work(mp, dfp, attrp, &ip, nv); @@ -896,7 +898,8 @@ xlog_recover_attri_commit_pass2( } attr_name = item->ri_buf[i].i_addr; - if (!xfs_attr_namecheck(attr_name, name_len)) { + if (!xfs_attr_namecheck(mp, attr_name, name_len, + attri_formatp->alfi_attr_filter)) { XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, attri_formatp, len); return -EFSCORRUPTED; @@ -913,7 +916,8 @@ xlog_recover_attri_commit_pass2( } attr_new_name = item->ri_buf[i].i_addr; - if (!xfs_attr_namecheck(attr_new_name, new_name_len)) { + if (!xfs_attr_namecheck(mp, attr_new_name, new_name_len, + attri_formatp->alfi_attr_filter)) { XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, item->ri_buf[i].i_addr, item->ri_buf[i].i_len); @@ -931,6 +935,22 @@ xlog_recover_attri_commit_pass2( } attr_value = item->ri_buf[i].i_addr; + if ((attri_formatp->alfi_attr_filter & XFS_ATTR_PARENT) && + !xfs_parent_valuecheck(mp, attr_value, value_len)) { + XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, + item->ri_buf[i].i_addr, + item->ri_buf[i].i_len); + return -EFSCORRUPTED; + } + if ((attri_formatp->alfi_attr_filter & XFS_ATTR_PARENT) && + (attr_name == NULL || + !xfs_parent_hashcheck(mp, attr_name, attr_value, + value_len))) { + XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, + item->ri_buf[i].i_addr, + item->ri_buf[i].i_len); + return -EFSCORRUPTED; + } i++; } @@ -943,6 +963,22 @@ xlog_recover_attri_commit_pass2( } attr_new_value = item->ri_buf[i].i_addr; + if ((attri_formatp->alfi_attr_filter & XFS_ATTR_PARENT) && + !xfs_parent_valuecheck(mp, attr_new_value, new_value_len)) { + XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, + item->ri_buf[i].i_addr, + item->ri_buf[i].i_len); + return -EFSCORRUPTED; + } + if ((attri_formatp->alfi_attr_filter & XFS_ATTR_PARENT) && + (attr_new_name == NULL || + !xfs_parent_hashcheck(mp, attr_new_name, attr_new_value, + new_value_len))) { + XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, + item->ri_buf[i].i_addr, + item->ri_buf[i].i_len); + return -EFSCORRUPTED; + } i++; } diff --git a/fs/xfs/xfs_attr_list.c b/fs/xfs/xfs_attr_list.c index 24516f3ff2df7..c86e5952c1378 100644 --- a/fs/xfs/xfs_attr_list.c +++ b/fs/xfs/xfs_attr_list.c @@ -59,9 +59,13 @@ xfs_attr_shortform_list( struct xfs_attr_sf_sort *sbuf, *sbp; struct xfs_attr_shortform *sf; struct xfs_attr_sf_entry *sfe; + struct xfs_mount *mp; int sbsize, nsbuf, count, i; int error = 0; + ASSERT(context != NULL); + ASSERT(dp != NULL); + mp = dp->i_mount; sf = (struct xfs_attr_shortform *)dp->i_af.if_u1.if_data; ASSERT(sf != NULL); if (!sf->hdr.count) @@ -83,8 +87,9 @@ xfs_attr_shortform_list( (dp->i_af.if_bytes + sf->hdr.count * 16) < context->bufsize)) { for (i = 0, sfe = &sf->list[0]; i < sf->hdr.count; i++) { if (XFS_IS_CORRUPT(context->dp->i_mount, - !xfs_attr_namecheck(sfe->nameval, - sfe->namelen))) { + !xfs_attr_namecheck(mp, sfe->nameval, + sfe->namelen, + sfe->flags))) { xfs_dirattr_mark_sick(context->dp, XFS_ATTR_FORK); return -EFSCORRUPTED; } @@ -178,8 +183,9 @@ xfs_attr_shortform_list( cursor->offset = 0; } if (XFS_IS_CORRUPT(context->dp->i_mount, - !xfs_attr_namecheck(sbp->name, - sbp->namelen))) { + !xfs_attr_namecheck(mp, sbp->name, + sbp->namelen, + sbp->flags))) { xfs_dirattr_mark_sick(context->dp, XFS_ATTR_FORK); error = -EFSCORRUPTED; goto out; @@ -503,7 +509,8 @@ xfs_attr3_leaf_list_int( } if (XFS_IS_CORRUPT(context->dp->i_mount, - !xfs_attr_namecheck(name, namelen))) { + !xfs_attr_namecheck(mp, name, namelen, + entry->flags))) { xfs_dirattr_mark_sick(context->dp, XFS_ATTR_FORK); return -EFSCORRUPTED; } From patchwork Sun Dec 31 20:49:48 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: 13507494 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 1D6B2BA2E for ; Sun, 31 Dec 2023 20:49:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Ub7eERCr" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 96AB7C433C8; Sun, 31 Dec 2023 20:49:48 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704055788; bh=45IJMIwCDeSqHo7vo/S8nqi0Hrf43mOv/fDYqyBMWZQ=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=Ub7eERCrb7PdMJpXKwm6azTNlb/qLvAwJHu9I2rXOk3Q1n3Z11DyfTLsYfnCsZBm4 g6ro2qVbrHRjM60BaaIauDb53sBIPGwal3QdXKd635n4sph+xHRtJKEtQoumkmxJD8 3960KEVBYeXQqSWGSSrhcPPjFHJUSZNqqoVf9YpVukzW5jtAnA7t6FXi9ZtfvVhnnS f9+gQTCU+pUqN3XsDx7GCuwUnBW5TZaTP0GiZs41jweSe5+ZuJdARIk4caCSvT2ALk RfQl9U6yTrpZUZUAp1VqcPfoVHc2TLP+NSYvTXAQWfAdWqJ/gt6qjFFUob2mRjMs34 O/q0Bxhky+ADw== Date: Sun, 31 Dec 2023 12:49:48 -0800 Subject: [PATCH 05/18] xfs: extend transaction reservations for parent attributes From: "Darrick J. Wong" To: djwong@kernel.org Cc: Dave Chinner , Allison Henderson , catherine.hoang@oracle.com, allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <170404841118.1756905.15714840751590105073.stgit@frogsfrogsfrogs> In-Reply-To: <170404840995.1756905.18018727013229504371.stgit@frogsfrogsfrogs> References: <170404840995.1756905.18018727013229504371.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 --- fs/xfs/libxfs/xfs_trans_resv.c | 326 ++++++++++++++++++++++++++++++++++------ 1 file changed, 274 insertions(+), 52 deletions(-) diff --git a/fs/xfs/libxfs/xfs_trans_resv.c b/fs/xfs/libxfs/xfs_trans_resv.c index 6cd45e8c118da..b390d9aa02142 100644 --- a/fs/xfs/libxfs/xfs_trans_resv.c +++ b/fs/xfs/libxfs/xfs_trans_resv.c @@ -20,6 +20,9 @@ #include "xfs_qm.h" #include "xfs_trans_space.h" #include "xfs_rtbitmap.h" +#include "xfs_attr_item.h" +#include "xfs_log.h" +#include "xfs_da_format.h" #define _ALLOC true #define _FREE false @@ -422,29 +425,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; } /* @@ -461,6 +545,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 @@ -477,14 +578,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); } /* @@ -499,6 +609,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 @@ -515,14 +642,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); } /* @@ -571,12 +708,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 @@ -589,6 +754,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. */ @@ -599,6 +781,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 @@ -911,6 +1109,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, @@ -930,35 +1174,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; @@ -988,6 +1208,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 20:50: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: 13507495 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 CA199BA2B for ; Sun, 31 Dec 2023 20:50:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="A+XKi9cV" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 49A02C433C8; Sun, 31 Dec 2023 20:50:04 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704055804; bh=78JarBRLz3QjY1lDxBi7IeTeMpvb4jxRubRzH1BQaEI=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=A+XKi9cVdmMl8+t1HV0PXNUKf6Qekh6clLZss+0ZyirG8dJCoEMxN2uMsqtgvdf7+ bwVyF3/37tZKUhhQaGTRs51zuS9U0A0kKykssTgeaLDd5uGSkeO2atJGoVttTtYSTR 0wuqq4RKFNfFP2d45dvTlZilnFgG07mIYhQnv3QirJzsim2d7v2v8VjLap5ii7hsq1 NUo2fORbLKBhA4Ki6pAa2X/muMQOs9K76g6RxAdeVCZCNipGldvZvxBZuuBRWqr9ft 8jPvwXeeIyTaYAe84vKQVMvZqswrUXY+mr4aTKOGSbJxcl8B5jGtokxpABxflqc0N0 DwXNxc/ezuEGw== Date: Sun, 31 Dec 2023 12:50:03 -0800 Subject: [PATCH 06/18] xfs: parent pointer attribute creation From: "Darrick J. Wong" To: djwong@kernel.org Cc: Dave Chinner , Allison Henderson , catherine.hoang@oracle.com, allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <170404841134.1756905.1993997240273692140.stgit@frogsfrogsfrogs> In-Reply-To: <170404840995.1756905.18018727013229504371.stgit@frogsfrogsfrogs> References: <170404840995.1756905.18018727013229504371.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 --- fs/xfs/Makefile | 1 fs/xfs/libxfs/xfs_attr.c | 2 - fs/xfs/libxfs/xfs_attr.h | 2 - fs/xfs/libxfs/xfs_parent.c | 91 +++++++++++++++++++++++++++++++++++++++ fs/xfs/libxfs/xfs_parent.h | 77 +++++++++++++++++++++++++++++++++ fs/xfs/libxfs/xfs_trans_space.c | 52 ++++++++++++++++++++++ fs/xfs/libxfs/xfs_trans_space.h | 9 ++-- fs/xfs/scrub/tempfile.c | 2 - fs/xfs/xfs_inode.c | 30 ++++++++++--- fs/xfs/xfs_iops.c | 15 ++++++ fs/xfs/xfs_super.c | 10 ++++ fs/xfs/xfs_xattr.c | 4 +- fs/xfs/xfs_xattr.h | 2 + 13 files changed, 280 insertions(+), 17 deletions(-) create mode 100644 fs/xfs/libxfs/xfs_trans_space.c diff --git a/fs/xfs/Makefile b/fs/xfs/Makefile index 64ff5295d3fc9..5a358113ad9d7 100644 --- a/fs/xfs/Makefile +++ b/fs/xfs/Makefile @@ -51,6 +51,7 @@ xfs-y += $(addprefix libxfs/, \ xfs_symlink_remote.o \ xfs_trans_inode.o \ xfs_trans_resv.o \ + xfs_trans_space.o \ xfs_types.o \ ) # xfs_rtbitmap is shared with libxfs diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c index d513ed57177e1..c13eb7b7b5b8f 100644 --- a/fs/xfs/libxfs/xfs_attr.c +++ b/fs/xfs/libxfs/xfs_attr.c @@ -895,7 +895,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/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h index 5b3a0d4b1583c..4a4d45a96dd6c 100644 --- a/fs/xfs/libxfs/xfs_attr.h +++ b/fs/xfs/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/fs/xfs/libxfs/xfs_parent.c b/fs/xfs/libxfs/xfs_parent.c index 1d45f926c13a6..05ef155388a12 100644 --- a/fs/xfs/libxfs/xfs_parent.c +++ b/fs/xfs/libxfs/xfs_parent.c @@ -28,6 +28,8 @@ #include "xfs_parent.h" #include "xfs_trans_space.h" +struct kmem_cache *xfs_parent_args_cache; + /* * Parent pointer attribute handling. * @@ -111,3 +113,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/fs/xfs/libxfs/xfs_parent.h b/fs/xfs/libxfs/xfs_parent.h index fcfeddb645f6d..e2115a2b9648b 100644 --- a/fs/xfs/libxfs/xfs_parent.h +++ b/fs/xfs/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/fs/xfs/libxfs/xfs_trans_space.c b/fs/xfs/libxfs/xfs_trans_space.c new file mode 100644 index 0000000000000..90532c3fa2053 --- /dev/null +++ b/fs/xfs/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 "xfs.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/fs/xfs/libxfs/xfs_trans_space.h b/fs/xfs/libxfs/xfs_trans_space.h index 9640fc232c147..6cda87153b38c 100644 --- a/fs/xfs/libxfs/xfs_trans_space.h +++ b/fs/xfs/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/fs/xfs/scrub/tempfile.c b/fs/xfs/scrub/tempfile.c index 9e0f1d311118b..43d48f1e331de 100644 --- a/fs/xfs/scrub/tempfile.c +++ b/fs/xfs/scrub/tempfile.c @@ -71,7 +71,7 @@ xrep_tempfile_create( return error; if (is_dir) { - resblks = XFS_MKDIR_SPACE_RES(mp, 0); + resblks = xfs_mkdir_space_res(mp, 0); tres = &M_RES(mp)->tr_mkdir; } else { resblks = XFS_IALLOC_SPACE_RES(mp); diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index f1f8f85f941eb..20aee9db1b43a 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -40,6 +40,8 @@ #include "xfs_log_priv.h" #include "xfs_health.h" #include "xfs_pnfs.h" +#include "xfs_parent.h" +#include "xfs_xattr.h" struct kmem_cache *xfs_inode_cache; @@ -1029,7 +1031,7 @@ xfs_dir_hook_del( int xfs_create( struct mnt_idmap *idmap, - xfs_inode_t *dp, + struct xfs_inode *dp, struct xfs_name *name, umode_t mode, dev_t rdev, @@ -1041,7 +1043,7 @@ xfs_create( struct xfs_inode *ip = NULL; struct xfs_trans *tp = NULL; int error; - bool unlock_dp_on_error = false; + bool unlock_dp_on_error = false; prid_t prid; struct xfs_dquot *udqp = NULL; struct xfs_dquot *gdqp = NULL; @@ -1049,6 +1051,7 @@ xfs_create( struct xfs_trans_res *tres; uint resblks; xfs_ino_t ino; + struct xfs_parent_args *ppargs; trace_xfs_create(dp, name); @@ -1070,13 +1073,17 @@ xfs_create( return error; if (is_dir) { - resblks = XFS_MKDIR_SPACE_RES(mp, name->len); + resblks = xfs_mkdir_space_res(mp, name->len); tres = &M_RES(mp)->tr_mkdir; } else { - resblks = XFS_CREATE_SPACE_RES(mp, name->len); + resblks = xfs_create_space_res(mp, name->len); tres = &M_RES(mp)->tr_create; } + error = xfs_parent_start(mp, &ppargs); + if (error) + goto out_release_dquots; + /* * Initially assume that the file does not exist and * reserve the resources for that case. If that is not @@ -1092,7 +1099,7 @@ xfs_create( resblks, &tp); } if (error) - goto out_release_dquots; + goto out_parent; xfs_ilock(dp, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT); unlock_dp_on_error = true; @@ -1135,6 +1142,14 @@ xfs_create( xfs_bumplink(tp, dp); } + /* + * If we have parent pointers, we need to add the attribute containing + * the parent information now. + */ + error = xfs_parent_add(tp, ppargs, dp, name, ip); + if (error) + goto out_trans_cancel; + /* * Create ip with a reference from dp, and add '.' and '..' references * if it's a directory. @@ -1167,6 +1182,7 @@ xfs_create( *ipp = ip; xfs_iunlock(ip, XFS_ILOCK_EXCL); xfs_iunlock(dp, XFS_ILOCK_EXCL); + xfs_parent_finish(mp, ppargs); return 0; out_trans_cancel: @@ -1182,6 +1198,8 @@ xfs_create( xfs_finish_inode_setup(ip); xfs_irele(ip); } + out_parent: + xfs_parent_finish(mp, ppargs); out_release_dquots: xfs_qm_dqrele(udqp); xfs_qm_dqrele(gdqp); @@ -3039,7 +3057,7 @@ xfs_rename_alloc_whiteout( int error; error = xfs_create_tmpfile(idmap, dp, S_IFCHR | WHITEOUT_MODE, - false, &tmpfile); + xfs_has_parent(dp->i_mount), &tmpfile); if (error) return error; diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c index d9277f7faf534..62b425129d11c 100644 --- a/fs/xfs/xfs_iops.c +++ b/fs/xfs/xfs_iops.c @@ -158,6 +158,8 @@ xfs_create_need_xattr( if (dir->i_sb->s_security) return true; #endif + if (xfs_has_parent(XFS_I(dir)->i_mount)) + return true; return false; } @@ -202,7 +204,18 @@ xfs_generic_create( xfs_create_need_xattr(dir, default_acl, acl), &ip); } else { - error = xfs_create_tmpfile(idmap, XFS_I(dir), mode, false, &ip); + bool init_xattrs = false; + + /* + * If this temporary file will be linkable, set up the file + * with an attr fork to receive a parent pointer. + */ + if (!(tmpfile->f_flags & O_EXCL) && + xfs_has_parent(XFS_I(dir)->i_mount)) + init_xattrs = true; + + error = xfs_create_tmpfile(idmap, XFS_I(dir), mode, + init_xattrs, &ip); } if (unlikely(error)) goto out_free_acl; diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c index e6e8e8fb17a19..e981c8b666a5d 100644 --- a/fs/xfs/xfs_super.c +++ b/fs/xfs/xfs_super.c @@ -44,6 +44,7 @@ #include "xfs_dahash_test.h" #include "xfs_rtbitmap.h" #include "xfs_swapext_item.h" +#include "xfs_parent.h" #include "scrub/stats.h" #include "scrub/rcbag_btree.h" @@ -2209,8 +2210,16 @@ xfs_init_caches(void) if (!xfs_sxi_cache) goto out_destroy_sxd_cache; + xfs_parent_args_cache = kmem_cache_create("xfs_parent_args", + sizeof(struct xfs_parent_args), + 0, 0, NULL); + if (!xfs_parent_args_cache) + goto out_destroy_sxi_cache; + return 0; + out_destroy_sxi_cache: + kmem_cache_destroy(xfs_sxi_cache); out_destroy_sxd_cache: kmem_cache_destroy(xfs_sxd_cache); out_destroy_iul_cache: @@ -2271,6 +2280,7 @@ xfs_destroy_caches(void) * destroy caches. */ rcu_barrier(); + kmem_cache_destroy(xfs_parent_args_cache); kmem_cache_destroy(xfs_sxd_cache); kmem_cache_destroy(xfs_sxi_cache); kmem_cache_destroy(xfs_iunlink_cache); diff --git a/fs/xfs/xfs_xattr.c b/fs/xfs/xfs_xattr.c index 2339e3fcfb384..12405e4a70c1b 100644 --- a/fs/xfs/xfs_xattr.c +++ b/fs/xfs/xfs_xattr.c @@ -27,7 +27,7 @@ * they must release the permission by calling xlog_drop_incompat_feat * when they're done. */ -static inline int +int xfs_attr_grab_log_assist( struct xfs_mount *mp) { @@ -79,7 +79,7 @@ xfs_attr_grab_log_assist( return error; } -static inline void +void xfs_attr_rele_log_assist( struct xfs_mount *mp) { diff --git a/fs/xfs/xfs_xattr.h b/fs/xfs/xfs_xattr.h index cec766cad26cd..f097002d06571 100644 --- a/fs/xfs/xfs_xattr.h +++ b/fs/xfs/xfs_xattr.h @@ -7,6 +7,8 @@ #define __XFS_XATTR_H__ int xfs_attr_change(struct xfs_da_args *args); +int xfs_attr_grab_log_assist(struct xfs_mount *mp); +void xfs_attr_rele_log_assist(struct xfs_mount *mp); extern const struct xattr_handler * const xfs_xattr_handlers[]; From patchwork Sun Dec 31 20:50: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: 13507496 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 7189BBA22 for ; Sun, 31 Dec 2023 20:50:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="ZzYNOlZr" Received: by smtp.kernel.org (Postfix) with ESMTPSA id EBBE7C433C7; Sun, 31 Dec 2023 20:50:19 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704055820; bh=oohAL0wQbW5ZmFHnT9tQTGXP0N0ALueH+bgE2ngb/cM=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=ZzYNOlZr9Kh7y78FDTK1ujQsknGlsE2Z155yLujrB8nT9Yz5NOz4zlK78hxEWloik 0CCksZmeTlcUmc6ydLWcF9MK6gebvv16ecC76s1jfjXWrrINrg1a6NeGr4O9FN4fJh /k/rGt0TZVskt2rwhnqPzMS0WS/ufs3gf11YV2j7yTrRPLruM7zlcw+52AY9v9Ko4x 0RBbxq+/obhAoWKaEU/8EhNwnd0oYs75EpzYckUIRaxoDtlClDDhxIy27+NyaH19/f HQ/K/OCEJmy4J0puO0g+uwtz8gGZdBsiuWHmsxPOxyBVPN7gc15qmajRSCICwg1ZBj cBU3d0tQH9stQ== Date: Sun, 31 Dec 2023 12:50:19 -0800 Subject: [PATCH 07/18] xfs: add parent attributes to link From: "Darrick J. Wong" To: djwong@kernel.org Cc: Dave Chinner , Allison Henderson , catherine.hoang@oracle.com, allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <170404841152.1756905.9141159000997600645.stgit@frogsfrogsfrogs> In-Reply-To: <170404840995.1756905.18018727013229504371.stgit@frogsfrogsfrogs> References: <170404840995.1756905.18018727013229504371.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 --- fs/xfs/libxfs/xfs_trans_space.c | 14 +++++++++++++ fs/xfs/libxfs/xfs_trans_space.h | 3 +-- fs/xfs/scrub/dir_repair.c | 2 +- fs/xfs/scrub/orphanage.c | 2 +- fs/xfs/xfs_inode.c | 41 +++++++++++++++++++++++++++++++++------ 5 files changed, 52 insertions(+), 10 deletions(-) diff --git a/fs/xfs/libxfs/xfs_trans_space.c b/fs/xfs/libxfs/xfs_trans_space.c index 90532c3fa2053..cf775750120e8 100644 --- a/fs/xfs/libxfs/xfs_trans_space.c +++ b/fs/xfs/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/fs/xfs/libxfs/xfs_trans_space.h b/fs/xfs/libxfs/xfs_trans_space.h index 6cda87153b38c..5539634009fb2 100644 --- a/fs/xfs/libxfs/xfs_trans_space.h +++ b/fs/xfs/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__ */ diff --git a/fs/xfs/scrub/dir_repair.c b/fs/xfs/scrub/dir_repair.c index 48e30a9baeae0..e74f456c7b444 100644 --- a/fs/xfs/scrub/dir_repair.c +++ b/fs/xfs/scrub/dir_repair.c @@ -705,7 +705,7 @@ xrep_dir_replay_update( uint resblks; int error; - resblks = XFS_LINK_SPACE_RES(mp, dirent->namelen); + resblks = xfs_link_space_res(mp, dirent->namelen); error = xchk_trans_alloc(rd->sc, resblks); if (error) return error; diff --git a/fs/xfs/scrub/orphanage.c b/fs/xfs/scrub/orphanage.c index e1024a7bc9e96..84e6dcef067c1 100644 --- a/fs/xfs/scrub/orphanage.c +++ b/fs/xfs/scrub/orphanage.c @@ -326,7 +326,7 @@ xrep_adoption_trans_alloc( /* Compute the worst case space reservation that we need. */ adopt->sc = sc; - adopt->orphanage_blkres = XFS_LINK_SPACE_RES(mp, MAXNAMELEN); + adopt->orphanage_blkres = xfs_link_space_res(mp, MAXNAMELEN); if (S_ISDIR(VFS_I(sc->ip)->i_mode)) child_blkres = XFS_RENAME_SPACE_RES(mp, xfs_name_dotdot.len); adopt->child_blkres = child_blkres; diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index 20aee9db1b43a..4d7d923cf72ec 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -1309,14 +1309,15 @@ xfs_create_tmpfile( int xfs_link( - xfs_inode_t *tdp, - xfs_inode_t *sip, + struct xfs_inode *tdp, + struct xfs_inode *sip, struct xfs_name *target_name) { - xfs_mount_t *mp = tdp->i_mount; - xfs_trans_t *tp; + struct xfs_mount *mp = tdp->i_mount; + struct xfs_trans *tp; int error, nospace_error = 0; int resblks; + struct xfs_parent_args *ppargs; trace_xfs_link(tdp, target_name); @@ -1335,11 +1336,25 @@ xfs_link( if (error) goto std_return; - resblks = XFS_LINK_SPACE_RES(mp, target_name->len); + error = xfs_parent_start(mp, &ppargs); + if (error) + goto std_return; + + resblks = xfs_link_space_res(mp, target_name->len); error = xfs_trans_alloc_dir(tdp, &M_RES(mp)->tr_link, sip, &resblks, &tp, &nospace_error); if (error) - goto std_return; + goto out_parent; + + /* + * We don't allow reservationless or quotaless hardlinking when parent + * pointers are enabled because we can't back out if the xattrs must + * grow. + */ + if (ppargs && nospace_error) { + error = nospace_error; + goto error_return; + } /* * If we are using project inheritance, we only allow hard link @@ -1379,6 +1394,17 @@ xfs_link( xfs_trans_log_inode(tp, tdp, XFS_ILOG_CORE); xfs_bumplink(tp, sip); + + /* + * If we have parent pointers, we now need to add the parent record to + * the attribute fork of the inode. If this is the initial parent + * attribute, we need to create it correctly, otherwise we can just add + * the parent to the inode. + */ + error = xfs_parent_add(tp, ppargs, tdp, target_name, sip); + if (error) + goto error_return; + xfs_dir_update_hook(tdp, sip, 1, target_name); /* @@ -1392,12 +1418,15 @@ xfs_link( error = xfs_trans_commit(tp); xfs_iunlock(tdp, XFS_ILOCK_EXCL); xfs_iunlock(sip, XFS_ILOCK_EXCL); + xfs_parent_finish(mp, ppargs); return error; error_return: xfs_trans_cancel(tp); xfs_iunlock(tdp, XFS_ILOCK_EXCL); xfs_iunlock(sip, XFS_ILOCK_EXCL); + out_parent: + xfs_parent_finish(mp, ppargs); std_return: if (error == -ENOSPC && nospace_error) error = nospace_error; From patchwork Sun Dec 31 20:50:35 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: 13507497 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 19890BA22 for ; Sun, 31 Dec 2023 20:50:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="kvZEbARf" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 8CC6FC433C8; Sun, 31 Dec 2023 20:50:35 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704055835; bh=kgyEQeowIu4fQNWGEhwbQUlgF6ABeqrslfLtIcgBODs=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=kvZEbARfwhLPMt03+6AObfg4Q/HrqGJBTy7jJ4ukubRVY5fj5hvAjnp7v2MDiO+bv rxLz2lU0LlQk4ktG7WTlHQFLZ+jVfVWRtj8Y6TWeTQnW2lW4zcGZL8cbXHKIjeACRD jfN9QSXDYfxhDqJ6VilujlP/8K605zrtjC4/COjeF6inD5Ybfw436Vrgce5xKo8+xs zaXU67yI9edgSQxXdwfs4sWHd67k4UwuZpGYC3tpXqzCUNz+vBK5YTEWlI7ZYIT06g ILhOu+wnhJV/Fx2s2513FPrl21gqgO/SGwOnMaelfZteadqoVeKiRbsEXo69QODt7u kn9Ow143gLpdQ== Date: Sun, 31 Dec 2023 12:50:35 -0800 Subject: [PATCH 08/18] xfs: add parent attributes to symlink From: "Darrick J. Wong" To: djwong@kernel.org Cc: Allison Henderson , catherine.hoang@oracle.com, allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <170404841168.1756905.3742334033342369885.stgit@frogsfrogsfrogs> In-Reply-To: <170404840995.1756905.18018727013229504371.stgit@frogsfrogsfrogs> References: <170404840995.1756905.18018727013229504371.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 --- fs/xfs/libxfs/xfs_trans_space.c | 17 +++++++++++++++++ fs/xfs/libxfs/xfs_trans_space.h | 4 ++-- fs/xfs/scrub/symlink_repair.c | 2 +- fs/xfs/xfs_symlink.c | 28 +++++++++++++++++++++++----- 4 files changed, 43 insertions(+), 8 deletions(-) diff --git a/fs/xfs/libxfs/xfs_trans_space.c b/fs/xfs/libxfs/xfs_trans_space.c index cf775750120e8..c8adda82debe0 100644 --- a/fs/xfs/libxfs/xfs_trans_space.c +++ b/fs/xfs/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/fs/xfs/libxfs/xfs_trans_space.h b/fs/xfs/libxfs/xfs_trans_space.h index 5539634009fb2..354ad1d6e18d6 100644 --- a/fs/xfs/libxfs/xfs_trans_space.h +++ b/fs/xfs/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__ */ diff --git a/fs/xfs/scrub/symlink_repair.c b/fs/xfs/scrub/symlink_repair.c index 60246350ebfc9..62190fa738553 100644 --- a/fs/xfs/scrub/symlink_repair.c +++ b/fs/xfs/scrub/symlink_repair.c @@ -403,7 +403,7 @@ xrep_symlink_rebuild( * unlikely. */ fs_blocks = xfs_symlink_blocks(sc->mp, target_len); - resblks = XFS_SYMLINK_SPACE_RES(sc->mp, target_len, fs_blocks); + resblks = xfs_symlink_space_res(sc->mp, target_len, fs_blocks); error = xfs_trans_reserve_quota_nblks(sc->tp, sc->tempip, resblks, 0, true); if (error) diff --git a/fs/xfs/xfs_symlink.c b/fs/xfs/xfs_symlink.c index 307a2b7e5426e..ced29d8c48c0a 100644 --- a/fs/xfs/xfs_symlink.c +++ b/fs/xfs/xfs_symlink.c @@ -25,6 +25,8 @@ #include "xfs_error.h" #include "xfs_health.h" #include "xfs_symlink_remote.h" +#include "xfs_parent.h" +#include "xfs_defer.h" /* ----- Kernel only functions below ----- */ int @@ -101,6 +103,7 @@ xfs_symlink( struct xfs_dquot *pdqp = NULL; uint resblks; xfs_ino_t ino; + struct xfs_parent_args *ppargs; *ipp = NULL; @@ -131,18 +134,24 @@ xfs_symlink( /* * The symlink will fit into the inode data fork? - * There can't be any attributes so we get the whole variable part. + * If there are no parent pointers, then there wont't be any attributes. + * So we get the whole variable part, and do not need to reserve extra + * blocks. Otherwise, we need to reserve the blocks. */ - if (pathlen <= XFS_LITINO(mp)) + if (pathlen <= XFS_LITINO(mp) && !xfs_has_parent(mp)) fs_blocks = 0; else fs_blocks = xfs_symlink_blocks(mp, pathlen); - resblks = XFS_SYMLINK_SPACE_RES(mp, link_name->len, fs_blocks); + resblks = xfs_symlink_space_res(mp, link_name->len, fs_blocks); + + error = xfs_parent_start(mp, &ppargs); + if (error) + goto out_release_dquots; error = xfs_trans_alloc_icreate(mp, &M_RES(mp)->tr_symlink, udqp, gdqp, pdqp, resblks, &tp); if (error) - goto out_release_dquots; + goto out_parent; xfs_ilock(dp, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT); unlock_dp_on_error = true; @@ -162,7 +171,7 @@ xfs_symlink( if (!error) error = xfs_init_new_inode(idmap, tp, dp, ino, S_IFLNK | (mode & ~S_IFMT), 1, 0, prid, - false, &ip); + xfs_has_parent(mp), &ip); if (error) goto out_trans_cancel; @@ -196,6 +205,12 @@ xfs_symlink( goto out_trans_cancel; xfs_trans_ichgtime(tp, dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE); + + /* Add parent pointer for the new symlink. */ + error = xfs_parent_add(tp, ppargs, dp, link_name, ip); + if (error) + goto out_trans_cancel; + xfs_dir_update_hook(dp, ip, 1, link_name); /* @@ -217,6 +232,7 @@ xfs_symlink( *ipp = ip; xfs_iunlock(ip, XFS_ILOCK_EXCL); xfs_iunlock(dp, XFS_ILOCK_EXCL); + xfs_parent_finish(mp, ppargs); return 0; out_trans_cancel: @@ -232,6 +248,8 @@ xfs_symlink( xfs_finish_inode_setup(ip); xfs_irele(ip); } +out_parent: + xfs_parent_finish(mp, ppargs); out_release_dquots: xfs_qm_dqrele(udqp); xfs_qm_dqrele(gdqp); From patchwork Sun Dec 31 20:50: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: 13507498 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 C6609BA30 for ; Sun, 31 Dec 2023 20:50:51 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Y6ApYSxy" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 3FB3FC433C8; Sun, 31 Dec 2023 20:50:51 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704055851; bh=945qDD6NNMuN3fCcd2DpVDywl0R0U93IzDB+iUVcV7c=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=Y6ApYSxyZ4Tvmzm7F8FmGUGxf5sDBoT8JXA5b+f8V7iwKFZ2nuUtlyAhKOsAtxpuN dScCp7LfiKJ8g3x/DYFTfVpahel2oGKgqxk9VEmeD4i7Iz0frJxQKuOgVE+xUyAC5p B0+N5l9CcAVnalcolecxU/iU4I9Ihnl4Qy7JhxpjoMi63UAuV9AJg4QGv6ycif40NS drQDXILaQikgKwGZ3PMfSGBZF8G+ZaK1MiV6OYA2DDOnLOAo+WnX228z34pNtJRcE+ 0zuHAY/vVBvBdJj00EHiELgwt4rjUnX4CGVo2T/EVQtZaqLCEpUq0TN5zqhrUO+wpe qmLJHztVzO6Aw== Date: Sun, 31 Dec 2023 12:50:50 -0800 Subject: [PATCH 09/18] xfs: remove parent pointers in unlink From: "Darrick J. Wong" To: djwong@kernel.org Cc: Dave Chinner , Allison Henderson , catherine.hoang@oracle.com, allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <170404841185.1756905.1245621133689162196.stgit@frogsfrogsfrogs> In-Reply-To: <170404840995.1756905.18018727013229504371.stgit@frogsfrogsfrogs> References: <170404840995.1756905.18018727013229504371.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 --- fs/xfs/libxfs/xfs_parent.c | 39 +++++++++++++++++++++++++++++++++++++++ fs/xfs/libxfs/xfs_parent.h | 16 ++++++++++++++++ fs/xfs/libxfs/xfs_trans_space.c | 13 +++++++++++++ fs/xfs/libxfs/xfs_trans_space.h | 3 +-- fs/xfs/xfs_inode.c | 25 +++++++++++++++++++------ 5 files changed, 88 insertions(+), 8 deletions(-) diff --git a/fs/xfs/libxfs/xfs_parent.c b/fs/xfs/libxfs/xfs_parent.c index 05ef155388a12..1c3542d264618 100644 --- a/fs/xfs/libxfs/xfs_parent.c +++ b/fs/xfs/libxfs/xfs_parent.c @@ -27,6 +27,7 @@ #include "xfs_xattr.h" #include "xfs_parent.h" #include "xfs_trans_space.h" +#include "xfs_health.h" struct kmem_cache *xfs_parent_args_cache; @@ -194,6 +195,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/fs/xfs/libxfs/xfs_parent.h b/fs/xfs/libxfs/xfs_parent.h index e2115a2b9648b..31349130a330e 100644 --- a/fs/xfs/libxfs/xfs_parent.h +++ b/fs/xfs/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/fs/xfs/libxfs/xfs_trans_space.c b/fs/xfs/libxfs/xfs_trans_space.c index c8adda82debe0..df729e4f1a4c9 100644 --- a/fs/xfs/libxfs/xfs_trans_space.c +++ b/fs/xfs/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/fs/xfs/libxfs/xfs_trans_space.h b/fs/xfs/libxfs/xfs_trans_space.h index 354ad1d6e18d6..a4490813c56f1 100644 --- a/fs/xfs/libxfs/xfs_trans_space.h +++ b/fs/xfs/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/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index 4d7d923cf72ec..85c9fa6bed2b9 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -2718,16 +2718,17 @@ xfs_iunpin_wait( */ int xfs_remove( - xfs_inode_t *dp, + struct xfs_inode *dp, struct xfs_name *name, - xfs_inode_t *ip) + struct xfs_inode *ip) { - xfs_mount_t *mp = dp->i_mount; - xfs_trans_t *tp = NULL; + struct xfs_mount *mp = dp->i_mount; + struct xfs_trans *tp = NULL; int is_dir = S_ISDIR(VFS_I(ip)->i_mode); int dontcare; int error = 0; uint resblks; + struct xfs_parent_args *ppargs; trace_xfs_remove(dp, name); @@ -2744,6 +2745,10 @@ xfs_remove( if (error) goto std_return; + error = xfs_parent_start(mp, &ppargs); + if (error) + goto std_return; + /* * We try to get the real space reservation first, allowing for * directory btree deletion(s) implying possible bmap insert(s). If we @@ -2755,12 +2760,12 @@ xfs_remove( * the directory code can handle a reservationless update and we don't * want to prevent a user from trying to free space by deleting things. */ - resblks = XFS_REMOVE_SPACE_RES(mp); + resblks = xfs_remove_space_res(mp, name->len); error = xfs_trans_alloc_dir(dp, &M_RES(mp)->tr_remove, ip, &resblks, &tp, &dontcare); if (error) { ASSERT(error != -ENOSPC); - goto std_return; + goto out_parent; } /* @@ -2820,6 +2825,11 @@ xfs_remove( goto out_trans_cancel; } + /* Remove parent pointer. */ + error = xfs_parent_remove(tp, ppargs, dp, name, ip); + if (error) + goto out_trans_cancel; + /* * Drop the link from dp to ip, and if ip was a directory, remove the * '.' and '..' references since we freed the directory. @@ -2843,6 +2853,7 @@ xfs_remove( xfs_iunlock(ip, XFS_ILOCK_EXCL); xfs_iunlock(dp, XFS_ILOCK_EXCL); + xfs_parent_finish(mp, ppargs); return 0; out_trans_cancel: @@ -2850,6 +2861,8 @@ xfs_remove( out_unlock: xfs_iunlock(ip, XFS_ILOCK_EXCL); xfs_iunlock(dp, XFS_ILOCK_EXCL); + out_parent: + xfs_parent_finish(mp, ppargs); std_return: return error; } From patchwork Sun Dec 31 20:51: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: 13507499 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 12883BE48 for ; Sun, 31 Dec 2023 20:51:07 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="RM4akvjv" Received: by smtp.kernel.org (Postfix) with ESMTPSA id D775EC433C8; Sun, 31 Dec 2023 20:51:06 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704055866; bh=PQ6l6qOWWvk2vw9fLlnLDILcnZLdLZ1NPaXQj89lxes=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=RM4akvjvEkhSLtS4DNN8gJUloXLe9uEo8+6AkVvFlO6Y3Su29NU/ix7FZ9pq50bzi asYIQHpaxVPD6gw/lJpjr2/UGOl/hpGLMzgkkANtWXOvn4XmXbaklXwVYI+XcO4GcC 2KjrkChokDE5Cb1WY0VOSyNNemP8Om7Z7S8F/LPHeixekff6BWiQ1RaBrjn5tmez7K rAOhAEadOKLtTQkJvLh1vilQk0Sx6CkouoV5CN+eM2icaHCJMk7o2jIYVcvun/gnvQ LaTZnA4jnStFJ/KBxKxvaJEbstdwgzHjnX7g1S6j2+DwKUFx94My9FmD5lNW3Ldq22 9fYgmlQu6AnJg== Date: Sun, 31 Dec 2023 12:51:06 -0800 Subject: [PATCH 10/18] xfs: Add parent pointers to rename From: "Darrick J. Wong" To: djwong@kernel.org Cc: Allison Henderson , catherine.hoang@oracle.com, allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <170404841200.1756905.7675999107721670548.stgit@frogsfrogsfrogs> In-Reply-To: <170404840995.1756905.18018727013229504371.stgit@frogsfrogsfrogs> References: <170404840995.1756905.18018727013229504371.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 --- fs/xfs/libxfs/xfs_parent.c | 63 ++++++++++++++++++++++++++++++++++ fs/xfs/libxfs/xfs_parent.h | 20 +++++++++++ fs/xfs/libxfs/xfs_trans_space.c | 25 +++++++++++++ fs/xfs/libxfs/xfs_trans_space.h | 6 ++- fs/xfs/scrub/orphanage.c | 3 +- fs/xfs/scrub/parent_repair.c | 3 +- fs/xfs/xfs_inode.c | 73 +++++++++++++++++++++++++++++++++++---- 7 files changed, 182 insertions(+), 11 deletions(-) diff --git a/fs/xfs/libxfs/xfs_parent.c b/fs/xfs/libxfs/xfs_parent.c index 1c3542d264618..1bff67f8f1176 100644 --- a/fs/xfs/libxfs/xfs_parent.c +++ b/fs/xfs/libxfs/xfs_parent.c @@ -138,6 +138,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. @@ -233,6 +246,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/fs/xfs/libxfs/xfs_parent.h b/fs/xfs/libxfs/xfs_parent.h index 31349130a330e..c68c501388e82 100644 --- a/fs/xfs/libxfs/xfs_parent.h +++ b/fs/xfs/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/fs/xfs/libxfs/xfs_trans_space.c b/fs/xfs/libxfs/xfs_trans_space.c index df729e4f1a4c9..b9dc3752f702c 100644 --- a/fs/xfs/libxfs/xfs_trans_space.c +++ b/fs/xfs/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/fs/xfs/libxfs/xfs_trans_space.h b/fs/xfs/libxfs/xfs_trans_space.h index a4490813c56f1..1155ff2d37e29 100644 --- a/fs/xfs/libxfs/xfs_trans_space.h +++ b/fs/xfs/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__ */ diff --git a/fs/xfs/scrub/orphanage.c b/fs/xfs/scrub/orphanage.c index 84e6dcef067c1..ace7a0f23e474 100644 --- a/fs/xfs/scrub/orphanage.c +++ b/fs/xfs/scrub/orphanage.c @@ -328,7 +328,8 @@ xrep_adoption_trans_alloc( adopt->sc = sc; adopt->orphanage_blkres = xfs_link_space_res(mp, MAXNAMELEN); if (S_ISDIR(VFS_I(sc->ip)->i_mode)) - child_blkres = XFS_RENAME_SPACE_RES(mp, xfs_name_dotdot.len); + child_blkres = xfs_rename_space_res(mp, 0, false, + xfs_name_dotdot.len, false); adopt->child_blkres = child_blkres; /* diff --git a/fs/xfs/scrub/parent_repair.c b/fs/xfs/scrub/parent_repair.c index 2eb0dbde9c459..099620fc119e9 100644 --- a/fs/xfs/scrub/parent_repair.c +++ b/fs/xfs/scrub/parent_repair.c @@ -169,7 +169,8 @@ xrep_parent_reset_dotdot( * Reserve more space just in case we have to expand the dir. We're * allowed to exceed quota to repair inconsistent metadata. */ - spaceres = XFS_RENAME_SPACE_RES(sc->mp, xfs_name_dotdot.len); + spaceres = xfs_rename_space_res(sc->mp, 0, false, xfs_name_dotdot.len, + false); error = xfs_trans_reserve_more_inode(sc->tp, sc->ip, spaceres, 0, true); if (error) diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index 85c9fa6bed2b9..3723b4bdc47c7 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -3143,6 +3143,9 @@ xfs_rename( struct xfs_trans *tp; struct xfs_inode *wip = NULL; /* whiteout inode */ struct xfs_inode *inodes[__XFS_SORT_INODES]; + struct xfs_parent_args *src_ppargs = NULL; + struct xfs_parent_args *tgt_ppargs = NULL; + struct xfs_parent_args *wip_ppargs = NULL; int i; int num_inodes = __XFS_SORT_INODES; bool new_parent = (src_dp != target_dp); @@ -3174,9 +3177,26 @@ xfs_rename( xfs_sort_for_rename(src_dp, target_dp, src_ip, target_ip, wip, inodes, &num_inodes); + error = xfs_parent_start(mp, &src_ppargs); + if (error) + goto out_release_wip; + + if (wip) { + error = xfs_parent_start(mp, &wip_ppargs); + if (error) + goto out_src_ppargs; + } + + if (target_ip) { + error = xfs_parent_start(mp, &tgt_ppargs); + if (error) + goto out_wip_ppargs; + } + retry: nospace_error = 0; - spaceres = XFS_RENAME_SPACE_RES(mp, target_name->len); + spaceres = xfs_rename_space_res(mp, src_name->len, target_ip != NULL, + target_name->len, wip != NULL); error = xfs_trans_alloc(mp, &M_RES(mp)->tr_rename, spaceres, 0, 0, &tp); if (error == -ENOSPC) { nospace_error = error; @@ -3185,7 +3205,17 @@ xfs_rename( &tp); } if (error) - goto out_release_wip; + goto out_tgt_ppargs; + + /* + * We don't allow reservationless renaming when parent pointers are + * enabled because we can't back out if the xattrs must grow. + */ + if (src_ppargs && nospace_error) { + error = nospace_error; + xfs_trans_cancel(tp); + goto out_tgt_ppargs; + } /* * Attach the dquots to the inodes @@ -3193,7 +3223,7 @@ xfs_rename( error = xfs_qm_vop_rename_dqattach(inodes); if (error) { xfs_trans_cancel(tp); - goto out_release_wip; + goto out_tgt_ppargs; } /* @@ -3262,6 +3292,15 @@ xfs_rename( goto out_trans_cancel; } + /* + * We don't allow quotaless renaming when parent pointers are enabled + * because we can't back out if the xattrs must grow. + */ + if (src_ppargs && nospace_error) { + error = nospace_error; + goto out_trans_cancel; + } + /* * Check for expected errors before we dirty the transaction * so we can return an error without a transaction abort. @@ -3454,6 +3493,21 @@ xfs_rename( if (error) goto out_trans_cancel; + /* Schedule parent pointer updates. */ + error = xfs_parent_add(tp, wip_ppargs, src_dp, src_name, wip); + if (error) + goto out_trans_cancel; + + error = xfs_parent_replace(tp, src_ppargs, src_dp, src_name, target_dp, + target_name, src_ip); + if (error) + goto out_trans_cancel; + + error = xfs_parent_remove(tp, tgt_ppargs, target_dp, target_name, + target_ip); + if (error) + goto out_trans_cancel; + xfs_trans_ichgtime(tp, src_dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); xfs_trans_log_inode(tp, src_dp, XFS_ILOG_CORE); if (new_parent) @@ -3475,14 +3529,19 @@ xfs_rename( xfs_dir_update_hook(src_dp, wip, 1, src_name); error = xfs_finish_rename(tp); - xfs_iunlock_rename(inodes, num_inodes); - if (wip) - xfs_irele(wip); - return error; + nospace_error = 0; + goto out_unlock; out_trans_cancel: xfs_trans_cancel(tp); +out_unlock: xfs_iunlock_rename(inodes, num_inodes); +out_tgt_ppargs: + xfs_parent_finish(mp, tgt_ppargs); +out_wip_ppargs: + xfs_parent_finish(mp, wip_ppargs); +out_src_ppargs: + xfs_parent_finish(mp, src_ppargs); out_release_wip: if (wip) xfs_irele(wip); From patchwork Sun Dec 31 20:51: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: 13507500 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 AB816BE48 for ; Sun, 31 Dec 2023 20:51:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Yaprtm2f" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 7CA67C433C8; Sun, 31 Dec 2023 20:51:22 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704055882; bh=DWGlmIFIEXkMWyOhQEJiMYy6mPESxCBebRmsXNBkcqk=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=Yaprtm2fiFMcUD52Eks46Zexh5/prlaGgnC3Q0ejgog+5tstccSR0d62S8LVsqBqV r7o6NtyHGVuZr2wVBJVruI63HHuCpRsclkVXfq+CjBxKTmItTD/vxjjpEDCKsPCD+Z t9+mClE/4jargfhSmfyixX6YqlkdifvSZ+VBUQoqhWy9Vv/7fEJT3r8IszLIFXMhQJ oHng7l+ENVHA1jhmj6JXPjOb2XZLX096WpW72WZSgZE9HTB2JtK7kgctv7ulv0BGYn w583dDepwAs4tcwt5F3FRDbBkTFWv+6xwPGVlT/YBwU5llrnX39Mkm1ZvB4PiyOR0j +bnyity+Yinvg== Date: Sun, 31 Dec 2023 12:51:22 -0800 Subject: [PATCH 11/18] xfs: Add parent pointers to xfs_cross_rename From: "Darrick J. Wong" To: djwong@kernel.org Cc: Allison Henderson , catherine.hoang@oracle.com, allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <170404841217.1756905.45527345331323865.stgit@frogsfrogsfrogs> In-Reply-To: <170404840995.1756905.18018727013229504371.stgit@frogsfrogsfrogs> References: <170404840995.1756905.18018727013229504371.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 Cross renames are handled separately from standard renames, and need different handling to update the parent attributes correctly. Signed-off-by: Allison Henderson Reviewed-by: Darrick J. Wong Signed-off-by: Darrick J. Wong --- fs/xfs/xfs_inode.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index 3723b4bdc47c7..998df0d5dac3c 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -2967,15 +2967,17 @@ xfs_cross_rename( struct xfs_inode *dp1, struct xfs_name *name1, struct xfs_inode *ip1, + struct xfs_parent_args *ip1_ppargs, struct xfs_inode *dp2, struct xfs_name *name2, struct xfs_inode *ip2, + struct xfs_parent_args *ip2_ppargs, int spaceres) { - int error = 0; - int ip1_flags = 0; - int ip2_flags = 0; - int dp2_flags = 0; + int error = 0; + int ip1_flags = 0; + int ip2_flags = 0; + int dp2_flags = 0; /* Swap inode number for dirent in first parent */ error = xfs_dir_replace(tp, dp1, name1, ip2->i_ino, spaceres); @@ -3044,6 +3046,15 @@ xfs_cross_rename( } } + /* Schedule parent pointer replacements */ + error = xfs_parent_replace(tp, ip1_ppargs, dp1, name1, dp2, name2, ip1); + if (error) + goto out_trans_abort; + + error = xfs_parent_replace(tp, ip2_ppargs, dp2, name2, dp1, name1, ip2); + if (error) + goto out_trans_abort; + if (ip1_flags) { xfs_trans_ichgtime(tp, ip1, ip1_flags); xfs_trans_log_inode(tp, ip1, XFS_ILOG_CORE); @@ -3260,10 +3271,10 @@ xfs_rename( /* RENAME_EXCHANGE is unique from here on. */ if (flags & RENAME_EXCHANGE) { error = xfs_cross_rename(tp, src_dp, src_name, src_ip, - target_dp, target_name, target_ip, - spaceres); - xfs_iunlock_rename(inodes, num_inodes); - return error; + src_ppargs, target_dp, target_name, target_ip, + tgt_ppargs, spaceres); + nospace_error = 0; + goto out_unlock; } /* From patchwork Sun Dec 31 20:51: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: 13507501 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 547F6BE47 for ; Sun, 31 Dec 2023 20:51:38 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Zl+7kcaI" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 2198BC433C7; Sun, 31 Dec 2023 20:51:38 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704055898; bh=nbN1rt5S0ystaD32BxN8VfSLW+xRGWiG+F/zo2rCsok=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=Zl+7kcaIUzFt3YvHfgxjjHJANywptq+4xKi2lWRp6/Ecef1r0ITs2mZZOxsU54Ixj wUF8oIsONg5NM4Mvr7vMNrFR9MYjW0uWElJy6UDyWJB4qxBOSByMk6WWsD3lODNrjX eZNQJ2hkpa+uuFYK4qf1wiSvGbEOgHZ0+KYHI34pSumn7D+Z6DAStknU3ciJEFk/zj V8jOO0EwicwT4f6cQkWCuw8GKlkoqYtWU/+fWHi730e6ChMI4dDw+3BT0yAvFA6doz 9J2Aojswh3ozW6jYVmfVRTlUth/dCUzymnUtxooRkQCDOck7ncvm2AnN4QyETqypqW sYD3BeBDAKefA== Date: Sun, 31 Dec 2023 12:51:37 -0800 Subject: [PATCH 12/18] xfs: Filter XFS_ATTR_PARENT for getfattr From: "Darrick J. Wong" To: djwong@kernel.org Cc: Allison Henderson , catherine.hoang@oracle.com, allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <170404841232.1756905.15803071363377442128.stgit@frogsfrogsfrogs> In-Reply-To: <170404840995.1756905.18018727013229504371.stgit@frogsfrogsfrogs> References: <170404840995.1756905.18018727013229504371.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 Parent pointers returned to the get_fattr tool cause errors since the tool cannot parse parent pointers. Fix this by filtering parent parent pointers from xfs_xattr_put_listent. Signed-off-by: Allison Henderson Reviewed-by: Darrick J. Wong Signed-off-by: Darrick J. Wong --- fs/xfs/xfs_xattr.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fs/xfs/xfs_xattr.c b/fs/xfs/xfs_xattr.c index 12405e4a70c1b..483685dbaaceb 100644 --- a/fs/xfs/xfs_xattr.c +++ b/fs/xfs/xfs_xattr.c @@ -259,6 +259,9 @@ xfs_xattr_put_listent( ASSERT(context->count >= 0); + if (flags & XFS_ATTR_PARENT) + return; + if (flags & XFS_ATTR_ROOT) { #ifdef CONFIG_XFS_POSIX_ACL if (namelen == SGI_ACL_FILE_SIZE && From patchwork Sun Dec 31 20:51: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: 13507502 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 44469BE47 for ; Sun, 31 Dec 2023 20:51:54 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="GT2dnH8I" Received: by smtp.kernel.org (Postfix) with ESMTPSA id C74B9C433C8; Sun, 31 Dec 2023 20:51:53 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704055913; bh=BHCgrktHtu4B+bI4xOEPVnuPt3TAQ/NXl1DRaVMhRcY=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=GT2dnH8I3OQDrFrfVTleEpTznujuYLAmvliw3GpH8mwCNPOd7vJavA2a3YmciTDCj 3KbxlJk0o/RZ7pL0jYnb/OR+UEyfEdTlxhJiVygTyX2Ryv53qs6Lpz0rF9znWJIvLc od1Cwlk3SHOK4Y5Hl12BdUdOgXmMxXkkmWhKGEc/3C1HvN5x6dOR3kv0UBK9IkEPjm yrBPKOJOFebiVK9DrDdo6+e+aTCxw0QAqHo7XrkjKqEoQVHvF8AGr1aAHAsCPyX9AI ehOxgB0cETaiTMnQNnWZpEVwqj/KRWt6KAsCAK60AsyCT7lFBv7kleknQ1yEYyNsw5 6AlR24ZYmxS+A== Date: Sun, 31 Dec 2023 12:51:53 -0800 Subject: [PATCH 13/18] xfs: pass the attr value to put_listent when possible From: "Darrick J. Wong" To: djwong@kernel.org Cc: Allison Henderson , catherine.hoang@oracle.com, allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <170404841247.1756905.8271659540788084705.stgit@frogsfrogsfrogs> In-Reply-To: <170404840995.1756905.18018727013229504371.stgit@frogsfrogsfrogs> References: <170404840995.1756905.18018727013229504371.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 --- fs/xfs/libxfs/xfs_attr.h | 5 +++-- fs/xfs/libxfs/xfs_attr_sf.h | 1 + fs/xfs/xfs_attr_list.c | 8 +++++++- fs/xfs/xfs_ioctl.c | 1 + fs/xfs/xfs_xattr.c | 1 + 5 files changed, 13 insertions(+), 3 deletions(-) diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h index 4a4d45a96dd6c..0204f62298cb5 100644 --- a/fs/xfs/libxfs/xfs_attr.h +++ b/fs/xfs/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/fs/xfs/libxfs/xfs_attr_sf.h b/fs/xfs/libxfs/xfs_attr_sf.h index 37578b369d9b9..c6e259791bc37 100644 --- a/fs/xfs/libxfs/xfs_attr_sf.h +++ b/fs/xfs/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 */ \ diff --git a/fs/xfs/xfs_attr_list.c b/fs/xfs/xfs_attr_list.c index c86e5952c1378..0eba5c9d21bb8 100644 --- a/fs/xfs/xfs_attr_list.c +++ b/fs/xfs/xfs_attr_list.c @@ -97,6 +97,7 @@ xfs_attr_shortform_list( sfe->flags, sfe->nameval, (int)sfe->namelen, + &sfe->nameval[sfe->namelen], (int)sfe->valuelen); /* * Either search callback finished early or @@ -143,6 +144,7 @@ xfs_attr_shortform_list( sbp->name = sfe->nameval; sbp->namelen = sfe->namelen; /* These are bytes, and both on-disk, don't endian-flip */ + sbp->value = &sfe->nameval[sfe->namelen], sbp->valuelen = sfe->valuelen; sbp->flags = sfe->flags; sfe = xfs_attr_sf_nextentry(sfe); @@ -194,6 +196,7 @@ xfs_attr_shortform_list( sbp->flags, sbp->name, sbp->namelen, + sbp->value, sbp->valuelen); if (context->seen_enough) break; @@ -481,6 +484,7 @@ xfs_attr3_leaf_list_int( */ for (; i < ichdr.count; entry++, i++) { char *name; + void *value; int namelen, valuelen; if (be32_to_cpu(entry->hashval) != cursor->hashval) { @@ -498,6 +502,7 @@ xfs_attr3_leaf_list_int( 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); } else { xfs_attr_leaf_name_remote_t *name_rmt; @@ -505,6 +510,7 @@ xfs_attr3_leaf_list_int( name_rmt = xfs_attr3_leaf_name_remote(leaf, i); name = name_rmt->name; namelen = name_rmt->namelen; + value = NULL; valuelen = be32_to_cpu(name_rmt->valuelen); } @@ -515,7 +521,7 @@ xfs_attr3_leaf_list_int( return -EFSCORRUPTED; } context->put_listent(context, entry->flags, - name, namelen, valuelen); + name, namelen, value, valuelen); if (context->seen_enough) break; cursor->offset++; diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c index de16dbc9e7ded..968412c0ba59e 100644 --- a/fs/xfs/xfs_ioctl.c +++ b/fs/xfs/xfs_ioctl.c @@ -310,6 +310,7 @@ xfs_ioc_attr_put_listent( int flags, unsigned char *name, int namelen, + void *value, int valuelen) { struct xfs_attrlist *alist = context->buffer; diff --git a/fs/xfs/xfs_xattr.c b/fs/xfs/xfs_xattr.c index 483685dbaaceb..9ae2dbc7da6c2 100644 --- a/fs/xfs/xfs_xattr.c +++ b/fs/xfs/xfs_xattr.c @@ -252,6 +252,7 @@ xfs_xattr_put_listent( int flags, unsigned char *name, int namelen, + void *value, int valuelen) { char *prefix; From patchwork Sun Dec 31 20:52: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: 13507503 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 ECCC8BE47 for ; Sun, 31 Dec 2023 20:52:09 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="rO6rsOCd" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 741BEC433C7; Sun, 31 Dec 2023 20:52:09 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704055929; bh=CyZZyNtnV/us7AU51pC3DSordnXTeTT0Dkc4jJqrIKc=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=rO6rsOCdBhCCUs8s72TUMY15jB58uSqkFbG1HCLNQnhoD4/j2cwbGmoYamm7izz+C PpQ6RuAELxu5rhagmENrhl7re6THaQCyMXczEc0iDh7A6PTNW5EKm0TKsqdR2GWMog kw5c0HazPdO+g2vmSiPFHbV1ODq/nPVRQFRXaK/u5Bn+T1+1T6H0zYqsZf8hvgXLVZ HxOSXx5Hj9mCX3AABkHPHgTNHTBr3fX4Lb17akOP8GpaQAKbMEAP2t+R7qTReP0T+h 7SQTTumfbDwth8gseDvMhEs6+FGOGgyiae/wvPvoIFClxHcfUwKz9kdkdDODg8i3cU gc6vwghwIvsHQ== Date: Sun, 31 Dec 2023 12:52:08 -0800 Subject: [PATCH 14/18] xfs: Add parent pointer ioctl From: "Darrick J. Wong" To: djwong@kernel.org Cc: Allison Henderson , catherine.hoang@oracle.com, allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <170404841263.1756905.7211684066520577589.stgit@frogsfrogsfrogs> In-Reply-To: <170404840995.1756905.18018727013229504371.stgit@frogsfrogsfrogs> References: <170404840995.1756905.18018727013229504371.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 --- fs/xfs/Makefile | 1 fs/xfs/libxfs/xfs_fs.h | 1 fs/xfs/libxfs/xfs_fs_staging.h | 66 ++++++++++++++++ fs/xfs/libxfs/xfs_ondisk.h | 4 + fs/xfs/libxfs/xfs_parent.c | 62 +++++++++++++++ fs/xfs/libxfs/xfs_parent.h | 25 ++++++ fs/xfs/xfs_ioctl.c | 145 ++++++++++++++++++++++++++++++++++++ fs/xfs/xfs_parent_utils.c | 161 ++++++++++++++++++++++++++++++++++++++++ fs/xfs/xfs_parent_utils.h | 20 +++++ fs/xfs/xfs_trace.c | 1 fs/xfs/xfs_trace.h | 73 ++++++++++++++++++ 11 files changed, 558 insertions(+), 1 deletion(-) create mode 100644 fs/xfs/xfs_parent_utils.c create mode 100644 fs/xfs/xfs_parent_utils.h diff --git a/fs/xfs/Makefile b/fs/xfs/Makefile index 5a358113ad9d7..49480c81eaeab 100644 --- a/fs/xfs/Makefile +++ b/fs/xfs/Makefile @@ -89,6 +89,7 @@ xfs-y += xfs_aops.o \ xfs_mount.o \ xfs_mru_cache.o \ xfs_pwork.o \ + xfs_parent_utils.o \ xfs_reflink.o \ xfs_stats.o \ xfs_super.o \ diff --git a/fs/xfs/libxfs/xfs_fs.h b/fs/xfs/libxfs/xfs_fs.h index 63a145e50350b..e92b6a9612a95 100644 --- a/fs/xfs/libxfs/xfs_fs.h +++ b/fs/xfs/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/fs/xfs/libxfs/xfs_fs_staging.h b/fs/xfs/libxfs/xfs_fs_staging.h index e3d9f3b32b078..e0650af055895 100644 --- a/fs/xfs/libxfs/xfs_fs_staging.h +++ b/fs/xfs/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/fs/xfs/libxfs/xfs_ondisk.h b/fs/xfs/libxfs/xfs_ondisk.h index d9c988c5ad692..bffd39242d487 100644 --- a/fs/xfs/libxfs/xfs_ondisk.h +++ b/fs/xfs/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/fs/xfs/libxfs/xfs_parent.c b/fs/xfs/libxfs/xfs_parent.c index 1bff67f8f1176..48a2dfcc465fa 100644 --- a/fs/xfs/libxfs/xfs_parent.c +++ b/fs/xfs/libxfs/xfs_parent.c @@ -304,3 +304,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/fs/xfs/libxfs/xfs_parent.h b/fs/xfs/libxfs/xfs_parent.h index c68c501388e82..e43ae5a7df826 100644 --- a/fs/xfs/libxfs/xfs_parent.h +++ b/fs/xfs/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/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c index 968412c0ba59e..5db70a11151dd 100644 --- a/fs/xfs/xfs_ioctl.c +++ b/fs/xfs/xfs_ioctl.c @@ -37,6 +37,7 @@ #include "xfs_health.h" #include "xfs_reflink.h" #include "xfs_ioctl.h" +#include "xfs_parent_utils.h" #include "xfs_xattr.h" #include "xfs_rtbitmap.h" #include "xfs_xchgrange.h" @@ -1669,6 +1670,147 @@ xfs_ioc_scrub_metadata( return 0; } +/* + * IOCTL routine to get the parent pointers of an inode and return it to user + * space. Caller must pass a buffer space containing a struct xfs_getparents, + * followed by a region large enough to contain an array of struct + * xfs_getparents_rec of a size specified in gp_bufsize. If the inode contains + * more parent pointers than can fit in the buffer space, caller may re-call + * the function using the returned gp_cursor to resume iteration. The + * number of xfs_getparents_rec returned will be stored in gp_count. + * + * Returns 0 on success or non-zero on failure + */ +STATIC int +xfs_ioc_get_parent_pointer( + struct file *filp, + void __user *arg) +{ + struct xfs_getparents *ppi = NULL; + int error = 0; + struct xfs_inode *file_ip = XFS_I(file_inode(filp)); + struct xfs_inode *call_ip = file_ip; + struct xfs_mount *mp = file_ip->i_mount; + void __user *o_pptr; + struct xfs_getparents_rec *i_pptr; + unsigned int bytes; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + /* Allocate an xfs_getparents to put the user data */ + ppi = kvmalloc(sizeof(struct xfs_getparents), GFP_KERNEL); + if (!ppi) + return -ENOMEM; + + /* Copy the data from the user */ + error = copy_from_user(ppi, arg, sizeof(struct xfs_getparents)); + if (error) { + error = -EFAULT; + goto out; + } + + /* Check size of buffer requested by user */ + if (ppi->gp_bufsize > XFS_XATTR_LIST_MAX) { + error = -ENOMEM; + goto out; + } + if (ppi->gp_bufsize < sizeof(struct xfs_getparents)) { + error = -EINVAL; + goto out; + } + + if (ppi->gp_flags & ~XFS_GETPARENTS_FLAG_ALL) { + error = -EINVAL; + goto out; + } + ppi->gp_flags &= ~(XFS_GETPARENTS_OFLAG_ROOT | XFS_GETPARENTS_OFLAG_DONE); + + /* + * Now that we know how big the trailing buffer is, expand + * our kernel xfs_getparents to be the same size + */ + ppi = kvrealloc(ppi, sizeof(struct xfs_getparents), ppi->gp_bufsize, + GFP_KERNEL | __GFP_ZERO); + if (!ppi) + return -ENOMEM; + + if (ppi->gp_flags & XFS_GETPARENTS_IFLAG_HANDLE) { + struct xfs_handle *hanp = &ppi->gp_handle; + + if (memcmp(&hanp->ha_fsid, mp->m_fixedfsid, + sizeof(xfs_fsid_t))) { + error = -EINVAL; + goto out; + } + + if (hanp->ha_fid.fid_ino != file_ip->i_ino) { + error = xfs_iget(mp, NULL, hanp->ha_fid.fid_ino, + XFS_IGET_UNTRUSTED, 0, &call_ip); + if (error) + goto out; + + /* + * Reload the incore unlinked list to avoid failure in + * inodegc. Use an unlocked check here because + * unrecovered unlinked inodes should be somewhat rare. + */ + if (xfs_inode_unlinked_incomplete(call_ip)) { + error = xfs_inode_reload_unlinked(call_ip); + if (error) + goto out; + } + } + + if (VFS_I(call_ip)->i_generation != hanp->ha_fid.fid_gen) { + error = -EINVAL; + goto out; + } + } + + /* Get the parent pointers */ + error = xfs_getparent_pointers(call_ip, ppi); + if (error) + goto out; + + /* + * If we ran out of buffer space before copying any parent pointers at + * all, the caller's buffer was too short. Tell userspace that, erm, + * the message is too long. + */ + if (ppi->gp_count == 0 && !(ppi->gp_flags & XFS_GETPARENTS_OFLAG_DONE)) { + error = -EMSGSIZE; + goto out; + } + + /* Copy the parent pointer head back to the user */ + bytes = xfs_getparents_arraytop(ppi, ppi->gp_count); + error = copy_to_user(arg, ppi, bytes); + if (error) { + error = -EFAULT; + goto out; + } + + if (ppi->gp_count == 0) + goto out; + + /* Copy the parent pointer records back to the user. */ + o_pptr = (__user char*)arg + ppi->gp_offsets[ppi->gp_count - 1]; + i_pptr = xfs_getparents_rec(ppi, ppi->gp_count - 1); + bytes = ((char *)ppi + ppi->gp_bufsize) - (char *)i_pptr; + error = copy_to_user(o_pptr, i_pptr, bytes); + if (error) { + error = -EFAULT; + goto out; + } + +out: + if (call_ip != file_ip) + xfs_irele(call_ip); + kvfree(ppi); + return error; +} + int xfs_ioc_swapext( struct xfs_swapext *sxp) @@ -1947,7 +2089,8 @@ xfs_file_ioctl( case XFS_IOC_FSGETXATTRA: return xfs_ioc_fsgetxattra(ip, arg); - + case XFS_IOC_GETPARENTS: + return xfs_ioc_get_parent_pointer(filp, arg); case XFS_IOC_GETBMAP: case XFS_IOC_GETBMAPA: case XFS_IOC_GETBMAPX: diff --git a/fs/xfs/xfs_parent_utils.c b/fs/xfs/xfs_parent_utils.c new file mode 100644 index 0000000000000..95eeac1e79c21 --- /dev/null +++ b/fs/xfs/xfs_parent_utils.c @@ -0,0 +1,161 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2022-2024 Oracle. + * All rights reserved. + */ +#include "xfs.h" +#include "xfs_fs.h" +#include "xfs_format.h" +#include "xfs_log_format.h" +#include "xfs_shared.h" +#include "xfs_trans_resv.h" +#include "xfs_mount.h" +#include "xfs_bmap_btree.h" +#include "xfs_inode.h" +#include "xfs_error.h" +#include "xfs_trace.h" +#include "xfs_trans.h" +#include "xfs_da_format.h" +#include "xfs_da_btree.h" +#include "xfs_attr.h" +#include "xfs_ioctl.h" +#include "xfs_parent.h" +#include "xfs_da_btree.h" +#include "xfs_parent_utils.h" +#include "xfs_health.h" + +struct xfs_getparent_ctx { + struct xfs_attr_list_context context; + struct xfs_parent_name_irec pptr_irec; + struct xfs_getparents *ppi; +}; + +static inline unsigned int +xfs_getparents_rec_sizeof( + const struct xfs_parent_name_irec *irec) +{ + return round_up(sizeof(struct xfs_getparents_rec) + irec->p_namelen + 1, + sizeof(uint32_t)); +} + +static void +xfs_getparent_listent( + struct xfs_attr_list_context *context, + int flags, + unsigned char *name, + int namelen, + void *value, + int valuelen) +{ + struct xfs_getparent_ctx *gp; + struct xfs_getparents *ppi; + struct xfs_getparents_rec *pptr; + struct xfs_parent_name_rec *rec = (void *)name; + struct xfs_parent_name_irec *irec; + struct xfs_mount *mp = context->dp->i_mount; + int arraytop; + + gp = container_of(context, struct xfs_getparent_ctx, context); + ppi = gp->ppi; + irec = &gp->pptr_irec; + + /* Ignore non-parent xattrs */ + if (!(flags & XFS_ATTR_PARENT)) + return; + + /* + * Report corruption for anything that doesn't look like a parent + * pointer. The attr list functions filtered out INCOMPLETE attrs. + */ + if (XFS_IS_CORRUPT(mp, + !xfs_parent_namecheck(mp, rec, namelen, flags)) || + XFS_IS_CORRUPT(mp, + !xfs_parent_valuecheck(mp, value, valuelen)) || + XFS_IS_CORRUPT(mp, + !xfs_parent_hashcheck(mp, rec, value, valuelen))) { + xfs_inode_mark_sick(context->dp, XFS_SICK_INO_PARENT); + context->seen_enough = -EFSCORRUPTED; + return; + } + + xfs_parent_irec_from_disk(&gp->pptr_irec, rec, value, valuelen); + + /* + * We found a parent pointer, but we've filled up the buffer. Signal + * to the caller that we did /not/ reach the end of the parent pointer + * recordset. + */ + arraytop = xfs_getparents_arraytop(ppi, ppi->gp_count + 1); + context->firstu -= xfs_getparents_rec_sizeof(irec); + if (context->firstu < arraytop) { + context->seen_enough = 1; + return; + } + + trace_xfs_getparent_listent(context->dp, ppi, irec); + + /* Format the parent pointer directly into the caller buffer. */ + ppi->gp_offsets[ppi->gp_count] = context->firstu; + pptr = xfs_getparents_rec(ppi, ppi->gp_count); + pptr->gpr_ino = irec->p_ino; + pptr->gpr_gen = irec->p_gen; + pptr->gpr_pad = 0; + pptr->gpr_rsvd = 0; + + memcpy(pptr->gpr_name, irec->p_name, irec->p_namelen); + pptr->gpr_name[irec->p_namelen] = 0; + ppi->gp_count++; +} + +/* Retrieve the parent pointers for a given inode. */ +int +xfs_getparent_pointers( + struct xfs_inode *ip, + struct xfs_getparents *ppi) +{ + struct xfs_getparent_ctx *gp; + int error; + + gp = kzalloc(sizeof(struct xfs_getparent_ctx), GFP_KERNEL); + if (!gp) + return -ENOMEM; + gp->ppi = ppi; + gp->context.dp = ip; + gp->context.resynch = 1; + gp->context.put_listent = xfs_getparent_listent; + gp->context.bufsize = round_down(ppi->gp_bufsize, sizeof(uint32_t)); + gp->context.firstu = gp->context.bufsize; + + /* Copy the cursor provided by caller */ + memcpy(&gp->context.cursor, &ppi->gp_cursor, + sizeof(struct xfs_attrlist_cursor)); + ppi->gp_count = 0; + + trace_xfs_getparent_pointers(ip, ppi, &gp->context.cursor); + + error = xfs_attr_list(&gp->context); + if (error) + goto out_free; + if (gp->context.seen_enough < 0) { + error = gp->context.seen_enough; + goto out_free; + } + + /* Is this the root directory? */ + if (ip->i_ino == ip->i_mount->m_sb.sb_rootino) + ppi->gp_flags |= XFS_GETPARENTS_OFLAG_ROOT; + + /* + * If we did not run out of buffer space, then we reached the end of + * the pptr recordset, so set the DONE flag. + */ + if (gp->context.seen_enough == 0) + ppi->gp_flags |= XFS_GETPARENTS_OFLAG_DONE; + + /* Update the caller with the current cursor position */ + memcpy(&ppi->gp_cursor, &gp->context.cursor, + sizeof(struct xfs_attrlist_cursor)); +out_free: + kfree(gp); + return error; +} diff --git a/fs/xfs/xfs_parent_utils.h b/fs/xfs/xfs_parent_utils.h new file mode 100644 index 0000000000000..2a1d5306a02c2 --- /dev/null +++ b/fs/xfs/xfs_parent_utils.h @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2022-2024 Oracle. + * All rights reserved. + */ +#ifndef __XFS_PARENT_UTILS_H__ +#define __XFS_PARENT_UTILS_H__ + +static inline unsigned int +xfs_getparents_arraytop( + const struct xfs_getparents *ppi, + unsigned int nr) +{ + return sizeof(struct xfs_getparents) + + (nr * sizeof(ppi->gp_offsets[0])); +} + +int xfs_getparent_pointers(struct xfs_inode *ip, struct xfs_getparents *ppi); + +#endif /* __XFS_PARENT_UTILS_H__ */ diff --git a/fs/xfs/xfs_trace.c b/fs/xfs/xfs_trace.c index e38814f4380c8..7ccb7b3473943 100644 --- a/fs/xfs/xfs_trace.c +++ b/fs/xfs/xfs_trace.c @@ -42,6 +42,7 @@ #include "xfs_bmap.h" #include "xfs_swapext.h" #include "xfs_xchgrange.h" +#include "xfs_parent.h" /* * We include this last to have the helpers above available for the trace diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h index 1dac853aa659e..070c76f443737 100644 --- a/fs/xfs/xfs_trace.h +++ b/fs/xfs/xfs_trace.h @@ -83,6 +83,9 @@ struct xfs_perag; struct xfs_bmap_intent; struct xfs_swapext_intent; struct xfs_swapext_req; +struct xfs_getparents; +struct xfs_parent_name_irec; +struct xfs_attrlist_cursor_kern; #define XFS_ATTR_FILTER_FLAGS \ { XFS_ATTR_ROOT, "ROOT" }, \ @@ -4981,6 +4984,76 @@ TRACE_EVENT(xfs_swapext_delta_nextents, __entry->d_nexts1, __entry->d_nexts2) ); +TRACE_EVENT(xfs_getparent_listent, + TP_PROTO(struct xfs_inode *ip, const struct xfs_getparents *ppi, + const struct xfs_parent_name_irec *irec), + TP_ARGS(ip, ppi, irec), + TP_STRUCT__entry( + __field(dev_t, dev) + __field(xfs_ino_t, ino) + __field(unsigned int, count) + __field(unsigned int, bufsize) + __field(xfs_ino_t, parent_ino) + __field(unsigned int, parent_gen) + __field(unsigned int, namelen) + __dynamic_array(char, name, irec->p_namelen) + ), + TP_fast_assign( + __entry->dev = ip->i_mount->m_super->s_dev; + __entry->ino = ip->i_ino; + __entry->count = ppi->gp_count; + __entry->bufsize = ppi->gp_bufsize; + __entry->parent_ino = irec->p_ino; + __entry->parent_gen = irec->p_gen; + __entry->namelen = irec->p_namelen; + memcpy(__get_str(name), irec->p_name, irec->p_namelen); + ), + TP_printk("dev %d:%d ino 0x%llx bufsize %u count %u: parent_ino 0x%llx parent_gen 0x%x name '%.*s'", + MAJOR(__entry->dev), MINOR(__entry->dev), + __entry->ino, + __entry->bufsize, + __entry->count, + __entry->parent_ino, + __entry->parent_gen, + __entry->namelen, + __get_str(name)) +); + +TRACE_EVENT(xfs_getparent_pointers, + TP_PROTO(struct xfs_inode *ip, const struct xfs_getparents *ppi, + const struct xfs_attrlist_cursor_kern *cur), + TP_ARGS(ip, ppi, cur), + TP_STRUCT__entry( + __field(dev_t, dev) + __field(xfs_ino_t, ino) + __field(unsigned int, flags) + __field(unsigned int, bufsize) + __field(unsigned int, hashval) + __field(unsigned int, blkno) + __field(unsigned int, offset) + __field(int, initted) + ), + TP_fast_assign( + __entry->dev = ip->i_mount->m_super->s_dev; + __entry->ino = ip->i_ino; + __entry->flags = ppi->gp_flags; + __entry->bufsize = ppi->gp_bufsize; + __entry->hashval = cur->hashval; + __entry->blkno = cur->blkno; + __entry->offset = cur->offset; + __entry->initted = cur->initted; + ), + TP_printk("dev %d:%d ino 0x%llx flags 0x%x bufsize %u cur_init? %d hashval 0x%x blkno %u offset %u", + MAJOR(__entry->dev), MINOR(__entry->dev), + __entry->ino, + __entry->flags, + __entry->bufsize, + __entry->initted, + __entry->hashval, + __entry->blkno, + __entry->offset) +); + #endif /* _TRACE_XFS_H */ #undef TRACE_INCLUDE_PATH From patchwork Sun Dec 31 20:52: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: 13507504 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 515B9BE4D for ; Sun, 31 Dec 2023 20:52:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="l8+D/RHM" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 1E1D8C433C7; Sun, 31 Dec 2023 20:52:25 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704055945; bh=viqE2uyVV+Tv+PVTaywZPDMXlPPbBVd2ZayIHXoNkU4=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=l8+D/RHMKJGgN0IhdU5odIVRQ5VzizuiUwp3FSlHElvCvhsfyA96kBL8FbupPDE8m 1V5dufgoTAByvkdP6ax7MWSwt+v2Q6RSPD1bnCK8a6CgPOhuEjiWWH4uQ3iRm7mFbo KoTYoWXp7gkfrTwM0envhX12IfBnjMYpFU2q8YdGsQDTlAdGCSvmib2N1ULrd12npj ZuhQ5pnnXSkFSFL4aTm58ASV2BbGC4tGkFQGQS8mfI7CAs3tEsNCN/hAAyFfDyQzqO Z+h7iK1trr0S944MQfQT4T6bxMw9MHKWjJY7cCAfw+Xw7076ZcIJeSwLi8qURZaaRI VJWP9DEOI0NUw== Date: Sun, 31 Dec 2023 12:52:24 -0800 Subject: [PATCH 15/18] xfs: fix unit conversion error in xfs_log_calc_max_attrsetm_res From: "Darrick J. Wong" To: djwong@kernel.org Cc: Allison Henderson , catherine.hoang@oracle.com, allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <170404841280.1756905.11348512883221395485.stgit@frogsfrogsfrogs> In-Reply-To: <170404840995.1756905.18018727013229504371.stgit@frogsfrogsfrogs> References: <170404840995.1756905.18018727013229504371.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 --- fs/xfs/libxfs/xfs_log_rlimit.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/fs/xfs/libxfs/xfs_log_rlimit.c b/fs/xfs/libxfs/xfs_log_rlimit.c index 9975b93a7412d..b836de0de5b95 100644 --- a/fs/xfs/libxfs/xfs_log_rlimit.c +++ b/fs/xfs/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 20:52: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: 13507508 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 43298BE50 for ; Sun, 31 Dec 2023 20:52:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="gF5UHoFg" Received: by smtp.kernel.org (Postfix) with ESMTPSA id BF60CC433C8; Sun, 31 Dec 2023 20:52:40 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704055960; bh=bmXyXVFD8TGEn6d0AVvfwWb4bH1hbwzQr9k747LhqaQ=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=gF5UHoFgVZVOtE5vsyZWwz1TGubQOXWSuxbCsrm8oQJwmPZVxRNWHXNq+He4RywVE sKXzxSQB3VGlmUF2k4Tfzl5TlNZ2l0h/pPONkE6y2XyRifq6mFHYPazwixtR314tkf QNQ6WPellLUriJUZrcWiu+dd8unz4P7LG8tDqUKbucjwxgP7dZY2X6d9N75VLIRSVW DKb6/KFn3GtX9MH9+wczNorDQd0WE52SW39/VsGzTyk95rWAgVPqhuVr/wiWb5TTpP VlVEnHyjLfQstisvxg3Mzc8t9eaggONnA5OyM+lr4TBv9Z7xbrzsq0XQ3iKlYcXpY2 J6Pk9vpBpMBIg== Date: Sun, 31 Dec 2023 12:52:40 -0800 Subject: [PATCH 16/18] xfs: drop compatibility minimum log size computations for reflink From: "Darrick J. Wong" To: djwong@kernel.org Cc: Allison Henderson , catherine.hoang@oracle.com, allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <170404841296.1756905.7666232213618503816.stgit@frogsfrogsfrogs> In-Reply-To: <170404840995.1756905.18018727013229504371.stgit@frogsfrogsfrogs> References: <170404840995.1756905.18018727013229504371.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 --- fs/xfs/libxfs/xfs_log_rlimit.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/fs/xfs/libxfs/xfs_log_rlimit.c b/fs/xfs/libxfs/xfs_log_rlimit.c index b836de0de5b95..1ccd4aa921756 100644 --- a/fs/xfs/libxfs/xfs_log_rlimit.c +++ b/fs/xfs/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 20:52: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: 13507509 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 99159BE4A for ; Sun, 31 Dec 2023 20:52:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="ZMOCjjgQ" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 6E651C433C8; Sun, 31 Dec 2023 20:52:56 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704055976; bh=uOH/GGNHM80kkN8ob2khXThwkQOWbhJh4uQbHMQCpao=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=ZMOCjjgQSzl7ZSQrK8Xmz9/sxVHz/hy+AY3Jwsz/zukzI6p+fwRYyoGvb43oBIjHM w98fuuU5zftB8meckNwsGORjyyxauRlj9+Fkfmg2wYicVq0Cj2qavDFMlmd0+t+EvH siF4VnWo5Mk/+nSuDSSAxjPt34PFqBRxjnu/Q2JXP7RgjUSr/tTabUfS0feCV2Sm20 Jxj/VZ6IMXO8lNWSj78HHBse0vpQKlgnHolQoA+oUelVnl6IvETM3gx4EoGcTyEzz6 GOuEE/QNeGkYkW7iHYj/WMFtKAxfkGuL5CxfCvDFAhoxt1uVs015rVkXCJZlsyd7QA T+yh1ZNsrENfg== Date: Sun, 31 Dec 2023 12:52:55 -0800 Subject: [PATCH 17/18] xfs: don't remove the attr fork when parent pointers are enabled From: "Darrick J. Wong" To: djwong@kernel.org Cc: Allison Henderson , catherine.hoang@oracle.com, allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <170404841311.1756905.5574521682852862097.stgit@frogsfrogsfrogs> In-Reply-To: <170404840995.1756905.18018727013229504371.stgit@frogsfrogsfrogs> References: <170404840995.1756905.18018727013229504371.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 --- fs/xfs/libxfs/xfs_attr_leaf.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c index f7a4839e93e3f..2168747aaa2dc 100644 --- a/fs/xfs/libxfs/xfs_attr_leaf.c +++ b/fs/xfs/libxfs/xfs_attr_leaf.c @@ -913,7 +913,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); @@ -922,7 +923,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 20:53: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: 13507510 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 30857BE48 for ; Sun, 31 Dec 2023 20:53:12 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="MWs3+Gma" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 0258BC433C7; Sun, 31 Dec 2023 20:53:11 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1704055992; bh=zLeESHnAs845S/uNRLkpM6hV9AXxBjVaj+BfXEhy1r8=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=MWs3+Gmaqrc7JDH9AyosdEas1yfeUlf2SBzjNbkQ/87aq/FySSPtrA8FW9IwM4+nQ hfbHz4NmjvVDP5D9199hYhKlDkrmf3KZM+u/+ghD9eeGm6/i1nBg2J0NLbg00TxXAQ XeRw2atEISHgWrmlVF2yxP4+f1PXHiSxBlr26nLQBYwEa//6OGw6WR/7HyX+w7m9+l K0HCw3H7OLPBubMgMSRT+FDR3f58n1Oz2mIXZJ2FF3oeUSct3NZwtIAA8Q/ogvUUY9 FR/101s2cL6Z4/Pt2gBXWveRCWQguxfEqZ/cl7gEtu074mAYpodaNPIG5KUHUtidTr 1plr9XoEWeX5A== Date: Sun, 31 Dec 2023 12:53:11 -0800 Subject: [PATCH 18/18] xfs: Add the parent pointer support to the superblock version 5. From: "Darrick J. Wong" To: djwong@kernel.org Cc: Mark Tinguely , Dave Chinner , Allison Henderson , "Darrick J. Wong" , catherine.hoang@oracle.com, allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <170404841327.1756905.15450684873930124193.stgit@frogsfrogsfrogs> In-Reply-To: <170404840995.1756905.18018727013229504371.stgit@frogsfrogsfrogs> References: <170404840995.1756905.18018727013229504371.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 --- fs/xfs/libxfs/xfs_format.h | 4 +++- fs/xfs/libxfs/xfs_fs.h | 1 + fs/xfs/libxfs/xfs_sb.c | 4 ++++ fs/xfs/xfs_super.c | 4 ++++ 4 files changed, 12 insertions(+), 1 deletion(-) diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h index 8b952909ce1e2..b0aaa825539f6 100644 --- a/fs/xfs/libxfs/xfs_format.h +++ b/fs/xfs/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/fs/xfs/libxfs/xfs_fs.h b/fs/xfs/libxfs/xfs_fs.h index e92b6a9612a95..efa68a2d82a1d 100644 --- a/fs/xfs/libxfs/xfs_fs.h +++ b/fs/xfs/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/fs/xfs/libxfs/xfs_sb.c b/fs/xfs/libxfs/xfs_sb.c index 5de377c2b0fea..d4f72d4c85f83 100644 --- a/fs/xfs/libxfs/xfs_sb.c +++ b/fs/xfs/libxfs/xfs_sb.c @@ -176,6 +176,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; } @@ -1251,6 +1253,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; diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c index e981c8b666a5d..8b4e5b8579a9b 100644 --- a/fs/xfs/xfs_super.c +++ b/fs/xfs/xfs_super.c @@ -1734,6 +1734,10 @@ xfs_fs_fill_super( goto out_filestream_unmount; } + if (xfs_has_parent(mp)) + xfs_warn(mp, + "EXPERIMENTAL parent pointer feature enabled. Use at your own risk!"); + error = xfs_mountfs(mp); if (error) goto out_filestream_unmount;