From patchwork Thu Feb 16 20:51:41 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: 13143851 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id D808BC636CC for ; Thu, 16 Feb 2023 20:51:47 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229784AbjBPUvr (ORCPT ); Thu, 16 Feb 2023 15:51:47 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58994 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229768AbjBPUvp (ORCPT ); Thu, 16 Feb 2023 15:51:45 -0500 Received: from ams.source.kernel.org (ams.source.kernel.org [IPv6:2604:1380:4601:e00::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A43DB4BEA8 for ; Thu, 16 Feb 2023 12:51:44 -0800 (PST) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ams.source.kernel.org (Postfix) with ESMTPS id 60438B82958 for ; Thu, 16 Feb 2023 20:51:43 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 22478C433D2; Thu, 16 Feb 2023 20:51:42 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1676580702; bh=NmdTBs5yThDdU56H4M0ZQXhwNN9h6w6Lt03FP2T4/5k=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=i2EHVDhj7QGbaJ5kj805wjyqY4eg2m2Ur/R3ID/R0OVoSIeQVSeld8LVP6Vc0h1ft Izh8fVVbAVwsGGoh3iadkqNc/Gd6UqwnWpaGHT3HSdQ8W8IEOrkf1Gukst7lUWRUSw TwLYkppqJL41g1HSXhUlFf86GIMQ4Cc8e1C0vdfTEjxTjsST0fgSmxg/OWO5LhplJK M6YoEGGzh5Mw1UM2wCI7RqkdaB60h7nLolzxI26BEs8ZhjNOifWNe43hRo6qh0CM2Z +C029CCRubFpO8dn6RA0TZ76PozjnooDjCwliDgxb2VvTYARHhQ9UC37ZyQUIS4O4M 48WSWnroQdvNA== Date: Thu, 16 Feb 2023 12:51:41 -0800 Subject: [PATCH 1/5] xfs: load secure hash algorithm for parent pointers From: "Darrick J. Wong" To: djwong@kernel.org Cc: allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <167657875880.3475422.10684205315154918672.stgit@magnolia> In-Reply-To: <167657875861.3475422.10929602650869169128.stgit@magnolia> References: <167657875861.3475422.10929602650869169128.stgit@magnolia> User-Agent: StGit/0.19 MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-xfs@vger.kernel.org From: Darrick J. Wong We're about to start replacing the diroffset field of parent pointers with a collision-resistant hash of the directory entry name. Start by attaching the sha512 crypto implementation if parent pointers are attached. Signed-off-by: Darrick J. Wong --- fs/xfs/Kconfig | 1 + fs/xfs/xfs_linux.h | 1 + fs/xfs/xfs_mount.c | 13 +++++++++++++ fs/xfs/xfs_mount.h | 3 +++ fs/xfs/xfs_super.c | 3 +++ 5 files changed, 21 insertions(+) diff --git a/fs/xfs/Kconfig b/fs/xfs/Kconfig index 4798a147fd9e..6422daaf8914 100644 --- a/fs/xfs/Kconfig +++ b/fs/xfs/Kconfig @@ -5,6 +5,7 @@ config XFS_FS select EXPORTFS select LIBCRC32C select FS_IOMAP + select CRYPTO_SHA512 help XFS is a high performance journaling filesystem which originated on the SGI IRIX platform. It is completely multi-threaded, can diff --git a/fs/xfs/xfs_linux.h b/fs/xfs/xfs_linux.h index c05f7e309c3e..3f93a742b896 100644 --- a/fs/xfs/xfs_linux.h +++ b/fs/xfs/xfs_linux.h @@ -62,6 +62,7 @@ typedef __u32 xfs_nlink_t; #include #include #include +#include #include #include diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c index fb87ffb48f7f..a5f3dce658e9 100644 --- a/fs/xfs/xfs_mount.c +++ b/fs/xfs/xfs_mount.c @@ -983,6 +983,19 @@ xfs_mountfs( goto out_agresv; } + if (xfs_has_parent(mp)) { + struct crypto_shash *tfm; + + tfm = crypto_alloc_shash("sha512", 0, 0); + if (IS_ERR(tfm)) { + error = PTR_ERR(tfm); + goto out_agresv; + } + xfs_info(mp, "parent pointer hash %s", + crypto_shash_driver_name(tfm)); + mp->m_sha512 = tfm; + } + return 0; out_agresv: diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h index c08f55cc4f36..7c8e15e84cd6 100644 --- a/fs/xfs/xfs_mount.h +++ b/fs/xfs/xfs_mount.h @@ -244,6 +244,9 @@ typedef struct xfs_mount { #endif /* Hook to feed file directory updates to an active online repair. */ struct xfs_hooks m_dirent_update_hooks; + + /* sha512 engine, if needed */ + struct crypto_shash *m_sha512; } xfs_mount_t; #define M_IGEO(mp) (&(mp)->m_ino_geo) diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c index 0432a4a096e8..610d72353f39 100644 --- a/fs/xfs/xfs_super.c +++ b/fs/xfs/xfs_super.c @@ -738,6 +738,8 @@ xfs_mount_free( { kfree(mp->m_rtname); kfree(mp->m_logname); + if (mp->m_sha512) + crypto_free_shash(mp->m_sha512); kmem_free(mp); } @@ -1961,6 +1963,7 @@ static int xfs_init_fs_context( if (fc->sb_flags & SB_SYNCHRONOUS) mp->m_features |= XFS_FEAT_WSYNC; + mp->m_sha512 = NULL; fc->s_fs_info = mp; fc->ops = &xfs_context_ops; From patchwork Thu Feb 16 20:51:57 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: 13143852 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id E4FB6C61DA4 for ; Thu, 16 Feb 2023 20:52:05 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229789AbjBPUwF (ORCPT ); Thu, 16 Feb 2023 15:52:05 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59016 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229768AbjBPUwE (ORCPT ); Thu, 16 Feb 2023 15:52:04 -0500 Received: from ams.source.kernel.org (ams.source.kernel.org [IPv6:2604:1380:4601:e00::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 8C7314BEA8 for ; Thu, 16 Feb 2023 12:52:00 -0800 (PST) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ams.source.kernel.org (Postfix) with ESMTPS id 1E8DEB826BA for ; Thu, 16 Feb 2023 20:51:59 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id A1B9CC433D2; Thu, 16 Feb 2023 20:51:57 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1676580717; bh=1QQ4YKVV3q3epL//tNJthSQ5tN/ABhaEBLd7Kyb7l7E=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=E6RJT/7ggF9IUO3pG8L6JFdHNOm5GNQqTyA/foqqifnx6WfjQzaUWq2bU8NsJMSXn NbDAeLf/AVRag+SGEQlDcmIy3qujNxBSPA11gw3PA46i3+2JnCFz6o789V8rdq7hqn vqxnYZStt+Y7Qmq8NlNBRRYTp7TIIBn172cwfqGg5VYry1m2PJE07o8bnRjka1nOrS tcrZA9NrZAoZN+2i5TKA5wCJ5oLj9GJShI2rbsIVVoS3KbbQFiAxOtYGOcAP4MSQY8 CqrJza91nikGoyatT5Udgiuo1YxZwOtqVg3alyLEPB9jkAMdTERa+wWX1gcqZTDLmS taaOSUxWpN2Bg== Date: Thu, 16 Feb 2023 12:51:57 -0800 Subject: [PATCH 2/5] xfs: replace parent pointer diroffset with sha512 hash of name From: "Darrick J. Wong" To: djwong@kernel.org Cc: allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <167657875894.3475422.15148689769962427834.stgit@magnolia> In-Reply-To: <167657875861.3475422.10929602650869169128.stgit@magnolia> References: <167657875861.3475422.10929602650869169128.stgit@magnolia> User-Agent: StGit/0.19 MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-xfs@vger.kernel.org From: Darrick J. Wong Replace the diroffset with the sha512 hash of the dirent name, thereby eliminating the need for directory repair to update all the parent pointers after rebuilding the directory. Signed-off-by: Darrick J. Wong --- fs/xfs/libxfs/xfs_da_format.h | 15 +++-- fs/xfs/libxfs/xfs_fs.h | 4 + fs/xfs/libxfs/xfs_parent.c | 125 +++++++++++++++++++++++++++++++---------- fs/xfs/libxfs/xfs_parent.h | 21 ++++--- fs/xfs/scrub/dir.c | 12 +++- fs/xfs/scrub/dir_repair.c | 83 ++++++++------------------- fs/xfs/scrub/parent.c | 43 ++++++++++---- fs/xfs/scrub/parent_repair.c | 27 ++++----- fs/xfs/scrub/trace.h | 48 +++++----------- fs/xfs/xfs_inode.c | 30 ++++------ fs/xfs/xfs_ondisk.h | 4 + fs/xfs/xfs_parent_utils.c | 2 - fs/xfs/xfs_sha512.h | 42 ++++++++++++++ fs/xfs/xfs_symlink.c | 3 - 14 files changed, 271 insertions(+), 188 deletions(-) create mode 100644 fs/xfs/xfs_sha512.h diff --git a/fs/xfs/libxfs/xfs_da_format.h b/fs/xfs/libxfs/xfs_da_format.h index c07b8166e8ff..386f63b262d5 100644 --- a/fs/xfs/libxfs/xfs_da_format.h +++ b/fs/xfs/libxfs/xfs_da_format.h @@ -824,17 +824,22 @@ 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); +/* We use sha512 for the parent pointer name hash. */ +#define XFS_PARENT_NAME_HASH_SIZE (64) + /* * Parent pointer attribute format definition * - * EA name encodes the parent inode number, generation and the offset of - * the dirent that points to the child inode. The EA value contains the - * same name as the dirent in the parent directory. + * The EA name encodes the parent inode number, generation and a collision + * resistant hash computed from the dirent name. The hash is defined to be the + * sha512 of the child inode generation and the dirent name. + * + * The EA value contains the same name as the dirent in the parent directory. */ struct xfs_parent_name_rec { __be64 p_ino; __be32 p_gen; - __be32 p_diroffset; -}; + __u8 p_namehash[XFS_PARENT_NAME_HASH_SIZE]; +} __attribute__((packed)); #endif /* __XFS_DA_FORMAT_H__ */ diff --git a/fs/xfs/libxfs/xfs_fs.h b/fs/xfs/libxfs/xfs_fs.h index 9e59a1fdfb0c..c65345d2ba7a 100644 --- a/fs/xfs/libxfs/xfs_fs.h +++ b/fs/xfs/libxfs/xfs_fs.h @@ -770,8 +770,8 @@ struct xfs_scrub_metadata { struct xfs_parent_ptr { __u64 xpp_ino; /* Inode */ __u32 xpp_gen; /* Inode generation */ - __u32 xpp_diroffset; /* Directory offset */ - __u64 xpp_rsvd; /* Reserved */ + __u32 xpp_rsvd; /* Reserved */ + __u64 xpp_rsvd2; /* Reserved */ __u8 xpp_name[XFS_PPTR_MAXNAMELEN]; /* File name */ }; diff --git a/fs/xfs/libxfs/xfs_parent.c b/fs/xfs/libxfs/xfs_parent.c index a2575bf44c89..a28dcf18cb4d 100644 --- a/fs/xfs/libxfs/xfs_parent.c +++ b/fs/xfs/libxfs/xfs_parent.c @@ -26,6 +26,7 @@ #include "xfs_xattr.h" #include "xfs_parent.h" #include "xfs_trans_space.h" +#include "xfs_sha512.h" struct kmem_cache *xfs_parent_intent_cache; @@ -54,7 +55,6 @@ xfs_parent_namecheck( unsigned int attr_flags) { xfs_ino_t p_ino; - xfs_dir2_dataptr_t p_diroffset; if (reclen != sizeof(struct xfs_parent_name_rec)) return false; @@ -67,10 +67,6 @@ xfs_parent_namecheck( if (!xfs_verify_ino(mp, p_ino)) return false; - p_diroffset = be32_to_cpu(rec->p_diroffset); - if (p_diroffset > XFS_DIR2_MAX_DATAPTR) - return false; - return true; } @@ -91,18 +87,17 @@ xfs_parent_valuecheck( } /* Initializes a xfs_parent_name_rec to be stored as an attribute name */ -static inline void +static inline int xfs_init_parent_name_rec( struct xfs_parent_name_rec *rec, - const struct xfs_inode *ip, - uint32_t p_diroffset) + const struct xfs_inode *dp, + const struct xfs_name *name, + struct xfs_inode *ip) { - xfs_ino_t p_ino = ip->i_ino; - uint32_t p_gen = VFS_IC(ip)->i_generation; - - rec->p_ino = cpu_to_be64(p_ino); - rec->p_gen = cpu_to_be32(p_gen); - rec->p_diroffset = cpu_to_be32(p_diroffset); + rec->p_ino = cpu_to_be64(dp->i_ino); + rec->p_gen = cpu_to_be32(VFS_IC(dp)->i_generation); + return xfs_parent_namehash(ip, name, rec->p_namehash, + sizeof(rec->p_namehash)); } /* @@ -118,7 +113,7 @@ xfs_parent_irec_from_disk( { irec->p_ino = be64_to_cpu(rec->p_ino); irec->p_gen = be32_to_cpu(rec->p_gen); - irec->p_diroffset = be32_to_cpu(rec->p_diroffset); + memcpy(irec->p_namehash, rec->p_namehash, sizeof(irec->p_namehash)); if (!value) { irec->p_namelen = 0; @@ -148,7 +143,7 @@ xfs_parent_irec_to_disk( { rec->p_ino = cpu_to_be64(irec->p_ino); rec->p_gen = cpu_to_be32(irec->p_gen); - rec->p_diroffset = cpu_to_be32(irec->p_diroffset); + memcpy(rec->p_namehash, irec->p_namehash, sizeof(rec->p_namehash)); if (valuelen) { ASSERT(*valuelen > 0); @@ -208,12 +203,15 @@ xfs_parent_add( struct xfs_parent_defer *parent, struct xfs_inode *dp, const struct xfs_name *parent_name, - xfs_dir2_dataptr_t diroffset, struct xfs_inode *child) { struct xfs_da_args *args = &parent->args; + int error; + + error = xfs_init_parent_name_rec(&parent->rec, dp, parent_name, child); + if (error) + return error; - xfs_init_parent_name_rec(&parent->rec, dp, diroffset); args->hashval = xfs_da_hashname(args->name, args->namelen); args->trans = tp; @@ -230,14 +228,18 @@ xfs_parent_add( int xfs_parent_remove( struct xfs_trans *tp, - struct xfs_inode *dp, struct xfs_parent_defer *parent, - xfs_dir2_dataptr_t diroffset, + struct xfs_inode *dp, + const struct xfs_name *name, struct xfs_inode *child) { struct xfs_da_args *args = &parent->args; + int error; + + error = xfs_init_parent_name_rec(&parent->rec, dp, name, child); + if (error) + return error; - xfs_init_parent_name_rec(&parent->rec, dp, diroffset); args->trans = tp; args->dp = child; args->hashval = xfs_da_hashname(args->name, args->namelen); @@ -250,16 +252,23 @@ xfs_parent_replace( struct xfs_trans *tp, struct xfs_parent_defer *new_parent, struct xfs_inode *old_dp, - xfs_dir2_dataptr_t old_diroffset, - const struct xfs_name *parent_name, + const struct xfs_name *old_name, struct xfs_inode *new_dp, - xfs_dir2_dataptr_t new_diroffset, + const struct xfs_name *new_name, struct xfs_inode *child) { struct xfs_da_args *args = &new_parent->args; + int error; + + error = xfs_init_parent_name_rec(&new_parent->old_rec, old_dp, + old_name, child); + if (error) + return error; + error = xfs_init_parent_name_rec(&new_parent->rec, new_dp, new_name, + child); + if (error) + return error; - xfs_init_parent_name_rec(&new_parent->old_rec, old_dp, old_diroffset); - xfs_init_parent_name_rec(&new_parent->rec, new_dp, new_diroffset); new_parent->args.name = (const uint8_t *)&new_parent->old_rec; new_parent->args.namelen = sizeof(struct xfs_parent_name_rec); new_parent->args.new_name = (const uint8_t *)&new_parent->rec; @@ -267,9 +276,8 @@ xfs_parent_replace( args->trans = tp; args->dp = child; - ASSERT(parent_name != NULL); - new_parent->args.value = (void *)parent_name->name; - new_parent->args.valuelen = parent_name->len; + new_parent->args.value = (void *)new_name->name; + new_parent->args.valuelen = new_name->len; args->hashval = xfs_da_hashname(args->name, args->namelen); return xfs_attr_defer_replace(args); @@ -388,3 +396,62 @@ xfs_parent_unset( return xfs_attr_set(&scr->args); } + +/* + * Compute the parent pointer namehash for the given child file and dirent + * name. + */ +int +xfs_parent_namehash( + struct xfs_inode *ip, + const struct xfs_name *name, + void *namehash, + unsigned int namehash_len) +{ + SHA512_DESC_ON_STACK(ip->i_mount, shash); + __be32 gen = cpu_to_be32(VFS_I(ip)->i_generation); + int error; + + ASSERT(SHA512_DIGEST_SIZE == + crypto_shash_digestsize(ip->i_mount->m_sha512)); + + if (namehash_len != SHA512_DIGEST_SIZE) { + ASSERT(0); + return -EINVAL; + } + + error = sha512_init(&shash); + if (error) + goto out; + + error = sha512_process(&shash, (const u8 *)&gen, sizeof(gen)); + if (error) + goto out; + + error = sha512_process(&shash, name->name, name->len); + if (error) + goto out; + + error = sha512_done(&shash, namehash); + if (error) + goto out; + +out: + sha512_erase(&shash); + return error; +} + +/* Recalculate the name hash of this parent pointer. */ +int +xfs_parent_irec_hash( + struct xfs_inode *ip, + struct xfs_parent_name_irec *pptr) +{ + struct xfs_name xname = { + .name = pptr->p_name, + .len = pptr->p_namelen, + }; + + return xfs_parent_namehash(ip, &xname, &pptr->p_namehash, + sizeof(pptr->p_namehash)); +} diff --git a/fs/xfs/libxfs/xfs_parent.h b/fs/xfs/libxfs/xfs_parent.h index a7fc621b82c4..d3f2841e0f6e 100644 --- a/fs/xfs/libxfs/xfs_parent.h +++ b/fs/xfs/libxfs/xfs_parent.h @@ -23,7 +23,7 @@ struct xfs_parent_name_irec { /* Key fields for looking up a particular parent pointer. */ xfs_ino_t p_ino; uint32_t p_gen; - xfs_dir2_dataptr_t p_diroffset; + uint8_t p_namehash[XFS_PARENT_NAME_HASH_SIZE]; /* Attributes of a parent pointer. */ uint8_t p_namelen; @@ -79,15 +79,14 @@ xfs_parent_start_locked( int xfs_parent_add(struct xfs_trans *tp, struct xfs_parent_defer *parent, struct xfs_inode *dp, const struct xfs_name *parent_name, - xfs_dir2_dataptr_t diroffset, struct xfs_inode *child); + struct xfs_inode *child); int xfs_parent_replace(struct xfs_trans *tp, struct xfs_parent_defer *new_parent, struct xfs_inode *old_dp, - xfs_dir2_dataptr_t old_diroffset, - const struct xfs_name *parent_name, struct xfs_inode *new_ip, - xfs_dir2_dataptr_t new_diroffset, struct xfs_inode *child); -int xfs_parent_remove(struct xfs_trans *tp, struct xfs_inode *dp, - struct xfs_parent_defer *parent, xfs_dir2_dataptr_t diroffset, - struct xfs_inode *child); + const struct xfs_name *old_name, struct xfs_inode *new_ip, + const struct xfs_name *new_name, struct xfs_inode *child); +int xfs_parent_remove(struct xfs_trans *tp, + struct xfs_parent_defer *parent, struct xfs_inode *dp, + const struct xfs_name *name, struct xfs_inode *child); void __xfs_parent_cancel(struct xfs_mount *mp, struct xfs_parent_defer *parent); @@ -100,6 +99,12 @@ xfs_parent_finish( __xfs_parent_cancel(mp, p); } +int xfs_parent_namehash(struct xfs_inode *ip, const struct xfs_name *name, + void *namehash, unsigned int namehash_len); + +int xfs_parent_irec_hash(struct xfs_inode *ip, + struct xfs_parent_name_irec *pptr); + unsigned int xfs_pptr_calc_space_res(struct xfs_mount *mp, unsigned int namelen); diff --git a/fs/xfs/scrub/dir.c b/fs/xfs/scrub/dir.c index 3f3223e563ae..2494947a0c93 100644 --- a/fs/xfs/scrub/dir.c +++ b/fs/xfs/scrub/dir.c @@ -139,16 +139,20 @@ xchk_dir_lock_child( STATIC int xchk_dir_parent_pointer( struct xchk_dir *sd, - xfs_dir2_dataptr_t dapos, const struct xfs_name *name, struct xfs_inode *ip) { struct xfs_scrub *sc = sd->sc; int pptr_namelen; + int error; sd->pptr.p_ino = sc->ip->i_ino; sd->pptr.p_gen = VFS_I(sc->ip)->i_generation; - sd->pptr.p_diroffset = dapos; + + error = xfs_parent_namehash(ip, name, &sd->pptr.p_namehash, + sizeof(sd->pptr.p_namehash)); + if (error) + return error; pptr_namelen = xfs_parent_lookup(sc->tp, ip, &sd->pptr, sd->namebuf, MAXNAMELEN, &sd->pptr_scratch); @@ -216,7 +220,7 @@ xchk_dir_check_pptr_fast( return 0; } - error = xchk_dir_parent_pointer(sd, dapos, name, ip); + error = xchk_dir_parent_pointer(sd, name, ip); xfs_iunlock(ip, lockmode); return error; } @@ -1041,7 +1045,7 @@ xchk_dir_slow_dirent( goto out_unlock; check_pptr: - error = xchk_dir_parent_pointer(sd, dirent->diroffset, &xname, ip); + error = xchk_dir_parent_pointer(sd, &xname, ip); out_unlock: xfs_iunlock(ip, lockmode); out_rele: diff --git a/fs/xfs/scrub/dir_repair.c b/fs/xfs/scrub/dir_repair.c index ec48b3268809..c0b2b78da277 100644 --- a/fs/xfs/scrub/dir_repair.c +++ b/fs/xfs/scrub/dir_repair.c @@ -93,9 +93,6 @@ struct xrep_dirent { /* Child inode number. */ xfs_ino_t ino; - /* Directory offset that we want. We're not going to get it. */ - xfs_dir2_dataptr_t diroffset; - /* Length of the dirent name. */ uint8_t namelen; @@ -261,8 +258,7 @@ xrep_dir_createname( struct xrep_dir *rd, const struct xfs_name *name, xfs_ino_t inum, - xfs_extlen_t total, - xfs_dir2_dataptr_t diroffset) + xfs_extlen_t total) { struct xfs_scrub *sc = rd->sc; struct xfs_inode *dp = rd->args.dp; @@ -275,7 +271,7 @@ xrep_dir_createname( if (error) return error; - trace_xrep_dir_createname(dp, name, inum, diroffset); + trace_xrep_dir_createname(dp, name, inum); /* reset cmpresult as if we haven't done a lookup */ rd->args.cmpresult = XFS_CMP_DIFFERENT; @@ -307,8 +303,7 @@ STATIC int xrep_dir_removename( struct xrep_dir *rd, const struct xfs_name *name, - xfs_extlen_t total, - xfs_dir2_dataptr_t diroffset) + xfs_extlen_t total) { struct xfs_inode *dp = rd->args.dp; bool is_block, is_leaf; @@ -321,7 +316,7 @@ xrep_dir_removename( rd->args.op_flags = 0; rd->args.total = total; - trace_xrep_dir_removename(dp, name, rd->args.inumber, diroffset); + trace_xrep_dir_removename(dp, name, rd->args.inumber); if (dp->i_df.if_format == XFS_DINODE_FMT_LOCAL) return xfs_dir2_sf_removename(&rd->args); @@ -385,8 +380,7 @@ xrep_dir_replay_update( goto out_cancel; } - error = xrep_dir_removename(rd, &xname, resblks, - dirent->diroffset); + error = xrep_dir_removename(rd, &xname, resblks); } else { /* Add this dirent. The lookup must not succeed. */ if (error == 0) @@ -394,8 +388,7 @@ xrep_dir_replay_update( if (error != -ENOENT) goto out_cancel; - error = xrep_dir_createname(rd, &xname, dirent->ino, resblks, - dirent->diroffset); + error = xrep_dir_createname(rd, &xname, dirent->ino, resblks); } if (error) goto out_cancel; @@ -465,19 +458,17 @@ STATIC int xrep_dir_add_dirent( struct xrep_dir *rd, const struct xfs_name *name, - xfs_ino_t ino, - xfs_dir2_dataptr_t diroffset) + xfs_ino_t ino) { struct xrep_dirent dirent = { .action = XREP_DIRENT_ADD, .ino = ino, .namelen = name->len, .ftype = name->type, - .diroffset = diroffset, }; int error; - trace_xrep_dir_add_dirent(rd->sc->tempip, name, ino, diroffset); + trace_xrep_dir_add_dirent(rd->sc->tempip, name, ino); error = xfblob_store(rd->dir_names, &dirent.name_cookie, name->name, name->len); @@ -495,19 +486,17 @@ STATIC int xrep_dir_remove_dirent( struct xrep_dir *rd, const struct xfs_name *name, - xfs_ino_t ino, - xfs_dir2_dataptr_t diroffset) + xfs_ino_t ino) { struct xrep_dirent dirent = { .action = XREP_DIRENT_REMOVE, .ino = ino, .namelen = name->len, .ftype = name->type, - .diroffset = diroffset, }; int error; - trace_xrep_dir_remove_dirent(rd->sc->tempip, name, ino, diroffset); + trace_xrep_dir_remove_dirent(rd->sc->tempip, name, ino); error = xfblob_store(rd->dir_names, &dirent.name_cookie, name->name, name->len); @@ -567,8 +556,7 @@ xrep_dir_scan_parent_pointer( xname.type = xfs_mode_to_ftype(VFS_I(ip)->i_mode); mutex_lock(&rd->lock); - error = xrep_dir_add_dirent(rd, &xname, ip->i_ino, - rd->pptr.p_diroffset); + error = xrep_dir_add_dirent(rd, &xname, ip->i_ino); mutex_unlock(&rd->lock); return error; } @@ -605,7 +593,7 @@ xrep_dir_scan_dirent( xrep_dir_samename(name, &xfs_name_dot)) return 0; - trace_xrep_dir_replacename(sc->tempip, &xfs_name_dotdot, dp->i_ino, 0); + trace_xrep_dir_replacename(sc->tempip, &xfs_name_dotdot, dp->i_ino); mutex_lock(&rd->lock); rd->parent_ino = dp->i_ino; @@ -773,7 +761,6 @@ xrep_dir_dump_tempdir( struct xrep_dir *rd = priv; xfs_ino_t child_ino; bool child = true; - xfs_dir2_dataptr_t child_diroffset = XFS_DIR2_NULL_DATAPTR; int error; /* @@ -800,7 +787,7 @@ xrep_dir_dump_tempdir( ino = sc->ip->i_ino; } - trace_xrep_dir_dumpname(sc->tempip, name, ino, dapos); + trace_xrep_dir_dumpname(sc->tempip, name, ino); if (!child) return 0; @@ -812,17 +799,15 @@ xrep_dir_dump_tempdir( * and reap it responsibly, but I didn't feel like porting all that. */ mutex_lock(&rd->lock); - error = xrep_dir_remove_dirent(rd, name, ino, dapos); + error = xrep_dir_remove_dirent(rd, name, ino); mutex_unlock(&rd->lock); if (error) return error; /* Check that the dir being repaired has the same entry. */ - error = xchk_dir_lookup(sc, sc->ip, name, &child_ino, - &child_diroffset); + error = xchk_dir_lookup(sc, sc->ip, name, &child_ino, NULL); if (error == -ENOENT) { - trace_xrep_dir_checkname(sc->ip, name, NULLFSINO, - XFS_DIR2_NULL_DATAPTR); + trace_xrep_dir_checkname(sc->ip, name, NULLFSINO); ASSERT(error != -ENOENT); return -EFSCORRUPTED; } @@ -830,18 +815,11 @@ xrep_dir_dump_tempdir( return error; if (ino != child_ino) { - trace_xrep_dir_checkname(sc->ip, name, child_ino, - child_diroffset); + trace_xrep_dir_checkname(sc->ip, name, child_ino); ASSERT(ino == child_ino); return -EFSCORRUPTED; } - if (dapos != child_diroffset) { - trace_xrep_dir_badposname(sc->ip, name, child_ino, - child_diroffset); - /* We have no way to update this, so we just leave it. */ - } - return 0; } @@ -860,7 +838,6 @@ xrep_dir_dump_baddir( void *priv) { xfs_ino_t child_ino; - xfs_dir2_dataptr_t child_diroffset = XFS_DIR2_NULL_DATAPTR; int error; /* Ignore the directory's dot and dotdot entries. */ @@ -868,14 +845,12 @@ xrep_dir_dump_baddir( xrep_dir_samename(name, &xfs_name_dot)) return 0; - trace_xrep_dir_dumpname(sc->ip, name, ino, dapos); + trace_xrep_dir_dumpname(sc->ip, name, ino); /* Check that the tempdir has the same entry. */ - error = xchk_dir_lookup(sc, sc->tempip, name, &child_ino, - &child_diroffset); + error = xchk_dir_lookup(sc, sc->tempip, name, &child_ino, NULL); if (error == -ENOENT) { - trace_xrep_dir_checkname(sc->tempip, name, NULLFSINO, - XFS_DIR2_NULL_DATAPTR); + trace_xrep_dir_checkname(sc->tempip, name, NULLFSINO); ASSERT(error != -ENOENT); return -EFSCORRUPTED; } @@ -883,18 +858,11 @@ xrep_dir_dump_baddir( return error; if (ino != child_ino) { - trace_xrep_dir_checkname(sc->tempip, name, child_ino, - child_diroffset); + trace_xrep_dir_checkname(sc->tempip, name, child_ino); ASSERT(ino == child_ino); return -EFSCORRUPTED; } - if (dapos != child_diroffset) { - trace_xrep_dir_badposname(sc->ip, name, child_ino, - child_diroffset); - /* We have no way to update this, so we just leave it. */ - } - return 0; } @@ -1011,11 +979,10 @@ xrep_dir_live_update( xchk_iscan_want_live_update(&rd->iscan, p->ip->i_ino)) { mutex_lock(&rd->lock); if (p->delta > 0) - error = xrep_dir_add_dirent(rd, p->name, p->ip->i_ino, - p->diroffset); + error = xrep_dir_add_dirent(rd, p->name, p->ip->i_ino); else error = xrep_dir_remove_dirent(rd, p->name, - p->ip->i_ino, p->diroffset); + p->ip->i_ino); mutex_unlock(&rd->lock); if (error) goto out_abort; @@ -1030,12 +997,12 @@ xrep_dir_live_update( mutex_lock(&rd->lock); if (p->delta > 0) { trace_xrep_dir_add_dirent(sc->tempip, &xfs_name_dotdot, - p->dp->i_ino, 0); + p->dp->i_ino); rd->parent_ino = p->dp->i_ino; } else { trace_xrep_dir_remove_dirent(sc->tempip, - &xfs_name_dotdot, NULLFSINO, 0); + &xfs_name_dotdot, NULLFSINO); rd->parent_ino = NULLFSINO; } diff --git a/fs/xfs/scrub/parent.c b/fs/xfs/scrub/parent.c index 14f16fefd1b0..53872a7be942 100644 --- a/fs/xfs/scrub/parent.c +++ b/fs/xfs/scrub/parent.c @@ -323,7 +323,6 @@ struct xchk_pptr { /* Parent pointer attr key. */ xfs_ino_t p_ino; uint32_t p_gen; - xfs_dir2_dataptr_t p_diroffset; /* Length of the pptr name. */ uint8_t namelen; @@ -350,6 +349,9 @@ struct xchk_pptrs { /* xattr key and da args for parent pointer revalidation. */ struct xfs_parent_scratch pptr_scratch; + /* Name hashes */ + uint8_t child_namehash[XFS_PARENT_NAME_HASH_SIZE]; + /* Name buffer for revalidation. */ uint8_t namebuf[MAXNAMELEN]; }; @@ -426,14 +428,13 @@ xchk_parent_dirent( }; struct xfs_scrub *sc = pp->sc; xfs_ino_t child_ino; - xfs_dir2_dataptr_t child_diroffset; int error; /* * Use the name attached to this parent pointer to look up the * directory entry in the alleged parent. */ - error = xchk_dir_lookup(sc, dp, &xname, &child_ino, &child_diroffset); + error = xchk_dir_lookup(sc, dp, &xname, &child_ino, NULL); if (error == -ENOENT) { xchk_fblock_xref_set_corrupt(sc, XFS_ATTR_FORK, 0); return 0; @@ -447,15 +448,6 @@ xchk_parent_dirent( return 0; } - /* Does the directory offset match? */ - if (pp->pptr.p_diroffset != child_diroffset) { - trace_xchk_parent_bad_dapos(sc->ip, pp->pptr.p_diroffset, - dp->i_ino, child_diroffset, xname.name, - xname.len); - xchk_fblock_xref_set_corrupt(sc, XFS_ATTR_FORK, 0); - return 0; - } - /* * If we're scanning a directory, we should only ever encounter a * single parent pointer, and it should match the dotdot entry. We set @@ -534,6 +526,7 @@ xchk_parent_scan_attr( unsigned int valuelen, void *priv) { + struct xfs_name xname = { }; struct xchk_pptrs *pp = priv; struct xfs_inode *dp = NULL; const struct xfs_parent_name_rec *rec = (const void *)name; @@ -561,6 +554,26 @@ xchk_parent_scan_attr( xfs_parent_irec_from_disk(&pp->pptr, rec, value, valuelen); + xname.name = pp->pptr.p_name; + xname.len = pp->pptr.p_namelen; + + /* + * Does the namehash in the parent pointer match the actual name? + * If not, there's no point in checking further. + */ + error = xfs_parent_namehash(sc->ip, &xname, pp->child_namehash, + sizeof(pp->child_namehash)); + if (!xchk_fblock_xref_process_error(sc, XFS_ATTR_FORK, 0, &error)) + return error; + + if (memcmp(pp->pptr.p_namehash, pp->child_namehash, + sizeof(pp->pptr.p_namehash))) { + trace_xchk_parent_bad_namehash(sc->ip, pp->pptr.p_ino, + xname.name, xname.len); + xchk_fblock_xref_set_corrupt(sc, XFS_ATTR_FORK, 0); + return 0; + } + error = xchk_parent_iget(pp, &dp); if (error) return error; @@ -573,7 +586,6 @@ xchk_parent_scan_attr( struct xchk_pptr save_pp = { .p_ino = pp->pptr.p_ino, .p_gen = pp->pptr.p_gen, - .p_diroffset = pp->pptr.p_diroffset, .namelen = pp->pptr.p_namelen, }; @@ -655,7 +667,6 @@ xchk_parent_slow_pptr( /* Restore the saved parent pointer into the irec. */ pp->pptr.p_ino = pptr->p_ino; pp->pptr.p_gen = pptr->p_gen; - pp->pptr.p_diroffset = pptr->p_diroffset; error = xfblob_load(pp->pptr_names, pptr->name_cookie, pp->pptr.p_name, pptr->namelen); @@ -664,6 +675,10 @@ xchk_parent_slow_pptr( pp->pptr.p_name[MAXNAMELEN - 1] = 0; pp->pptr.p_namelen = pptr->namelen; + error = xfs_parent_irec_hash(sc->ip, &pp->pptr); + if (error) + return error; + /* Check that the deferred parent pointer still exists. */ if (pp->need_revalidate) { error = xchk_parent_revalidate_pptr(pp); diff --git a/fs/xfs/scrub/parent_repair.c b/fs/xfs/scrub/parent_repair.c index 56b47bf2807b..51432ab61c94 100644 --- a/fs/xfs/scrub/parent_repair.c +++ b/fs/xfs/scrub/parent_repair.c @@ -95,7 +95,6 @@ struct xrep_pptr { /* Parent pointer attr key. */ xfs_ino_t p_ino; uint32_t p_gen; - xfs_dir2_dataptr_t p_diroffset; /* Length of the pptr name. */ uint8_t namelen; @@ -183,12 +182,16 @@ xrep_pptr_replay_update( const struct xrep_pptr *pptr) { struct xfs_scrub *sc = rp->sc; + int error; rp->pptr.p_ino = pptr->p_ino; rp->pptr.p_gen = pptr->p_gen; - rp->pptr.p_diroffset = pptr->p_diroffset; rp->pptr.p_namelen = pptr->namelen; + error = xfs_parent_irec_hash(sc->ip, &rp->pptr); + if (error) + return error; + if (pptr->action == XREP_PPTR_ADD) { /* Create parent pointer. */ trace_xrep_pptr_createname(sc->tempip, &rp->pptr); @@ -261,19 +264,17 @@ STATIC int xrep_pptr_add_pointer( struct xrep_pptrs *rp, const struct xfs_name *name, - const struct xfs_inode *dp, - xfs_dir2_dataptr_t diroffset) + const struct xfs_inode *dp) { struct xrep_pptr pptr = { .action = XREP_PPTR_ADD, .namelen = name->len, .p_ino = dp->i_ino, .p_gen = VFS_IC(dp)->i_generation, - .p_diroffset = diroffset, }; int error; - trace_xrep_pptr_add_pointer(rp->sc->tempip, dp, diroffset, name); + trace_xrep_pptr_add_pointer(rp->sc->tempip, dp, name); error = xfblob_store(rp->pptr_names, &pptr.name_cookie, name->name, name->len); @@ -291,19 +292,17 @@ STATIC int xrep_pptr_remove_pointer( struct xrep_pptrs *rp, const struct xfs_name *name, - const struct xfs_inode *dp, - xfs_dir2_dataptr_t diroffset) + const struct xfs_inode *dp) { struct xrep_pptr pptr = { .action = XREP_PPTR_REMOVE, .namelen = name->len, .p_ino = dp->i_ino, .p_gen = VFS_IC(dp)->i_generation, - .p_diroffset = diroffset, }; int error; - trace_xrep_pptr_remove_pointer(rp->sc->tempip, dp, diroffset, name); + trace_xrep_pptr_remove_pointer(rp->sc->tempip, dp, name); error = xfblob_store(rp->pptr_names, &pptr.name_cookie, name->name, name->len); @@ -352,7 +351,7 @@ xrep_pptr_scan_dirent( * addition to the temporary file. */ mutex_lock(&rp->lock); - error = xrep_pptr_add_pointer(rp, name, dp, dapos); + error = xrep_pptr_add_pointer(rp, name, dp); mutex_unlock(&rp->lock); return error; } @@ -646,11 +645,9 @@ xrep_pptr_live_update( xchk_iscan_want_live_update(&rp->iscan, p->dp->i_ino)) { mutex_lock(&rp->lock); if (p->delta > 0) - error = xrep_pptr_add_pointer(rp, p->name, p->dp, - p->diroffset); + error = xrep_pptr_add_pointer(rp, p->name, p->dp); else - error = xrep_pptr_remove_pointer(rp, p->name, p->dp, - p->diroffset); + error = xrep_pptr_remove_pointer(rp, p->name, p->dp); mutex_unlock(&rp->lock); if (error) goto out_abort; diff --git a/fs/xfs/scrub/trace.h b/fs/xfs/scrub/trace.h index 911d947db787..1af148d7617e 100644 --- a/fs/xfs/scrub/trace.h +++ b/fs/xfs/scrub/trace.h @@ -897,35 +897,28 @@ TRACE_EVENT(xchk_nlinks_live_update, __get_str(name)) ); -TRACE_EVENT(xchk_parent_bad_dapos, - TP_PROTO(struct xfs_inode *ip, unsigned int p_diroffset, - xfs_ino_t parent_ino, unsigned int dapos, - const char *name, unsigned int namelen), - TP_ARGS(ip, p_diroffset, parent_ino, dapos, name, namelen), +TRACE_EVENT(xchk_parent_bad_namehash, + TP_PROTO(struct xfs_inode *ip, xfs_ino_t parent_ino, const char *name, + unsigned int namelen), + TP_ARGS(ip, parent_ino, name, namelen), TP_STRUCT__entry( __field(dev_t, dev) __field(xfs_ino_t, ino) - __field(unsigned int, p_diroffset) __field(xfs_ino_t, parent_ino) - __field(unsigned int, dapos) __field(unsigned int, namelen) __dynamic_array(char, name, namelen) ), TP_fast_assign( __entry->dev = ip->i_mount->m_super->s_dev; __entry->ino = ip->i_ino; - __entry->p_diroffset = p_diroffset; __entry->parent_ino = parent_ino; - __entry->dapos = dapos; __entry->namelen = namelen; memcpy(__get_str(name), name, namelen); ), - TP_printk("dev %d:%d ino 0x%llx p_diroff 0x%x parent_ino 0x%llx parent_diroff 0x%x name '%.*s'", + TP_printk("dev %d:%d ino 0x%llx parent_ino 0x%llx name '%.*s'", MAJOR(__entry->dev), MINOR(__entry->dev), __entry->ino, - __entry->p_diroffset, __entry->parent_ino, - __entry->dapos, __entry->namelen, __get_str(name)) ); @@ -1253,8 +1246,8 @@ TRACE_EVENT(xrep_tempfile_create, DECLARE_EVENT_CLASS(xrep_dirent_class, TP_PROTO(struct xfs_inode *dp, const struct xfs_name *name, - xfs_ino_t ino, unsigned int diroffset), - TP_ARGS(dp, name, ino, diroffset), + xfs_ino_t ino), + TP_ARGS(dp, name, ino), TP_STRUCT__entry( __field(dev_t, dev) __field(xfs_ino_t, dir_ino) @@ -1262,7 +1255,6 @@ DECLARE_EVENT_CLASS(xrep_dirent_class, __dynamic_array(char, name, name->len) __field(xfs_ino_t, ino) __field(uint8_t, ftype) - __field(unsigned int, diroffset) ), TP_fast_assign( __entry->dev = dp->i_mount->m_super->s_dev; @@ -1271,12 +1263,10 @@ DECLARE_EVENT_CLASS(xrep_dirent_class, memcpy(__get_str(name), name->name, name->len); __entry->ino = ino; __entry->ftype = name->type; - __entry->diroffset = diroffset; ), - TP_printk("dev %d:%d dir 0x%llx dapos 0x%x ftype %s name '%.*s' ino 0x%llx", + TP_printk("dev %d:%d dir 0x%llx ftype %s name '%.*s' ino 0x%llx", MAJOR(__entry->dev), MINOR(__entry->dev), __entry->dir_ino, - __entry->diroffset, __print_symbolic(__entry->ftype, XFS_DIR3_FTYPE_STR), __entry->namelen, __get_str(name), @@ -1285,8 +1275,8 @@ DECLARE_EVENT_CLASS(xrep_dirent_class, #define DEFINE_XREP_DIRENT_CLASS(name) \ DEFINE_EVENT(xrep_dirent_class, name, \ TP_PROTO(struct xfs_inode *dp, const struct xfs_name *name, \ - xfs_ino_t ino, unsigned int diroffset), \ - TP_ARGS(dp, name, ino, diroffset)) + xfs_ino_t ino), \ + TP_ARGS(dp, name, ino)) DEFINE_XREP_DIRENT_CLASS(xrep_dir_add_dirent); DEFINE_XREP_DIRENT_CLASS(xrep_dir_remove_dirent); DEFINE_XREP_DIRENT_CLASS(xrep_dir_createname); @@ -1329,7 +1319,6 @@ DECLARE_EVENT_CLASS(xrep_pptr_class, __field(xfs_ino_t, ino) __field(xfs_ino_t, parent_ino) __field(unsigned int, parent_gen) - __field(unsigned int, parent_diroffset) __field(unsigned int, namelen) __dynamic_array(char, name, pptr->p_namelen) ), @@ -1338,16 +1327,14 @@ DECLARE_EVENT_CLASS(xrep_pptr_class, __entry->ino = ip->i_ino; __entry->parent_ino = pptr->p_ino; __entry->parent_gen = pptr->p_gen; - __entry->parent_diroffset = pptr->p_diroffset; __entry->namelen = pptr->p_namelen; memcpy(__get_str(name), pptr->p_name, pptr->p_namelen); ), - TP_printk("dev %d:%d ino 0x%llx parent_ino 0x%llx parent_gen 0x%x parent_dapos 0x%x name '%.*s'", + TP_printk("dev %d:%d ino 0x%llx parent_ino 0x%llx parent_gen 0x%x name '%.*s'", MAJOR(__entry->dev), MINOR(__entry->dev), __entry->ino, __entry->parent_ino, __entry->parent_gen, - __entry->parent_diroffset, __entry->namelen, __get_str(name)) ) @@ -1362,14 +1349,13 @@ DEFINE_XREP_PPTR_CLASS(xrep_pptr_checkname); DECLARE_EVENT_CLASS(xrep_pptr_scan_class, TP_PROTO(struct xfs_inode *ip, const struct xfs_inode *dp, - unsigned int diroffset, const struct xfs_name *name), - TP_ARGS(ip, dp, diroffset, name), + const struct xfs_name *name), + TP_ARGS(ip, dp, name), TP_STRUCT__entry( __field(dev_t, dev) __field(xfs_ino_t, ino) __field(xfs_ino_t, parent_ino) __field(unsigned int, parent_gen) - __field(unsigned int, parent_diroffset) __field(unsigned int, namelen) __dynamic_array(char, name, name->len) ), @@ -1378,24 +1364,22 @@ DECLARE_EVENT_CLASS(xrep_pptr_scan_class, __entry->ino = ip->i_ino; __entry->parent_ino = dp->i_ino; __entry->parent_gen = VFS_IC(dp)->i_generation; - __entry->parent_diroffset = diroffset; __entry->namelen = name->len; memcpy(__get_str(name), name->name, name->len); ), - TP_printk("dev %d:%d ino 0x%llx parent_ino 0x%llx parent_gen 0x%x parent_dapos 0x%x name '%.*s'", + TP_printk("dev %d:%d ino 0x%llx parent_ino 0x%llx parent_gen 0x%x name '%.*s'", MAJOR(__entry->dev), MINOR(__entry->dev), __entry->ino, __entry->parent_ino, __entry->parent_gen, - __entry->parent_diroffset, __entry->namelen, __get_str(name)) ) #define DEFINE_XREP_PPTR_SCAN_CLASS(name) \ DEFINE_EVENT(xrep_pptr_scan_class, name, \ TP_PROTO(struct xfs_inode *ip, const struct xfs_inode *dp, \ - unsigned int diroffset, const struct xfs_name *name), \ - TP_ARGS(ip, dp, diroffset, name)) + const struct xfs_name *name), \ + TP_ARGS(ip, dp, name)) DEFINE_XREP_PPTR_SCAN_CLASS(xrep_pptr_add_pointer); DEFINE_XREP_PPTR_SCAN_CLASS(xrep_pptr_remove_pointer); diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index 09b0ac6b99cb..4cd9a4fea5e0 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -1202,8 +1202,7 @@ xfs_create( * the parent information now. */ if (parent) { - error = xfs_parent_add(tp, parent, dp, name, diroffset, - ip); + error = xfs_parent_add(tp, parent, dp, name, ip); if (error) goto out_trans_cancel; } @@ -1477,8 +1476,7 @@ xfs_link( * the parent to the inode. */ if (parent) { - error = xfs_parent_add(tp, parent, tdp, target_name, - diroffset, sip); + error = xfs_parent_add(tp, parent, tdp, target_name, sip); if (error) goto error_return; } @@ -2750,7 +2748,7 @@ xfs_remove( } if (parent) { - error = xfs_parent_remove(tp, dp, parent, dir_offset, ip); + error = xfs_parent_remove(tp, parent, dp, name, ip); if (error) goto out_trans_cancel; } @@ -3061,13 +3059,13 @@ xfs_cross_rename( } if (xfs_has_parent(mp)) { - error = xfs_parent_replace(tp, ip1_pptr, dp1, - old_diroffset, name2, dp2, new_diroffset, ip1); + error = xfs_parent_replace(tp, ip1_pptr, dp1, name1, dp2, + name2, ip1); if (error) goto out_trans_abort; - error = xfs_parent_replace(tp, ip2_pptr, dp2, - new_diroffset, name1, dp1, old_diroffset, ip2); + error = xfs_parent_replace(tp, ip2_pptr, dp2, name2, dp1, + name1, ip2); if (error) goto out_trans_abort; } @@ -3540,25 +3538,21 @@ xfs_rename( goto out_trans_cancel; if (wip_pptr) { - error = xfs_parent_add(tp, wip_pptr, - src_dp, src_name, - old_diroffset, wip); + error = xfs_parent_add(tp, wip_pptr, src_dp, src_name, wip); if (error) goto out_trans_cancel; } if (src_ip_pptr) { - error = xfs_parent_replace(tp, src_ip_pptr, src_dp, - old_diroffset, target_name, target_dp, - new_diroffset, src_ip); + error = xfs_parent_replace(tp, src_ip_pptr, src_dp, src_name, + target_dp, target_name, src_ip); if (error) goto out_trans_cancel; } if (tgt_ip_pptr) { - error = xfs_parent_remove(tp, target_dp, - tgt_ip_pptr, - new_diroffset, target_ip); + error = xfs_parent_remove(tp, tgt_ip_pptr, target_dp, + target_name, target_ip); if (error) goto out_trans_cancel; } diff --git a/fs/xfs/xfs_ondisk.h b/fs/xfs/xfs_ondisk.h index 6a6bd05c2a68..2dc1eef63d96 100644 --- a/fs/xfs/xfs_ondisk.h +++ b/fs/xfs/xfs_ondisk.h @@ -6,6 +6,8 @@ #ifndef __XFS_ONDISK_H #define __XFS_ONDISK_H +#include + #define XFS_CHECK_STRUCT_SIZE(structname, size) \ BUILD_BUG_ON_MSG(sizeof(structname) != (size), "XFS: sizeof(" \ #structname ") is wrong, expected " #size) @@ -114,6 +116,8 @@ xfs_check_ondisk_structs(void) XFS_CHECK_OFFSET(xfs_dir2_sf_entry_t, offset, 1); XFS_CHECK_OFFSET(xfs_dir2_sf_entry_t, name, 3); XFS_CHECK_STRUCT_SIZE(xfs_dir2_sf_hdr_t, 10); + XFS_CHECK_STRUCT_SIZE(struct xfs_parent_name_rec, 76); + BUILD_BUG_ON(XFS_PARENT_NAME_HASH_SIZE != SHA512_DIGEST_SIZE); /* log structures */ XFS_CHECK_STRUCT_SIZE(struct xfs_buf_log_format, 88); diff --git a/fs/xfs/xfs_parent_utils.c b/fs/xfs/xfs_parent_utils.c index 5ff7d38bc375..65bec3875308 100644 --- a/fs/xfs/xfs_parent_utils.c +++ b/fs/xfs/xfs_parent_utils.c @@ -83,7 +83,7 @@ xfs_getparent_listent( pptr = &ppi->pi_parents[ppi->pi_ptrs_used++]; pptr->xpp_ino = irec->p_ino; pptr->xpp_gen = irec->p_gen; - pptr->xpp_diroffset = irec->p_diroffset; + pptr->xpp_rsvd2 = 0; pptr->xpp_rsvd = 0; memcpy(pptr->xpp_name, irec->p_name, irec->p_namelen); diff --git a/fs/xfs/xfs_sha512.h b/fs/xfs/xfs_sha512.h new file mode 100644 index 000000000000..d9756db63aa6 --- /dev/null +++ b/fs/xfs/xfs_sha512.h @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2023 Oracle. All Rights Reserved. + * Author: Darrick J. Wong + */ +#ifndef __XFS_SHA512_H__ +#define __XFS_SHA512_H__ + +struct sha512_state { + union { + struct shash_desc desc; + char __desc[sizeof(struct shash_desc) + HASH_MAX_DESCSIZE]; + }; +}; + +#define SHA512_DESC_ON_STACK(mp, name) \ + struct sha512_state name = { .desc.tfm = (mp)->m_sha512 } + +#define SHA512_DIGEST_SIZE 64 + +static inline int sha512_init(struct sha512_state *md) +{ + return crypto_shash_init(&md->desc); +} + +static inline int sha512_done(struct sha512_state *md, unsigned char *out) +{ + return crypto_shash_final(&md->desc, out); +} + +static inline int sha512_process(struct sha512_state *md, + const unsigned char *in, unsigned long inlen) +{ + return crypto_shash_update(&md->desc, in, inlen); +} + +static inline void sha512_erase(struct sha512_state *md) +{ + memset(md, 0, sizeof(*md)); +} + +#endif /* __XFS_SHA512_H__ */ diff --git a/fs/xfs/xfs_symlink.c b/fs/xfs/xfs_symlink.c index 63e68e832551..327c805815dc 100644 --- a/fs/xfs/xfs_symlink.c +++ b/fs/xfs/xfs_symlink.c @@ -348,8 +348,7 @@ xfs_symlink( xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE); if (parent) { - error = xfs_parent_add(tp, parent, dp, link_name, - diroffset, ip); + error = xfs_parent_add(tp, parent, dp, link_name, ip); if (error) goto out_trans_cancel; } From patchwork Thu Feb 16 20:52:12 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: 13143853 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 52BF3C636CC for ; Thu, 16 Feb 2023 20:52:19 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229768AbjBPUwS (ORCPT ); Thu, 16 Feb 2023 15:52:18 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59050 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229793AbjBPUwR (ORCPT ); Thu, 16 Feb 2023 15:52:17 -0500 Received: from ams.source.kernel.org (ams.source.kernel.org [IPv6:2604:1380:4601:e00::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 225AF4BEA8 for ; Thu, 16 Feb 2023 12:52:16 -0800 (PST) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ams.source.kernel.org (Postfix) with ESMTPS id AC052B826BA for ; Thu, 16 Feb 2023 20:52:14 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 6ED27C433EF; Thu, 16 Feb 2023 20:52:13 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1676580733; bh=FpUmytAPniEy1oYQnImTCN6lEp90tRtoqgQ2Wj4WE3E=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=iMzsSRHSQ9Ykd7Bkj2xal9v1gJx1m0aihfaFikGu+YVY5kZKojZYzc1SYPrfsy2Yu QySMkEQ6ATcYDaxSYZwm+Uyc0BpDQ31hIFbCJfMd9P4ojdhSy8TKimfpnytE6kGVGo YKq0Axa67Td+adX2NtLb2cioISJ1oSVU6ALEXIS4ouSsc5JcltWOotedtiaSyMtQwU kQR0hxGqbAnd/6oF1igUxPdQvJxj8vpxFQ3jYqUpnrNb1nJqY/Or6E+pAlKkVJzqGw SW+6O8x49tLkIho/Cp3y+QdriQ3qwHxc++xzJLFqUbr58jFZzWtzxcyfMY5zp9117k gxMMK2uuJzDbg== Date: Thu, 16 Feb 2023 12:52:12 -0800 Subject: [PATCH 3/5] xfs: skip the sha512 namehash when possible From: "Darrick J. Wong" To: djwong@kernel.org Cc: allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <167657875909.3475422.13864721417258672651.stgit@magnolia> In-Reply-To: <167657875861.3475422.10929602650869169128.stgit@magnolia> References: <167657875861.3475422.10929602650869169128.stgit@magnolia> User-Agent: StGit/0.19 MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-xfs@vger.kernel.org From: Darrick J. Wong Reduce the size and performance impacts of parent pointer name hashes by using the dirent name as the hash if the dirent name is shorter than a sha512 hash would be. IOWs, we only use sha512 for names longer than 63 bytes. Signed-off-by: Darrick J. Wong --- fs/xfs/libxfs/xfs_da_format.h | 21 +++++++++- fs/xfs/libxfs/xfs_parent.c | 85 +++++++++++++++++++++++++++-------------- fs/xfs/libxfs/xfs_parent.h | 8 ++-- fs/xfs/scrub/dir.c | 12 ++++-- fs/xfs/scrub/dir_repair.c | 2 - fs/xfs/scrub/parent.c | 16 +++++--- fs/xfs/scrub/parent_repair.c | 2 - fs/xfs/xfs_parent_utils.c | 2 - 8 files changed, 101 insertions(+), 47 deletions(-) diff --git a/fs/xfs/libxfs/xfs_da_format.h b/fs/xfs/libxfs/xfs_da_format.h index 386f63b262d5..275357506394 100644 --- a/fs/xfs/libxfs/xfs_da_format.h +++ b/fs/xfs/libxfs/xfs_da_format.h @@ -831,8 +831,11 @@ xfs_failaddr_t xfs_da3_blkinfo_verify(struct xfs_buf *bp, * Parent pointer attribute format definition * * The EA name encodes the parent inode number, generation and a collision - * resistant hash computed from the dirent name. The hash is defined to be the - * sha512 of the child inode generation and the dirent name. + * resistant hash computed from the dirent name. The hash is defined to be: + * + * - The dirent name if it fits within the EA name. + * + * - The sha512 of the child inode generation and the dirent name. * * The EA value contains the same name as the dirent in the parent directory. */ @@ -842,4 +845,18 @@ struct xfs_parent_name_rec { __u8 p_namehash[XFS_PARENT_NAME_HASH_SIZE]; } __attribute__((packed)); +static inline unsigned int +xfs_parent_name_rec_sizeof( + unsigned int hashlen) +{ + return offsetof(struct xfs_parent_name_rec, p_namehash) + hashlen; +} + +static inline unsigned int +xfs_parent_name_hashlen( + unsigned int rec_sizeof) +{ + return rec_sizeof - offsetof(struct xfs_parent_name_rec, p_namehash); +} + #endif /* __XFS_DA_FORMAT_H__ */ diff --git a/fs/xfs/libxfs/xfs_parent.c b/fs/xfs/libxfs/xfs_parent.c index a28dcf18cb4d..32235a0e9e0d 100644 --- a/fs/xfs/libxfs/xfs_parent.c +++ b/fs/xfs/libxfs/xfs_parent.c @@ -56,7 +56,8 @@ xfs_parent_namecheck( { xfs_ino_t p_ino; - if (reclen != sizeof(struct xfs_parent_name_rec)) + if (reclen <= xfs_parent_name_rec_sizeof(0) || + reclen > xfs_parent_name_rec_sizeof(XFS_PARENT_NAME_HASH_SIZE)) return false; /* Only one namespace bit allowed. */ @@ -108,12 +109,16 @@ void xfs_parent_irec_from_disk( struct xfs_parent_name_irec *irec, const struct xfs_parent_name_rec *rec, + int reclen, const void *value, int valuelen) { irec->p_ino = be64_to_cpu(rec->p_ino); irec->p_gen = be32_to_cpu(rec->p_gen); - memcpy(irec->p_namehash, rec->p_namehash, sizeof(irec->p_namehash)); + irec->hashlen = xfs_parent_name_hashlen(reclen); + memcpy(irec->p_namehash, rec->p_namehash, irec->hashlen); + memset(irec->p_namehash + irec->hashlen, 0, + sizeof(irec->p_namehash) - irec->hashlen); if (!value) { irec->p_namelen = 0; @@ -137,13 +142,15 @@ xfs_parent_irec_from_disk( void xfs_parent_irec_to_disk( struct xfs_parent_name_rec *rec, + int *reclen, void *value, int *valuelen, 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); - memcpy(rec->p_namehash, irec->p_namehash, sizeof(rec->p_namehash)); + *reclen = xfs_parent_name_rec_sizeof(irec->hashlen); + memcpy(rec->p_namehash, irec->p_namehash, irec->hashlen); if (valuelen) { ASSERT(*valuelen > 0); @@ -206,12 +213,14 @@ xfs_parent_add( struct xfs_inode *child) { struct xfs_da_args *args = &parent->args; - int error; + int hashlen; - error = xfs_init_parent_name_rec(&parent->rec, dp, parent_name, child); - if (error) - return error; + hashlen = xfs_init_parent_name_rec(&parent->rec, dp, parent_name, + child); + if (hashlen < 0) + return hashlen; + args->namelen = xfs_parent_name_rec_sizeof(hashlen); args->hashval = xfs_da_hashname(args->name, args->namelen); args->trans = tp; @@ -234,12 +243,13 @@ xfs_parent_remove( struct xfs_inode *child) { struct xfs_da_args *args = &parent->args; - int error; + int hashlen; - error = xfs_init_parent_name_rec(&parent->rec, dp, name, child); - if (error) - return error; + hashlen = xfs_init_parent_name_rec(&parent->rec, dp, name, child); + if (hashlen < 0) + return hashlen; + args->namelen = xfs_parent_name_rec_sizeof(hashlen); args->trans = tp; args->dp = child; args->hashval = xfs_da_hashname(args->name, args->namelen); @@ -258,21 +268,21 @@ xfs_parent_replace( struct xfs_inode *child) { struct xfs_da_args *args = &new_parent->args; - int error; + int old_hashlen, new_hashlen; - error = xfs_init_parent_name_rec(&new_parent->old_rec, old_dp, + old_hashlen = xfs_init_parent_name_rec(&new_parent->old_rec, old_dp, old_name, child); - if (error) - return error; - error = xfs_init_parent_name_rec(&new_parent->rec, new_dp, new_name, - child); - if (error) - return error; + if (old_hashlen < 0) + return old_hashlen; + new_hashlen = xfs_init_parent_name_rec(&new_parent->rec, new_dp, + new_name, child); + if (new_hashlen < 0) + return new_hashlen; new_parent->args.name = (const uint8_t *)&new_parent->old_rec; - new_parent->args.namelen = sizeof(struct xfs_parent_name_rec); + new_parent->args.namelen = xfs_parent_name_rec_sizeof(old_hashlen); new_parent->args.new_name = (const uint8_t *)&new_parent->rec; - new_parent->args.new_namelen = sizeof(struct xfs_parent_name_rec); + new_parent->args.new_namelen = xfs_parent_name_rec_sizeof(new_hashlen); args->trans = tp; args->dp = child; @@ -320,16 +330,17 @@ xfs_parent_lookup( unsigned int namelen, struct xfs_parent_scratch *scr) { + int reclen; int error; - xfs_parent_irec_to_disk(&scr->rec, NULL, NULL, pptr); + xfs_parent_irec_to_disk(&scr->rec, &reclen, NULL, NULL, pptr); memset(&scr->args, 0, sizeof(struct xfs_da_args)); scr->args.attr_filter = XFS_ATTR_PARENT; scr->args.dp = ip; scr->args.geo = ip->i_mount->m_attr_geo; scr->args.name = (const unsigned char *)&scr->rec; - scr->args.namelen = sizeof(struct xfs_parent_name_rec); + scr->args.namelen = reclen; scr->args.op_flags = XFS_DA_OP_OKNOENT; scr->args.trans = tp; scr->args.valuelen = namelen; @@ -357,14 +368,16 @@ xfs_parent_set( const struct xfs_parent_name_irec *pptr, struct xfs_parent_scratch *scr) { - xfs_parent_irec_to_disk(&scr->rec, NULL, NULL, pptr); + int reclen; + + xfs_parent_irec_to_disk(&scr->rec, &reclen, NULL, NULL, pptr); memset(&scr->args, 0, sizeof(struct xfs_da_args)); scr->args.attr_filter = XFS_ATTR_PARENT; scr->args.dp = ip; scr->args.geo = ip->i_mount->m_attr_geo; scr->args.name = (const unsigned char *)&scr->rec; - scr->args.namelen = sizeof(struct xfs_parent_name_rec); + scr->args.namelen = reclen; scr->args.valuelen = pptr->p_namelen; scr->args.value = (void *)pptr->p_name; scr->args.whichfork = XFS_ATTR_FORK; @@ -384,14 +397,16 @@ xfs_parent_unset( const struct xfs_parent_name_irec *pptr, struct xfs_parent_scratch *scr) { - xfs_parent_irec_to_disk(&scr->rec, NULL, NULL, pptr); + int reclen; + + xfs_parent_irec_to_disk(&scr->rec, &reclen, NULL, NULL, pptr); memset(&scr->args, 0, sizeof(struct xfs_da_args)); scr->args.attr_filter = XFS_ATTR_PARENT; scr->args.dp = ip; scr->args.geo = ip->i_mount->m_attr_geo; scr->args.name = (const unsigned char *)&scr->rec; - scr->args.namelen = sizeof(struct xfs_parent_name_rec); + scr->args.namelen = reclen; scr->args.whichfork = XFS_ATTR_FORK; return xfs_attr_set(&scr->args); @@ -399,7 +414,7 @@ xfs_parent_unset( /* * Compute the parent pointer namehash for the given child file and dirent - * name. + * name. Returns the length of the hash in bytes, or a negative errno. */ int xfs_parent_namehash( @@ -420,6 +435,12 @@ xfs_parent_namehash( return -EINVAL; } + if (name->len < namehash_len) { + memcpy(namehash, name->name, name->len); + memset(namehash + name->len, 0, namehash_len - name->len); + return name->len; + } + error = sha512_init(&shash); if (error) goto out; @@ -436,6 +457,7 @@ xfs_parent_namehash( if (error) goto out; + error = SHA512_DIGEST_SIZE; out: sha512_erase(&shash); return error; @@ -451,7 +473,12 @@ xfs_parent_irec_hash( .name = pptr->p_name, .len = pptr->p_namelen, }; + int hashlen; - return xfs_parent_namehash(ip, &xname, &pptr->p_namehash, + hashlen = xfs_parent_namehash(ip, &xname, &pptr->p_namehash, sizeof(pptr->p_namehash)); + if (hashlen < 0) + return hashlen; + pptr->hashlen = hashlen; + return 0; } diff --git a/fs/xfs/libxfs/xfs_parent.h b/fs/xfs/libxfs/xfs_parent.h index d3f2841e0f6e..4c3100760bba 100644 --- a/fs/xfs/libxfs/xfs_parent.h +++ b/fs/xfs/libxfs/xfs_parent.h @@ -23,6 +23,7 @@ struct xfs_parent_name_irec { /* Key fields for looking up a particular parent pointer. */ xfs_ino_t p_ino; uint32_t p_gen; + uint8_t hashlen; uint8_t p_namehash[XFS_PARENT_NAME_HASH_SIZE]; /* Attributes of a parent pointer. */ @@ -31,10 +32,11 @@ struct xfs_parent_name_irec { }; void xfs_parent_irec_from_disk(struct xfs_parent_name_irec *irec, - const struct xfs_parent_name_rec *rec, + const struct xfs_parent_name_rec *rec, int reclen, const void *value, int valuelen); -void xfs_parent_irec_to_disk(struct xfs_parent_name_rec *rec, void *value, - int *valuelen, const struct xfs_parent_name_irec *irec); +void xfs_parent_irec_to_disk(struct xfs_parent_name_rec *rec, int *reclen, + void *value, int *valuelen, + const struct xfs_parent_name_irec *irec); /* * Dynamically allocd structure used to wrap the needed data to pass around diff --git a/fs/xfs/scrub/dir.c b/fs/xfs/scrub/dir.c index 2494947a0c93..87cff40b15f1 100644 --- a/fs/xfs/scrub/dir.c +++ b/fs/xfs/scrub/dir.c @@ -144,15 +144,19 @@ xchk_dir_parent_pointer( { struct xfs_scrub *sc = sd->sc; int pptr_namelen; - int error; + int hashlen; sd->pptr.p_ino = sc->ip->i_ino; sd->pptr.p_gen = VFS_I(sc->ip)->i_generation; - error = xfs_parent_namehash(ip, name, &sd->pptr.p_namehash, + hashlen = xfs_parent_namehash(ip, name, &sd->pptr.p_namehash, sizeof(sd->pptr.p_namehash)); - if (error) - return error; + if (hashlen < 0) { + xchk_fblock_xref_process_error(sc, XFS_DATA_FORK, 0, + &hashlen); + return hashlen; + } + sd->pptr.hashlen = hashlen; pptr_namelen = xfs_parent_lookup(sc->tp, ip, &sd->pptr, sd->namebuf, MAXNAMELEN, &sd->pptr_scratch); diff --git a/fs/xfs/scrub/dir_repair.c b/fs/xfs/scrub/dir_repair.c index c0b2b78da277..b12548787321 100644 --- a/fs/xfs/scrub/dir_repair.c +++ b/fs/xfs/scrub/dir_repair.c @@ -540,7 +540,7 @@ xrep_dir_scan_parent_pointer( !xfs_parent_valuecheck(sc->mp, value, valuelen)) return -EFSCORRUPTED; - xfs_parent_irec_from_disk(&rd->pptr, rec, value, valuelen); + xfs_parent_irec_from_disk(&rd->pptr, rec, namelen, value, valuelen); /* Ignore parent pointers that point back to a different dir. */ if (rd->pptr.p_ino != sc->ip->i_ino || diff --git a/fs/xfs/scrub/parent.c b/fs/xfs/scrub/parent.c index 53872a7be942..b47f0bcef690 100644 --- a/fs/xfs/scrub/parent.c +++ b/fs/xfs/scrub/parent.c @@ -531,6 +531,7 @@ xchk_parent_scan_attr( struct xfs_inode *dp = NULL; const struct xfs_parent_name_rec *rec = (const void *)name; unsigned int lockmode; + int hashlen; int error; /* Ignore incomplete xattrs */ @@ -552,7 +553,7 @@ xchk_parent_scan_attr( return -ECANCELED; } - xfs_parent_irec_from_disk(&pp->pptr, rec, value, valuelen); + xfs_parent_irec_from_disk(&pp->pptr, rec, namelen, value, valuelen); xname.name = pp->pptr.p_name; xname.len = pp->pptr.p_namelen; @@ -561,13 +562,16 @@ xchk_parent_scan_attr( * Does the namehash in the parent pointer match the actual name? * If not, there's no point in checking further. */ - error = xfs_parent_namehash(sc->ip, &xname, pp->child_namehash, + hashlen = xfs_parent_namehash(sc->ip, &xname, pp->child_namehash, sizeof(pp->child_namehash)); - if (!xchk_fblock_xref_process_error(sc, XFS_ATTR_FORK, 0, &error)) - return error; + if (hashlen < 0) { + xchk_fblock_xref_process_error(sc, XFS_ATTR_FORK, 0, &hashlen); + return hashlen; + } - if (memcmp(pp->pptr.p_namehash, pp->child_namehash, - sizeof(pp->pptr.p_namehash))) { + if (hashlen != pp->pptr.hashlen || + memcmp(pp->pptr.p_namehash, pp->child_namehash, + pp->pptr.hashlen)) { trace_xchk_parent_bad_namehash(sc->ip, pp->pptr.p_ino, xname.name, xname.len); xchk_fblock_xref_set_corrupt(sc, XFS_ATTR_FORK, 0); diff --git a/fs/xfs/scrub/parent_repair.c b/fs/xfs/scrub/parent_repair.c index 51432ab61c94..7d3b9c82bd05 100644 --- a/fs/xfs/scrub/parent_repair.c +++ b/fs/xfs/scrub/parent_repair.c @@ -522,7 +522,7 @@ xrep_pptr_dump_tempptr( else return -EFSCORRUPTED; - xfs_parent_irec_from_disk(&rp->pptr, rec, value, valuelen); + xfs_parent_irec_from_disk(&rp->pptr, rec, namelen, value, valuelen); trace_xrep_pptr_dumpname(sc->tempip, &rp->pptr); diff --git a/fs/xfs/xfs_parent_utils.c b/fs/xfs/xfs_parent_utils.c index 65bec3875308..284ca3c14a0f 100644 --- a/fs/xfs/xfs_parent_utils.c +++ b/fs/xfs/xfs_parent_utils.c @@ -74,7 +74,7 @@ xfs_getparent_listent( return; } - xfs_parent_irec_from_disk(&gp->pptr_irec, (void *)name, value, + xfs_parent_irec_from_disk(&gp->pptr_irec, (void *)name, namelen, value, valuelen); trace_xfs_getparent_listent(context->dp, ppi, irec); From patchwork Thu Feb 16 20:52:28 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: 13143854 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 23460C636CC for ; Thu, 16 Feb 2023 20:52:34 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229794AbjBPUwd (ORCPT ); Thu, 16 Feb 2023 15:52:33 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59086 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229793AbjBPUwc (ORCPT ); Thu, 16 Feb 2023 15:52:32 -0500 Received: from ams.source.kernel.org (ams.source.kernel.org [IPv6:2604:1380:4601:e00::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id BFD6E4BEA8 for ; Thu, 16 Feb 2023 12:52:31 -0800 (PST) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ams.source.kernel.org (Postfix) with ESMTPS id 6C6A3B829AB for ; Thu, 16 Feb 2023 20:52:30 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 11D7BC433EF; Thu, 16 Feb 2023 20:52:29 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1676580749; bh=dy8in5Ii1dF36Hd9o97Bz8yHz6Mb9e6xQfCoY9SSjAU=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=TDYqkh1u1iFynM0dYd4r0ob0UtuzrpjSWpSAI7om7DePJiv//vf5Em+/0Aac0DYr2 xYAvm2PkCmvRId1awtoEexhXzyov8TJUyggp2iAmgEwGF7+/++TggV99srmXuWo+Rb QIT2K2iAi9XPZ/IZCgZGcoLIcChMDubxPSJcFFdITIHNzYBJTGZssx7c34ontAPTEu NzHjXa/ftZSrrL7R/PVSj9wKPnpGBW6gMHuEz7QorDHSNHoJk5x0qmVVDCKRl4bhy0 VM2vLH+jRM6KIvnoa9EEFh0DxcygWrjB3TmbnlM9u9VFT+79AV72VvLT0vJnPvQBDH C2R9QGJn3M4fg== Date: Thu, 16 Feb 2023 12:52:28 -0800 Subject: [PATCH 4/5] xfs: make the ondisk parent pointer record a flex array From: "Darrick J. Wong" To: djwong@kernel.org Cc: allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <167657875924.3475422.11827990483807692730.stgit@magnolia> In-Reply-To: <167657875861.3475422.10929602650869169128.stgit@magnolia> References: <167657875861.3475422.10929602650869169128.stgit@magnolia> User-Agent: StGit/0.19 MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-xfs@vger.kernel.org From: Darrick J. Wong Now that we can use the filename as the parent pointer name hash, we always write the full 64 bytes into the xattr. In other words, the namehash is really a flex array, so adjust its C definition. Signed-off-by: Darrick J. Wong --- fs/xfs/libxfs/xfs_da_format.h | 9 ++++++--- fs/xfs/libxfs/xfs_parent.c | 4 ++-- fs/xfs/libxfs/xfs_parent.h | 15 ++++++++++++--- fs/xfs/libxfs/xfs_trans_resv.c | 6 +++--- fs/xfs/xfs_ondisk.h | 2 +- 5 files changed, 24 insertions(+), 12 deletions(-) diff --git a/fs/xfs/libxfs/xfs_da_format.h b/fs/xfs/libxfs/xfs_da_format.h index 275357506394..4d85830785ae 100644 --- a/fs/xfs/libxfs/xfs_da_format.h +++ b/fs/xfs/libxfs/xfs_da_format.h @@ -842,21 +842,24 @@ xfs_failaddr_t xfs_da3_blkinfo_verify(struct xfs_buf *bp, struct xfs_parent_name_rec { __be64 p_ino; __be32 p_gen; - __u8 p_namehash[XFS_PARENT_NAME_HASH_SIZE]; + __u8 p_namehash[]; } __attribute__((packed)); +#define XFS_PARENT_NAME_MAX_SIZE \ + (sizeof(struct xfs_parent_name_rec) + XFS_PARENT_NAME_HASH_SIZE) + static inline unsigned int xfs_parent_name_rec_sizeof( unsigned int hashlen) { - return offsetof(struct xfs_parent_name_rec, p_namehash) + hashlen; + return sizeof(struct xfs_parent_name_rec) + hashlen; } static inline unsigned int xfs_parent_name_hashlen( unsigned int rec_sizeof) { - return rec_sizeof - offsetof(struct xfs_parent_name_rec, p_namehash); + return rec_sizeof - sizeof(struct xfs_parent_name_rec); } #endif /* __XFS_DA_FORMAT_H__ */ diff --git a/fs/xfs/libxfs/xfs_parent.c b/fs/xfs/libxfs/xfs_parent.c index 32235a0e9e0d..6520e35178a0 100644 --- a/fs/xfs/libxfs/xfs_parent.c +++ b/fs/xfs/libxfs/xfs_parent.c @@ -98,7 +98,7 @@ xfs_init_parent_name_rec( rec->p_ino = cpu_to_be64(dp->i_ino); rec->p_gen = cpu_to_be32(VFS_IC(dp)->i_generation); return xfs_parent_namehash(ip, name, rec->p_namehash, - sizeof(rec->p_namehash)); + XFS_PARENT_NAME_HASH_SIZE); } /* @@ -197,7 +197,7 @@ __xfs_parent_init( parent->args.attr_filter = XFS_ATTR_PARENT; parent->args.op_flags = XFS_DA_OP_OKNOENT | XFS_DA_OP_LOGGED; parent->args.name = (const uint8_t *)&parent->rec; - parent->args.namelen = sizeof(struct xfs_parent_name_rec); + parent->args.namelen = 0; *parentp = parent; return 0; diff --git a/fs/xfs/libxfs/xfs_parent.h b/fs/xfs/libxfs/xfs_parent.h index 4c3100760bba..3431aac75e92 100644 --- a/fs/xfs/libxfs/xfs_parent.h +++ b/fs/xfs/libxfs/xfs_parent.h @@ -43,8 +43,14 @@ void xfs_parent_irec_to_disk(struct xfs_parent_name_rec *rec, int *reclen, * the defer ops machinery */ struct xfs_parent_defer { - struct xfs_parent_name_rec rec; - struct xfs_parent_name_rec old_rec; + union { + struct xfs_parent_name_rec rec; + __u8 dummy1[XFS_PARENT_NAME_MAX_SIZE]; + }; + union { + struct xfs_parent_name_rec old_rec; + __u8 dummy2[XFS_PARENT_NAME_MAX_SIZE]; + }; struct xfs_da_args args; bool have_log; }; @@ -112,7 +118,10 @@ unsigned int xfs_pptr_calc_space_res(struct xfs_mount *mp, /* Scratchpad memory so that raw parent operations don't burn stack space. */ struct xfs_parent_scratch { - struct xfs_parent_name_rec rec; + union { + struct xfs_parent_name_rec rec; + __u8 dummy1[XFS_PARENT_NAME_MAX_SIZE]; + }; struct xfs_da_args args; }; diff --git a/fs/xfs/libxfs/xfs_trans_resv.c b/fs/xfs/libxfs/xfs_trans_resv.c index 93419956b9e5..0e625c6b0153 100644 --- a/fs/xfs/libxfs/xfs_trans_resv.c +++ b/fs/xfs/libxfs/xfs_trans_resv.c @@ -427,19 +427,19 @@ static inline unsigned int xfs_calc_pptr_link_overhead(void) { return sizeof(struct xfs_attri_log_format) + xlog_calc_iovec_len(XATTR_NAME_MAX) + - xlog_calc_iovec_len(sizeof(struct xfs_parent_name_rec)); + xlog_calc_iovec_len(XFS_PARENT_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_NAME_MAX_SIZE); } static inline unsigned int xfs_calc_pptr_replace_overhead(void) { return sizeof(struct xfs_attri_log_format) + xlog_calc_iovec_len(XATTR_NAME_MAX) + xlog_calc_iovec_len(XATTR_NAME_MAX) + - xlog_calc_iovec_len(sizeof(struct xfs_parent_name_rec)); + xlog_calc_iovec_len(XFS_PARENT_NAME_MAX_SIZE); } /* diff --git a/fs/xfs/xfs_ondisk.h b/fs/xfs/xfs_ondisk.h index 2dc1eef63d96..24361ae0fd48 100644 --- a/fs/xfs/xfs_ondisk.h +++ b/fs/xfs/xfs_ondisk.h @@ -116,7 +116,7 @@ xfs_check_ondisk_structs(void) XFS_CHECK_OFFSET(xfs_dir2_sf_entry_t, offset, 1); XFS_CHECK_OFFSET(xfs_dir2_sf_entry_t, name, 3); XFS_CHECK_STRUCT_SIZE(xfs_dir2_sf_hdr_t, 10); - XFS_CHECK_STRUCT_SIZE(struct xfs_parent_name_rec, 76); + XFS_CHECK_STRUCT_SIZE(struct xfs_parent_name_rec, 12); BUILD_BUG_ON(XFS_PARENT_NAME_HASH_SIZE != SHA512_DIGEST_SIZE); /* log structures */ From patchwork Thu Feb 16 20:52:44 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: 13143855 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id B537AC61DA4 for ; Thu, 16 Feb 2023 20:52:51 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229633AbjBPUwu (ORCPT ); Thu, 16 Feb 2023 15:52:50 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59224 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229797AbjBPUwu (ORCPT ); Thu, 16 Feb 2023 15:52:50 -0500 Received: from ams.source.kernel.org (ams.source.kernel.org [IPv6:2604:1380:4601:e00::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6F3F64B53D for ; Thu, 16 Feb 2023 12:52:47 -0800 (PST) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ams.source.kernel.org (Postfix) with ESMTPS id 030FBB82962 for ; Thu, 16 Feb 2023 20:52:46 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 97FF5C433D2; Thu, 16 Feb 2023 20:52:44 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1676580764; bh=NY6Z/LF5ttDWJLpQfZDfqpBwKiZKHvqnONySXsGAFxg=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=jEKIm4KacnQg/7YO3efIo/6vbkLGNXiSRLIn2elzW7bPoaEszMre6+PERu3BlDNKD w1+QZ91S5dJ88KqT2l32YkvEvrwEZzzaWKY7qTdGz5Z863a/1wQzXC8czYINt4MyXl 3branEVpnaUUn9PtMLE/qBuXMMy8jLz/TSF5pWyZkltnmgnVIghlDPDahqi6ZLvCJX kpKV890gSv9NBiV22lyVMeHva58ho1Re8RkM8I2HCJgZ6lkpe3rWDRRHkGFV10Foit LuP77X1pNpiy/h5JAPuOn7O2LlioJECVCe/MLZO8YXFYsT6HTUKG74zS89gWB4JE1p eER/D0UEEjXNA== Date: Thu, 16 Feb 2023 12:52:44 -0800 Subject: [PATCH 5/5] xfs: use parent pointer xattr space more efficiently From: "Darrick J. Wong" To: djwong@kernel.org Cc: allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <167657875939.3475422.16922640784869505922.stgit@magnolia> In-Reply-To: <167657875861.3475422.10929602650869169128.stgit@magnolia> References: <167657875861.3475422.10929602650869169128.stgit@magnolia> User-Agent: StGit/0.19 MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-xfs@vger.kernel.org From: Darrick J. Wong Amend the parent pointer xattr format even more. Now we put as much of the dirent name in the namehash as we can. For names that don't fit, the namehash is the truncated dirent name with the sha512 of the entire name at the end of the namehash. The EA value is then truncated to whatever doesn't fit in the namehash. Signed-off-by: Darrick J. Wong --- fs/xfs/libxfs/xfs_da_format.h | 26 +++++++--- fs/xfs/libxfs/xfs_parent.c | 111 ++++++++++++++++++++++++++++++++--------- fs/xfs/libxfs/xfs_parent.h | 6 +- fs/xfs/scrub/dir_repair.c | 2 - fs/xfs/scrub/parent.c | 4 + fs/xfs/xfs_attr_item.c | 4 + fs/xfs/xfs_ondisk.h | 4 + 7 files changed, 118 insertions(+), 39 deletions(-) diff --git a/fs/xfs/libxfs/xfs_da_format.h b/fs/xfs/libxfs/xfs_da_format.h index 4d85830785ae..55f510f82e8d 100644 --- a/fs/xfs/libxfs/xfs_da_format.h +++ b/fs/xfs/libxfs/xfs_da_format.h @@ -825,19 +825,24 @@ xfs_failaddr_t xfs_da3_blkinfo_verify(struct xfs_buf *bp, struct xfs_da3_blkinfo *hdr3); /* We use sha512 for the parent pointer name hash. */ -#define XFS_PARENT_NAME_HASH_SIZE (64) +#define XFS_PARENT_NAME_SHA512_SIZE (64) /* * Parent pointer attribute format definition * * The EA name encodes the parent inode number, generation and a collision - * resistant hash computed from the dirent name. The hash is defined to be: + * resistant hash computed from the dirent name. The hash is defined to be + * one of the following: * - * - The dirent name if it fits within the EA name. + * - The dirent name, as long as it does not use the last possible byte of the + * EA name space. * - * - The sha512 of the child inode generation and the dirent name. + * - The truncated dirent name, with the sha512 hash of the child inode + * generation number and dirent name. The hash is written at the end of the + * EA name. * - * The EA value contains the same name as the dirent in the parent directory. + * The EA value contains however much of the dirent name that does not fit in + * the EA name. */ struct xfs_parent_name_rec { __be64 p_ino; @@ -845,8 +850,17 @@ struct xfs_parent_name_rec { __u8 p_namehash[]; } __attribute__((packed)); +/* Maximum size of a parent pointer EA name. */ #define XFS_PARENT_NAME_MAX_SIZE \ - (sizeof(struct xfs_parent_name_rec) + XFS_PARENT_NAME_HASH_SIZE) + (MAXNAMELEN - 1) + +/* Maximum size of a parent pointer name hash. */ +#define XFS_PARENT_NAME_MAX_HASH_SIZE \ + (XFS_PARENT_NAME_MAX_SIZE - sizeof(struct xfs_parent_name_rec)) + +/* Offset of the sha512 hash, if used. */ +#define XFS_PARENT_NAME_SHA512_OFFSET \ + (XFS_PARENT_NAME_MAX_HASH_SIZE - XFS_PARENT_NAME_SHA512_SIZE) static inline unsigned int xfs_parent_name_rec_sizeof( diff --git a/fs/xfs/libxfs/xfs_parent.c b/fs/xfs/libxfs/xfs_parent.c index 6520e35178a0..f7fecee93894 100644 --- a/fs/xfs/libxfs/xfs_parent.c +++ b/fs/xfs/libxfs/xfs_parent.c @@ -57,7 +57,7 @@ xfs_parent_namecheck( xfs_ino_t p_ino; if (reclen <= xfs_parent_name_rec_sizeof(0) || - reclen > xfs_parent_name_rec_sizeof(XFS_PARENT_NAME_HASH_SIZE)) + reclen > xfs_parent_name_rec_sizeof(XFS_PARENT_NAME_MAX_HASH_SIZE)) return false; /* Only one namespace bit allowed. */ @@ -75,10 +75,18 @@ xfs_parent_namecheck( bool xfs_parent_valuecheck( struct xfs_mount *mp, + size_t namelen, const void *value, size_t valuelen) { - if (valuelen == 0 || valuelen >= MAXNAMELEN) + if (namelen > XFS_PARENT_NAME_MAX_SIZE) + return false; + + if (namelen < XFS_PARENT_NAME_MAX_SIZE && valuelen != 0) + return false; + + if (namelen == XFS_PARENT_NAME_MAX_SIZE && + valuelen >= MAXNAMELEN - XFS_PARENT_NAME_SHA512_OFFSET) return false; if (value == NULL) @@ -98,7 +106,20 @@ xfs_init_parent_name_rec( rec->p_ino = cpu_to_be64(dp->i_ino); rec->p_gen = cpu_to_be32(VFS_IC(dp)->i_generation); return xfs_parent_namehash(ip, name, rec->p_namehash, - XFS_PARENT_NAME_HASH_SIZE); + XFS_PARENT_NAME_MAX_HASH_SIZE); +} + +/* Compute the number of name bytes that can be encoded in the namehash. */ +static inline unsigned int +xfs_parent_valuelen_adj( + int hashlen) +{ + ASSERT(hashlen > 0); + + if (hashlen == XFS_PARENT_NAME_MAX_HASH_SIZE) + return XFS_PARENT_NAME_SHA512_OFFSET; + + return hashlen; } /* @@ -125,14 +146,29 @@ xfs_parent_irec_from_disk( return; } - ASSERT(valuelen > 0); ASSERT(valuelen < MAXNAMELEN); - valuelen = min(valuelen, MAXNAMELEN); + if (irec->hashlen == XFS_PARENT_NAME_MAX_HASH_SIZE) { + ASSERT(valuelen > 0); + ASSERT(valuelen <= MAXNAMELEN - XFS_PARENT_NAME_SHA512_OFFSET); - irec->p_namelen = valuelen; - memcpy(irec->p_name, value, valuelen); - memset(&irec->p_name[valuelen], 0, sizeof(irec->p_name) - valuelen); + valuelen = min_t(int, valuelen, + MAXNAMELEN - XFS_PARENT_NAME_SHA512_OFFSET); + + memcpy(irec->p_name, irec->p_namehash, + XFS_PARENT_NAME_SHA512_OFFSET); + memcpy(&irec->p_name[XFS_PARENT_NAME_SHA512_OFFSET], + value, valuelen); + irec->p_namelen = XFS_PARENT_NAME_SHA512_OFFSET + valuelen; + } else { + ASSERT(valuelen == 0); + + memcpy(irec->p_name, irec->p_namehash, irec->hashlen); + irec->p_namelen = irec->hashlen; + } + + memset(&irec->p_name[irec->p_namelen], 0, + sizeof(irec->p_name) - irec->p_namelen); } /* @@ -157,11 +193,15 @@ xfs_parent_irec_to_disk( ASSERT(*valuelen >= irec->p_namelen); ASSERT(*valuelen < MAXNAMELEN); - *valuelen = irec->p_namelen; + if (irec->hashlen == XFS_PARENT_NAME_MAX_HASH_SIZE) + *valuelen = irec->p_namelen - XFS_PARENT_NAME_SHA512_OFFSET; + else + *valuelen = 0; } - if (value) - memcpy(value, irec->p_name, irec->p_namelen); + if (value && irec->hashlen == XFS_PARENT_NAME_MAX_HASH_SIZE) + memcpy(value, irec->p_name + XFS_PARENT_NAME_SHA512_OFFSET, + irec->p_namelen - XFS_PARENT_NAME_SHA512_OFFSET); } /* @@ -214,6 +254,7 @@ xfs_parent_add( { struct xfs_da_args *args = &parent->args; int hashlen; + unsigned int name_adj; hashlen = xfs_init_parent_name_rec(&parent->rec, dp, parent_name, child); @@ -223,11 +264,13 @@ xfs_parent_add( args->namelen = xfs_parent_name_rec_sizeof(hashlen); args->hashval = xfs_da_hashname(args->name, args->namelen); + name_adj = xfs_parent_valuelen_adj(hashlen); + args->trans = tp; args->dp = child; if (parent_name) { - parent->args.value = (void *)parent_name->name; - parent->args.valuelen = parent_name->len; + parent->args.value = (void *)parent_name->name + name_adj; + parent->args.valuelen = parent_name->len - name_adj; } return xfs_attr_defer_add(args); @@ -269,6 +312,7 @@ xfs_parent_replace( { struct xfs_da_args *args = &new_parent->args; int old_hashlen, new_hashlen; + int new_name_adj; old_hashlen = xfs_init_parent_name_rec(&new_parent->old_rec, old_dp, old_name, child); @@ -279,6 +323,8 @@ xfs_parent_replace( if (new_hashlen < 0) return new_hashlen; + new_name_adj = xfs_parent_valuelen_adj(new_hashlen); + new_parent->args.name = (const uint8_t *)&new_parent->old_rec; new_parent->args.namelen = xfs_parent_name_rec_sizeof(old_hashlen); new_parent->args.new_name = (const uint8_t *)&new_parent->rec; @@ -286,8 +332,8 @@ xfs_parent_replace( args->trans = tp; args->dp = child; - new_parent->args.value = (void *)new_name->name; - new_parent->args.valuelen = new_name->len; + new_parent->args.value = (void *)new_name->name + new_name_adj; + new_parent->args.valuelen = new_name->len - new_name_adj; args->hashval = xfs_da_hashname(args->name, args->namelen); return xfs_attr_defer_replace(args); @@ -331,10 +377,13 @@ xfs_parent_lookup( struct xfs_parent_scratch *scr) { int reclen; + int name_adj; int error; xfs_parent_irec_to_disk(&scr->rec, &reclen, NULL, NULL, pptr); + name_adj = xfs_parent_valuelen_adj(pptr->hashlen); + memset(&scr->args, 0, sizeof(struct xfs_da_args)); scr->args.attr_filter = XFS_ATTR_PARENT; scr->args.dp = ip; @@ -343,8 +392,8 @@ xfs_parent_lookup( scr->args.namelen = reclen; scr->args.op_flags = XFS_DA_OP_OKNOENT; scr->args.trans = tp; - scr->args.valuelen = namelen; - scr->args.value = name; + scr->args.valuelen = namelen - name_adj; + scr->args.value = name + name_adj; scr->args.whichfork = XFS_ATTR_FORK; scr->args.hashval = xfs_da_hashname(scr->args.name, scr->args.namelen); @@ -353,7 +402,8 @@ xfs_parent_lookup( if (error) return error; - return scr->args.valuelen; + memcpy(name, pptr->p_namehash, name_adj); + return scr->args.valuelen + name_adj; } /* @@ -369,17 +419,20 @@ xfs_parent_set( struct xfs_parent_scratch *scr) { int reclen; + int name_adj; xfs_parent_irec_to_disk(&scr->rec, &reclen, NULL, NULL, pptr); + name_adj = xfs_parent_valuelen_adj(pptr->hashlen); + memset(&scr->args, 0, sizeof(struct xfs_da_args)); scr->args.attr_filter = XFS_ATTR_PARENT; scr->args.dp = ip; scr->args.geo = ip->i_mount->m_attr_geo; scr->args.name = (const unsigned char *)&scr->rec; scr->args.namelen = reclen; - scr->args.valuelen = pptr->p_namelen; - scr->args.value = (void *)pptr->p_name; + scr->args.valuelen = pptr->p_namelen - name_adj; + scr->args.value = (void *)pptr->p_name + name_adj; scr->args.whichfork = XFS_ATTR_FORK; return xfs_attr_set(&scr->args); @@ -430,12 +483,16 @@ xfs_parent_namehash( ASSERT(SHA512_DIGEST_SIZE == crypto_shash_digestsize(ip->i_mount->m_sha512)); - if (namehash_len != SHA512_DIGEST_SIZE) { + if (namehash_len != XFS_PARENT_NAME_MAX_HASH_SIZE) { ASSERT(0); return -EINVAL; } - if (name->len < namehash_len) { + if (name->len < XFS_PARENT_NAME_MAX_HASH_SIZE) { + /* + * If the dirent name is shorter than the size of the namehash + * field, write it directly into the namehash field. + */ memcpy(namehash, name->name, name->len); memset(namehash + name->len, 0, namehash_len - name->len); return name->len; @@ -453,11 +510,17 @@ xfs_parent_namehash( if (error) goto out; - error = sha512_done(&shash, namehash); + /* + * The sha512 hash of the child gen and dirent name is placed at the + * end of the namehash, and as many bytes as will fit are copied from + * the dirent name to the start of the namehash. + */ + error = sha512_done(&shash, namehash + XFS_PARENT_NAME_SHA512_OFFSET); if (error) goto out; - error = SHA512_DIGEST_SIZE; + memcpy(namehash, name->name, XFS_PARENT_NAME_SHA512_OFFSET); + error = XFS_PARENT_NAME_MAX_HASH_SIZE; out: sha512_erase(&shash); return error; diff --git a/fs/xfs/libxfs/xfs_parent.h b/fs/xfs/libxfs/xfs_parent.h index 3431aac75e92..6f6136165efe 100644 --- a/fs/xfs/libxfs/xfs_parent.h +++ b/fs/xfs/libxfs/xfs_parent.h @@ -12,8 +12,8 @@ extern struct kmem_cache *xfs_parent_intent_cache; 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_valuecheck(struct xfs_mount *mp, size_t namelen, + const void *value, size_t valuelen); /* * Incore version of a parent pointer, also contains dirent name so callers @@ -24,7 +24,7 @@ struct xfs_parent_name_irec { xfs_ino_t p_ino; uint32_t p_gen; uint8_t hashlen; - uint8_t p_namehash[XFS_PARENT_NAME_HASH_SIZE]; + uint8_t p_namehash[XFS_PARENT_NAME_MAX_HASH_SIZE]; /* Attributes of a parent pointer. */ uint8_t p_namelen; diff --git a/fs/xfs/scrub/dir_repair.c b/fs/xfs/scrub/dir_repair.c index b12548787321..76953575f0b2 100644 --- a/fs/xfs/scrub/dir_repair.c +++ b/fs/xfs/scrub/dir_repair.c @@ -537,7 +537,7 @@ xrep_dir_scan_parent_pointer( /* Does the ondisk parent pointer structure make sense? */ if (!xfs_parent_namecheck(sc->mp, rec, namelen, attr_flags) || - !xfs_parent_valuecheck(sc->mp, value, valuelen)) + !xfs_parent_valuecheck(sc->mp, namelen, value, valuelen)) return -EFSCORRUPTED; xfs_parent_irec_from_disk(&rd->pptr, rec, namelen, value, valuelen); diff --git a/fs/xfs/scrub/parent.c b/fs/xfs/scrub/parent.c index b47f0bcef690..f3b1d7cbe415 100644 --- a/fs/xfs/scrub/parent.c +++ b/fs/xfs/scrub/parent.c @@ -350,7 +350,7 @@ struct xchk_pptrs { struct xfs_parent_scratch pptr_scratch; /* Name hashes */ - uint8_t child_namehash[XFS_PARENT_NAME_HASH_SIZE]; + uint8_t child_namehash[XFS_PARENT_NAME_MAX_HASH_SIZE]; /* Name buffer for revalidation. */ uint8_t namebuf[MAXNAMELEN]; @@ -548,7 +548,7 @@ xchk_parent_scan_attr( return -ECANCELED; } - if (!xfs_parent_valuecheck(sc->mp, value, valuelen)) { + if (!xfs_parent_valuecheck(sc->mp, namelen, value, valuelen)) { xchk_fblock_set_corrupt(sc, XFS_ATTR_FORK, 0); return -ECANCELED; } diff --git a/fs/xfs/xfs_attr_item.c b/fs/xfs/xfs_attr_item.c index da807f286a09..792c01a49749 100644 --- a/fs/xfs/xfs_attr_item.c +++ b/fs/xfs/xfs_attr_item.c @@ -769,7 +769,7 @@ xlog_recover_attri_commit_pass2( switch (op) { case XFS_ATTRI_OP_FLAGS_SET: case XFS_ATTRI_OP_FLAGS_REPLACE: - if (item->ri_total != 3) { + if (item->ri_total != 3 && item->ri_total != 2) { XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, attri_formatp, len); return -EFSCORRUPTED; @@ -783,7 +783,7 @@ xlog_recover_attri_commit_pass2( } break; case XFS_ATTRI_OP_FLAGS_NVREPLACE: - if (item->ri_total != 4) { + if (item->ri_total != 3 && item->ri_total != 4) { XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, attri_formatp, len); return -EFSCORRUPTED; diff --git a/fs/xfs/xfs_ondisk.h b/fs/xfs/xfs_ondisk.h index 24361ae0fd48..5f32dea26221 100644 --- a/fs/xfs/xfs_ondisk.h +++ b/fs/xfs/xfs_ondisk.h @@ -117,7 +117,9 @@ xfs_check_ondisk_structs(void) XFS_CHECK_OFFSET(xfs_dir2_sf_entry_t, name, 3); XFS_CHECK_STRUCT_SIZE(xfs_dir2_sf_hdr_t, 10); XFS_CHECK_STRUCT_SIZE(struct xfs_parent_name_rec, 12); - BUILD_BUG_ON(XFS_PARENT_NAME_HASH_SIZE != SHA512_DIGEST_SIZE); + BUILD_BUG_ON(XFS_PARENT_NAME_MAX_HASH_SIZE < SHA512_DIGEST_SIZE); + BUILD_BUG_ON(XFS_PARENT_NAME_MAX_HASH_SIZE != 243); + BUILD_BUG_ON(XFS_PARENT_NAME_SHA512_OFFSET != 179); /* log structures */ XFS_CHECK_STRUCT_SIZE(struct xfs_buf_log_format, 88);