From patchwork Thu Apr 6 19:31: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: 13203962 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 A6BC9C7618D for ; Thu, 6 Apr 2023 19:31:54 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229792AbjDFTbx (ORCPT ); Thu, 6 Apr 2023 15:31:53 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:60252 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236270AbjDFTbw (ORCPT ); Thu, 6 Apr 2023 15:31:52 -0400 Received: from dfw.source.kernel.org (dfw.source.kernel.org [IPv6:2604:1380:4641:c500::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id BE3094ED2 for ; Thu, 6 Apr 2023 12:31:51 -0700 (PDT) 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 dfw.source.kernel.org (Postfix) with ESMTPS id 5DA4E64B84 for ; Thu, 6 Apr 2023 19:31:51 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id B6DB3C433D2; Thu, 6 Apr 2023 19:31:50 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1680809510; bh=Dcsl0y3nUkmAw/pkVq7LdIFcYsBflNIKtKOQj5pEfQg=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=hCKlqZNx6apLzJXndnSLrWZDe3RnQ5gr0mdbFZKYLkjC+XSWq75iM5ntL74of2GT2 RxTU/iSsCCzO5cPoabL0woNDrTjbD1DRTKcYYuVxfJaS0GNSMwboaIC3nZvx7h05/g 3DcpTa0VBU5MUcBzBHbmfcI2AkH7iDSwg7bCZ55jgmE45MQE+My1xnzswo7rrDH7Jo HxMtURYtKulEBCX5ekZZNP3bExeevSexFasT9AKnGYlNydaD9sv7aBeM+tyRDySyzN EvYsmsJUD1JqHCjGSwtkCEt/UnvUQqsPNckSbGNs4ZtbGnkU+LB2E73zBhpjgWHnkB bWpbTjhohk9yQ== Date: Thu, 06 Apr 2023 12:31:50 -0700 Subject: [PATCH 01/32] xfsprogs: Increase XFS_DEFER_OPS_NR_INODES to 5 From: "Darrick J. Wong" To: djwong@kernel.org Cc: Allison Henderson , Catherine Hoang , allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <168080827571.616793.46028655914667874.stgit@frogsfrogsfrogs> In-Reply-To: <168080827546.616793.7264157843231723676.stgit@frogsfrogsfrogs> References: <168080827546.616793.7264157843231723676.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-xfs@vger.kernel.org From: Allison Henderson Source kernel commit: e9dc6a1e293b7e3843cd3868603801a1af2704c3 Renames that generate parent pointer updates can join up to 5 inodes locked in sorted order. So we need to increase the number of defer ops inodes and relock them in the same way. Signed-off-by: Allison Henderson Reviewed-by: Darrick J. Wong Reviewed-by: Catherine Hoang --- libxfs/libxfs_priv.h | 1 + libxfs/xfs_defer.c | 28 ++++++++++++++++++++++++++-- libxfs/xfs_defer.h | 8 +++++++- 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/libxfs/libxfs_priv.h b/libxfs/libxfs_priv.h index e5f37df28..98966f584 100644 --- a/libxfs/libxfs_priv.h +++ b/libxfs/libxfs_priv.h @@ -478,6 +478,7 @@ void __xfs_buf_mark_corrupt(struct xfs_buf *bp, xfs_failaddr_t fa); __mode = __mode; /* no set-but-unused warning */ \ }) #define xfs_lock_two_inodes(ip0,mode0,ip1,mode1) ((void) 0) +#define xfs_lock_inodes(ips,num_ips,mode) ((void) 0) /* space allocation */ #define XFS_EXTENT_BUSY_DISCARDED 0x01 /* undergoing a discard op. */ diff --git a/libxfs/xfs_defer.c b/libxfs/xfs_defer.c index c4f0269d6..415fcaf56 100644 --- a/libxfs/xfs_defer.c +++ b/libxfs/xfs_defer.c @@ -815,13 +815,37 @@ xfs_defer_ops_continue( struct xfs_trans *tp, struct xfs_defer_resources *dres) { - unsigned int i; + unsigned int i, j; + struct xfs_inode *sips[XFS_DEFER_OPS_NR_INODES]; + struct xfs_inode *temp; ASSERT(tp->t_flags & XFS_TRANS_PERM_LOG_RES); ASSERT(!(tp->t_flags & XFS_TRANS_DIRTY)); /* Lock the captured resources to the new transaction. */ - if (dfc->dfc_held.dr_inos == 2) + if (dfc->dfc_held.dr_inos > 2) { + /* + * Renames with parent pointer updates can lock up to 5 inodes, + * sorted by their inode number. So we need to make sure they + * are relocked in the same way. + */ + memset(sips, 0, sizeof(sips)); + for (i = 0; i < dfc->dfc_held.dr_inos; i++) + sips[i] = dfc->dfc_held.dr_ip[i]; + + /* Bubble sort of at most 5 inodes */ + for (i = 0; i < dfc->dfc_held.dr_inos; i++) { + for (j = 1; j < dfc->dfc_held.dr_inos; j++) { + if (sips[j]->i_ino < sips[j-1]->i_ino) { + temp = sips[j]; + sips[j] = sips[j-1]; + sips[j-1] = temp; + } + } + } + + xfs_lock_inodes(sips, dfc->dfc_held.dr_inos, XFS_ILOCK_EXCL); + } else if (dfc->dfc_held.dr_inos == 2) xfs_lock_two_inodes(dfc->dfc_held.dr_ip[0], XFS_ILOCK_EXCL, dfc->dfc_held.dr_ip[1], XFS_ILOCK_EXCL); else if (dfc->dfc_held.dr_inos == 1) diff --git a/libxfs/xfs_defer.h b/libxfs/xfs_defer.h index 114a3a493..fdf6941f8 100644 --- a/libxfs/xfs_defer.h +++ b/libxfs/xfs_defer.h @@ -70,7 +70,13 @@ extern const struct xfs_defer_op_type xfs_attr_defer_type; /* * Deferred operation item relogging limits. */ -#define XFS_DEFER_OPS_NR_INODES 2 /* join up to two inodes */ + +/* + * Rename w/ parent pointers can require up to 5 inodes with deferred ops to + * be joined to the transaction: src_dp, target_dp, src_ip, target_ip, and wip. + * These inodes are locked in sorted order by their inode numbers + */ +#define XFS_DEFER_OPS_NR_INODES 5 #define XFS_DEFER_OPS_NR_BUFS 2 /* join up to two buffers */ /* Resources that must be held across a transaction roll. */ From patchwork Thu Apr 6 19:32:05 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13203963 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 1C6E9C76196 for ; Thu, 6 Apr 2023 19:32:10 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230032AbjDFTcJ (ORCPT ); Thu, 6 Apr 2023 15:32:09 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:60470 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229564AbjDFTcI (ORCPT ); Thu, 6 Apr 2023 15:32:08 -0400 Received: from dfw.source.kernel.org (dfw.source.kernel.org [IPv6:2604:1380:4641:c500::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5C376C3 for ; Thu, 6 Apr 2023 12:32:07 -0700 (PDT) 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 dfw.source.kernel.org (Postfix) with ESMTPS id EC3F664B8B for ; Thu, 6 Apr 2023 19:32:06 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 4D87BC433D2; Thu, 6 Apr 2023 19:32:06 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1680809526; bh=vrW5gLgeTRDsDjH2YsdcLn8GmMtxeELNRClXyedPn44=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=jt8qwdz96V0WRDgKMKYWVG8CyS29Q3UqfWKxijQyrxjewo39wSX6UsTqyi20IvcPw IgEg08XvjcwtsCBdaK7fuuNtUeGDRNDpUjWxDVRkKZ2ipiQotPsMGDwSsFj3Bc+UZQ uFNzYOG9NVkHOC/eD0bAhwY7uB1W8ki8GQfBdRzv8pO3RemLMqQivZwf76m2+q4occ nApXPjKIW9f8se2v33jQCKwMFzLQI9cKGjBHgRi1p8ASFUGMzfgi/A8NOvjvssxftJ mCvmJyC99+USmXsGwyDCFxjH4FhUq5ixCTHUhIkuRzaiTY3ggg0KbdfbqnXdIvTC95 qAVZ7sGJKb/xw== Date: Thu, 06 Apr 2023 12:32:05 -0700 Subject: [PATCH 02/32] xfs: add parent pointer support to attribute code From: "Darrick J. Wong" To: djwong@kernel.org Cc: Mark Tinguely , Dave Chinner , Allison Henderson , allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <168080827584.616793.16573170066321135662.stgit@frogsfrogsfrogs> In-Reply-To: <168080827546.616793.7264157843231723676.stgit@frogsfrogsfrogs> References: <168080827546.616793.7264157843231723676.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-xfs@vger.kernel.org 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 --- libxfs/xfs_attr.c | 3 ++- libxfs/xfs_da_format.h | 5 ++++- libxfs/xfs_log_format.h | 1 + 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/libxfs/xfs_attr.c b/libxfs/xfs_attr.c index 41d7a56c1..13bc77f7c 100644 --- a/libxfs/xfs_attr.c +++ b/libxfs/xfs_attr.c @@ -990,7 +990,8 @@ xfs_attr_set( struct xfs_inode *dp = args->dp; struct xfs_mount *mp = dp->i_mount; struct xfs_trans_res tres; - bool rsvd = (args->attr_filter & XFS_ATTR_ROOT); + bool rsvd = (args->attr_filter & (XFS_ATTR_ROOT | + XFS_ATTR_PARENT)); bool is_remove = args->op_flags & XFS_DA_OP_REMOVE; int error, local; int rmt_blks = 0; diff --git a/libxfs/xfs_da_format.h b/libxfs/xfs_da_format.h index 25e284108..3dc03968b 100644 --- a/libxfs/xfs_da_format.h +++ b/libxfs/xfs_da_format.h @@ -688,12 +688,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) /* * Alignment for namelist and valuelist entries (since they are mixed diff --git a/libxfs/xfs_log_format.h b/libxfs/xfs_log_format.h index d666bfa5d..5728805a3 100644 --- a/libxfs/xfs_log_format.h +++ b/libxfs/xfs_log_format.h @@ -969,6 +969,7 @@ struct xfs_icreate_log { */ #define XFS_ATTRI_FILTER_MASK (XFS_ATTR_ROOT | \ XFS_ATTR_SECURE | \ + XFS_ATTR_PARENT | \ XFS_ATTR_INCOMPLETE) /* From patchwork Thu Apr 6 19:32:21 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13203964 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 47CC7C7618D for ; Thu, 6 Apr 2023 19:32:25 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229916AbjDFTcY (ORCPT ); Thu, 6 Apr 2023 15:32:24 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:60624 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229564AbjDFTcX (ORCPT ); Thu, 6 Apr 2023 15:32:23 -0400 Received: from dfw.source.kernel.org (dfw.source.kernel.org [IPv6:2604:1380:4641:c500::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id DBC0CC3 for ; Thu, 6 Apr 2023 12:32:22 -0700 (PDT) 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 dfw.source.kernel.org (Postfix) with ESMTPS id 74C8164ADB for ; Thu, 6 Apr 2023 19:32:22 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id D5518C433EF; Thu, 6 Apr 2023 19:32:21 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1680809541; bh=O5beOeXCdbmtSkQDv/CqJrU1S+gXDHEki9Tk4wUiCNk=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=FudPtfBkypK/XJs8q0ggvzehVHCbCbDvmfP7mffeu55hG3mnS+9sHF/xGxJO3OkA6 8Jrbc+NNe3rAgBubluVkwYyeaiAi1qLznusCrB9+JoPPRznthgA7Q7MBspdYrRc8ws YigFpboIv787+6YCAbN5HPFznBEXh7TvLeG+WA9CQnPoNHzFN1Xv0qfYwo+W0Hcxh+ txkTSm5imYWx9+Fv5Sn4CQP8CiFkyje3cKzaNA4KoiJiNLZh6M9tVUhq0bHuv4Z965 YhDfSKiSRGzDpbthbnAjRMUFnAd0tDoB9X1uMC8O7FkFwAFr1vvHmyswUKpnG3pe54 N6nfoyNhEzRPA== Date: Thu, 06 Apr 2023 12:32:21 -0700 Subject: [PATCH 03/32] xfs: define parent pointer ondisk extended attribute format From: "Darrick J. Wong" To: djwong@kernel.org Cc: Dave Chinner , Allison Henderson , allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <168080827597.616793.3716560180702383686.stgit@frogsfrogsfrogs> In-Reply-To: <168080827546.616793.7264157843231723676.stgit@frogsfrogsfrogs> References: <168080827546.616793.7264157843231723676.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-xfs@vger.kernel.org From: Allison Henderson We need to define the parent pointer attribute format before we start adding support for it into all the code that needs to use it. The EA format we will use encodes the following information: name={parent inode #, parent inode generation, dirent namehash} value={dirent name} The inode/gen gives all the information we need to reliably identify the parent without requiring child->parent lock ordering, and allows userspace to do pathname component level reconstruction without the kernel ever needing to verify the parent itself as part of ioctl calls. Storing the dirent name hash in the key reduces hash collisions if a file is hardlinked multiple times in the same directory. By using the NVLOOKUP mode in the extended attribute code to match parent pointers using both the xattr name and value, we can identify the exact parent pointer EA we need to modify/remove in rename/unlink operations without searching the entire EA space. By storing the dirent name, we have enough information to be able to validate and reconstruct damaged directory trees. Earlier iterations of this patchset encoded the directory offset in the parent pointer key, but this format required repair to keep that in sync across directory rebuilds, which is unnecessary complexity. Signed-off-by: Dave Chinner Signed-off-by: Allison Henderson Reviewed-by: Darrick J. Wong [djwong: replace diroffset with the namehash in the pptr key] Signed-off-by: Darrick J. Wong --- libxfs/xfs_da_format.h | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/libxfs/xfs_da_format.h b/libxfs/xfs_da_format.h index 3dc03968b..40016eb08 100644 --- a/libxfs/xfs_da_format.h +++ b/libxfs/xfs_da_format.h @@ -805,4 +805,25 @@ 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 Thu Apr 6 19:32: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: 13203965 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 179AEC7618D for ; Thu, 6 Apr 2023 19:32:41 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229697AbjDFTck (ORCPT ); Thu, 6 Apr 2023 15:32:40 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:60700 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229564AbjDFTcj (ORCPT ); Thu, 6 Apr 2023 15:32:39 -0400 Received: from dfw.source.kernel.org (dfw.source.kernel.org [139.178.84.217]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 763B440DC for ; Thu, 6 Apr 2023 12:32:38 -0700 (PDT) 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 dfw.source.kernel.org (Postfix) with ESMTPS id 1272C617E2 for ; Thu, 6 Apr 2023 19:32:38 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 75075C433EF; Thu, 6 Apr 2023 19:32:37 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1680809557; bh=HPsggvluFEi8fAv0FJlvgrOR4YBI0PulelDCTay81JI=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=BX7SF2LU7dsPpJsErMbjewKIJ96/M6/Xjt+wvSkFVulFKZuiUuPQoVhyiPoSbnBe6 WKSrJkmsMGWoauboZrF2HhbAD//HhGvYi21XpVPaUSvmqYoSjXJ72Rbee1f7pBuPX6 CmalQDtbDRBUaAn6uBMj040xvc7P47YniLTJkY1OZZ5AikQhw0fQjufoD3FCg+na7f +yHqSQ4MJ6RuJh1n1FUhdylQpSVV6hdycNF4dmY7ytDGlkNNeZaBcUUyvzxSbeGXHs G/fN+wwBZrq4ag4FNL3PGFUGLOYv5RPfMrPQ7aPHijt5QEao/cRoo+JewtgY/rH+Wc HcCo1slUIO0cw== Date: Thu, 06 Apr 2023 12:32:37 -0700 Subject: [PATCH 04/32] xfs: add parent pointer validator functions From: "Darrick J. Wong" To: djwong@kernel.org Cc: Allison Henderson , allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <168080827610.616793.3284991197002231123.stgit@frogsfrogsfrogs> In-Reply-To: <168080827546.616793.7264157843231723676.stgit@frogsfrogsfrogs> References: <168080827546.616793.7264157843231723676.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-xfs@vger.kernel.org From: Allison Henderson Attribute names of parent pointers are not strings. So we need to modify attr_namecheck to verify parent pointer records when the XFS_ATTR_PARENT flag is set. At the same time, we need to validate attr values during log recovery if the xattr is really a parent pointer. Signed-off-by: Allison Henderson Reviewed-by: Darrick J. Wong [djwong: move functions to xfs_parent.c, adjust for new disk format] Signed-off-by: Darrick J. Wong --- libxfs/Makefile | 2 + libxfs/xfs_attr.c | 10 ++++- libxfs/xfs_attr.h | 3 +- libxfs/xfs_da_format.h | 8 ++++ libxfs/xfs_parent.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++++ libxfs/xfs_parent.h | 16 ++++++++ repair/attr_repair.c | 19 ++++++---- 7 files changed, 140 insertions(+), 10 deletions(-) create mode 100644 libxfs/xfs_parent.c create mode 100644 libxfs/xfs_parent.h diff --git a/libxfs/Makefile b/libxfs/Makefile index 010ee68e2..89d29dc97 100644 --- a/libxfs/Makefile +++ b/libxfs/Makefile @@ -45,6 +45,7 @@ HFILES = \ xfs_ialloc_btree.h \ xfs_inode_buf.h \ xfs_inode_fork.h \ + xfs_parent.h \ xfs_quota_defs.h \ xfs_refcount.h \ xfs_refcount_btree.h \ @@ -92,6 +93,7 @@ CFILES = cache.c \ xfs_inode_fork.c \ xfs_ialloc_btree.c \ xfs_log_rlimit.c \ + xfs_parent.c \ xfs_refcount.c \ xfs_refcount_btree.c \ xfs_rmap.c \ diff --git a/libxfs/xfs_attr.c b/libxfs/xfs_attr.c index 13bc77f7c..809c285d4 100644 --- a/libxfs/xfs_attr.c +++ b/libxfs/xfs_attr.c @@ -24,6 +24,7 @@ #include "xfs_quota_defs.h" #include "xfs_trans_space.h" #include "xfs_trace.h" +#include "xfs_parent.h" struct kmem_cache *xfs_attr_intent_cache; @@ -1594,9 +1595,14 @@ xfs_attr_node_get( /* Returns true if the attribute entry name is valid. */ bool xfs_attr_namecheck( - const void *name, - size_t length) + struct xfs_mount *mp, + const void *name, + size_t length, + unsigned int flags) { + if (flags & XFS_ATTR_PARENT) + return xfs_parent_namecheck(mp, name, length, flags); + /* * MAXNAMELEN includes the trailing null, but (name/length) leave it * out, so use >= for the length check. diff --git a/libxfs/xfs_attr.h b/libxfs/xfs_attr.h index d543a6a01..13b65aaf3 100644 --- a/libxfs/xfs_attr.h +++ b/libxfs/xfs_attr.h @@ -552,7 +552,8 @@ int xfs_attr_get(struct xfs_da_args *args); int xfs_attr_set(struct xfs_da_args *args); int xfs_attr_set_iter(struct xfs_attr_intent *attr); int xfs_attr_remove_iter(struct xfs_attr_intent *attr); -bool xfs_attr_namecheck(const void *name, size_t length); +bool xfs_attr_namecheck(struct xfs_mount *mp, const void *name, size_t length, + unsigned int flags); int xfs_attr_calc_size(struct xfs_da_args *args, int *local); void xfs_init_attr_trans(struct xfs_da_args *args, struct xfs_trans_res *tres, unsigned int *total); diff --git a/libxfs/xfs_da_format.h b/libxfs/xfs_da_format.h index 40016eb08..7426f9052 100644 --- a/libxfs/xfs_da_format.h +++ b/libxfs/xfs_da_format.h @@ -731,6 +731,14 @@ xfs_attr3_leaf_name(xfs_attr_leafblock_t *leafp, int idx) return &((char *)leafp)[be16_to_cpu(entries[idx].nameidx)]; } +static inline int +xfs_attr3_leaf_flags(xfs_attr_leafblock_t *leafp, int idx) +{ + struct xfs_attr_leaf_entry *entries = xfs_attr3_leaf_entryp(leafp); + + return entries[idx].flags; +} + static inline xfs_attr_leaf_name_remote_t * xfs_attr3_leaf_name_remote(xfs_attr_leafblock_t *leafp, int idx) { diff --git a/libxfs/xfs_parent.c b/libxfs/xfs_parent.c new file mode 100644 index 000000000..583607c13 --- /dev/null +++ b/libxfs/xfs_parent.c @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2022-2023 Oracle, Inc. + * All rights reserved. + */ +#include "libxfs_priv.h" +#include "xfs_shared.h" +#include "xfs_format.h" +#include "xfs_log_format.h" +#include "xfs_trans_resv.h" +#include "xfs_mount.h" +#include "xfs_inode.h" +#include "xfs_trans_resv.h" +#include "xfs_mount.h" +#include "xfs_trace.h" +#include "xfs.h" +#include "xfs_fs.h" +#include "xfs_da_format.h" +#include "xfs_bmap_btree.h" +#include "xfs_trans.h" +#include "xfs_da_btree.h" +#include "xfs_attr.h" +#include "xfs_dir2.h" +#include "xfs_attr_sf.h" +#include "xfs_bmap.h" +#include "xfs_parent.h" +#include "xfs_da_format.h" +#include "xfs_format.h" +#include "xfs_trans_space.h" + +/* + * Parent pointer attribute handling. + * + * Because the attribute value is a filename component, it will never be longer + * than 255 bytes. This means the attribute will always be a local format + * attribute as it is xfs_attr_leaf_entsize_local_max() for v5 filesystems will + * always be larger than this (max is 75% of block size). + * + * Creating a new parent attribute will always create a new attribute - there + * should never, ever be an existing attribute in the tree for a new inode. + * ENOSPC behavior is problematic - creating the inode without the parent + * pointer is effectively a corruption, so we allow parent attribute creation + * to dip into the reserve block pool to avoid unexpected ENOSPC errors from + * occurring. + */ + +/* Return true if parent pointer EA name is valid. */ +bool +xfs_parent_namecheck( + struct xfs_mount *mp, + const struct xfs_parent_name_rec *rec, + size_t reclen, + unsigned int attr_flags) +{ + xfs_ino_t p_ino; + + if (!(attr_flags & XFS_ATTR_PARENT)) + 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; + + p_ino = be64_to_cpu(rec->p_ino); + if (!xfs_verify_ino(mp, p_ino)) + 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; + + /* Valid dirent name? */ + if (!xfs_dir2_namecheck(value, valuelen)) + return false; + + return true; +} diff --git a/libxfs/xfs_parent.h b/libxfs/xfs_parent.h new file mode 100644 index 000000000..6e2a2528d --- /dev/null +++ b/libxfs/xfs_parent.h @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2022-2023 Oracle, Inc. + * 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); + +#endif /* __XFS_PARENT_H__ */ diff --git a/repair/attr_repair.c b/repair/attr_repair.c index c3a6d5026..afe8073ca 100644 --- a/repair/attr_repair.c +++ b/repair/attr_repair.c @@ -293,8 +293,9 @@ process_shortform_attr( } /* namecheck checks for null chars in attr names. */ - if (!libxfs_attr_namecheck(currententry->nameval, - currententry->namelen)) { + if (!libxfs_attr_namecheck(mp, currententry->nameval, + currententry->namelen, + currententry->flags)) { do_warn( _("entry contains illegal character in shortform attribute name\n")); junkit = 1; @@ -454,12 +455,14 @@ process_leaf_attr_local( xfs_dablk_t da_bno, xfs_ino_t ino) { - xfs_attr_leaf_name_local_t *local; + xfs_attr_leaf_name_local_t *local; + int flags; local = xfs_attr3_leaf_name_local(leaf, i); + flags = xfs_attr3_leaf_flags(leaf, i); if (local->namelen == 0 || - !libxfs_attr_namecheck(local->nameval, - local->namelen)) { + !libxfs_attr_namecheck(mp, local->nameval, + local->namelen, flags)) { do_warn( _("attribute entry %d in attr block %u, inode %" PRIu64 " has bad name (namelen = %d)\n"), i, da_bno, ino, local->namelen); @@ -510,12 +513,14 @@ process_leaf_attr_remote( { xfs_attr_leaf_name_remote_t *remotep; char* value; + int flags; remotep = xfs_attr3_leaf_name_remote(leaf, i); + flags = xfs_attr3_leaf_flags(leaf, i); if (remotep->namelen == 0 || - !libxfs_attr_namecheck(remotep->name, - remotep->namelen) || + !libxfs_attr_namecheck(mp, remotep->name, + remotep->namelen, flags) || be32_to_cpu(entry->hashval) != libxfs_da_hashname((unsigned char *)&remotep->name[0], remotep->namelen) || From patchwork Thu Apr 6 19:32:52 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13203966 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 0CDBEC7618D for ; Thu, 6 Apr 2023 19:32:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229741AbjDFTc5 (ORCPT ); Thu, 6 Apr 2023 15:32:57 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:60756 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229564AbjDFTc4 (ORCPT ); Thu, 6 Apr 2023 15:32:56 -0400 Received: from dfw.source.kernel.org (dfw.source.kernel.org [IPv6:2604:1380:4641:c500::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1DCCBC3 for ; Thu, 6 Apr 2023 12:32:54 -0700 (PDT) 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 dfw.source.kernel.org (Postfix) with ESMTPS id 9D28260EFE for ; Thu, 6 Apr 2023 19:32:53 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 07039C433EF; Thu, 6 Apr 2023 19:32:53 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1680809573; bh=5XTb5nQH234SvOm3NHS2rzV0lSmqAYQarf7AGkeOk8Q=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=PEHeJkqtWe6UncBsYMbjPr3b9kpCor/4kVK6dOrhYO0LRmTeFuVkGYJwPWb7KviK4 NPrEc0KO3Oi5hYlYtRZsLnOo1ijaBrJznDNFw8hdZwZb3Pmyj0bPg4LtBhZwOuh7wm qfuHMl+9acueikH0HUaPtnwrQiANa2/+S/fE1DalVu9pUT5F4w1j7EO27n4iwy/4Ml 5GtffZIwaQA7jlW/nlMtW/Lhp3jGo+NxolxwhpFydegteVUwJnhqL1KWkBHdX0qdlk wpxi5N4QhVQsKQUv1bxeyUUs0eRNdNW5Livs8sg09cR9PojEZgPQOuUcj7W57wMLev kFr64qjsccAVA== Date: Thu, 06 Apr 2023 12:32:52 -0700 Subject: [PATCH 05/32] xfs: extend transaction reservations for parent attributes From: "Darrick J. Wong" To: djwong@kernel.org Cc: Dave Chinner , Allison Henderson , allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <168080827623.616793.11046251915219134205.stgit@frogsfrogsfrogs> In-Reply-To: <168080827546.616793.7264157843231723676.stgit@frogsfrogsfrogs> References: <168080827546.616793.7264157843231723676.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-xfs@vger.kernel.org From: Allison Henderson We need to add, remove or modify parent pointer attributes during create/link/unlink/rename operations atomically with the dirents in the parent directories being modified. This means they need to be modified in the same transaction as the parent directories, and so we need to add the required space for the attribute modifications to the transaction reservations. Signed-off-by: Dave Chinner Signed-off-by: Allison Henderson Reviewed-by: Darrick J. Wong [djwong: fix indenting errors, adjust for new log format] Signed-off-by: Darrick J. Wong --- libxfs/libxfs_priv.h | 1 libxfs/xfs_trans_resv.c | 324 +++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 273 insertions(+), 52 deletions(-) diff --git a/libxfs/libxfs_priv.h b/libxfs/libxfs_priv.h index 98966f584..db6c40131 100644 --- a/libxfs/libxfs_priv.h +++ b/libxfs/libxfs_priv.h @@ -523,6 +523,7 @@ static inline int retzero(void) { return 0; } #define xfs_icreate_log(tp, agno, agbno, cnt, isize, len, gen) ((void) 0) #define xfs_sb_validate_fsb_count(sbp, nblks) (0) +#define xlog_calc_iovec_len(len) roundup(len, sizeof(uint32_t)) /* * Prototypes for kernel static functions that are aren't in their diff --git a/libxfs/xfs_trans_resv.c b/libxfs/xfs_trans_resv.c index 04c444806..b555d455f 100644 --- a/libxfs/xfs_trans_resv.c +++ b/libxfs/xfs_trans_resv.c @@ -18,6 +18,7 @@ #include "xfs_trans.h" #include "xfs_trans_space.h" #include "xfs_quota_defs.h" +#include "xfs_da_format.h" #define _ALLOC true #define _FREE false @@ -419,29 +420,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; } /* @@ -458,6 +540,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 @@ -474,14 +573,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); } /* @@ -496,6 +604,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 @@ -512,14 +637,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); } /* @@ -568,12 +703,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 @@ -586,6 +749,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. */ @@ -596,6 +776,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 @@ -908,6 +1104,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, @@ -927,35 +1169,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; @@ -985,6 +1203,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 Thu Apr 6 19:33: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: 13203967 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 E96B1C76196 for ; Thu, 6 Apr 2023 19:33:15 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236405AbjDFTdP (ORCPT ); Thu, 6 Apr 2023 15:33:15 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:33118 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236539AbjDFTdM (ORCPT ); Thu, 6 Apr 2023 15:33:12 -0400 Received: from dfw.source.kernel.org (dfw.source.kernel.org [139.178.84.217]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B09607EFA for ; Thu, 6 Apr 2023 12:33:09 -0700 (PDT) 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 dfw.source.kernel.org (Postfix) with ESMTPS id 3310364B8F for ; Thu, 6 Apr 2023 19:33:09 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 9A585C433D2; Thu, 6 Apr 2023 19:33:08 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1680809588; bh=EYu0sEln4WjV99vC2pd2B0JekyTXENU71wVbzvNQCO8=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=gCiHSDxdBvMIc9o58Rw4d08rpRD85hJDVwx6+/2cr3aq2G8Wt4LQsgWiu9gpLqkwK rr+LMO3zi/dwpJ2WyEmM2z4QKKgI9Nig/842zLTm1xe5LlCx+Mho/yYSIZcKI/WnYW Gk+y5xAA4t9s4DcFnWuKSzsycAle+Cw8Uby22a4MubIwgaiOf7vcD1m9r7cj5lKO6V Qh42aUD0Sirm+Nid82t2Dc7k7zFOAnz//W3gA2JDfP5RSnXIoqLtdPfYYZ3QJCYbnh CZYd1ckM0vhCOHhNHvQw0kaejobo/lYJkmUpheirOOyQYE319fI6k2lizY6LDgEi0F l1BQCtBRl0v7Q== Date: Thu, 06 Apr 2023 12:33:08 -0700 Subject: [PATCH 06/32] xfs: parent pointer attribute creation From: "Darrick J. Wong" To: djwong@kernel.org Cc: Dave Chinner , Allison Henderson , allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <168080827636.616793.4228168136077769272.stgit@frogsfrogsfrogs> In-Reply-To: <168080827546.616793.7264157843231723676.stgit@frogsfrogsfrogs> References: <168080827546.616793.7264157843231723676.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-xfs@vger.kernel.org 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] Signed-off-by: Darrick J. Wong --- include/libxfs.h | 1 include/xfs_inode.h | 6 +++ libxfs/init.c | 3 + libxfs/libxfs_priv.h | 3 + libxfs/xfs_attr.c | 4 +- libxfs/xfs_attr.h | 4 +- libxfs/xfs_parent.c | 116 ++++++++++++++++++++++++++++++++++++++++++++++++++ libxfs/xfs_parent.h | 44 +++++++++++++++++++ 8 files changed, 176 insertions(+), 5 deletions(-) diff --git a/include/libxfs.h b/include/libxfs.h index b28781d19..cc57e8887 100644 --- a/include/libxfs.h +++ b/include/libxfs.h @@ -78,6 +78,7 @@ struct iomap; #include "xfs_refcount_btree.h" #include "xfs_refcount.h" #include "xfs_btree_staging.h" +#include "xfs_parent.h" #ifndef ARRAY_SIZE #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) diff --git a/include/xfs_inode.h b/include/xfs_inode.h index b0bba1094..74de05191 100644 --- a/include/xfs_inode.h +++ b/include/xfs_inode.h @@ -175,6 +175,12 @@ static inline struct inode *VFS_I(struct xfs_inode *ip) return &ip->i_vnode; } +/* convert from const xfs inode to const vfs inode */ +static inline const struct inode *VFS_IC(const struct xfs_inode *ip) +{ + return &ip->i_vnode; +} + /* We only have i_size in the xfs inode in userspace */ static inline loff_t i_size_read(struct inode *inode) { diff --git a/libxfs/init.c b/libxfs/init.c index fda36ba0f..59cd547d6 100644 --- a/libxfs/init.c +++ b/libxfs/init.c @@ -258,6 +258,8 @@ init_caches(void) "xfs_extfree_item"); xfs_trans_cache = kmem_cache_init( sizeof(struct xfs_trans), "xfs_trans"); + xfs_parent_intent_cache = kmem_cache_init( + sizeof(struct xfs_parent_defer), "xfs_parent_defer"); } static int @@ -275,6 +277,7 @@ destroy_caches(void) xfs_btree_destroy_cur_caches(); leaked += kmem_cache_destroy(xfs_extfree_item_cache); leaked += kmem_cache_destroy(xfs_trans_cache); + leaked += kmem_cache_destroy(xfs_parent_intent_cache); return leaked; } diff --git a/libxfs/libxfs_priv.h b/libxfs/libxfs_priv.h index db6c40131..ff027dbe3 100644 --- a/libxfs/libxfs_priv.h +++ b/libxfs/libxfs_priv.h @@ -616,7 +616,8 @@ int libxfs_zero_extent(struct xfs_inode *ip, xfs_fsblock_t start_fsb, /* xfs_log.c */ bool xfs_log_check_lsn(struct xfs_mount *, xfs_lsn_t); void xfs_log_item_init(struct xfs_mount *, struct xfs_log_item *, int); -#define xfs_attr_use_log_assist(mp) (0) +#define xfs_attr_grab_log_assist(mp) (0) +#define xfs_attr_rele_log_assist(mp) ((void) 0) #define xlog_drop_incompat_feat(log) do { } while (0) #define xfs_log_in_recovery(mp) (false) diff --git a/libxfs/xfs_attr.c b/libxfs/xfs_attr.c index 809c285d4..4e1d9551a 100644 --- a/libxfs/xfs_attr.c +++ b/libxfs/xfs_attr.c @@ -893,7 +893,7 @@ xfs_attr_lookup( return error; } -static int +int xfs_attr_intent_init( struct xfs_da_args *args, unsigned int op_flags, /* op flag (set or remove) */ @@ -911,7 +911,7 @@ xfs_attr_intent_init( } /* Sets an attribute for an inode as a deferred operation */ -static int +int xfs_attr_defer_add( struct xfs_da_args *args) { diff --git a/libxfs/xfs_attr.h b/libxfs/xfs_attr.h index 13b65aaf3..1002e431b 100644 --- a/libxfs/xfs_attr.h +++ b/libxfs/xfs_attr.h @@ -549,6 +549,7 @@ int xfs_inode_hasattr(struct xfs_inode *ip); bool xfs_attr_is_leaf(struct xfs_inode *ip); int xfs_attr_get_ilocked(struct xfs_da_args *args); int xfs_attr_get(struct xfs_da_args *args); +int xfs_attr_defer_add(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); @@ -557,7 +558,8 @@ 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); - +int xfs_attr_intent_init(struct xfs_da_args *args, unsigned int op_flags, + struct xfs_attr_intent **attr); /* * Check to see if the attr should be upgraded from non-existent or shortform to * single-leaf-block attribute list. diff --git a/libxfs/xfs_parent.c b/libxfs/xfs_parent.c index 583607c13..ca1c6eeaf 100644 --- a/libxfs/xfs_parent.c +++ b/libxfs/xfs_parent.c @@ -21,6 +21,7 @@ #include "xfs_da_btree.h" #include "xfs_attr.h" #include "xfs_dir2.h" +#include "xfs_dir2_priv.h" #include "xfs_attr_sf.h" #include "xfs_bmap.h" #include "xfs_parent.h" @@ -28,6 +29,8 @@ #include "xfs_format.h" #include "xfs_trans_space.h" +struct kmem_cache *xfs_parent_intent_cache; + /* * Parent pointer attribute handling. * @@ -90,3 +93,116 @@ xfs_parent_valuecheck( return true; } + +/* 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_init( + struct xfs_mount *mp, + struct xfs_parent_defer **parentp) +{ + struct xfs_parent_defer *parent; + int error; + + error = xfs_attr_grab_log_assist(mp); + if (error) + return error; + + parent = kmem_cache_zalloc(xfs_parent_intent_cache, GFP_KERNEL); + if (!parent) { + xfs_attr_rele_log_assist(mp); + return -ENOMEM; + } + + /* init parent da_args */ + parent->args.geo = mp->m_attr_geo; + parent->args.whichfork = XFS_ATTR_FORK; + parent->args.attr_filter = XFS_ATTR_PARENT; + parent->args.op_flags = XFS_DA_OP_OKNOENT | XFS_DA_OP_LOGGED | + XFS_DA_OP_NVLOOKUP; + parent->args.name = (const uint8_t *)&parent->rec; + parent->args.namelen = sizeof(struct xfs_parent_name_rec); + + *parentp = parent; + return 0; +} + +static inline xfs_dahash_t +xfs_parent_hashname( + struct xfs_inode *ip, + const struct xfs_parent_defer *parent) +{ + return xfs_da_hashname((const void *)&parent->rec, + sizeof(struct xfs_parent_name_rec)); +} + +/* Add a parent pointer to reflect a dirent addition. */ +int +xfs_parent_add( + struct xfs_trans *tp, + struct xfs_parent_defer *parent, + struct xfs_inode *dp, + const struct xfs_name *parent_name, + struct xfs_inode *child) +{ + struct xfs_da_args *args = &parent->args; + + xfs_init_parent_name_rec(&parent->rec, dp, parent_name, child); + args->hashval = xfs_parent_hashname(dp, parent); + + args->trans = tp; + args->dp = child; + + xfs_init_parent_davalue(&parent->args, parent_name); + + return xfs_attr_defer_add(args); +} + +/* Cancel a parent pointer operation. */ +void +__xfs_parent_cancel( + struct xfs_mount *mp, + struct xfs_parent_defer *parent) +{ + xlog_drop_incompat_feat(mp->m_log); + kmem_cache_free(xfs_parent_intent_cache, parent); +} + +/* 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); +} diff --git a/libxfs/xfs_parent.h b/libxfs/xfs_parent.h index 6e2a2528d..8e7dbe22e 100644 --- a/libxfs/xfs_parent.h +++ b/libxfs/xfs_parent.h @@ -13,4 +13,46 @@ bool xfs_parent_namecheck(struct xfs_mount *mp, bool xfs_parent_valuecheck(struct xfs_mount *mp, const void *value, size_t valuelen); -#endif /* __XFS_PARENT_H__ */ +extern struct kmem_cache *xfs_parent_intent_cache; + +/* + * Dynamically allocd structure used to wrap the needed data to pass around + * the defer ops machinery + */ +struct xfs_parent_defer { + struct xfs_parent_name_rec rec; + struct xfs_da_args args; +}; + +int __xfs_parent_init(struct xfs_mount *mp, struct xfs_parent_defer **parentp); + +static inline int +xfs_parent_start( + struct xfs_mount *mp, + struct xfs_parent_defer **pp) +{ + *pp = NULL; + + if (xfs_has_parent(mp)) + return __xfs_parent_init(mp, pp); + return 0; +} + +int xfs_parent_add(struct xfs_trans *tp, struct xfs_parent_defer *parent, + struct xfs_inode *dp, const struct xfs_name *parent_name, + struct xfs_inode *child); +void __xfs_parent_cancel(struct xfs_mount *mp, struct xfs_parent_defer *parent); + +static inline void +xfs_parent_finish( + struct xfs_mount *mp, + struct xfs_parent_defer *p) +{ + if (p) + __xfs_parent_cancel(mp, p); +} + +unsigned int xfs_parent_calc_space_res(struct xfs_mount *mp, + unsigned int namelen); + +#endif /* __XFS_PARENT_H__ */ From patchwork Thu Apr 6 19:33:23 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: 13203968 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 A2A7FC76196 for ; Thu, 6 Apr 2023 19:33:33 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236627AbjDFTdc (ORCPT ); Thu, 6 Apr 2023 15:33:32 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:33430 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236500AbjDFTd0 (ORCPT ); Thu, 6 Apr 2023 15:33:26 -0400 Received: from dfw.source.kernel.org (dfw.source.kernel.org [IPv6:2604:1380:4641:c500::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 32A03E72 for ; Thu, 6 Apr 2023 12:33:25 -0700 (PDT) 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 dfw.source.kernel.org (Postfix) with ESMTPS id C337264902 for ; Thu, 6 Apr 2023 19:33:24 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 28673C433D2; Thu, 6 Apr 2023 19:33:24 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1680809604; bh=QsC+7QAXjp9I1zOzX/qu4XxD0xBCS5dUnYR+Zjby2jI=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=VWXRK9RccxWhrhh0JMoNgzk1fDiI2OQupmeb4WNYhOxQubjCAQ2nUld03F6q0CANF xV/iDxO/uNBJgEaapiQxuEd3lgh54X35JapX9a4INoDqmZBlroeNEDS8/1NCkHLynD J/67PEluTtSoTopYibSmgKojq61/I82CojXzPU7xq5AmAofjgJSpzXuPsqtoIMe1rX zwbHOErfvdi8yPHyT6PMZ1UN19smHyYJSdm5E7KSKF2IjsMhZHFXXjO8Z39KVGe04k JpIA22IhwkmcTxjEIa76J7XvuTouf1iahzRDLnl+6wvGFE4CNqRKWd6vQ+xIrpZeqn +RNWKNmR7Qb0Q== Date: Thu, 06 Apr 2023 12:33:23 -0700 Subject: [PATCH 07/32] xfs: add parent attributes to link From: "Darrick J. Wong" To: djwong@kernel.org Cc: Dave Chinner , Allison Henderson , allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <168080827650.616793.2845706168484202535.stgit@frogsfrogsfrogs> In-Reply-To: <168080827546.616793.7264157843231723676.stgit@frogsfrogsfrogs> References: <168080827546.616793.7264157843231723676.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-xfs@vger.kernel.org From: Allison Henderson This patch modifies xfs_link to add a parent pointer to the inode. Signed-off-by: Dave Chinner Signed-off-by: Allison Henderson Reviewed-by: Darrick J. Wong [djwong: minor rebase fixes] Signed-off-by: Darrick J. Wong --- libxfs/xfs_trans_space.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/libxfs/xfs_trans_space.h b/libxfs/xfs_trans_space.h index 87b31c69a..f72207923 100644 --- a/libxfs/xfs_trans_space.h +++ b/libxfs/xfs_trans_space.h @@ -84,8 +84,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_MKDIR_SPACE_RES(mp,nl) \ (XFS_IALLOC_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp,nl)) #define XFS_QM_DQALLOC_SPACE_RES(mp) \ From patchwork Thu Apr 6 19:33:39 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13203969 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 E9DC5C76196 for ; Thu, 6 Apr 2023 19:33:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229738AbjDFTdn (ORCPT ); Thu, 6 Apr 2023 15:33:43 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:33848 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236525AbjDFTdl (ORCPT ); Thu, 6 Apr 2023 15:33:41 -0400 Received: from dfw.source.kernel.org (dfw.source.kernel.org [139.178.84.217]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C8EC25243 for ; Thu, 6 Apr 2023 12:33:40 -0700 (PDT) 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 dfw.source.kernel.org (Postfix) with ESMTPS id 5AEB764876 for ; Thu, 6 Apr 2023 19:33:40 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id BD6ACC433EF; Thu, 6 Apr 2023 19:33:39 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1680809619; bh=zoQF0MRGrDL2xaetCDGYObIdzb+J7m0HWIp+HxALtnM=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=FWKix8Xcpk3vD8jlWZkc7GG2DapxTimyKOfOP/Zkq1zJg+AZFhUFbLFt0tbKeU5m3 CjUh1lLWdp9Edwc3GDBgkj8NCgZpjct7omZrGCkTO9ZzLGyQvNNhaxk63NRIgDeLxL EleXhrBN/guIQtuHsR7YZw5B0EUsWxvp+4yKmqa8ZvtB19QEM9Hbq6wqdcGKaHkrvp JSPCNbCss3XwO1HWZkvv9T6t7M5i03bbvqYIkJC6IKcQOMm5QuvF4VDRCCHVuOp7L8 lmIbvZaQn8SkAzxuIxESw3dY/7jNl16Nmd93HygeBDWladdyLrFOc42gH6n7H72CF9 /LLwl1PSlPX4g== Date: Thu, 06 Apr 2023 12:33:39 -0700 Subject: [PATCH 08/32] xfs: add parent attributes to symlink From: "Darrick J. Wong" To: djwong@kernel.org Cc: Allison Henderson , allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <168080827663.616793.2072925585458839551.stgit@frogsfrogsfrogs> In-Reply-To: <168080827546.616793.7264157843231723676.stgit@frogsfrogsfrogs> References: <168080827546.616793.7264157843231723676.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-xfs@vger.kernel.org From: Allison Henderson This patch modifies xfs_symlink to add a parent pointer to the inode. Signed-off-by: Allison Henderson Reviewed-by: Darrick J. Wong [djwong: minor rebase fixups] Signed-off-by: Darrick J. Wong --- libxfs/xfs_trans_space.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/libxfs/xfs_trans_space.h b/libxfs/xfs_trans_space.h index f72207923..25a55650b 100644 --- a/libxfs/xfs_trans_space.h +++ b/libxfs/xfs_trans_space.h @@ -95,8 +95,6 @@ XFS_DIRREMOVE_SPACE_RES(mp) #define XFS_RENAME_SPACE_RES(mp,nl) \ (XFS_DIRREMOVE_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp,nl)) -#define XFS_SYMLINK_SPACE_RES(mp,nl,b) \ - (XFS_IALLOC_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp,nl) + (b)) #define XFS_IFREE_SPACE_RES(mp) \ (xfs_has_finobt(mp) ? M_IGEO(mp)->inobt_maxlevels : 0) From patchwork Thu Apr 6 19:33:54 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: 13203970 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 58C34C76196 for ; Thu, 6 Apr 2023 19:34:12 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236663AbjDFTeL (ORCPT ); Thu, 6 Apr 2023 15:34:11 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34690 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236891AbjDFTeF (ORCPT ); Thu, 6 Apr 2023 15:34:05 -0400 Received: from dfw.source.kernel.org (dfw.source.kernel.org [IPv6:2604:1380:4641:c500::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 54D14A255 for ; Thu, 6 Apr 2023 12:33:56 -0700 (PDT) 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 dfw.source.kernel.org (Postfix) with ESMTPS id DEDAF64B94 for ; Thu, 6 Apr 2023 19:33:55 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 4B884C433EF; Thu, 6 Apr 2023 19:33:55 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1680809635; bh=zmkt8BmpGiySKsl6QNYor76882oCPuY6bByTMOFOVKI=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=B8VdW4cPymIGhDf4fJ48h9E+tOh2URWp/3emjGeyku5jpD7HTgEGdSYl/xup7dmWc aQEmWIhUvAvVXkJJGGFK9u7GTCJxNX8ytHbJc+p2PN0lOSThMS5lXNDxhzXxrPpm7G M2twdiymG21x2tqBpGZt9tZQLPKAw5ZcngHSd+2zNp/ViVkNnkCA66PWDKMZLQKM/L g1bUBQNiq2OSJXrlTZpl1SYMlU9Uoav9A5BR2Ho9WCM7HilaxYx+liMlYuXyUOjQHC 39wnUtejjBZHeOd6KWfNldL3u/09MpwW+cp8GJpdInK6Zm0WFeGZjI+/FXmsvx9AH2 FgNCFXfFEcC5w== Date: Thu, 06 Apr 2023 12:33:54 -0700 Subject: [PATCH 09/32] xfs: remove parent pointers in unlink From: "Darrick J. Wong" To: djwong@kernel.org Cc: Dave Chinner , Allison Henderson , allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <168080827676.616793.5681339109484884112.stgit@frogsfrogsfrogs> In-Reply-To: <168080827546.616793.7264157843231723676.stgit@frogsfrogsfrogs> References: <168080827546.616793.7264157843231723676.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-xfs@vger.kernel.org From: Allison Henderson This patch removes the parent pointer attribute during unlink Signed-off-by: Dave Chinner Signed-off-by: Allison Henderson Reviewed-by: Darrick J. Wong [djwong: adjust to new ondisk format, minor rebase fixes] Signed-off-by: Darrick J. Wong --- libxfs/xfs_attr.c | 2 +- libxfs/xfs_attr.h | 1 + libxfs/xfs_parent.c | 22 ++++++++++++++++++++++ libxfs/xfs_parent.h | 4 ++++ libxfs/xfs_trans_space.h | 2 -- repair/phase6.c | 6 +++--- 6 files changed, 31 insertions(+), 6 deletions(-) diff --git a/libxfs/xfs_attr.c b/libxfs/xfs_attr.c index 4e1d9551a..30d1a2992 100644 --- a/libxfs/xfs_attr.c +++ b/libxfs/xfs_attr.c @@ -957,7 +957,7 @@ xfs_attr_defer_replace( } /* Removes an attribute for an inode as a deferred operation */ -static int +int xfs_attr_defer_remove( struct xfs_da_args *args) { diff --git a/libxfs/xfs_attr.h b/libxfs/xfs_attr.h index 1002e431b..07c61bd70 100644 --- a/libxfs/xfs_attr.h +++ b/libxfs/xfs_attr.h @@ -550,6 +550,7 @@ 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); int xfs_attr_defer_add(struct xfs_da_args *args); +int xfs_attr_defer_remove(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); diff --git a/libxfs/xfs_parent.c b/libxfs/xfs_parent.c index ca1c6eeaf..b06033243 100644 --- a/libxfs/xfs_parent.c +++ b/libxfs/xfs_parent.c @@ -183,6 +183,28 @@ xfs_parent_add( return xfs_attr_defer_add(args); } +/* Remove a parent pointer to reflect a dirent removal. */ +int +xfs_parent_remove( + struct xfs_trans *tp, + struct xfs_parent_defer *parent, + struct xfs_inode *dp, + const struct xfs_name *parent_name, + struct xfs_inode *child) +{ + struct xfs_da_args *args = &parent->args; + + xfs_init_parent_name_rec(&parent->rec, dp, parent_name, child); + args->hashval = xfs_parent_hashname(dp, parent); + + args->trans = tp; + args->dp = child; + + xfs_init_parent_davalue(&parent->args, parent_name); + + return xfs_attr_defer_remove(args); +} + /* Cancel a parent pointer operation. */ void __xfs_parent_cancel( diff --git a/libxfs/xfs_parent.h b/libxfs/xfs_parent.h index 8e7dbe22e..0f8194cd8 100644 --- a/libxfs/xfs_parent.h +++ b/libxfs/xfs_parent.h @@ -41,6 +41,10 @@ xfs_parent_start( int xfs_parent_add(struct xfs_trans *tp, struct xfs_parent_defer *parent, struct xfs_inode *dp, const struct xfs_name *parent_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 *parent_name, + struct xfs_inode *child); + void __xfs_parent_cancel(struct xfs_mount *mp, struct xfs_parent_defer *parent); static inline void diff --git a/libxfs/xfs_trans_space.h b/libxfs/xfs_trans_space.h index 25a55650b..b5ab6701e 100644 --- a/libxfs/xfs_trans_space.h +++ b/libxfs/xfs_trans_space.h @@ -91,8 +91,6 @@ XFS_DQUOT_CLUSTER_SIZE_FSB) #define XFS_QM_QINOCREATE_SPACE_RES(mp) \ XFS_IALLOC_SPACE_RES(mp) -#define XFS_REMOVE_SPACE_RES(mp) \ - XFS_DIRREMOVE_SPACE_RES(mp) #define XFS_RENAME_SPACE_RES(mp,nl) \ (XFS_DIRREMOVE_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp,nl)) #define XFS_IFREE_SPACE_RES(mp) \ diff --git a/repair/phase6.c b/repair/phase6.c index 0be2c9c97..40d7e17b1 100644 --- a/repair/phase6.c +++ b/repair/phase6.c @@ -1266,7 +1266,7 @@ longform_dir2_rebuild( libxfs_dir_ino_validate(mp, pip.i_ino)) pip.i_ino = mp->m_sb.sb_rootino; - nres = XFS_REMOVE_SPACE_RES(mp); + nres = XFS_DIRREMOVE_SPACE_RES(mp); error = -libxfs_trans_alloc(mp, &M_RES(mp)->tr_remove, nres, 0, 0, &tp); if (error) res_failed(error); @@ -1371,7 +1371,7 @@ dir2_kill_block( int nres; xfs_trans_t *tp; - nres = XFS_REMOVE_SPACE_RES(mp); + nres = XFS_DIRREMOVE_SPACE_RES(mp); error = -libxfs_trans_alloc(mp, &M_RES(mp)->tr_remove, nres, 0, 0, &tp); if (error) res_failed(error); @@ -2887,7 +2887,7 @@ process_dir_inode( * inode but it's easier than wedging a * new define in ourselves. */ - nres = no_modify ? 0 : XFS_REMOVE_SPACE_RES(mp); + nres = no_modify ? 0 : XFS_DIRREMOVE_SPACE_RES(mp); error = -libxfs_trans_alloc(mp, &M_RES(mp)->tr_remove, nres, 0, 0, &tp); if (error) From patchwork Thu Apr 6 19:34:10 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: 13203973 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 55C9FC76196 for ; Thu, 6 Apr 2023 19:34:23 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236961AbjDFTeW (ORCPT ); Thu, 6 Apr 2023 15:34:22 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35136 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237133AbjDFTeQ (ORCPT ); Thu, 6 Apr 2023 15:34:16 -0400 Received: from dfw.source.kernel.org (dfw.source.kernel.org [139.178.84.217]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E82745580 for ; Thu, 6 Apr 2023 12:34:11 -0700 (PDT) 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 dfw.source.kernel.org (Postfix) with ESMTPS id 7F8DF64B8E for ; Thu, 6 Apr 2023 19:34:11 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id DA4F0C4339E; Thu, 6 Apr 2023 19:34:10 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1680809650; bh=UFt1+l/dY+xUFZte5+9jCs9c33ASKJThrcpVRG19Jo0=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=M+WZNPtv1DKuhfRCTBdTr3k1CqgH13pAq113mruKT4DmG7QBFi0iaseVgo0/GX+W2 h6uihs+arkOQMQH5c4M/jFP9qCUEaa1qp239reEeA8Wh8P9Vvft2V7b7ASm2l8lyUF UkI9F6tPvTGAn8z/pGgNho4X3v9Kyqkqz6dfsAAqGdFN+n7v6ncowi6aUEuyDN5rfv ZVy977+OjwOUazZNjeG5YyImDUCNh83KaKaVa0iXnbQ964LRgbTnB+ixRNjoGb6yUu cZYhEWCM+FMPWdjaMAB4uEL6tw0bK7LjelufoePi7UFih1dFlGksBc0L+fue/Kbwei Dyv2ExAK5kxNw== Date: Thu, 06 Apr 2023 12:34:10 -0700 Subject: [PATCH 10/32] xfs: Add parent pointers to rename From: "Darrick J. Wong" To: djwong@kernel.org Cc: Allison Henderson , allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <168080827689.616793.1739964310813468288.stgit@frogsfrogsfrogs> In-Reply-To: <168080827546.616793.7264157843231723676.stgit@frogsfrogsfrogs> References: <168080827546.616793.7264157843231723676.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-xfs@vger.kernel.org From: Allison Henderson This patch removes the old parent pointer attribute during the rename operation, and re-adds the updated parent pointer. Signed-off-by: Allison Henderson Reviewed-by: Darrick J. Wong [djwong: adjust to new ondisk format] Signed-off-by: Darrick J. Wong --- libxfs/xfs_attr.c | 2 +- libxfs/xfs_attr.h | 1 + libxfs/xfs_parent.c | 58 ++++++++++++++++++++++++++++++++++++++++++---- libxfs/xfs_parent.h | 23 +++++++++++++++++- libxfs/xfs_trans_space.h | 2 -- 5 files changed, 76 insertions(+), 10 deletions(-) diff --git a/libxfs/xfs_attr.c b/libxfs/xfs_attr.c index 30d1a2992..5a713f612 100644 --- a/libxfs/xfs_attr.c +++ b/libxfs/xfs_attr.c @@ -934,7 +934,7 @@ xfs_attr_defer_add( } /* Sets an attribute for an inode as a deferred operation */ -static int +int xfs_attr_defer_replace( struct xfs_da_args *args) { diff --git a/libxfs/xfs_attr.h b/libxfs/xfs_attr.h index 07c61bd70..3ad1f12a5 100644 --- a/libxfs/xfs_attr.h +++ b/libxfs/xfs_attr.h @@ -551,6 +551,7 @@ int xfs_attr_get_ilocked(struct xfs_da_args *args); int xfs_attr_get(struct xfs_da_args *args); int xfs_attr_defer_add(struct xfs_da_args *args); int xfs_attr_defer_remove(struct xfs_da_args *args); +int xfs_attr_defer_replace(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); diff --git a/libxfs/xfs_parent.c b/libxfs/xfs_parent.c index b06033243..9f61b9fc6 100644 --- a/libxfs/xfs_parent.c +++ b/libxfs/xfs_parent.c @@ -117,6 +117,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. @@ -124,22 +137,27 @@ xfs_init_parent_davalue( int __xfs_parent_init( struct xfs_mount *mp, + bool grab_log, struct xfs_parent_defer **parentp) { struct xfs_parent_defer *parent; int error; - error = xfs_attr_grab_log_assist(mp); - if (error) - return error; + if (grab_log) { + error = xfs_attr_grab_log_assist(mp); + if (error) + return error; + } parent = kmem_cache_zalloc(xfs_parent_intent_cache, GFP_KERNEL); if (!parent) { - xfs_attr_rele_log_assist(mp); + if (grab_log) + xfs_attr_rele_log_assist(mp); return -ENOMEM; } /* init parent da_args */ + parent->have_log = grab_log; parent->args.geo = mp->m_attr_geo; parent->args.whichfork = XFS_ATTR_FORK; parent->args.attr_filter = XFS_ATTR_PARENT; @@ -205,13 +223,43 @@ xfs_parent_remove( return xfs_attr_defer_remove(args); } +/* Replace one parent pointer with another to reflect a rename. */ +int +xfs_parent_replace( + struct xfs_trans *tp, + struct xfs_parent_defer *parent, + 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 = &parent->args; + + xfs_init_parent_name_rec(&parent->rec, old_dp, old_name, child); + args->hashval = xfs_parent_hashname(old_dp, parent); + + xfs_init_parent_name_rec(&parent->new_rec, new_dp, new_name, child); + args->new_name = (const uint8_t *)&parent->new_rec; + args->new_namelen = sizeof(struct xfs_parent_name_rec); + + args->trans = tp; + args->dp = child; + + xfs_init_parent_davalue(&parent->args, old_name); + xfs_init_parent_danewvalue(&parent->args, new_name); + + return xfs_attr_defer_replace(args); +} + /* Cancel a parent pointer operation. */ void __xfs_parent_cancel( struct xfs_mount *mp, struct xfs_parent_defer *parent) { - xlog_drop_incompat_feat(mp->m_log); + if (parent->have_log) + xlog_drop_incompat_feat(mp->m_log); kmem_cache_free(xfs_parent_intent_cache, parent); } diff --git a/libxfs/xfs_parent.h b/libxfs/xfs_parent.h index 0f8194cd8..f4a0793bc 100644 --- a/libxfs/xfs_parent.h +++ b/libxfs/xfs_parent.h @@ -21,10 +21,13 @@ extern struct kmem_cache *xfs_parent_intent_cache; */ struct xfs_parent_defer { struct xfs_parent_name_rec rec; + struct xfs_parent_name_rec new_rec; struct xfs_da_args args; + bool have_log; }; -int __xfs_parent_init(struct xfs_mount *mp, struct xfs_parent_defer **parentp); +int __xfs_parent_init(struct xfs_mount *mp, bool grab_log, + struct xfs_parent_defer **parentp); static inline int xfs_parent_start( @@ -34,7 +37,19 @@ xfs_parent_start( *pp = NULL; if (xfs_has_parent(mp)) - return __xfs_parent_init(mp, pp); + return __xfs_parent_init(mp, true, pp); + return 0; +} + +static inline int +xfs_parent_start_locked( + struct xfs_mount *mp, + struct xfs_parent_defer **pp) +{ + *pp = NULL; + + if (xfs_has_parent(mp)) + return __xfs_parent_init(mp, false, pp); return 0; } @@ -44,6 +59,10 @@ int xfs_parent_add(struct xfs_trans *tp, struct xfs_parent_defer *parent, int xfs_parent_remove(struct xfs_trans *tp, struct xfs_parent_defer *parent, struct xfs_inode *dp, const struct xfs_name *parent_name, struct xfs_inode *child); +int xfs_parent_replace(struct xfs_trans *tp, struct xfs_parent_defer *parent, + 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); void __xfs_parent_cancel(struct xfs_mount *mp, struct xfs_parent_defer *parent); diff --git a/libxfs/xfs_trans_space.h b/libxfs/xfs_trans_space.h index b5ab6701e..810610a14 100644 --- a/libxfs/xfs_trans_space.h +++ b/libxfs/xfs_trans_space.h @@ -91,8 +91,6 @@ XFS_DQUOT_CLUSTER_SIZE_FSB) #define XFS_QM_QINOCREATE_SPACE_RES(mp) \ XFS_IALLOC_SPACE_RES(mp) -#define XFS_RENAME_SPACE_RES(mp,nl) \ - (XFS_DIRREMOVE_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp,nl)) #define XFS_IFREE_SPACE_RES(mp) \ (xfs_has_finobt(mp) ? M_IGEO(mp)->inobt_maxlevels : 0) From patchwork Thu Apr 6 19:34:26 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13203974 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 10AF4C7618D for ; Thu, 6 Apr 2023 19:34:30 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236658AbjDFTe3 (ORCPT ); Thu, 6 Apr 2023 15:34:29 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35326 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236625AbjDFTe2 (ORCPT ); Thu, 6 Apr 2023 15:34:28 -0400 Received: from dfw.source.kernel.org (dfw.source.kernel.org [139.178.84.217]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6C5B85277 for ; Thu, 6 Apr 2023 12:34:27 -0700 (PDT) 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 dfw.source.kernel.org (Postfix) with ESMTPS id 0765064B8E for ; Thu, 6 Apr 2023 19:34:27 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 6AD01C433D2; Thu, 6 Apr 2023 19:34:26 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1680809666; bh=NRYK5b/zkT8VlzHeg09aajCcE/+YrYtVcvWEhuDjQ0w=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=Okd9mqczZgo2CD72r/KYS5mTsHu4bq3sMWkgXJkCI7ObSOHZ4oWoexEa6sNB9JgOX 3V7O84CwVzbHL+Z7uFGvrte1lATf1Xs/I0DgtnB8k/84YY+gEQXO5w9i9z4sNEHNhF yGKpUDwe4mDRhH7tLL+pm4z9JvCuF2F+kITdOn84guiHoBzbJBQ1o5NKvlEK3E9Rr3 UCTC1biAQaoSvpqtx/8MgBISoyfq3D87EVmtUh2HOND/uw97yVOEsmp1S1g1b7WxOp JeXOXVD9Nzi3vULP0QToi6Ie59y8J4qFh1hlBryrZkiHFOaKBln5IB7kXTnU6BwyxZ vtNMAIfiVGvpA== Date: Thu, 06 Apr 2023 12:34:26 -0700 Subject: [PATCH 11/32] xfsprogs: pass the attr value to put_listent when possible From: "Darrick J. Wong" To: djwong@kernel.org Cc: Allison Henderson , allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <168080827702.616793.8420185075618409206.stgit@frogsfrogsfrogs> In-Reply-To: <168080827546.616793.7264157843231723676.stgit@frogsfrogsfrogs> References: <168080827546.616793.7264157843231723676.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-xfs@vger.kernel.org From: Allison Henderson Source kernel commit: 45a4366e940b853beb4d65efec08e204aee0113d Pass the attr value to put_listent when we have local xattrs or shortform xattrs. Signed-off-by: Darrick J. Wong Signed-off-by: Allison Henderson --- libxfs/xfs_attr.h | 5 +++-- libxfs/xfs_attr_sf.h | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/libxfs/xfs_attr.h b/libxfs/xfs_attr.h index 3ad1f12a5..0185d29d5 100644 --- a/libxfs/xfs_attr.h +++ b/libxfs/xfs_attr.h @@ -47,8 +47,9 @@ struct xfs_attrlist_cursor_kern { /* void; state communicated via *context */ -typedef void (*put_listent_func_t)(struct xfs_attr_list_context *, int, - unsigned char *, int, int); +typedef void (*put_listent_func_t)(struct xfs_attr_list_context *context, + int flags, unsigned char *name, int namelen, void *value, + int valuelen); struct xfs_attr_list_context { struct xfs_trans *tp; diff --git a/libxfs/xfs_attr_sf.h b/libxfs/xfs_attr_sf.h index 37578b369..c6e259791 100644 --- a/libxfs/xfs_attr_sf.h +++ b/libxfs/xfs_attr_sf.h @@ -24,6 +24,7 @@ typedef struct xfs_attr_sf_sort { uint8_t flags; /* flags bits (see xfs_attr_leaf.h) */ xfs_dahash_t hash; /* this entry's hash value */ unsigned char *name; /* name value, pointer into buffer */ + void *value; } xfs_attr_sf_sort_t; #define XFS_ATTR_SF_ENTSIZE_MAX /* max space for name&value */ \ From patchwork Thu Apr 6 19:34: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: 13203975 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 E4E86C7618D for ; Thu, 6 Apr 2023 19:34:45 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230048AbjDFTeo (ORCPT ); Thu, 6 Apr 2023 15:34:44 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35520 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229674AbjDFTeo (ORCPT ); Thu, 6 Apr 2023 15:34:44 -0400 Received: from dfw.source.kernel.org (dfw.source.kernel.org [139.178.84.217]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 0641935BE for ; Thu, 6 Apr 2023 12:34:43 -0700 (PDT) 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 dfw.source.kernel.org (Postfix) with ESMTPS id 900B560EFE for ; Thu, 6 Apr 2023 19:34:42 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 01BFBC433D2; Thu, 6 Apr 2023 19:34:41 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1680809682; bh=cuKAPtdDdWMKk5ITd6PLYZtOC6OERwGsCeXE46BfPQ0=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=hvqWjHNwicl4JOmiXi/ZTtPB2CS4H3TXjJ5LKtDYdy2ocM78MPurMjlGo/21huJ9U oDgPUIN/dqD9JlMQ2eXUBXitqwTGqIkyRqzp8b8VsKCf2KQv9ol8EnQYP60qTz0aTF 8cExLkEQHPugnIghe31JM2m+/VOzs8DMELNm/MYZFk2EJVOMh9gCOuAbc+l0mh48Xu WQCYWDpGohcADBDoODvAHMvAVP6ECcTMLsaPApnyBXp4vGdFHxljy0Pr3sp7G/bPPY gqu5XDYeFcUudmnbf9nn9A1zsde4I7aGzyve3NrSwTWnVAQCiR0SJW95GrX1Iz4R3b 4C1zgSlyC/PbA== Date: Thu, 06 Apr 2023 12:34:41 -0700 Subject: [PATCH 12/32] xfs: add a libxfs header file for staging new ioctls From: "Darrick J. Wong" To: djwong@kernel.org Cc: allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <168080827715.616793.7225609100253350537.stgit@frogsfrogsfrogs> In-Reply-To: <168080827546.616793.7264157843231723676.stgit@frogsfrogsfrogs> References: <168080827546.616793.7264157843231723676.stgit@frogsfrogsfrogs> 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 Create a new xfs_fs_staging.h header where we can land experimental ioctls without committing them to any stable interfaces anywhere. Signed-off-by: Darrick J. Wong --- include/libxfs.h | 1 + include/xfs.h | 1 + libxfs/Makefile | 1 + libxfs/libxfs_priv.h | 1 + libxfs/xfs_fs_staging.h | 18 ++++++++++++++++++ 5 files changed, 22 insertions(+) create mode 100644 libxfs/xfs_fs_staging.h diff --git a/include/libxfs.h b/include/libxfs.h index cc57e8887..3340e2af3 100644 --- a/include/libxfs.h +++ b/include/libxfs.h @@ -23,6 +23,7 @@ #include "xfs_types.h" #include "xfs_fs.h" +#include "xfs_fs_staging.h" #include "xfs_arch.h" #include "xfs_shared.h" diff --git a/include/xfs.h b/include/xfs.h index e97158c8d..c4a95bec9 100644 --- a/include/xfs.h +++ b/include/xfs.h @@ -44,5 +44,6 @@ extern int xfs_assert_largefile[sizeof(off_t)-8]; /* Include deprecated/compat pre-vfs xfs-specific symbols */ #include #include +#include #endif /* __XFS_H__ */ diff --git a/libxfs/Makefile b/libxfs/Makefile index 89d29dc97..951df6231 100644 --- a/libxfs/Makefile +++ b/libxfs/Makefile @@ -14,6 +14,7 @@ LTLDFLAGS += -static # headers to install in include/xfs PKGHFILES = xfs_fs.h \ + xfs_fs_staging.h \ xfs_types.h \ xfs_da_format.h \ xfs_format.h \ diff --git a/libxfs/libxfs_priv.h b/libxfs/libxfs_priv.h index ff027dbe3..411cafb26 100644 --- a/libxfs/libxfs_priv.h +++ b/libxfs/libxfs_priv.h @@ -56,6 +56,7 @@ #include "xfs_arch.h" #include "xfs_fs.h" +#include "xfs_fs_staging.h" #include "libfrog/crc32c.h" #include diff --git a/libxfs/xfs_fs_staging.h b/libxfs/xfs_fs_staging.h new file mode 100644 index 000000000..bc97193dd --- /dev/null +++ b/libxfs/xfs_fs_staging.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: LGPL-2.1 */ +/* + * Copyright (C) 2020-2023 Oracle. All Rights Reserved. + * Author: Darrick J. Wong + */ +#ifndef __XFS_FS_STAGING_H__ +#define __XFS_FS_STAGING_H__ + +/* + * Experimental system calls, ioctls and data structures supporting them. + * Nothing in here should be considered part of a stable interface of any kind. + * + * If you add an ioctl here, please leave a comment in xfs_fs.h marking it + * reserved. If you promote anything out of this file, please leave a comment + * explaining where it went. + */ + +#endif /* __XFS_FS_STAGING_H__ */ From patchwork Thu Apr 6 19:34: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: 13203976 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 CAB89C76196 for ; Thu, 6 Apr 2023 19:35:05 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237098AbjDFTfE (ORCPT ); Thu, 6 Apr 2023 15:35:04 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35858 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236921AbjDFTfD (ORCPT ); Thu, 6 Apr 2023 15:35:03 -0400 Received: from dfw.source.kernel.org (dfw.source.kernel.org [IPv6:2604:1380:4641:c500::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B4C1786A5 for ; Thu, 6 Apr 2023 12:34:58 -0700 (PDT) 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 dfw.source.kernel.org (Postfix) with ESMTPS id 2F5F964B97 for ; Thu, 6 Apr 2023 19:34:58 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 8C139C433D2; Thu, 6 Apr 2023 19:34:57 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1680809697; bh=zi8a8zpliJ7aEelYQcewBp6t8xww1DEDi+oCivBoZtc=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=IfTGDkbU+jubgnlsDb89MieOBy5uWLyHFgcvnIy0dWR/mMORG+kloEOTVB91tbT1K o2JJzfJsH0yPSV9vACthF9PlbKSU98nacJue1qY23DRT9f6cWZGw38rtTFpjJtk+7X +wAnwbg0fhryzaqO2L6LZLDUjSXqDyZs0KECqDmNtBDcAjLTWuYu0G/zsV+gQD8jTv FaPQQWKXMVB/rSnbKl0aZwpZT5liFf63Zc7toO6dx6MtswwKreqRncq5KkonxNo60T 5FR9aiBsjDZ8CylzuCwQF/PIjZoQIDPePacGTY/bnXUKwdz1hv6Fqj180DT0Yg7VaI UzZN1mq8r+wLA== Date: Thu, 06 Apr 2023 12:34:57 -0700 Subject: [PATCH 13/32] xfs: Add parent pointer ioctl From: "Darrick J. Wong" To: djwong@kernel.org Cc: Allison Henderson , allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <168080827728.616793.892984000897631824.stgit@frogsfrogsfrogs> In-Reply-To: <168080827546.616793.7264157843231723676.stgit@frogsfrogsfrogs> References: <168080827546.616793.7264157843231723676.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-xfs@vger.kernel.org From: Allison Henderson This patch adds a new file ioctl to retrieve the parent pointer of a given inode Signed-off-by: Allison Henderson Reviewed-by: Darrick J. Wong [djwong: move new ioctl to xfs_fs_staging.h, adjust to new ondisk format] Signed-off-by: Darrick J. Wong --- libxfs/xfs_fs.h | 1 + libxfs/xfs_fs_staging.h | 66 +++++++++++++++++++++++++++++++++++++++++++++++ libxfs/xfs_parent.c | 40 ++++++++++++++++++++++++++++ libxfs/xfs_parent.h | 23 ++++++++++++++++ man/man3/xfsctl.3 | 63 +++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 193 insertions(+) diff --git a/libxfs/xfs_fs.h b/libxfs/xfs_fs.h index 1cfd5bc65..390b8cbe2 100644 --- a/libxfs/xfs_fs.h +++ b/libxfs/xfs_fs.h @@ -796,6 +796,7 @@ struct xfs_scrub_metadata { /* XFS_IOC_GETFSMAP ------ hoisted 59 */ #define XFS_IOC_SCRUB_METADATA _IOWR('X', 60, struct xfs_scrub_metadata) #define XFS_IOC_AG_GEOMETRY _IOWR('X', 61, struct xfs_ag_geometry) +/* XFS_IOC_GETPARENTS ---- staging 62 */ /* * ioctl commands that replace IRIX syssgi()'s diff --git a/libxfs/xfs_fs_staging.h b/libxfs/xfs_fs_staging.h index bc97193dd..fe11ad6f2 100644 --- a/libxfs/xfs_fs_staging.h +++ b/libxfs/xfs_fs_staging.h @@ -15,4 +15,70 @@ * explaining where it went. */ +/* Iterating parent pointers of files. */ + +/* return parents of the handle, not the open fd */ +#define XFS_GETPARENTS_IFLAG_HANDLE (1U << 0) + +/* target was the root directory */ +#define XFS_GETPARENTS_OFLAG_ROOT (1U << 1) + +/* Cursor is done iterating pptrs */ +#define XFS_GETPARENTS_OFLAG_DONE (1U << 2) + +#define XFS_GETPARENTS_FLAG_ALL (XFS_GETPARENTS_IFLAG_HANDLE | \ + XFS_GETPARENTS_OFLAG_ROOT | \ + XFS_GETPARENTS_OFLAG_DONE) + +/* Get an inode parent pointer through ioctl */ +struct xfs_getparents_rec { + __u64 gpr_ino; /* Inode number */ + __u32 gpr_gen; /* Inode generation */ + __u32 gpr_pad; /* Reserved */ + __u64 gpr_rsvd; /* Reserved */ + __u8 gpr_name[]; /* File name and null terminator */ +}; + +/* Iterate through an inodes parent pointers */ +struct xfs_getparents { + /* File handle, if XFS_GETPARENTS_IFLAG_HANDLE is set */ + struct xfs_handle gp_handle; + + /* + * Structure to track progress in iterating the parent pointers. + * Must be initialized to zeroes before the first ioctl call, and + * not touched by callers after that. + */ + struct xfs_attrlist_cursor gp_cursor; + + /* Operational flags: XFS_GETPARENTS_*FLAG* */ + __u32 gp_flags; + + /* Must be set to zero */ + __u32 gp_reserved; + + /* Size of the buffer in bytes, including this header */ + __u32 gp_bufsize; + + /* # of entries filled in (output) */ + __u32 gp_count; + + /* Must be set to zero */ + __u64 gp_reserved2[5]; + + /* Byte offset of each record within the buffer */ + __u32 gp_offsets[]; +}; + +static inline struct xfs_getparents_rec* +xfs_getparents_rec( + struct xfs_getparents *info, + unsigned int idx) +{ + return (struct xfs_getparents_rec *)((char *)info + + info->gp_offsets[idx]); +} + +#define XFS_IOC_GETPARENTS _IOWR('X', 62, struct xfs_getparents) + #endif /* __XFS_FS_STAGING_H__ */ diff --git a/libxfs/xfs_parent.c b/libxfs/xfs_parent.c index 9f61b9fc6..e276a1d91 100644 --- a/libxfs/xfs_parent.c +++ b/libxfs/xfs_parent.c @@ -276,3 +276,43 @@ xfs_parent_calc_space_res( return XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK) + XFS_NEXTENTADD_SPACE_RES(mp, namelen, XFS_ATTR_FORK); } + +/* 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); +} + +/* Compute p_namehash for the this parent pointer. */ +void +xfs_parent_irec_hashname( + struct xfs_mount *mp, + struct xfs_parent_name_irec *irec) +{ + struct xfs_name dname = { + .name = irec->p_name, + .len = irec->p_namelen, + }; + + irec->p_namehash = xfs_dir2_hashname(mp, &dname); +} diff --git a/libxfs/xfs_parent.h b/libxfs/xfs_parent.h index f4a0793bc..1cc477896 100644 --- a/libxfs/xfs_parent.h +++ b/libxfs/xfs_parent.h @@ -78,4 +78,27 @@ xfs_parent_finish( unsigned int xfs_parent_calc_space_res(struct xfs_mount *mp, unsigned int namelen); +/* + * 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); + #endif /* __XFS_PARENT_H__ */ diff --git a/man/man3/xfsctl.3 b/man/man3/xfsctl.3 index 4a0d4d08d..e663b64a8 100644 --- a/man/man3/xfsctl.3 +++ b/man/man3/xfsctl.3 @@ -321,6 +321,69 @@ They are all subject to change and should not be called directly by applications. XFS_IOC_FSSETDM_BY_HANDLE is not supported as of Linux 5.5. +.PP +.TP +.B XFS_IOC_GETPARENTS +This command is used to get a file's parent pointers. +Parent pointers point upwards in the directory tree towards directories that +have entries pointing downwards. + +Calling programs should allocate a large memory buffer, initialize the head +structure to zeroes, set gp_bufsize to the size of the buffer, and call the +ioctl. +The kernel will fill out the gp_offsets array with integer offsets to +struct xfs_getparents_rec objects that are written within the provided memory +buffer. +The size of the gp_offsets array is given by gp_count. +The XFS_GETPARENTS_OFLAG_DONE flag will be set in gp_flags when there are no +more parent pointers to be read. +The below code is an example of XFS_IOC_GETPARENTS usage: + +.nf +#include +#include +#include +#include +#include +#include +#include +#include + +int main() { + struct xfs_getparents *pi; + struct xfs_getparents_rec *p; + int i, error, fd, nr_ptrs = 4; + + error = malloc(65536); + if (!error) { + perror("malloc"); + return 1; + } + + memset(pi, 0, sizeof(*pi)); + pi->gp_bufsize = 65536; + + fd = open("/mnt/test/foo.txt", O_RDONLY | O_CREAT); + if (fd == -1) + return errno; + + do { + error = ioctl(fd, XFS_IOC_GETPARENTS, pi); + if (error) + return error; + + for (i = 0; i < pi->gp_count; i++) { + p = xfs_getparents_rec(pi, i); + printf("inode = %llu\\n", (unsigned long long)p->gpr_ino); + printf("generation = %u\\n", (unsigned int)p->gpr_gen); + printf("name = \\"%s\\"\\n\\n", (char *)p->gpr_name); + } + } while (!(pi->gp_flags & XFS_GETPARENTS_OFLAG_DONE)); + + return 0; +} +.fi + .SS Filesystem Operations In order to effect one of the following operations, the pathname and descriptor arguments passed to From patchwork Thu Apr 6 19:35: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: 13203977 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 DD02EC76196 for ; Thu, 6 Apr 2023 19:35:16 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229892AbjDFTfQ (ORCPT ); Thu, 6 Apr 2023 15:35:16 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:36192 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229463AbjDFTfP (ORCPT ); Thu, 6 Apr 2023 15:35:15 -0400 Received: from dfw.source.kernel.org (dfw.source.kernel.org [139.178.84.217]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 359844EFA for ; Thu, 6 Apr 2023 12:35:14 -0700 (PDT) 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 dfw.source.kernel.org (Postfix) with ESMTPS id BD60864876 for ; Thu, 6 Apr 2023 19:35:13 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 283CCC433D2; Thu, 6 Apr 2023 19:35:13 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1680809713; bh=XYnm/ONVKVKKawmzZQfA2R9bKwvXNSWLmlZhSb+umDY=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=jmTiKOMzfCxVUtZKYsF6Y3K4Pijn95Bi7fB3/blJDngh2dG88oERt6HqbrSbcOd1j cXeFsHYTXtMvEaiW7+jZusEjikqqimCviblH0UAfC3Imsq8L7GCQZ3gREH3TkuQoEy IrGr87Vgh0+iOHJuSoZAzvBhEXfYp2FKG60bdVamW70CAPB9lZdsj8feOBueEqUrw6 UrB1FzF4mH+/GM/AvB3JH4QkgyUQHcTkdInEOFgv5wUmXiOAvGKlkESQPTJR4QUSoa UDuG5x+4CxBKQR0BBG5aUPFXLjtnwA1a1tdDhuFJTb7HJBroVqiBWjOMx/ea0lIh+4 HvTSn9/xdH8mA== Date: Thu, 06 Apr 2023 12:35:12 -0700 Subject: [PATCH 14/32] xfs: fix unit conversion error in xfs_log_calc_max_attrsetm_res From: "Darrick J. Wong" To: djwong@kernel.org Cc: Allison Henderson , allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <168080827741.616793.10309747666644698123.stgit@frogsfrogsfrogs> In-Reply-To: <168080827546.616793.7264157843231723676.stgit@frogsfrogsfrogs> References: <168080827546.616793.7264157843231723676.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-xfs@vger.kernel.org From: Allison Henderson Dave and I were discussing some recent test regressions as a result of me turning on nrext64=1 on realtime filesystems, when we noticed that the minimum log size of a 32M filesystem jumped from 954 blocks to 4287 blocks. Digging through xfs_log_calc_max_attrsetm_res, Dave noticed that @size contains the maximum estimated amount of space needed for a local format xattr, in bytes, but we feed this quantity to XFS_NEXTENTADD_SPACE_RES, which requires units of blocks. This has resulted in an overestimation of the minimum log size over the years. We should nominally correct this, but there's a backwards compatibility problem -- if we enable it now, the minimum log size will decrease. If a corrected mkfs formats a filesystem with this new smaller log size, a user will encounter mount failures on an uncorrected kernel due to the larger minimum log size computations there. However, the large extent counters feature is still EXPERIMENTAL, so we can gate the correction on that feature (or any features that get added after that) being enabled. Any filesystem with nrext64 or any of the as-yet-undefined feature bits turned on will be rejected by old uncorrected kernels, so this should be safe even in the upgrade case. Signed-off-by: Darrick J. Wong Reviewed-by: Allison Henderson --- libxfs/xfs_log_rlimit.c | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/libxfs/xfs_log_rlimit.c b/libxfs/xfs_log_rlimit.c index cba24493f..6ecb9ad51 100644 --- a/libxfs/xfs_log_rlimit.c +++ b/libxfs/xfs_log_rlimit.c @@ -16,6 +16,39 @@ #include "xfs_bmap_btree.h" #include "xfs_trace.h" +/* + * Decide if the filesystem has the parent pointer feature or any feature + * added after that. + */ +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_compat_feature(&mp->m_sb, ~0)) + return true; + + if (xfs_sb_has_ro_compat_feature(&mp->m_sb, + ~(XFS_SB_FEAT_RO_COMPAT_FINOBT | + XFS_SB_FEAT_RO_COMPAT_RMAPBT | + XFS_SB_FEAT_RO_COMPAT_REFLINK | + XFS_SB_FEAT_RO_COMPAT_INOBTCNT))) + return true; + + 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_NEEDSREPAIR | + 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 +64,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 Thu Apr 6 19:35: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: 13203978 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 E8239C7618D for ; Thu, 6 Apr 2023 19:35:39 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229871AbjDFTfi (ORCPT ); Thu, 6 Apr 2023 15:35:38 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:36812 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237261AbjDFTfe (ORCPT ); Thu, 6 Apr 2023 15:35:34 -0400 Received: from dfw.source.kernel.org (dfw.source.kernel.org [139.178.84.217]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B18BF901C for ; Thu, 6 Apr 2023 12:35:29 -0700 (PDT) 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 dfw.source.kernel.org (Postfix) with ESMTPS id 4C01F64B89 for ; Thu, 6 Apr 2023 19:35:29 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id A991AC433D2; Thu, 6 Apr 2023 19:35:28 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1680809728; bh=s47meeJ4xP2+OZk0nbyc/W2qYGh1jl4HGDevpUSHD2I=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=bNlszqHledIM9AefndIz9xYX6P12B0XLuccAga3SAogaU4pWJtDuL6oOj+SECHEoC HJMEoJaScxnqCO2dui+7mA/yfw2ruLL5K6vbsVTpkvXLMa4sJ2nDTLL6hfkasGIiJ+ 50zYQyQQcgmzwnJ39CQlIWarsAStT0058a7YEktyCkriKm2A/phhc2Nc9WpF7aAFyE Ws/hFFKv/sjNj5JFpY7YVDQjaKJvDpO+YXaSyd90JxcZ6wVpMOpGHm49RUoqBiFKEZ FlWZivxfhN10hAZt+gmywZnKSwxw7ducsV6SvIxo7ZJsK8wmixoH9L5mXWOP0neecQ +vVKv9WowfLHQ== Date: Thu, 06 Apr 2023 12:35:28 -0700 Subject: [PATCH 15/32] xfs: drop compatibility minimum log size computations for reflink From: "Darrick J. Wong" To: djwong@kernel.org Cc: Allison Henderson , allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <168080827754.616793.10713015735486315248.stgit@frogsfrogsfrogs> In-Reply-To: <168080827546.616793.7264157843231723676.stgit@frogsfrogsfrogs> References: <168080827546.616793.7264157843231723676.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-xfs@vger.kernel.org From: Allison Henderson Having established that we can reduce the minimum log size computation for filesystems with parent pointers or any newer feature, we should also drop the compat minlogsize code that we added when we reduced the transaction reservation size for rmap and reflink. Signed-off-by: Darrick J. Wong Reviewed-by: Allison Henderson --- libxfs/xfs_log_rlimit.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/libxfs/xfs_log_rlimit.c b/libxfs/xfs_log_rlimit.c index 6ecb9ad51..59605f0dc 100644 --- a/libxfs/xfs_log_rlimit.c +++ b/libxfs/xfs_log_rlimit.c @@ -91,6 +91,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 Thu Apr 6 19:35:43 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: 13203979 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 B4BB2C7618D for ; Thu, 6 Apr 2023 19:35:47 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230030AbjDFTfq (ORCPT ); Thu, 6 Apr 2023 15:35:46 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:36874 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229882AbjDFTfq (ORCPT ); Thu, 6 Apr 2023 15:35:46 -0400 Received: from dfw.source.kernel.org (dfw.source.kernel.org [IPv6:2604:1380:4641:c500::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 7093DE72 for ; Thu, 6 Apr 2023 12:35:45 -0700 (PDT) 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 dfw.source.kernel.org (Postfix) with ESMTPS id 0DB6060EFE for ; Thu, 6 Apr 2023 19:35:45 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 6BA40C433D2; Thu, 6 Apr 2023 19:35:44 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1680809744; bh=IaEQIJdRAhMD8z4yP3K+0aYpfiQYxYjTi+iRQWMRgLs=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=l/1TcDoa8SeFqqL9Wq5KRXQYNXzpYnT5pDGm43ZrsIvDU7DWcTiFyoenJVgAJiKNY G9K3ddNnoONTZg3bkHmZyWAozCTQB9boCKw7jRpgNlrTgVs+6u8sSFUoaXupxZswgy ySTPoVrUdPAvsJ+K0FxiahvdsfgJkx6eQwJ535e0yjX5xalX/OK2gRVhXGL9Km8Rrp 2kUMGpkeILarPus4bzvEs96hot/+hfxOp21cFp489jQ04VyNo+3y/g/Kmis08SV0Kh yi7VUXPrqgNRZvbdBBUbRKiwNsqGodZrFx0BUgsZ+ygs8I2U3lJEz4xn57Q1KNm6ef iuOq3FbHxxSRA== Date: Thu, 06 Apr 2023 12:35:43 -0700 Subject: [PATCH 16/32] xfs: don't remove the attr fork when parent pointers are enabled From: "Darrick J. Wong" To: djwong@kernel.org Cc: Allison Henderson , allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <168080827767.616793.12096415904216447722.stgit@frogsfrogsfrogs> In-Reply-To: <168080827546.616793.7264157843231723676.stgit@frogsfrogsfrogs> References: <168080827546.616793.7264157843231723676.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-xfs@vger.kernel.org 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: Darrick J. Wong Signed-off-by: Allison Henderson --- libxfs/xfs_attr_leaf.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libxfs/xfs_attr_leaf.c b/libxfs/xfs_attr_leaf.c index b095b25a6..63d96bed4 100644 --- a/libxfs/xfs_attr_leaf.c +++ b/libxfs/xfs_attr_leaf.c @@ -875,7 +875,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); @@ -884,7 +885,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 Thu Apr 6 19:35:59 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: 13203980 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 17202C7618D for ; Thu, 6 Apr 2023 19:36:07 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237224AbjDFTgF (ORCPT ); Thu, 6 Apr 2023 15:36:05 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37104 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236962AbjDFTgC (ORCPT ); Thu, 6 Apr 2023 15:36:02 -0400 Received: from dfw.source.kernel.org (dfw.source.kernel.org [139.178.84.217]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 7D7CC7EDC for ; Thu, 6 Apr 2023 12:36:01 -0700 (PDT) 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 dfw.source.kernel.org (Postfix) with ESMTPS id 9C68664876 for ; Thu, 6 Apr 2023 19:36:00 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 08FD6C433D2; Thu, 6 Apr 2023 19:35:59 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1680809760; bh=2OvDWzOYxjTmPCR1/v9VOj3YspswazxKQLBpokMO3Ko=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=mrdeapcXiQpHThstbxnNUu216O/+69fwhyOP6kwgFMMlH2cRpBUcNCU7LqoLQq4ce haBj3hmzmpixLk10XYz9n8LlnxxJHS5zlaxXIyaCU/U4DzAm2kp5GbLfcXWWtZtNIN 4UqEeF25YhfHhwsL7tnsYGbK4IsXwyimM3Sq5IPnjBITpYmueD7dA5EPT5sZSbKJI5 wn3gwp4+T9XjMRK7udMY1Ec4BW4l1ydN0Ep1HEKGyaE5dcmPicZI2be1pa4QI/49oG gVGvqJbfM6kEafOVjkrUAVG0NkARt2Y5RTNOiF5bB8mGWb9IOf+ahYNBR0T9vFTlot 2Xd/svTRtwm5Q== Date: Thu, 06 Apr 2023 12:35:59 -0700 Subject: [PATCH 17/32] 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" , allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <168080827780.616793.10655715621044365806.stgit@frogsfrogsfrogs> In-Reply-To: <168080827546.616793.7264157843231723676.stgit@frogsfrogsfrogs> References: <168080827546.616793.7264157843231723676.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-xfs@vger.kernel.org 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 --- libfrog/fsgeom.c | 4 ++++ libxfs/xfs_format.h | 4 +++- libxfs/xfs_fs.h | 1 + libxfs/xfs_sb.c | 4 ++++ 4 files changed, 12 insertions(+), 1 deletion(-) diff --git a/libfrog/fsgeom.c b/libfrog/fsgeom.c index 3e7f0797d..3bb753ac9 100644 --- a/libfrog/fsgeom.c +++ b/libfrog/fsgeom.c @@ -31,6 +31,7 @@ xfs_report_geom( int bigtime_enabled; int inobtcount; int nrext64; + int parent; isint = geo->logstart > 0; lazycount = geo->flags & XFS_FSOP_GEOM_FLAGS_LAZYSB ? 1 : 0; @@ -49,12 +50,14 @@ xfs_report_geom( bigtime_enabled = geo->flags & XFS_FSOP_GEOM_FLAGS_BIGTIME ? 1 : 0; inobtcount = geo->flags & XFS_FSOP_GEOM_FLAGS_INOBTCNT ? 1 : 0; nrext64 = geo->flags & XFS_FSOP_GEOM_FLAGS_NREXT64 ? 1 : 0; + parent = geo->flags & XFS_FSOP_GEOM_FLAGS_PARENT ? 1 : 0; printf(_( "meta-data=%-22s isize=%-6d agcount=%u, agsize=%u blks\n" " =%-22s sectsz=%-5u attr=%u, projid32bit=%u\n" " =%-22s crc=%-8u finobt=%u, sparse=%u, rmapbt=%u\n" " =%-22s reflink=%-4u bigtime=%u inobtcount=%u nrext64=%u\n" +" =%-22s parent=%d\n" "data =%-22s bsize=%-6u blocks=%llu, imaxpct=%u\n" " =%-22s sunit=%-6u swidth=%u blks\n" "naming =version %-14u bsize=%-6u ascii-ci=%d, ftype=%d\n" @@ -65,6 +68,7 @@ xfs_report_geom( "", geo->sectsize, attrversion, projid32bit, "", crcs_enabled, finobt_enabled, spinodes, rmapbt_enabled, "", reflink_enabled, bigtime_enabled, inobtcount, nrext64, + "", parent, "", geo->blocksize, (unsigned long long)geo->datablocks, geo->imaxpct, "", geo->sunit, geo->swidth, diff --git a/libxfs/xfs_format.h b/libxfs/xfs_format.h index 371dc0723..f413819b2 100644 --- a/libxfs/xfs_format.h +++ b/libxfs/xfs_format.h @@ -373,13 +373,15 @@ xfs_sb_has_ro_compat_feature( #define XFS_SB_FEAT_INCOMPAT_BIGTIME (1 << 3) /* large timestamps */ #define XFS_SB_FEAT_INCOMPAT_NEEDSREPAIR (1 << 4) /* needs xfs_repair */ #define XFS_SB_FEAT_INCOMPAT_NREXT64 (1 << 5) /* large extent counters */ +#define XFS_SB_FEAT_INCOMPAT_PARENT (1 << 6) /* parent pointers */ #define XFS_SB_FEAT_INCOMPAT_ALL \ (XFS_SB_FEAT_INCOMPAT_FTYPE| \ XFS_SB_FEAT_INCOMPAT_SPINODES| \ XFS_SB_FEAT_INCOMPAT_META_UUID| \ XFS_SB_FEAT_INCOMPAT_BIGTIME| \ XFS_SB_FEAT_INCOMPAT_NEEDSREPAIR| \ - XFS_SB_FEAT_INCOMPAT_NREXT64) + XFS_SB_FEAT_INCOMPAT_NREXT64| \ + XFS_SB_FEAT_INCOMPAT_PARENT) #define XFS_SB_FEAT_INCOMPAT_UNKNOWN ~XFS_SB_FEAT_INCOMPAT_ALL static inline bool diff --git a/libxfs/xfs_fs.h b/libxfs/xfs_fs.h index 390b8cbe2..fc45b0e25 100644 --- a/libxfs/xfs_fs.h +++ b/libxfs/xfs_fs.h @@ -237,6 +237,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 (1 << 24) /* parent pointers */ /* * Minimum and maximum sizes need for growth checks. diff --git a/libxfs/xfs_sb.c b/libxfs/xfs_sb.c index 64b4e7bea..61f86777e 100644 --- a/libxfs/xfs_sb.c +++ b/libxfs/xfs_sb.c @@ -171,6 +171,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; } @@ -1188,6 +1190,8 @@ xfs_fs_geometry( geo->flags |= XFS_FSOP_GEOM_FLAGS_BIGTIME; if (xfs_has_inobtcounts(mp)) geo->flags |= XFS_FSOP_GEOM_FLAGS_INOBTCNT; + if (xfs_has_parent(mp)) + geo->flags |= XFS_FSOP_GEOM_FLAGS_PARENT; if (xfs_has_sector(mp)) { geo->flags |= XFS_FSOP_GEOM_FLAGS_SECTOR; geo->logsectsize = sbp->sb_logsectsize; From patchwork Thu Apr 6 19:36:15 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: 13203981 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 0F766C76196 for ; Thu, 6 Apr 2023 19:36:21 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237183AbjDFTgT (ORCPT ); Thu, 6 Apr 2023 15:36:19 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37608 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237207AbjDFTgT (ORCPT ); Thu, 6 Apr 2023 15:36:19 -0400 Received: from dfw.source.kernel.org (dfw.source.kernel.org [139.178.84.217]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B35AC93D2 for ; Thu, 6 Apr 2023 12:36:16 -0700 (PDT) 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 dfw.source.kernel.org (Postfix) with ESMTPS id 412DC64BB0 for ; Thu, 6 Apr 2023 19:36:16 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 9AD94C433D2; Thu, 6 Apr 2023 19:36:15 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1680809775; bh=4A4Y8gBqNJxcft58Sb3Y73QX3vjUdGveWvWkS5JYTBk=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=r8kGLqTStefxbfdAv1vBGLJwi8Jo4PVHyA/iDXOwQuRf257eoRl21+9nuFszCmN7J uliu5tIm1veA91FuKqMOiCjL3oj7KOZ46NCc5yz82YTi6le822h3Kef0TOvPNBFetn VGRD2Suw+FEySG/EN+4h8Rf3Pwukt73mc47e7GmQSsmD5GL0rLprHDK4ZYV23uSi04 +1UjBDtzpGWnCgcdxPCNlMGFOSMWgmHOB9GiFzkbVBsGEkilnrLCZudntJ+ak5C3rQ P1YjI/OlWapZsTMzAxmFCWp51zK2VYYzOAaAy+eV69UTdS3fBB9NA3nZbh8xb2q5lS L43br6OAlIxFQ== Date: Thu, 06 Apr 2023 12:36:15 -0700 Subject: [PATCH 18/32] libfrog: add parent pointer support code From: "Darrick J. Wong" To: djwong@kernel.org Cc: Allison Collins , allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <168080827794.616793.16808165014334622001.stgit@frogsfrogsfrogs> In-Reply-To: <168080827546.616793.7264157843231723676.stgit@frogsfrogsfrogs> References: <168080827546.616793.7264157843231723676.stgit@frogsfrogsfrogs> 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 Add some support code to libfrog so that client programs can walk file descriptors and handles upwards through the directory tree; and obtain a reasonable file path from a file descriptor/handle. This code will be used in xfsprogs utilities. Signed-off-by: Darrick J. Wong Signed-off-by: Allison Collins --- include/handle.h | 1 libfrog/Makefile | 2 libfrog/getparents.c | 338 ++++++++++++++++++++++++++++++++++++++++++++++++++ libfrog/getparents.h | 36 +++++ libfrog/paths.c | 167 +++++++++++++++++++++++++ libfrog/paths.h | 25 ++++ libhandle/handle.c | 7 + 7 files changed, 573 insertions(+), 3 deletions(-) create mode 100644 libfrog/getparents.c create mode 100644 libfrog/getparents.h diff --git a/include/handle.h b/include/handle.h index 34246f385..ba0650051 100644 --- a/include/handle.h +++ b/include/handle.h @@ -17,6 +17,7 @@ struct parent; extern int path_to_handle (char *__path, void **__hanp, size_t *__hlen); extern int path_to_fshandle (char *__path, void **__fshanp, size_t *__fshlen); extern int fd_to_handle (int fd, void **hanp, size_t *hlen); +extern int handle_to_fsfd(void *, char **); extern int handle_to_fshandle (void *__hanp, size_t __hlen, void **__fshanp, size_t *__fshlen); extern void free_handle (void *__hanp, size_t __hlen); diff --git a/libfrog/Makefile b/libfrog/Makefile index 011070823..b327c1fdf 100644 --- a/libfrog/Makefile +++ b/libfrog/Makefile @@ -19,6 +19,7 @@ bulkstat.c \ convert.c \ crc32.c \ fsgeom.c \ +getparents.c \ list_sort.c \ linux.c \ logging.c \ @@ -40,6 +41,7 @@ crc32cselftest.h \ crc32defs.h \ crc32table.h \ fsgeom.h \ +getparents.h \ logging.h \ paths.h \ projects.h \ diff --git a/libfrog/getparents.c b/libfrog/getparents.c new file mode 100644 index 000000000..3b4fc011a --- /dev/null +++ b/libfrog/getparents.c @@ -0,0 +1,338 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2017-2023 Oracle. All Rights Reserved. + * Author: Darrick J. Wong + */ +#include "platform_defs.h" +#include "xfs.h" +#include "xfs_arch.h" +#include "list.h" +#include "libfrog/paths.h" +#include "handle.h" +#include "libfrog/getparents.h" + +/* Allocate a buffer large enough for some parent pointer records. */ +static inline struct xfs_getparents * +alloc_pptr_buf( + size_t bufsize) +{ + struct xfs_getparents *pi; + + pi = calloc(bufsize, 1); + if (!pi) + return NULL; + pi->gp_bufsize = bufsize; + return pi; +} + +/* + * Walk all parents of the given file handle. Returns 0 on success or positive + * errno. + */ +static int +call_getparents( + int fd, + struct xfs_handle *handle, + walk_parent_fn fn, + void *arg) +{ + struct xfs_getparents *pi; + struct xfs_getparents_rec *p; + unsigned int i; + ssize_t ret = -1; + + pi = alloc_pptr_buf(XFS_XATTR_LIST_MAX); + if (!pi) + return errno; + + if (handle) { + memcpy(&pi->gp_handle, handle, sizeof(struct xfs_handle)); + pi->gp_flags = XFS_GETPARENTS_IFLAG_HANDLE; + } + + ret = ioctl(fd, XFS_IOC_GETPARENTS, pi); + while (!ret) { + if (pi->gp_flags & XFS_GETPARENTS_OFLAG_ROOT) { + struct parent_rec rec = { + .p_flags = PARENT_IS_ROOT, + }; + + ret = fn(&rec, arg); + goto out_pi; + } + + for (i = 0; i < pi->gp_count; i++) { + struct parent_rec rec = { 0 }; + + p = xfs_getparents_rec(pi, i); + rec.p_ino = p->gpr_ino; + rec.p_gen = p->gpr_gen; + strncpy((char *)rec.p_name, (char *)p->gpr_name, + MAXNAMELEN - 1); + + ret = fn(&rec, arg); + if (ret) + goto out_pi; + } + + if (pi->gp_flags & XFS_GETPARENTS_OFLAG_DONE) + break; + + ret = ioctl(fd, XFS_IOC_GETPARENTS, pi); + } + if (ret) + ret = errno; + +out_pi: + free(pi); + return ret; +} + +/* Walk all parent pointers of this handle. Returns 0 or positive errno. */ +int +handle_walk_parents( + void *hanp, + size_t hlen, + walk_parent_fn fn, + void *arg) +{ + char *mntpt; + int fd; + + if (hlen != sizeof(struct xfs_handle)) + return EINVAL; + + fd = handle_to_fsfd(hanp, &mntpt); + if (fd < 0) + return errno; + + return call_getparents(fd, hanp, fn, arg); +} + +/* Walk all parent pointers of this fd. Returns 0 or positive errno. */ +int +fd_walk_parents( + int fd, + walk_parent_fn fn, + void *arg) +{ + return call_getparents(fd, NULL, fn, arg); +} + +struct walk_ppaths_info { + walk_path_fn fn; + void *arg; + char *mntpt; + struct path_list *path; + int fd; +}; + +struct walk_ppath_level_info { + struct xfs_handle newhandle; + struct path_component *pc; + struct walk_ppaths_info *wpi; +}; + +static int handle_walk_ppath(struct walk_ppaths_info *wpi, + struct xfs_handle *handle); + +static int +handle_walk_ppath_rec( + const struct parent_rec *rec, + void *arg) +{ + struct walk_ppath_level_info *wpli = arg; + struct walk_ppaths_info *wpi = wpli->wpi; + int ret = 0; + + if (rec->p_flags & PARENT_IS_ROOT) + return wpi->fn(wpi->mntpt, wpi->path, wpi->arg); + + ret = path_component_change(wpli->pc, rec->p_name, + strlen((char *)rec->p_name), rec->p_ino); + if (ret) + return ret; + + wpli->newhandle.ha_fid.fid_ino = rec->p_ino; + wpli->newhandle.ha_fid.fid_gen = rec->p_gen; + + path_list_add_parent_component(wpi->path, wpli->pc); + ret = handle_walk_ppath(wpi, &wpli->newhandle); + path_list_del_component(wpi->path, wpli->pc); + + return ret; +} + +/* + * Recursively walk all parents of the given file handle; if we hit the + * fs root then we call the associated function with the constructed path. + * Returns 0 for success or positive errno. + */ +static int +handle_walk_ppath( + struct walk_ppaths_info *wpi, + struct xfs_handle *handle) +{ + struct walk_ppath_level_info *wpli; + int ret; + + wpli = malloc(sizeof(struct walk_ppath_level_info)); + if (!wpli) + return errno; + wpli->pc = path_component_init("", 0); + if (!wpli->pc) { + ret = errno; + free(wpli); + return ret; + } + wpli->wpi = wpi; + memcpy(&wpli->newhandle, handle, sizeof(struct xfs_handle)); + + ret = call_getparents(wpi->fd, handle, handle_walk_ppath_rec, wpli); + + path_component_free(wpli->pc); + free(wpli); + return ret; +} + +/* + * Call the given function on all known paths from the vfs root to the inode + * described in the handle. Returns 0 for success or positive errno. + */ +int +handle_walk_parent_paths( + void *hanp, + size_t hlen, + walk_path_fn fn, + void *arg) +{ + struct walk_ppaths_info wpi; + ssize_t ret; + + if (hlen != sizeof(struct xfs_handle)) + return EINVAL; + + wpi.fd = handle_to_fsfd(hanp, &wpi.mntpt); + if (wpi.fd < 0) + return errno; + wpi.path = path_list_init(); + if (!wpi.path) + return errno; + wpi.fn = fn; + wpi.arg = arg; + + ret = handle_walk_ppath(&wpi, hanp); + path_list_free(wpi.path); + + return ret; +} + +/* + * Call the given function on all known paths from the vfs root to the inode + * referred to by the file description. Returns 0 or positive errno. + */ +int +fd_walk_parent_paths( + int fd, + walk_path_fn fn, + void *arg) +{ + struct walk_ppaths_info wpi; + void *hanp; + size_t hlen; + int fsfd; + int ret; + + ret = fd_to_handle(fd, &hanp, &hlen); + if (ret) + return errno; + + fsfd = handle_to_fsfd(hanp, &wpi.mntpt); + if (fsfd < 0) + return errno; + wpi.fd = fd; + wpi.path = path_list_init(); + if (!wpi.path) + return errno; + wpi.fn = fn; + wpi.arg = arg; + + ret = handle_walk_ppath(&wpi, hanp); + path_list_free(wpi.path); + + return ret; +} + +struct path_walk_info { + char *buf; + size_t len; +}; + +/* Helper that stringifies the first full path that we find. */ +static int +handle_to_path_walk( + const char *mntpt, + const struct path_list *path, + void *arg) +{ + struct path_walk_info *pwi = arg; + int mntpt_len = strlen(mntpt); + int ret; + + /* Trim trailing slashes from the mountpoint */ + while (mntpt_len > 0 && mntpt[mntpt_len - 1] == '/') + mntpt_len--; + + ret = snprintf(pwi->buf, pwi->len, "%.*s", mntpt_len, mntpt); + if (ret != mntpt_len) + return ENAMETOOLONG; + + ret = path_list_to_string(path, pwi->buf + ret, pwi->len - ret); + if (ret < 0) + return ENAMETOOLONG; + + return ECANCELED; +} + +/* + * Return any eligible path to this file handle. Returns 0 for success or + * positive errno. + */ +int +handle_to_path( + void *hanp, + size_t hlen, + char *path, + size_t pathlen) +{ + struct path_walk_info pwi; + int ret; + + pwi.buf = path; + pwi.len = pathlen; + ret = handle_walk_parent_paths(hanp, hlen, handle_to_path_walk, &pwi); + if (ret == ECANCELED) + return 0; + return ret; +} + +/* + * Return any eligible path to this file description. Returns 0 for success + * or positive errno. + */ +int +fd_to_path( + int fd, + char *path, + size_t pathlen) +{ + struct path_walk_info pwi; + int ret; + + pwi.buf = path; + pwi.len = pathlen; + ret = fd_walk_parent_paths(fd, handle_to_path_walk, &pwi); + if (ret == ECANCELED) + return 0; + return ret; +} diff --git a/libfrog/getparents.h b/libfrog/getparents.h new file mode 100644 index 000000000..c95efed24 --- /dev/null +++ b/libfrog/getparents.h @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2023 Oracle. All Rights Reserved. + * Author: Darrick J. Wong + */ +#ifndef __LIBFROG_GETPARENTS_H_ +#define __LIBFROG_GETPARENTS_H_ + +struct path_list; + +struct parent_rec { + uint64_t p_ino; + uint32_t p_gen; + uint32_t p_flags; + unsigned char p_name[MAXNAMELEN]; +}; + +/* This is the root directory. */ +#define PARENT_IS_ROOT (1U << 0) + +typedef int (*walk_parent_fn)(const struct parent_rec *rec, void *arg); +typedef int (*walk_path_fn)(const char *mntpt, const struct path_list *path, + void *arg); + +int fd_walk_parents(int fd, walk_parent_fn fn, void *arg); +int handle_walk_parents(void *hanp, size_t hanlen, walk_parent_fn fn, + void *arg); + +int fd_walk_parent_paths(int fd, walk_path_fn fn, void *arg); +int handle_walk_parent_paths(void *hanp, size_t hanlen, walk_path_fn fn, + void *arg); + +int fd_to_path(int fd, char *path, size_t pathlen); +int handle_to_path(void *hanp, size_t hlen, char *path, size_t pathlen); + +#endif /* __LIBFROG_GETPARENTS_H_ */ diff --git a/libfrog/paths.c b/libfrog/paths.c index abb29a237..4b9c8c644 100644 --- a/libfrog/paths.c +++ b/libfrog/paths.c @@ -15,6 +15,7 @@ #include "paths.h" #include "input.h" #include "projects.h" +#include "list.h" #include extern char *progname; @@ -563,3 +564,169 @@ fs_table_insert_project_path( return error; } + +/* Structured path components. */ + +struct path_list { + struct list_head p_head; +}; + +struct path_component { + struct list_head pc_list; + uint64_t pc_ino; + char *pc_fname; +}; + +/* Initialize a path component with a given name. */ +struct path_component * +path_component_init( + const char *name, + uint64_t ino) +{ + struct path_component *pc; + + pc = malloc(sizeof(struct path_component)); + if (!pc) + return NULL; + INIT_LIST_HEAD(&pc->pc_list); + pc->pc_fname = strdup(name); + if (!pc->pc_fname) { + free(pc); + return NULL; + } + pc->pc_ino = ino; + return pc; +} + +/* Free a path component. */ +void +path_component_free( + struct path_component *pc) +{ + free(pc->pc_fname); + free(pc); +} + +/* Change a path component's filename or returns positive errno. */ +int +path_component_change( + struct path_component *pc, + const void *name, + size_t namelen, + uint64_t ino) +{ + void *p; + + p = realloc(pc->pc_fname, namelen + 1); + if (!p) + return errno; + pc->pc_fname = p; + memcpy(pc->pc_fname, name, namelen); + pc->pc_fname[namelen] = 0; + pc->pc_ino = ino; + return 0; +} + +/* Initialize a pathname or returns positive errno. */ +struct path_list * +path_list_init(void) +{ + struct path_list *path; + + path = malloc(sizeof(struct path_list)); + if (!path) + return NULL; + INIT_LIST_HEAD(&path->p_head); + return path; +} + +/* Empty out a pathname. */ +void +path_list_free( + struct path_list *path) +{ + struct path_component *pos; + struct path_component *n; + + list_for_each_entry_safe(pos, n, &path->p_head, pc_list) { + path_list_del_component(path, pos); + path_component_free(pos); + } + free(path); +} + +/* Add a parent component to a pathname. */ +void +path_list_add_parent_component( + struct path_list *path, + struct path_component *pc) +{ + list_add(&pc->pc_list, &path->p_head); +} + +/* Add a component to a pathname. */ +void +path_list_add_component( + struct path_list *path, + struct path_component *pc) +{ + list_add_tail(&pc->pc_list, &path->p_head); +} + +/* Remove a component from a pathname. */ +void +path_list_del_component( + struct path_list *path, + struct path_component *pc) +{ + list_del_init(&pc->pc_list); +} + +/* + * Convert a pathname into a string or returns -1 if the buffer isn't long + * enough. + */ +ssize_t +path_list_to_string( + const struct path_list *path, + char *buf, + size_t buflen) +{ + struct path_component *pos; + char *buf_end = buf + buflen; + ssize_t bytes = 0; + int ret; + + list_for_each_entry(pos, &path->p_head, pc_list) { + if (buf >= buf_end) + return -1; + + ret = snprintf(buf, buflen, "/%s", pos->pc_fname); + if (ret < 0 || ret >= buflen) + return -1; + + bytes += ret; + buf += ret; + buflen -= ret; + } + return bytes; +} + +/* Walk each component of a path. */ +int +path_walk_components( + const struct path_list *path, + path_walk_fn_t fn, + void *arg) +{ + struct path_component *pos; + int ret; + + list_for_each_entry(pos, &path->p_head, pc_list) { + ret = fn(pos->pc_fname, pos->pc_ino, arg); + if (ret) + return ret; + } + + return 0; +} diff --git a/libfrog/paths.h b/libfrog/paths.h index f20a2c3ef..6be74c42b 100644 --- a/libfrog/paths.h +++ b/libfrog/paths.h @@ -58,4 +58,29 @@ typedef struct fs_cursor { extern void fs_cursor_initialise(char *__dir, uint __flags, fs_cursor_t *__cp); extern fs_path_t *fs_cursor_next_entry(fs_cursor_t *__cp); +/* Path information. */ + +struct path_list; +struct path_component; + +struct path_component *path_component_init(const char *name, uint64_t ino); +void path_component_free(struct path_component *pc); +int path_component_change(struct path_component *pc, const void *name, + size_t namelen, uint64_t ino); + +struct path_list *path_list_init(void); +void path_list_free(struct path_list *path); +void path_list_add_parent_component(struct path_list *path, + struct path_component *pc); +void path_list_add_component(struct path_list *path, struct path_component *pc); +void path_list_del_component(struct path_list *path, struct path_component *pc); + +ssize_t path_list_to_string(const struct path_list *path, char *buf, + size_t buflen); + +typedef int (*path_walk_fn_t)(const char *name, uint64_t ino, void *arg); + +int path_walk_components(const struct path_list *path, path_walk_fn_t fn, + void *arg); + #endif /* __LIBFROG_PATH_H__ */ diff --git a/libhandle/handle.c b/libhandle/handle.c index 333c21909..1e8fe9ac5 100644 --- a/libhandle/handle.c +++ b/libhandle/handle.c @@ -29,7 +29,6 @@ typedef union { } comarg_t; static int obj_to_handle(char *, int, unsigned int, comarg_t, void**, size_t*); -static int handle_to_fsfd(void *, char **); static char *path_to_fspath(char *path); @@ -203,8 +202,10 @@ handle_to_fshandle( return 0; } -static int -handle_to_fsfd(void *hanp, char **path) +int +handle_to_fsfd( + void *hanp, + char **path) { struct fdhash *fdhp; From patchwork Thu Apr 6 19:36:30 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: 13203982 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 79B98C7618D for ; Thu, 6 Apr 2023 19:36:36 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233368AbjDFTgf (ORCPT ); Thu, 6 Apr 2023 15:36:35 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37938 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229610AbjDFTge (ORCPT ); Thu, 6 Apr 2023 15:36:34 -0400 Received: from dfw.source.kernel.org (dfw.source.kernel.org [139.178.84.217]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 50EDC4EFA for ; Thu, 6 Apr 2023 12:36:32 -0700 (PDT) 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 dfw.source.kernel.org (Postfix) with ESMTPS id D23A462C5A for ; Thu, 6 Apr 2023 19:36:31 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 3BBF4C433D2; Thu, 6 Apr 2023 19:36:31 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1680809791; bh=kYO6QMnZGlYxP6mbdbdfhw/y5a1BP7Y9BAKmsxopJ+8=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=mRakSiR1VS2DKOacAoHbTBAl1vYupUJf5LwQr7pH90J6TncCAYv0n+CEEKtZqoHWd a7za6RB2IDVicw2F5wFYHniNmjd6vZIRmRaN+JQN0yfieicWkm0MyoU6pCZb96CaRf 2AZ4ahVahoP5foUdKxC8V+CvVsdm4y/avtHAw8BGK6s3HYVQnbELWyumFfyQyUiN4I 0HDPk+fMJPRwyUq112pq1l3MAOWRqY2lIEfPnb6LgS5tHjgQSvCOqIviloK65A6yhg bY1UZT6blZfrBCP2X/AXmJQrToJZURuGIn5GZsmwK04tXhQHb5z06/mfGLAvp8Wdcc dPrncbgcL5jog== Date: Thu, 06 Apr 2023 12:36:30 -0700 Subject: [PATCH 19/32] xfs_io: adapt parent command to new parent pointer ioctls From: "Darrick J. Wong" To: djwong@kernel.org Cc: Allison Henderson , allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <168080827807.616793.4373205164397932253.stgit@frogsfrogsfrogs> In-Reply-To: <168080827546.616793.7264157843231723676.stgit@frogsfrogsfrogs> References: <168080827546.616793.7264157843231723676.stgit@frogsfrogsfrogs> 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 For ages, xfs_io has had a totally useless 'parent' command that enabled callers to walk the parents or print the directory tree path of an open file. This code used the ioctl interface presented by SGI's version of parent pointers that was never merged. Rework the code in here to use the new ioctl interfaces that we've settled upon. Get rid of the old parent pointer checking code since xfs_repair/xfs_scrub will take care of that. (This originally was in the "xfsprogs: implement the upper half of parent pointers" megapatch.) Signed-off-by: Allison Henderson Signed-off-by: Darrick J. Wong --- io/parent.c | 470 ++++++++++++++--------------------------------------- man/man8/xfs_io.8 | 21 +- 2 files changed, 133 insertions(+), 358 deletions(-) diff --git a/io/parent.c b/io/parent.c index 8f63607ff..65fd892bf 100644 --- a/io/parent.c +++ b/io/parent.c @@ -7,365 +7,112 @@ #include "command.h" #include "input.h" #include "libfrog/paths.h" -#include "parent.h" +#include "libfrog/getparents.h" #include "handle.h" -#include "jdm.h" #include "init.h" #include "io.h" -#define PARENTBUF_SZ 16384 -#define BSTATBUF_SZ 16384 - static cmdinfo_t parent_cmd; -static int verbose_flag; -static int err_status; -static __u64 inodes_checked; static char *mntpt; -/* - * check out a parent entry to see if the values seem valid - */ -static void -check_parent_entry(struct xfs_bstat *bstatp, parent_t *parent) +static int +pptr_print( + const struct parent_rec *rec, + void *arg) { - int sts; - char fullpath[PATH_MAX]; - struct stat statbuf; - char *str; - - sprintf(fullpath, _("%s%s"), mntpt, parent->p_name); - - sts = lstat(fullpath, &statbuf); - if (sts != 0) { - fprintf(stderr, - _("inode-path for inode: %llu is incorrect - path \"%s\" non-existent\n"), - (unsigned long long) bstatp->bs_ino, fullpath); - if (verbose_flag) { - fprintf(stderr, - _("path \"%s\" does not stat for inode: %llu; err = %s\n"), - fullpath, - (unsigned long long) bstatp->bs_ino, - strerror(errno)); - } - err_status++; - return; - } else { - if (verbose_flag > 1) { - printf(_("path \"%s\" found\n"), fullpath); - } - } - - if (statbuf.st_ino != bstatp->bs_ino) { - fprintf(stderr, - _("inode-path for inode: %llu is incorrect - wrong inode#\n"), - (unsigned long long) bstatp->bs_ino); - if (verbose_flag) { - fprintf(stderr, - _("ino mismatch for path \"%s\" %llu vs %llu\n"), - fullpath, - (unsigned long long)statbuf.st_ino, - (unsigned long long)bstatp->bs_ino); - } - err_status++; - return; - } else if (verbose_flag > 1) { - printf(_("inode number match: %llu\n"), - (unsigned long long)statbuf.st_ino); - } + const char *name = (char *)rec->p_name; + unsigned int namelen; - /* get parent path */ - str = strrchr(fullpath, '/'); - *str = '\0'; - sts = stat(fullpath, &statbuf); - if (sts != 0) { - fprintf(stderr, - _("parent path \"%s\" does not stat: %s\n"), - fullpath, - strerror(errno)); - err_status++; - return; - } else { - if (parent->p_ino != statbuf.st_ino) { - fprintf(stderr, - _("inode-path for inode: %llu is incorrect - wrong parent inode#\n"), - (unsigned long long) bstatp->bs_ino); - if (verbose_flag) { - fprintf(stderr, - _("ino mismatch for path \"%s\" %llu vs %llu\n"), - fullpath, - (unsigned long long)parent->p_ino, - (unsigned long long)statbuf.st_ino); - } - err_status++; - return; - } else { - if (verbose_flag > 1) { - printf(_("parent ino match for %llu\n"), - (unsigned long long) parent->p_ino); - } - } + if (rec->p_flags & PARENT_IS_ROOT) { + printf(_("Root directory.\n")); + return 0; } -} - -static void -check_parents(parent_t *parentbuf, size_t *parentbuf_size, - jdm_fshandle_t *fshandlep, struct xfs_bstat *statp) -{ - int error, i; - __u32 count; - parent_t *entryp; - - do { - error = jdm_parentpaths(fshandlep, statp, parentbuf, *parentbuf_size, &count); - - if (error == ERANGE) { - *parentbuf_size *= 2; - parentbuf = (parent_t *)realloc(parentbuf, *parentbuf_size); - } else if (error) { - fprintf(stderr, _("parentpaths failed for ino %llu: %s\n"), - (unsigned long long) statp->bs_ino, - strerror(errno)); - err_status++; - break; - } - } while (error == ERANGE); - - if (count == 0) { - /* no links for inode - something wrong here */ - fprintf(stderr, _("inode-path for inode: %llu is missing\n"), - (unsigned long long) statp->bs_ino); - err_status++; - } + namelen = strlen(name); + printf(_("p_ino = %llu\n"), (unsigned long long)rec->p_ino); + printf(_("p_gen = %u\n"), (unsigned int)rec->p_gen); + printf(_("p_namelen = %u\n"), namelen); + printf(_("p_name = \"%s\"\n\n"), rec->p_name); - entryp = parentbuf; - for (i = 0; i < count; i++) { - check_parent_entry(statp, entryp); - entryp = (parent_t*) (((char*)entryp) + entryp->p_reclen); - } + return 0; } static int -do_bulkstat(parent_t *parentbuf, size_t *parentbuf_size, - struct xfs_bstat *bstatbuf, int fsfd, jdm_fshandle_t *fshandlep) +print_parents( + struct xfs_handle *handle) { - __s32 buflenout; - __u64 lastino = 0; - struct xfs_bstat *p; - struct xfs_bstat *endp; - struct xfs_fsop_bulkreq bulkreq; - struct stat mntstat; - - if (stat(mntpt, &mntstat)) { - fprintf(stderr, _("can't stat mount point \"%s\": %s\n"), - mntpt, strerror(errno)); - return 1; - } - - bulkreq.lastip = &lastino; - bulkreq.icount = BSTATBUF_SZ; - bulkreq.ubuffer = (void *)bstatbuf; - bulkreq.ocount = &buflenout; - - while (xfsctl(mntpt, fsfd, XFS_IOC_FSBULKSTAT, &bulkreq) == 0) { - if (*(bulkreq.ocount) == 0) { - return 0; - } - for (p = bstatbuf, endp = bstatbuf + *bulkreq.ocount; p < endp; p++) { - - /* inode being modified, get synced data with iget */ - if ( (!p->bs_nlink || !p->bs_mode) && p->bs_ino != 0 ) { - - if (xfsctl(mntpt, fsfd, XFS_IOC_FSBULKSTAT_SINGLE, &bulkreq) < 0) { - fprintf(stderr, - _("failed to get bulkstat information for inode %llu\n"), - (unsigned long long) p->bs_ino); - continue; - } - if (!p->bs_nlink || !p->bs_mode || !p->bs_ino) { - fprintf(stderr, - _("failed to get valid bulkstat information for inode %llu\n"), - (unsigned long long) p->bs_ino); - continue; - } - } - - /* skip root */ - if (p->bs_ino == mntstat.st_ino) { - continue; - } - - if (verbose_flag > 1) { - printf(_("checking inode %llu\n"), - (unsigned long long) p->bs_ino); - } - - /* print dotted progress */ - if ((inodes_checked % 100) == 0 && verbose_flag == 1) { - printf("."); fflush(stdout); - } - inodes_checked++; - - check_parents(parentbuf, parentbuf_size, fshandlep, p); - } + int ret; - }/*while*/ + if (handle) + ret = handle_walk_parents(handle, sizeof(*handle), pptr_print, + NULL); + else + ret = fd_walk_parents(file->fd, pptr_print, NULL); + if (ret) + fprintf(stderr, "%s: %s\n", file->name, strerror(ret)); - fprintf(stderr, _("syssgi bulkstat failed: %s\n"), strerror(errno)); - return 1; + return 0; } static int -parent_check(void) +path_print( + const char *mntpt, + const struct path_list *path, + void *arg) { - int fsfd; - jdm_fshandle_t *fshandlep; - parent_t *parentbuf; - size_t parentbuf_size = PARENTBUF_SZ; - struct xfs_bstat *bstatbuf; - - err_status = 0; - inodes_checked = 0; - - sync(); - - fsfd = file->fd; - - fshandlep = jdm_getfshandle(mntpt); - if (fshandlep == NULL) { - fprintf(stderr, _("unable to open \"%s\" for jdm: %s\n"), - mntpt, - strerror(errno)); - return 1; - } + char buf[PATH_MAX]; + size_t len = PATH_MAX; + int mntpt_len = strlen(mntpt); + int ret; - /* allocate buffers */ - bstatbuf = (struct xfs_bstat *)calloc(BSTATBUF_SZ, sizeof(struct xfs_bstat)); - parentbuf = (parent_t *)malloc(parentbuf_size); - if (!bstatbuf || !parentbuf) { - fprintf(stderr, _("unable to allocate buffers: %s\n"), - strerror(errno)); - err_status = 1; - goto out; - } - - if (do_bulkstat(parentbuf, &parentbuf_size, bstatbuf, fsfd, fshandlep) != 0) - err_status++; + /* Trim trailing slashes from the mountpoint */ + while (mntpt_len > 0 && mntpt[mntpt_len - 1] == '/') + mntpt_len--; - if (err_status > 0) - fprintf(stderr, _("num errors: %d\n"), err_status); - else - printf(_("succeeded checking %llu inodes\n"), - (unsigned long long) inodes_checked); + ret = snprintf(buf, len, "%.*s", mntpt_len, mntpt); + if (ret != mntpt_len) + return ENAMETOOLONG; -out: - free(bstatbuf); - free(parentbuf); - free(fshandlep); - return err_status; -} + ret = path_list_to_string(path, buf + ret, len - ret); + if (ret < 0) + return ENAMETOOLONG; -static void -print_parent_entry(parent_t *parent, int fullpath) -{ - printf(_("p_ino = %llu\n"), (unsigned long long) parent->p_ino); - printf(_("p_gen = %u\n"), parent->p_gen); - printf(_("p_reclen = %u\n"), parent->p_reclen); - if (fullpath) - printf(_("p_name = \"%s%s\"\n"), mntpt, parent->p_name); - else - printf(_("p_name = \"%s\"\n"), parent->p_name); + printf("%s\n", buf); + return 0; } static int -parent_list(int fullpath) +print_paths( + struct xfs_handle *handle) { - void *handlep = NULL; - size_t handlen; - int error, i; - int retval = 1; - __u32 count; - parent_t *entryp; - parent_t *parentbuf = NULL; - char *path = file->name; - int pb_size = PARENTBUF_SZ; + int ret; - /* XXXX for linux libhandle version - to set libhandle fsfd cache */ - { - void *fshandle; - size_t fshlen; - - if (path_to_fshandle(mntpt, &fshandle, &fshlen) != 0) { - fprintf(stderr, _("%s: failed path_to_fshandle \"%s\": %s\n"), - progname, path, strerror(errno)); - goto error; - } - free_handle(fshandle, fshlen); - } - - if (path_to_handle(path, &handlep, &handlen) != 0) { - fprintf(stderr, _("%s: path_to_handle failed for \"%s\"\n"), progname, path); - goto error; - } - - do { - parentbuf = (parent_t *)realloc(parentbuf, pb_size); - if (!parentbuf) { - fprintf(stderr, _("%s: unable to allocate parent buffer: %s\n"), - progname, strerror(errno)); - goto error; - } - - if (fullpath) { - error = parentpaths_by_handle(handlep, - handlen, - parentbuf, - pb_size, - &count); - } else { - error = parents_by_handle(handlep, - handlen, - parentbuf, - pb_size, - &count); - } - if (error == ERANGE) { - pb_size *= 2; - } else if (error) { - fprintf(stderr, _("%s: %s call failed for \"%s\": %s\n"), - progname, fullpath ? "parentpaths" : "parents", - path, strerror(errno)); - goto error; - } - } while (error == ERANGE); - - if (count == 0) { - /* no links for inode - something wrong here */ - fprintf(stderr, _("%s: inode-path is missing\n"), progname); - goto error; - } - - entryp = parentbuf; - for (i = 0; i < count; i++) { - print_parent_entry(entryp, fullpath); - entryp = (parent_t*) (((char*)entryp) + entryp->p_reclen); - } - - retval = 0; -error: - free(handlep); - free(parentbuf); - return retval; + if (handle) + ret = handle_walk_parent_paths(handle, sizeof(*handle), + path_print, NULL); + else + ret = fd_walk_parent_paths(file->fd, path_print, NULL); + if (ret) + fprintf(stderr, "%s: %s\n", file->name, strerror(ret)); + return 0; } static int -parent_f(int argc, char **argv) +parent_f( + int argc, + char **argv) { - int c; - int listpath_flag = 0; - int check_flag = 0; - fs_path_t *fs; - static int tab_init; + struct xfs_handle handle; + void *hanp = NULL; + size_t hlen; + struct fs_path *fs; + char *p; + uint64_t ino = 0; + uint32_t gen = 0; + int c; + int listpath_flag = 0; + int ret; + static int tab_init; if (!tab_init) { tab_init = 1; @@ -380,46 +127,74 @@ parent_f(int argc, char **argv) } mntpt = fs->fs_dir; - verbose_flag = 0; - - while ((c = getopt(argc, argv, "cpv")) != EOF) { + while ((c = getopt(argc, argv, "p")) != EOF) { switch (c) { - case 'c': - check_flag = 1; - break; case 'p': listpath_flag = 1; break; - case 'v': - verbose_flag++; - break; default: return command_usage(&parent_cmd); } } - if (!check_flag && !listpath_flag) /* default case */ - exitcode = parent_list(listpath_flag); - else { - if (listpath_flag) - exitcode = parent_list(listpath_flag); - if (check_flag) - exitcode = parent_check(); + /* + * Always initialize the fshandle table because we need it for + * the ppaths functions to work. + */ + ret = path_to_fshandle((char *)mntpt, &hanp, &hlen); + if (ret) { + perror(mntpt); + return 0; } + if (optind + 2 == argc) { + ino = strtoull(argv[optind], &p, 0); + if (*p != '\0' || ino == 0) { + fprintf(stderr, + _("Bad inode number '%s'.\n"), + argv[optind]); + return 0; + } + gen = strtoul(argv[optind + 1], &p, 0); + if (*p != '\0') { + fprintf(stderr, + _("Bad generation number '%s'.\n"), + argv[optind + 1]); + return 0; + } + + memcpy(&handle, hanp, sizeof(handle)); + handle.ha_fid.fid_len = sizeof(xfs_fid_t) - + sizeof(handle.ha_fid.fid_len); + handle.ha_fid.fid_pad = 0; + handle.ha_fid.fid_ino = ino; + handle.ha_fid.fid_gen = gen; + + } else if (optind != argc) { + return command_usage(&parent_cmd); + } + + if (listpath_flag) + exitcode = print_paths(ino ? &handle : NULL); + else + exitcode = print_parents(ino ? &handle : NULL); + + if (hanp) + free_handle(hanp, hlen); + return 0; } static void parent_help(void) { - printf(_( +printf(_( "\n" " list the current file's parents and their filenames\n" "\n" -" -c -- check the current file's file system for parent consistency\n" -" -p -- list the current file's parents and their full paths\n" -" -v -- verbose mode\n" +" -p -- list the current file's paths up to the root\n" +"\n" +"If ino and gen are supplied, use them instead.\n" "\n")); } @@ -430,11 +205,10 @@ parent_init(void) parent_cmd.cfunc = parent_f; parent_cmd.argmin = 0; parent_cmd.argmax = -1; - parent_cmd.args = _("[-cpv]"); + parent_cmd.args = _("[-p] [ino gen]"); parent_cmd.flags = CMD_NOMAP_OK; - parent_cmd.oneline = _("print or check parent inodes"); + parent_cmd.oneline = _("print parent inodes"); parent_cmd.help = parent_help; - if (expert) - add_command(&parent_cmd); + add_command(&parent_cmd); } diff --git a/man/man8/xfs_io.8 b/man/man8/xfs_io.8 index ef7087b3d..57ebe3a52 100644 --- a/man/man8/xfs_io.8 +++ b/man/man8/xfs_io.8 @@ -961,25 +961,26 @@ and options behave as described above, in .B chproj. .TP -.BR parent " [ " \-cpv " ]" +.BR parent " [ " \-p " ] [" " ino gen " "]" By default this command prints out the parent inode numbers, inode generation numbers and basenames of all the hardlinks which point to the inode of the current file. + +If the optional +.B ino +and +.B gen +parameters are provided, they will be used to create a file handle on the same +filesystem as the open file. +The parents of the file represented by the handle will be reported instead of +the open file. + .RS 1.0i .PD 0 .TP 0.4i .B \-p the output is similar to the default output except pathnames up to the mount-point are printed out instead of the component name. -.TP -.B \-c -the file's filesystem will check all the parent attributes for consistency. -.TP -.B \-v -verbose output will be printed. -.RE -.IP -.B [NOTE: Not currently operational on Linux.] .RE .PD .TP From patchwork Thu Apr 6 19:36:46 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: 13203983 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 9CFF2C7618D for ; Thu, 6 Apr 2023 19:36:50 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229463AbjDFTgt (ORCPT ); Thu, 6 Apr 2023 15:36:49 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38040 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229458AbjDFTgs (ORCPT ); Thu, 6 Apr 2023 15:36:48 -0400 Received: from dfw.source.kernel.org (dfw.source.kernel.org [IPv6:2604:1380:4641:c500::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id CC0D25243 for ; Thu, 6 Apr 2023 12:36:47 -0700 (PDT) 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 dfw.source.kernel.org (Postfix) with ESMTPS id 6900764B89 for ; Thu, 6 Apr 2023 19:36:47 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id C3D1AC433EF; Thu, 6 Apr 2023 19:36:46 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1680809806; bh=DmpGJmPjRk85qRX40UBFrBfPdbFqbWlSVzmlGdBs3dU=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=iHXCl7pl8JhPFAQ1FKXTYNAzgtJLGNqA1UEFbo2U2ylxKo9XYjUwqkBD6UoCzifx9 CEwYKDccCOD9Itujsp17tkca2c1cdXy6DeVsf8YzAVa7ctT83K/0XBOGilmR2VPYz4 nPuqfSMDC0Yn+r0ziy4E57Z1EhnnyQfwTslvSeAn+QT/P69Mv0C4P+PUu/nt/XbTV7 yXLu8On1YIiXA16C53wvJ5e15aTTCTu8Xm0a2EAd3gyYObyV8FNaziTOgXfgZfkeH/ UfySaeoZIafC/xHSQ0U3Osmu1kdETfceGb7nmJO9O8WRVtcseXeuz9QS/p0UPyZVqp S80UGZ4cxOVMQ== Date: Thu, 06 Apr 2023 12:36:46 -0700 Subject: [PATCH 20/32] xfs_io: Add i, n and f flags to parent command From: "Darrick J. Wong" To: djwong@kernel.org Cc: Allison Henderson , allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <168080827820.616793.9913618161221224360.stgit@frogsfrogsfrogs> In-Reply-To: <168080827546.616793.7264157843231723676.stgit@frogsfrogsfrogs> References: <168080827546.616793.7264157843231723676.stgit@frogsfrogsfrogs> 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 This patch adds the flags i, n, and f to the parent command. These flags add filtering options that are used by the new parent pointer tests in xfstests, and help to improve the test run time. The flags are: -i: Only show parent pointer records containing the given inode -n: Only show parent pointer records containing the given filename -f: Print records in short format: ino/gen/namelen/name Signed-off-by: Allison Henderson [djwong: adapt to new getparents ioctl] Reviewed-by: Darrick J. Wong --- io/parent.c | 89 +++++++++++++++++++++++++++++++++++++++++++++++------ man/man8/xfs_io.8 | 11 ++++++- 2 files changed, 89 insertions(+), 11 deletions(-) diff --git a/io/parent.c b/io/parent.c index 65fd892bf..6bb7571e1 100644 --- a/io/parent.c +++ b/io/parent.c @@ -15,11 +15,18 @@ static cmdinfo_t parent_cmd; static char *mntpt; +struct pptr_args { + uint64_t filter_ino; + char *filter_name; + bool shortformat; +}; + static int pptr_print( const struct parent_rec *rec, void *arg) { + struct pptr_args *args = arg; const char *name = (char *)rec->p_name; unsigned int namelen; @@ -28,7 +35,22 @@ pptr_print( return 0; } + if (args->filter_ino && rec->p_ino != args->filter_ino) + return 0; + if (args->filter_name && strcmp(args->filter_name, name)) + return 0; + namelen = strlen(name); + + if (args->shortformat) { + printf("%llu/%u/%u/%s\n", + (unsigned long long)rec->p_ino, + (unsigned int)rec->p_gen, + namelen, + rec->p_name); + return 0; + } + printf(_("p_ino = %llu\n"), (unsigned long long)rec->p_ino); printf(_("p_gen = %u\n"), (unsigned int)rec->p_gen); printf(_("p_namelen = %u\n"), namelen); @@ -39,32 +61,55 @@ pptr_print( static int print_parents( - struct xfs_handle *handle) + struct xfs_handle *handle, + struct pptr_args *args) { int ret; if (handle) ret = handle_walk_parents(handle, sizeof(*handle), pptr_print, - NULL); + args); else - ret = fd_walk_parents(file->fd, pptr_print, NULL); + ret = fd_walk_parents(file->fd, pptr_print, args); if (ret) fprintf(stderr, "%s: %s\n", file->name, strerror(ret)); return 0; } +static int +filter_path_components( + const char *name, + uint64_t ino, + void *arg) +{ + struct pptr_args *args = arg; + + if (args->filter_ino && ino == args->filter_ino) + return ECANCELED; + if (args->filter_name && !strcmp(args->filter_name, name)) + return ECANCELED; + return 0; +} + static int path_print( const char *mntpt, const struct path_list *path, void *arg) { + struct pptr_args *args = arg; char buf[PATH_MAX]; size_t len = PATH_MAX; int mntpt_len = strlen(mntpt); int ret; + if (args->filter_ino || args->filter_name) { + ret = path_walk_components(path, filter_path_components, args); + if (ret != ECANCELED) + return 0; + } + /* Trim trailing slashes from the mountpoint */ while (mntpt_len > 0 && mntpt[mntpt_len - 1] == '/') mntpt_len--; @@ -83,15 +128,16 @@ path_print( static int print_paths( - struct xfs_handle *handle) + struct xfs_handle *handle, + struct pptr_args *args) { int ret; if (handle) ret = handle_walk_parent_paths(handle, sizeof(*handle), - path_print, NULL); + path_print, args); else - ret = fd_walk_parent_paths(file->fd, path_print, NULL); + ret = fd_walk_parent_paths(file->fd, path_print, args); if (ret) fprintf(stderr, "%s: %s\n", file->name, strerror(ret)); return 0; @@ -103,6 +149,7 @@ parent_f( char **argv) { struct xfs_handle handle; + struct pptr_args args = { 0 }; void *hanp = NULL; size_t hlen; struct fs_path *fs; @@ -127,11 +174,27 @@ parent_f( } mntpt = fs->fs_dir; - while ((c = getopt(argc, argv, "p")) != EOF) { + while ((c = getopt(argc, argv, "pfi:n:")) != EOF) { switch (c) { case 'p': listpath_flag = 1; break; + case 'i': + args.filter_ino = strtoull(optarg, &p, 0); + if (*p != '\0' || args.filter_ino == 0) { + fprintf(stderr, + _("Bad inode number '%s'.\n"), + optarg); + return 0; + } + + break; + case 'n': + args.filter_name = optarg; + break; + case 'f': + args.shortformat = true; + break; default: return command_usage(&parent_cmd); } @@ -175,9 +238,9 @@ parent_f( } if (listpath_flag) - exitcode = print_paths(ino ? &handle : NULL); + exitcode = print_paths(ino ? &handle : NULL, &args); else - exitcode = print_parents(ino ? &handle : NULL); + exitcode = print_parents(ino ? &handle : NULL, &args); if (hanp) free_handle(hanp, hlen); @@ -195,6 +258,12 @@ printf(_( " -p -- list the current file's paths up to the root\n" "\n" "If ino and gen are supplied, use them instead.\n" +"\n" +" -i -- Only show parent pointer records containing the given inode\n" +"\n" +" -n -- Only show parent pointer records containing the given filename\n" +"\n" +" -f -- Print records in short format: ino/gen/namelen/filename\n" "\n")); } @@ -205,7 +274,7 @@ parent_init(void) parent_cmd.cfunc = parent_f; parent_cmd.argmin = 0; parent_cmd.argmax = -1; - parent_cmd.args = _("[-p] [ino gen]"); + parent_cmd.args = _("[-p] [ino gen] [-i ino] [-n name] [-f]"); parent_cmd.flags = CMD_NOMAP_OK; parent_cmd.oneline = _("print parent inodes"); parent_cmd.help = parent_help; diff --git a/man/man8/xfs_io.8 b/man/man8/xfs_io.8 index 57ebe3a52..7c88784a1 100644 --- a/man/man8/xfs_io.8 +++ b/man/man8/xfs_io.8 @@ -961,7 +961,7 @@ and options behave as described above, in .B chproj. .TP -.BR parent " [ " \-p " ] [" " ino gen " "]" +.BR parent " [ " \-fp " ] [-i " ino "] [-n " name "] [" " ino gen " "]" By default this command prints out the parent inode numbers, inode generation numbers and basenames of all the hardlinks which point to the inode of the current file. @@ -978,6 +978,15 @@ the open file. .RS 1.0i .PD 0 .TP 0.4i +.B \-f +Print records in short format: ino/gen/namelen/name +.TP 0.4i +.B \-i +Only show parent pointer records containing this inode number. +.TP 0.4i +.B \-n +Only show parent pointer records containing this directory entry name. +.TP 0.4i .B \-p the output is similar to the default output except pathnames up to the mount-point are printed out instead of the component name. From patchwork Thu Apr 6 19:37:02 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: 13203984 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 8F35AC76196 for ; Thu, 6 Apr 2023 19:37:06 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229806AbjDFThF (ORCPT ); Thu, 6 Apr 2023 15:37:05 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38244 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229610AbjDFThE (ORCPT ); Thu, 6 Apr 2023 15:37:04 -0400 Received: from dfw.source.kernel.org (dfw.source.kernel.org [139.178.84.217]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 91E52E72 for ; Thu, 6 Apr 2023 12:37:03 -0700 (PDT) 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 dfw.source.kernel.org (Postfix) with ESMTPS id 08E3164B89 for ; Thu, 6 Apr 2023 19:37:03 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 63F07C433EF; Thu, 6 Apr 2023 19:37:02 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1680809822; bh=sgNtJhpUzv8T32i+1w34lBRcFN1SPYu+zo1MIIWGZcI=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=n/B41I23RSp8XaLkrOrl5eae3iZ/wR6xcoBi9+YMHru1IkGu8ckyTM1mqOZMxOmes HSpurV8ZHqL+/grjARBLlzCwvcJoHcu3xuGjw3t0fiPUdMC2YXBajOkV4021eaVD6F bizVTyf1K/D8KJY8+v2qXas2dcxevByeSorDiVYYc2x60cd1zipnDVaJCUtx/j2ldz glfyJTeSqvLheav/urgz8fvsAbnvJGs9+phQL+BqpLC80rKB5LR9euI+U1A2OFL/Ox ini70zslhF/c7feLWyi7c69hW1UOYn6dZ1G5vEiBcb5GUU0pgaR8pKHa6sFhOgRjHx rvhc/fZS0wEcA== Date: Thu, 06 Apr 2023 12:37:02 -0700 Subject: [PATCH 21/32] xfs_logprint: decode parent pointers in ATTRI items fully From: "Darrick J. Wong" To: djwong@kernel.org Cc: Allison Henderson , allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <168080827833.616793.9679802078608173155.stgit@frogsfrogsfrogs> In-Reply-To: <168080827546.616793.7264157843231723676.stgit@frogsfrogsfrogs> References: <168080827546.616793.7264157843231723676.stgit@frogsfrogsfrogs> 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 This patch modifies the ATTRI print routines to look for the parent pointer flag, and decode logged parent pointers fully when dumping log contents. Between the existing ATTRI: printouts and the new ones introduced here, we can figure out what was stored in each log iovec, as well as the higher level parent pointer that was logged. Signed-off-by: Allison Henderson Reviewed-by: Darrick J. Wong [djwong: adjust to new ondisk format] Signed-off-by: Darrick J. Wong --- libxfs/libxfs_api_defs.h | 4 ++ logprint/log_redo.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+) diff --git a/libxfs/libxfs_api_defs.h b/libxfs/libxfs_api_defs.h index f8efcce77..092934935 100644 --- a/libxfs/libxfs_api_defs.h +++ b/libxfs/libxfs_api_defs.h @@ -139,6 +139,10 @@ #define xfs_log_get_max_trans_res libxfs_log_get_max_trans_res #define xfs_log_sb libxfs_log_sb #define xfs_mode_to_ftype libxfs_mode_to_ftype +#define xfs_parent_add libxfs_parent_add +#define xfs_parent_finish libxfs_parent_finish +#define xfs_parent_irec_from_disk libxfs_parent_irec_from_disk +#define xfs_parent_start libxfs_parent_start #define xfs_perag_get libxfs_perag_get #define xfs_perag_put libxfs_perag_put #define xfs_prealloc_blocks libxfs_prealloc_blocks diff --git a/logprint/log_redo.c b/logprint/log_redo.c index 8b6aa9279..a8a367bb0 100644 --- a/logprint/log_redo.c +++ b/logprint/log_redo.c @@ -674,6 +674,59 @@ xfs_attri_copy_log_format( return 1; } +static void +dump_pptr( + const char *tag, + const void *name_ptr, + unsigned int name_len, + const void *value_ptr, + unsigned int value_len) +{ + struct xfs_parent_name_irec irec; + + if (name_len < sizeof(struct xfs_parent_name_rec)) { + printf("PPTR: %s CORRUPT\n", tag); + return; + } + + libxfs_parent_irec_from_disk(&irec, name_ptr, value_ptr, value_len); + + printf("PPTR: %s attr_namelen %u attr_valuelen %u\n", tag, name_len, value_len); + printf("PPTR: %s parent_ino %llu parent_gen %u namehash 0x%x namelen %u name '%.*s'\n", + tag, + (unsigned long long)irec.p_ino, + irec.p_gen, + irec.p_namehash, + irec.p_namelen, + irec.p_namelen, + irec.p_name); +} + +static void +dump_pptr_update( + const void *name_ptr, + unsigned int name_len, + const void *new_name_ptr, + unsigned int new_name_len, + const void *value_ptr, + unsigned int value_len, + const void *new_value_ptr, + unsigned int new_value_len) +{ + if (new_name_ptr && name_ptr) { + dump_pptr("OLDNAME", name_ptr, name_len, value_ptr, value_len); + dump_pptr("NEWNAME", new_name_ptr, new_name_len, new_value_ptr, + new_value_len); + return; + } + + if (name_ptr) + dump_pptr("NAME", name_ptr, name_len, value_ptr, value_len); + if (new_name_ptr) + dump_pptr("NEWNAME", new_name_ptr, new_name_len, new_value_ptr, + new_value_len); +} + static inline unsigned int xfs_attr_log_item_op(const struct xfs_attri_log_format *attrp) { @@ -688,6 +741,10 @@ xlog_print_trans_attri( { struct xfs_attri_log_format *src_f = NULL; xlog_op_header_t *head = NULL; + void *name_ptr = NULL; + void *new_name_ptr = NULL; + void *value_ptr = NULL; + void *new_value_ptr = NULL; uint dst_len; unsigned int name_len = 0; unsigned int new_name_len = 0; @@ -741,6 +798,7 @@ xlog_print_trans_attri( (*i)++; head = (xlog_op_header_t *)*ptr; xlog_print_op_header(head, *i, ptr); + name_ptr = *ptr; error = xlog_print_trans_attri_name(ptr, be32_to_cpu(head->oh_len), "name"); if (error) @@ -752,6 +810,7 @@ xlog_print_trans_attri( (*i)++; head = (xlog_op_header_t *)*ptr; xlog_print_op_header(head, *i, ptr); + new_name_ptr = *ptr; error = xlog_print_trans_attri_name(ptr, be32_to_cpu(head->oh_len), "newname"); if (error) @@ -763,6 +822,7 @@ xlog_print_trans_attri( (*i)++; head = (xlog_op_header_t *)*ptr; xlog_print_op_header(head, *i, ptr); + value_ptr = *ptr; error = xlog_print_trans_attri_value(ptr, be32_to_cpu(head->oh_len), value_len, "value"); if (error) @@ -774,12 +834,19 @@ xlog_print_trans_attri( (*i)++; head = (xlog_op_header_t *)*ptr; xlog_print_op_header(head, *i, ptr); + new_value_ptr = *ptr; error = xlog_print_trans_attri_value(ptr, be32_to_cpu(head->oh_len), new_value_len, "newvalue"); if (error) goto error; } + + if (src_f->alfi_attr_filter & XFS_ATTR_PARENT) + dump_pptr_update(name_ptr, name_len, + new_name_ptr, new_name_len, + value_ptr, value_len, + new_value_ptr, new_value_len); error: free(src_f); @@ -822,6 +889,10 @@ xlog_recover_print_attri( struct xlog_recover_item *item) { struct xfs_attri_log_format *f, *src_f = NULL; + void *name_ptr = NULL; + void *new_name_ptr = NULL; + void *value_ptr = NULL; + void *new_value_ptr = NULL; uint src_len, dst_len; unsigned int name_len = 0; unsigned int new_name_len = 0; @@ -872,6 +943,7 @@ xlog_recover_print_attri( printf(_("ATTRI: name len:%u\n"), name_len); print_or_dump((char *)item->ri_buf[region].i_addr, name_len); + name_ptr = item->ri_buf[region].i_addr; } if (new_name_len > 0) { @@ -879,6 +951,7 @@ xlog_recover_print_attri( printf(_("ATTRI: newname len:%u\n"), new_name_len); print_or_dump((char *)item->ri_buf[region].i_addr, new_name_len); + new_name_ptr = item->ri_buf[region].i_addr; } if (value_len > 0) { @@ -887,6 +960,7 @@ xlog_recover_print_attri( region++; printf(_("ATTRI: value len:%u\n"), value_len); print_or_dump((char *)item->ri_buf[region].i_addr, len); + value_ptr = item->ri_buf[region].i_addr; } if (new_value_len > 0) { @@ -895,8 +969,15 @@ xlog_recover_print_attri( region++; printf(_("ATTRI: newvalue len:%u\n"), new_value_len); print_or_dump((char *)item->ri_buf[region].i_addr, len); + new_value_ptr = item->ri_buf[region].i_addr; } + if (src_f->alfi_attr_filter & XFS_ATTR_PARENT) + dump_pptr_update(name_ptr, name_len, + new_name_ptr, new_name_len, + value_ptr, value_len, + new_value_ptr, new_value_len); + out: free(f); From patchwork Thu Apr 6 19:37:17 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: 13203985 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 CDF49C7618D for ; Thu, 6 Apr 2023 19:37:21 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229610AbjDFThU (ORCPT ); Thu, 6 Apr 2023 15:37:20 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38414 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229458AbjDFThT (ORCPT ); Thu, 6 Apr 2023 15:37:19 -0400 Received: from dfw.source.kernel.org (dfw.source.kernel.org [IPv6:2604:1380:4641:c500::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 16096E72 for ; Thu, 6 Apr 2023 12:37:19 -0700 (PDT) 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 dfw.source.kernel.org (Postfix) with ESMTPS id A5B3964B89 for ; Thu, 6 Apr 2023 19:37:18 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 13E66C433D2; Thu, 6 Apr 2023 19:37:18 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1680809838; bh=nXrpHAVtfqRX4uEOQPMAtAeiYBKtaUd1LJTt5lxpaAs=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=kl9mY5WDRPSE7zXsk509+A3JPFkQIHgosM7wha2CxkcDQfmZurLMURVzt/ROvrOQ7 /NY43aiUsYxDnQMgsefi5YjaVfEZ9XF917+mtVzAOSclNm3N+UKY6SOyWHjHpiuWaJ Edoi5upA6kZJV1A6RSBkyuBagrSOwJFWIELOnGsHWqz/DG3cOh+i5lrrkmm9JFJWsF NtRTalIwk+yYw2TmUlzD17fRV2zcA0pjXo2UzUaF4qorv/GKcZRRwoQPtQiGHGWmFT eEgVbefSFjUdtRUI64iZE4kKlgmVhKw5rXFy7ZGMNLTwZ4zyvTglelpj8FZAh23lTw v4C13MgFvGAWQ== Date: Thu, 06 Apr 2023 12:37:17 -0700 Subject: [PATCH 22/32] xfs_scrub: use parent pointers when possible to report file operations From: "Darrick J. Wong" To: djwong@kernel.org Cc: allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <168080827847.616793.16002329266364259157.stgit@frogsfrogsfrogs> In-Reply-To: <168080827546.616793.7264157843231723676.stgit@frogsfrogsfrogs> References: <168080827546.616793.7264157843231723676.stgit@frogsfrogsfrogs> 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 If parent pointers are available, use them to supply file paths when doing things to files, instead of merely printing the inode number. Signed-off-by: Darrick J. Wong --- scrub/common.c | 41 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/scrub/common.c b/scrub/common.c index 49a87f412..172a32ba6 100644 --- a/scrub/common.c +++ b/scrub/common.c @@ -9,6 +9,7 @@ #include #include "platform_defs.h" #include "libfrog/paths.h" +#include "libfrog/getparents.h" #include "xfs_scrub.h" #include "common.h" #include "progress.h" @@ -403,19 +404,55 @@ scrub_render_ino_descr( ...) { va_list args; + size_t pathlen = 0; uint32_t agno; uint32_t agino; int ret; + if (ctx->mnt.fsgeom.flags & XFS_FSOP_GEOM_FLAGS_PARENT) { + struct xfs_handle handle; + + memcpy(&handle.ha_fsid, ctx->fshandle, sizeof(handle.ha_fsid)); + handle.ha_fid.fid_len = sizeof(xfs_fid_t) - + sizeof(handle.ha_fid.fid_len); + handle.ha_fid.fid_pad = 0; + handle.ha_fid.fid_ino = ino; + handle.ha_fid.fid_gen = gen; + + ret = handle_to_path(&handle, sizeof(struct xfs_handle), buf, + buflen); + if (ret) + goto report_inum; + + /* + * Leave at least 16 bytes for the description of what went + * wrong. If we can't do that, we'll use the inode number. + */ + pathlen = strlen(buf); + if (pathlen >= buflen - 16) + goto report_inum; + + if (format) { + buf[pathlen] = ' '; + buf[pathlen + 1] = 0; + pathlen++; + } + + goto report_format; + } + +report_inum: agno = cvt_ino_to_agno(&ctx->mnt, ino); agino = cvt_ino_to_agino(&ctx->mnt, ino); ret = snprintf(buf, buflen, _("inode %"PRIu64" (%"PRIu32"/%"PRIu32")%s"), ino, agno, agino, format ? " " : ""); if (ret < 0 || ret >= buflen || format == NULL) return ret; + pathlen = ret; +report_format: va_start(args, format); - ret += vsnprintf(buf + ret, buflen - ret, format, args); + pathlen += vsnprintf(buf + pathlen, buflen - pathlen, format, args); va_end(args); - return ret; + return pathlen; } From patchwork Thu Apr 6 19:37:33 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: 13203986 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 4F147C76196 for ; Thu, 6 Apr 2023 19:37:37 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229794AbjDFThg (ORCPT ); Thu, 6 Apr 2023 15:37:36 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38518 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229458AbjDFThf (ORCPT ); Thu, 6 Apr 2023 15:37:35 -0400 Received: from dfw.source.kernel.org (dfw.source.kernel.org [IPv6:2604:1380:4641:c500::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id BD873E72 for ; Thu, 6 Apr 2023 12:37:34 -0700 (PDT) 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 dfw.source.kernel.org (Postfix) with ESMTPS id 56CA260F24 for ; Thu, 6 Apr 2023 19:37:34 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id AF002C433D2; Thu, 6 Apr 2023 19:37:33 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1680809853; bh=4zog0V7X2LVKO95wOW+NtSxXVED0FGXZthcFixbxSP8=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=AoMhyMxDiND0QuaDwal2ofjjXPvu3dy2MjQEeXHB2Qzz98K6iCMf2mRSV/aJbfshI h/QRWQEUFlu/+yKUXPNzYVZzF+I5MJL5lro3idWw7xkC6Orb78vrnLc255spHiCS6O VHv7A3BcgMsbstjWIBnAtXOsAhziQUWnF2HAjYmUITP6ZPoukwBN/KQ0ZY7kKbBhpT Z9ButoJKvsz5gjNmtV7BwSWMrkLrka/CZ23Ycyf7PM31MvgEFT2L/U+45LsfiPadwG zJdqMomoJgn3/fP6hP+QRXtjX7e9B4I5Yir3SafhW4ypuiRleHl0s5mjwngpfMPb0G PZtiAr30YXa/w== Date: Thu, 06 Apr 2023 12:37:33 -0700 Subject: [PATCH 23/32] xfs_db: report parent bit on xattrs From: "Darrick J. Wong" To: djwong@kernel.org Cc: Allison Henderson , allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <168080827859.616793.17238285720530002492.stgit@frogsfrogsfrogs> In-Reply-To: <168080827546.616793.7264157843231723676.stgit@frogsfrogsfrogs> References: <168080827546.616793.7264157843231723676.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-xfs@vger.kernel.org From: Allison Henderson Display the parent bit on xattr keys Signed-off-by: Darrick J. Wong Reviewed-by: Allison Henderson --- db/attr.c | 3 +++ db/attrshort.c | 3 +++ 2 files changed, 6 insertions(+) diff --git a/db/attr.c b/db/attr.c index ba722e146..f29e4a544 100644 --- a/db/attr.c +++ b/db/attr.c @@ -82,6 +82,9 @@ const field_t attr_leaf_entry_flds[] = { { "local", FLDT_UINT1, OI(LEOFF(flags) + bitsz(uint8_t) - XFS_ATTR_LOCAL_BIT - 1), C1, 0, TYP_NONE }, + { "parent", FLDT_UINT1, + OI(LEOFF(flags) + bitsz(uint8_t) - XFS_ATTR_PARENT_BIT - 1), C1, 0, + TYP_NONE }, { "pad2", FLDT_UINT8X, OI(LEOFF(pad2)), C1, FLD_SKIPALL, TYP_NONE }, { NULL } }; diff --git a/db/attrshort.c b/db/attrshort.c index e234fbd83..872d771d5 100644 --- a/db/attrshort.c +++ b/db/attrshort.c @@ -44,6 +44,9 @@ const field_t attr_sf_entry_flds[] = { { "secure", FLDT_UINT1, OI(EOFF(flags) + bitsz(uint8_t) - XFS_ATTR_SECURE_BIT - 1), C1, 0, TYP_NONE }, + { "parent", FLDT_UINT1, + OI(EOFF(flags) + bitsz(uint8_t) - XFS_ATTR_PARENT_BIT - 1), C1, 0, + TYP_NONE }, { "name", FLDT_CHARNS, OI(EOFF(nameval)), attr_sf_entry_name_count, FLD_COUNT, TYP_NONE }, { "value", FLDT_CHARNS, attr_sf_entry_value_offset, From patchwork Thu Apr 6 19:37: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: 13203987 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 9D635C7618D for ; Thu, 6 Apr 2023 19:38:03 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236697AbjDFTiC (ORCPT ); Thu, 6 Apr 2023 15:38:02 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39260 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237423AbjDFThx (ORCPT ); Thu, 6 Apr 2023 15:37:53 -0400 Received: from dfw.source.kernel.org (dfw.source.kernel.org [IPv6:2604:1380:4641:c500::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A861A5277 for ; Thu, 6 Apr 2023 12:37:50 -0700 (PDT) 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 dfw.source.kernel.org (Postfix) with ESMTPS id DFBF964731 for ; Thu, 6 Apr 2023 19:37:49 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 4CC35C433EF; Thu, 6 Apr 2023 19:37:49 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1680809869; bh=6C7eM8RHMvJb/SUrJpdl6or4ng+YNCIEWYQQr97AJGw=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=SJQcFexpjoekRNOvNG6lrE4ebEJeDMrEUu76a6YqgdqpHtPrFxijdO6G815u3TsXC NoTRZEhfshiBEnEzmnxp858VnMYCs4EBRFGrjgc6VrmDBrdHuDovn9a8W6zyfSUWam tKj0h771ZoFH0RLT4fFC8VLdZJZ0IXNr788sKTLd2S8nGfbzSfhi3EjtglvEi1lYQb 9cH1vNZG962IGXgNWHEHnXAyvxyA44N6yYnikW9mNWLfvfc+oKylNd8sHI23DK8HpW mSOIBYXDlR+KOkZs2X2rAlEsiCvxZmMXyWdmhJ3E3sAJ/hX0gc39Kze3sCTRtBLz59 p88q+qqX0Cyww== Date: Thu, 06 Apr 2023 12:37:48 -0700 Subject: [PATCH 24/32] xfs_db: report parent pointers embedded in xattrs From: "Darrick J. Wong" To: djwong@kernel.org Cc: allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <168080827873.616793.12205479848532394957.stgit@frogsfrogsfrogs> In-Reply-To: <168080827546.616793.7264157843231723676.stgit@frogsfrogsfrogs> References: <168080827546.616793.7264157843231723676.stgit@frogsfrogsfrogs> 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 Decode the parent pointer inode, generation, namehash, and name fields if the parent pointer passes basic validation checks. Signed-off-by: Darrick J. Wong --- db/attr.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ db/attrshort.c | 48 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 110 insertions(+) diff --git a/db/attr.c b/db/attr.c index f29e4a544..9e7bbd164 100644 --- a/db/attr.c +++ b/db/attr.c @@ -19,6 +19,8 @@ static int attr_leaf_entries_count(void *obj, int startoff); static int attr_leaf_hdr_count(void *obj, int startoff); static int attr_leaf_name_local_count(void *obj, int startoff); static int attr_leaf_name_local_name_count(void *obj, int startoff); +static int attr_leaf_name_pptr_count(void *obj, int startoff); +static int attr_leaf_name_pptr_namelen(void *obj, int startoff); static int attr_leaf_name_local_value_count(void *obj, int startoff); static int attr_leaf_name_local_value_offset(void *obj, int startoff, int idx); @@ -111,6 +113,8 @@ const field_t attr_leaf_map_flds[] = { #define LNOFF(f) bitize(offsetof(xfs_attr_leaf_name_local_t, f)) #define LVOFF(f) bitize(offsetof(xfs_attr_leaf_name_remote_t, f)) +#define PPOFF(f) bitize(offsetof(xfs_attr_leaf_name_local_t, nameval) + \ + offsetof(struct xfs_parent_name_rec, f)) const field_t attr_leaf_name_flds[] = { { "valuelen", FLDT_UINT16D, OI(LNOFF(valuelen)), attr_leaf_name_local_count, FLD_COUNT, TYP_NONE }, @@ -118,6 +122,14 @@ const field_t attr_leaf_name_flds[] = { attr_leaf_name_local_count, FLD_COUNT, TYP_NONE }, { "name", FLDT_CHARNS, OI(LNOFF(nameval)), attr_leaf_name_local_name_count, FLD_COUNT, TYP_NONE }, + { "parent_ino", FLDT_INO, OI(PPOFF(p_ino)), + attr_leaf_name_pptr_count, FLD_COUNT, TYP_INODE }, + { "parent_gen", FLDT_UINT32D, OI(PPOFF(p_gen)), + attr_leaf_name_pptr_count, FLD_COUNT, TYP_NONE }, + { "parent_namehash", FLDT_UINT32X, OI(PPOFF(p_namehash)), + attr_leaf_name_pptr_count, FLD_COUNT, TYP_NONE }, + { "parent_name", FLDT_CHARNS, attr_leaf_name_local_value_offset, + attr_leaf_name_pptr_namelen, FLD_COUNT|FLD_OFFSET, TYP_NONE }, { "value", FLDT_CHARNS, attr_leaf_name_local_value_offset, attr_leaf_name_local_value_count, FLD_COUNT|FLD_OFFSET, TYP_NONE }, { "valueblk", FLDT_UINT32X, OI(LVOFF(valueblk)), @@ -273,6 +285,26 @@ attr_leaf_name_local_count( __attr_leaf_name_local_count); } +static int +__attr_leaf_name_pptr_count( + struct xfs_attr_leafblock *leaf, + struct xfs_attr_leaf_entry *e, + int i) +{ + if ((e->flags & XFS_ATTR_NSP_ONDISK_MASK) == XFS_ATTR_PARENT) + return 1; + return 0; +} + +static int +attr_leaf_name_pptr_count( + void *obj, + int startoff) +{ + return attr_leaf_entry_walk(obj, startoff, + __attr_leaf_name_pptr_count); +} + static int __attr_leaf_name_local_name_count( struct xfs_attr_leafblock *leaf, @@ -283,6 +315,8 @@ __attr_leaf_name_local_name_count( if (!(e->flags & XFS_ATTR_LOCAL)) return 0; + if ((e->flags & XFS_ATTR_NSP_ONDISK_MASK) == XFS_ATTR_PARENT) + return 0; l = xfs_attr3_leaf_name_local(leaf, i); return l->namelen; @@ -297,6 +331,32 @@ attr_leaf_name_local_name_count( __attr_leaf_name_local_name_count); } +static int +__attr_leaf_name_pptr_namelen( + struct xfs_attr_leafblock *leaf, + struct xfs_attr_leaf_entry *e, + int i) +{ + struct xfs_attr_leaf_name_local *l; + + if (!(e->flags & XFS_ATTR_LOCAL)) + return 0; + if ((e->flags & XFS_ATTR_NSP_ONDISK_MASK) != XFS_ATTR_PARENT) + return 0; + + l = xfs_attr3_leaf_name_local(leaf, i); + return be16_to_cpu(l->valuelen); +} + +static int +attr_leaf_name_pptr_namelen( + void *obj, + int startoff) +{ + return attr_leaf_entry_walk(obj, startoff, + __attr_leaf_name_pptr_namelen); +} + static int __attr_leaf_name_local_value_count( struct xfs_attr_leafblock *leaf, @@ -307,6 +367,8 @@ __attr_leaf_name_local_value_count( if (!(e->flags & XFS_ATTR_LOCAL)) return 0; + if ((e->flags & XFS_ATTR_NSP_ONDISK_MASK) == XFS_ATTR_PARENT) + return 0; l = xfs_attr3_leaf_name_local(leaf, i); return be16_to_cpu(l->valuelen); diff --git a/db/attrshort.c b/db/attrshort.c index 872d771d5..9cd3411be 100644 --- a/db/attrshort.c +++ b/db/attrshort.c @@ -13,6 +13,8 @@ #include "attrshort.h" static int attr_sf_entry_name_count(void *obj, int startoff); +static int attr_sf_entry_pptr_count(void *obj, int startoff); +static int attr_sf_entry_pptr_namelen(void *obj, int startoff); static int attr_sf_entry_value_count(void *obj, int startoff); static int attr_sf_entry_value_offset(void *obj, int startoff, int idx); static int attr_shortform_list_count(void *obj, int startoff); @@ -34,6 +36,8 @@ const field_t attr_sf_hdr_flds[] = { }; #define EOFF(f) bitize(offsetof(struct xfs_attr_sf_entry, f)) +#define PPOFF(f) bitize(offsetof(struct xfs_attr_sf_entry, nameval) + \ + offsetof(struct xfs_parent_name_rec, f)) const field_t attr_sf_entry_flds[] = { { "namelen", FLDT_UINT8D, OI(EOFF(namelen)), C1, 0, TYP_NONE }, { "valuelen", FLDT_UINT8D, OI(EOFF(valuelen)), C1, 0, TYP_NONE }, @@ -49,11 +53,33 @@ const field_t attr_sf_entry_flds[] = { TYP_NONE }, { "name", FLDT_CHARNS, OI(EOFF(nameval)), attr_sf_entry_name_count, FLD_COUNT, TYP_NONE }, + { "parent_ino", FLDT_INO, OI(PPOFF(p_ino)), attr_sf_entry_pptr_count, + FLD_COUNT, TYP_INODE }, + { "parent_gen", FLDT_UINT32D, OI(PPOFF(p_gen)), attr_sf_entry_pptr_count, + FLD_COUNT, TYP_NONE }, + { "parent_namehash", FLDT_UINT32X, OI(PPOFF(p_namehash)), + attr_sf_entry_pptr_count, FLD_COUNT, TYP_NONE }, + { "parent_name", FLDT_CHARNS, attr_sf_entry_value_offset, + attr_sf_entry_pptr_namelen, FLD_COUNT|FLD_OFFSET, TYP_NONE }, { "value", FLDT_CHARNS, attr_sf_entry_value_offset, attr_sf_entry_value_count, FLD_COUNT|FLD_OFFSET, TYP_NONE }, { NULL } }; +static int +attr_sf_entry_pptr_count( + void *obj, + int startoff) +{ + struct xfs_attr_sf_entry *e; + + ASSERT(bitoffs(startoff) == 0); + e = (struct xfs_attr_sf_entry *)((char *)obj + byteize(startoff)); + if ((e->flags & XFS_ATTR_NSP_ONDISK_MASK) == XFS_ATTR_PARENT) + return 1; + return 0; +} + static int attr_sf_entry_name_count( void *obj, @@ -63,6 +89,8 @@ attr_sf_entry_name_count( ASSERT(bitoffs(startoff) == 0); e = (struct xfs_attr_sf_entry *)((char *)obj + byteize(startoff)); + if ((e->flags & XFS_ATTR_NSP_ONDISK_MASK) == XFS_ATTR_PARENT) + return 0; return e->namelen; } @@ -84,6 +112,22 @@ attr_sf_entry_size( return bitize((int)xfs_attr_sf_entsize(e)); } +static int +attr_sf_entry_pptr_namelen( + void *obj, + int startoff) +{ + struct xfs_attr_sf_entry *e; + + ASSERT(bitoffs(startoff) == 0); + e = (struct xfs_attr_sf_entry *)((char *)obj + byteize(startoff)); + + if ((e->flags & XFS_ATTR_NSP_ONDISK_MASK) != XFS_ATTR_PARENT) + return 0; + + return e->valuelen; +} + static int attr_sf_entry_value_count( void *obj, @@ -93,6 +137,10 @@ attr_sf_entry_value_count( ASSERT(bitoffs(startoff) == 0); e = (struct xfs_attr_sf_entry *)((char *)obj + byteize(startoff)); + + if ((e->flags & XFS_ATTR_NSP_ONDISK_MASK) == XFS_ATTR_PARENT) + return 0; + return e->valuelen; } From patchwork Thu Apr 6 19:38:04 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: 13203988 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 790ACC7618D for ; Thu, 6 Apr 2023 19:38:24 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237377AbjDFTiX (ORCPT ); Thu, 6 Apr 2023 15:38:23 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39086 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237372AbjDFTiI (ORCPT ); Thu, 6 Apr 2023 15:38:08 -0400 Received: from dfw.source.kernel.org (dfw.source.kernel.org [IPv6:2604:1380:4641:c500::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D86E5186 for ; Thu, 6 Apr 2023 12:38:05 -0700 (PDT) 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 dfw.source.kernel.org (Postfix) with ESMTPS id 7835A60FB3 for ; Thu, 6 Apr 2023 19:38:05 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id D6E8CC433EF; Thu, 6 Apr 2023 19:38:04 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1680809884; bh=EGhYFd5UWcgR0vkBKdctpQM4ZNC1H6js8T6ty6Qjb8w=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=syZuLFJIfzKiQ8fh+8LyqpVx2bP1JXYzj+J9UmXNzAYyCRrm//cS7AzlZNd1Tm5ob jMkjxEYYBSIBYU3GpZg6oBxyroFb/A9n2kYTf4zrUBzGctIWmcdljJSRUddp9jBRN+ Xxn6KgsdjvLR/8boQ5Fe6yN5hQoEmzNNR6uoLAP+v3G1OXnp7CGOsnAr08PUAc0jxk 73Tlk8lEzPKwvNPDPeswRVSp+Q30vDZp7kQ/Nu+Nnm9NL3c+0oy5+hcpFZ0c0sYdOo 7+x7VQDWL8s6znZNxrmOTOHv8cGZwdCn3mygOBvssWRXJvD27E4dcTg0LanVJR1OBh ns8Zci3erWhnQ== Date: Thu, 06 Apr 2023 12:38:04 -0700 Subject: [PATCH 25/32] xfs_db: obfuscate dirent and parent pointer names consistently From: "Darrick J. Wong" To: djwong@kernel.org Cc: allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <168080827886.616793.2247932828058405961.stgit@frogsfrogsfrogs> In-Reply-To: <168080827546.616793.7264157843231723676.stgit@frogsfrogsfrogs> References: <168080827546.616793.7264157843231723676.stgit@frogsfrogsfrogs> 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 When someone wants to perform an obfuscated metadump of a filesystem where parent pointers are enabled, we have to use the *exact* same obfuscated name for both the directory entry and the parent pointer. Create a name remapping table so that when we obfuscate a dirent name or a parent pointer name, we can apply the same obfuscation when we find the corresponding parent pointer or dirent. Signed-off-by: Darrick J. Wong --- db/metadump.c | 313 ++++++++++++++++++++++++++++++++++++++++++++-- libxfs/libxfs_api_defs.h | 2 2 files changed, 304 insertions(+), 11 deletions(-) diff --git a/db/metadump.c b/db/metadump.c index 27d1df432..b413ef5b3 100644 --- a/db/metadump.c +++ b/db/metadump.c @@ -20,6 +20,14 @@ #include "field.h" #include "dir2.h" +#undef REMAP_DEBUG + +#ifdef REMAP_DEBUG +# define remap_debug printf +#else +# define remap_debug(...) ((void)0) +#endif + #define DEFAULT_MAX_EXT_SIZE XFS_MAX_BMBT_EXTLEN /* copy all metadata structures to/from a file */ @@ -736,6 +744,111 @@ nametable_add(xfs_dahash_t hash, int namelen, unsigned char *name) return ent; } +/* + * Obfuscated name remapping table for parent pointer-enabled filesystems. + * When this feature is enabled, we have to maintain consistency between the + * names that appears in the dirent and the corresponding parent pointer. + */ + +struct remap_ent { + struct remap_ent *next; + xfs_ino_t dir_ino; + xfs_dahash_t namehash; + uint8_t namelen; + + uint8_t names[]; +}; + +static inline uint8_t *remap_ent_before(struct remap_ent *ent) +{ + return &ent->names[0]; +} + +static inline uint8_t *remap_ent_after(struct remap_ent *ent) +{ + return &ent->names[ent->namelen]; +} + +#define REMAP_TABLE_SIZE 4096 + +static struct remap_ent *remaptable[REMAP_TABLE_SIZE]; + +static void +remaptable_clear(void) +{ + int i; + struct remap_ent *ent, *next; + + for (i = 0; i < REMAP_TABLE_SIZE; i++) { + ent = remaptable[i]; + + while (ent) { + next = ent->next; + free(ent); + ent = next; + } + } +} + +/* Try to find a remapping table entry. */ +static struct remap_ent * +remaptable_find( + xfs_ino_t dir_ino, + xfs_dahash_t namehash, + const unsigned char *name, + unsigned int namelen) +{ + struct remap_ent *ent = remaptable[namehash % REMAP_TABLE_SIZE]; + + remap_debug("REMAP FIND: 0x%lx hash 0x%x '%.*s'\n", + dir_ino, namehash, namelen, name); + + while (ent) { + remap_debug("REMAP ENT: 0x%lx hash 0x%x '%.*s'\n", + ent->dir_ino, ent->namehash, ent->namelen, + remap_ent_before(ent)); + + if (ent->dir_ino == dir_ino && + ent->namehash == namehash && + ent->namelen == namelen && + !memcmp(remap_ent_before(ent), name, namelen)) + return ent; + ent = ent->next; + } + + return NULL; +} + +/* Remember the remapping for a particular dirent that we obfuscated. */ +static struct remap_ent * +remaptable_add( + xfs_ino_t dir_ino, + xfs_dahash_t namehash, + const unsigned char *old_name, + unsigned int namelen, + const unsigned char *new_name) +{ + struct remap_ent *ent; + + ent = malloc(sizeof(struct remap_ent) + (namelen * 2)); + if (!ent) + return NULL; + + ent->dir_ino = dir_ino; + ent->namehash = namehash; + ent->namelen = namelen; + memcpy(remap_ent_before(ent), old_name, namelen); + memcpy(remap_ent_after(ent), new_name, namelen); + ent->next = remaptable[namehash % REMAP_TABLE_SIZE]; + + remaptable[namehash % REMAP_TABLE_SIZE] = ent; + + remap_debug("REMAP ADD: 0x%lx hash 0x%x '%.*s' -> '%.*s'\n", + dir_ino, namehash, namelen, old_name, namelen, + new_name); + return ent; +} + #define is_invalid_char(c) ((c) == '/' || (c) == '\0') #define rol32(x,y) (((x) << (y)) | ((x) >> (32 - (y)))) @@ -1184,6 +1297,7 @@ generate_obfuscated_name( int namelen, unsigned char *name) { + unsigned char *old_name = NULL; xfs_dahash_t hash; /* @@ -1205,8 +1319,32 @@ generate_obfuscated_name( name++; /* Obfuscate the name (if possible) */ - hash = libxfs_da_hashname(name, namelen); + + /* + * If we're obfuscating a dirent name on a pptrs filesystem, see if we + * already processed the parent pointer and use the same name. + */ + if (xfs_has_parent(mp) && ino) { + struct remap_ent *remap; + + remap = remaptable_find(cur_ino, hash, name, namelen); + if (remap) { + remap_debug("found obfuscated dir 0x%lx '%.*s' -> 0x%lx -> '%.*s' \n", + cur_ino, namelen, + remap_ent_before(remap), ino, namelen, + remap_ent_after(remap)); + memcpy(name, remap_ent_after(remap), namelen); + return; + } + + /* + * If we haven't procesed this dirent name before, save the + * old name for a remap table entry. Obfuscate the name. + */ + old_name = alloca(namelen); + memcpy(old_name, name, namelen); + } obfuscate_name(hash, namelen, name); /* @@ -1230,6 +1368,23 @@ generate_obfuscated_name( "in dir inode %llu\n", (unsigned long long) ino, (unsigned long long) cur_ino); + + /* + * We've obfuscated a name in the directory entry. Remember this + * remapping for when we come across the parent pointer later. + */ + if (!old_name) + return; + + remap_debug("obfuscating dir 0x%lx '%.*s' -> 0x%lx -> '%.*s' \n", + cur_ino, namelen, old_name, ino, namelen, + name); + + if (!remaptable_add(cur_ino, hash, old_name, namelen, name)) + print_warning("unable to record remapped dirent name for inode %llu " + "in dir inode %llu\n", + (unsigned long long) ino, + (unsigned long long) cur_ino); } static void @@ -1361,6 +1516,123 @@ process_sf_symlink( memset(&buf[len], 0, XFS_DFORK_DSIZE(dip, mp) - len); } +static inline bool +want_obfuscate_pptr( + unsigned int nsp_flags, + const void *name, + unsigned int namelen, + const void *value, + unsigned int valuelen) +{ + if (!obfuscate) + return false; + + /* Ignore if parent pointers aren't enabled. */ + if (!xfs_has_parent(mp)) + return false; + + /* Ignore anything not claiming to be a parent pointer. */ + if (!(nsp_flags & XFS_ATTR_PARENT)) + return false; + + /* Obfuscate this parent pointer if it passes basic checks. */ + if (libxfs_parent_namecheck(mp, name, namelen, nsp_flags) && + libxfs_parent_valuecheck(mp, value, valuelen)) + return true; + + /* Ignore otherwise. */ + return false; +} + +static void +obfuscate_parent_pointer( + const struct xfs_parent_name_rec *rec, + unsigned char *value, + unsigned int valuelen) +{ + struct xfs_parent_name_irec irec; + struct remap_ent *remap; + char *old_name = irec.p_name; + xfs_dahash_t hash; + xfs_ino_t child_ino = cur_ino; + + libxfs_parent_irec_from_disk(&irec, rec, value, valuelen); + + /* + * We don't obfuscate "lost+found" or any orphan files + * therein. If When the name table is used for extended + * attributes, the inode number provided is 0, in which + * case we don't need to make this check. + */ + cur_ino = irec.p_ino; + if (in_lost_found(child_ino, valuelen, value)) { + cur_ino = child_ino; + return; + } + cur_ino = child_ino; + + /* + * If the name starts with a slash, just skip over it. It isn't + * included in the hash and we don't record it in the name table. + */ + if (*value == '/') { + old_name++; + value++; + valuelen--; + } + + hash = libxfs_da_hashname(value, valuelen); + + /* + * If we already processed the dirent, use the same name for the parent + * pointer. + */ + remap = remaptable_find(irec.p_ino, hash, value, valuelen); + if (remap) { + remap_debug("found obfuscated pptr 0x%lx '%.*s' -> 0x%lx -> '%.*s' \n", + irec.p_ino, valuelen, remap_ent_before(remap), + cur_ino, valuelen, remap_ent_after(remap)); + memcpy(value, remap_ent_after(remap), valuelen); + return; + } + + /* + * Obfuscate the parent pointer name and remember this for later + * in case we encounter the dirent and need to reuse the name there. + */ + obfuscate_name(hash, valuelen, value); + + remap_debug("obfuscated pptr 0x%lx '%.*s' -> 0x%lx -> '%.*s'\n", + irec.p_ino, valuelen, old_name, cur_ino, valuelen, + value); + if (!remaptable_add(irec.p_ino, hash, old_name, valuelen, value)) + print_warning("unable to record remapped pptr name for inode %llu " + "in dir inode %llu\n", + (unsigned long long) cur_ino, + (unsigned long long) irec.p_ino); +} + +static inline bool +want_obfuscate_attr( + unsigned int nsp_flags, + const void *name, + unsigned int namelen, + const void *value, + unsigned int valuelen) +{ + if (!obfuscate) + return false; + + /* + * If we didn't already obfuscate the parent pointer, it's probably + * corrupt. Leave it intact for analysis. + */ + if (nsp_flags & XFS_ATTR_PARENT) + return false; + + return true; +} + static void process_sf_attr( struct xfs_dinode *dip) @@ -1390,7 +1662,7 @@ process_sf_attr( asfep = &asfp->list[0]; for (i = 0; (i < asfp->hdr.count) && ((char *)asfep - (char *)asfp < ino_attr_size); i++) { - + void *name, *value; int namelen = asfep->namelen; if (namelen == 0) { @@ -1406,11 +1678,16 @@ process_sf_attr( break; } - if (obfuscate) { - generate_obfuscated_name(0, asfep->namelen, - &asfep->nameval[0]); - memset(&asfep->nameval[asfep->namelen], 'v', - asfep->valuelen); + name = &asfep->nameval[0]; + value = &asfep->nameval[asfep->namelen]; + + if (want_obfuscate_pptr(asfep->flags, name, namelen, value, + asfep->valuelen)) { + obfuscate_parent_pointer(name, value, asfep->valuelen); + } else if (want_obfuscate_attr(asfep->flags, name, namelen, + value, asfep->valuelen)) { + generate_obfuscated_name(0, asfep->namelen, name); + memset(value, 'v', asfep->valuelen); } asfep = (struct xfs_attr_sf_entry *)((char *)asfep + @@ -1777,6 +2054,9 @@ process_attr_block( break; } if (entry->flags & XFS_ATTR_LOCAL) { + void *name, *value; + unsigned int valuelen; + local = xfs_attr3_leaf_name_local(leaf, i); if (local->namelen == 0) { if (show_warnings) @@ -1785,11 +2065,21 @@ process_attr_block( (long long)cur_ino); break; } - if (obfuscate) { + + name = &local->nameval[0]; + value = &local->nameval[local->namelen]; + valuelen = be16_to_cpu(local->valuelen); + + if (want_obfuscate_pptr(entry->flags, name, + local->namelen, value, + valuelen)) { + obfuscate_parent_pointer(name, value, valuelen); + } else if (want_obfuscate_attr(entry->flags, name, + local->namelen, value, + valuelen)) { generate_obfuscated_name(0, local->namelen, - &local->nameval[0]); - memset(&local->nameval[local->namelen], 'v', - be16_to_cpu(local->valuelen)); + name); + memset(value, 'v', valuelen); } /* zero from end of nameval[] to next name start */ nlen = local->namelen; @@ -3166,6 +3456,7 @@ metadump_f( pop_cur(); out: free(metablock); + remaptable_clear(); return 0; } diff --git a/libxfs/libxfs_api_defs.h b/libxfs/libxfs_api_defs.h index 092934935..11bde3073 100644 --- a/libxfs/libxfs_api_defs.h +++ b/libxfs/libxfs_api_defs.h @@ -143,6 +143,8 @@ #define xfs_parent_finish libxfs_parent_finish #define xfs_parent_irec_from_disk libxfs_parent_irec_from_disk #define xfs_parent_start libxfs_parent_start +#define xfs_parent_namecheck libxfs_parent_namecheck +#define xfs_parent_valuecheck libxfs_parent_valuecheck #define xfs_perag_get libxfs_perag_get #define xfs_perag_put libxfs_perag_put #define xfs_prealloc_blocks libxfs_prealloc_blocks From patchwork Thu Apr 6 19:38:20 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: 13203989 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 00C4BC76196 for ; Thu, 6 Apr 2023 19:38:42 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237197AbjDFTil (ORCPT ); Thu, 6 Apr 2023 15:38:41 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38692 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237730AbjDFTi1 (ORCPT ); Thu, 6 Apr 2023 15:38:27 -0400 Received: from dfw.source.kernel.org (dfw.source.kernel.org [IPv6:2604:1380:4641:c500::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A3F9D4EFA for ; Thu, 6 Apr 2023 12:38:21 -0700 (PDT) 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 dfw.source.kernel.org (Postfix) with ESMTPS id 1A96960DED for ; Thu, 6 Apr 2023 19:38:21 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 74BE9C433D2; Thu, 6 Apr 2023 19:38:20 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1680809900; bh=cmgpEJY8NoT/Fidw9rs/gGWVXfcGH3osyewOAD++eXs=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=GqEqkYM6NgF9bfnYk/oEtfNPHpm35tlTdn3qrnz1D77dYSM3l02KosuYpeBcaiS3K 5qBhCb9XghEuzoMQd95cU+h6Dg/N9LWRm6NFIwP6gU8OLK+PF8nl0KLRzYR/cTdJg5 cNxx10TUXpeboCBTO4EvyHXzpXnX9efJyi+zPb14sjRjioHqSJCoUkqJPcUv8qkylZ 2GSNm6qAXLqRXnSQET94fPHkCrWyK1ytq38KVWyLWOMXWs4J67PFFoSYllUuKMYAKj YXYJkyH+J71+oVLmgFFQ5FXSA98IyhD0OrroNmVqfo7mFOpJtrdSzLRrlA9DsXuBkY W9HQujLSHDj4A== Date: Thu, 06 Apr 2023 12:38:20 -0700 Subject: [PATCH 26/32] xfs_db: hoist name obfuscation code out of metadump.c From: "Darrick J. Wong" To: djwong@kernel.org Cc: allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <168080827899.616793.13744631474033216206.stgit@frogsfrogsfrogs> In-Reply-To: <168080827546.616793.7264157843231723676.stgit@frogsfrogsfrogs> References: <168080827546.616793.7264157843231723676.stgit@frogsfrogsfrogs> 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 want to create a debugger command that will create obfuscated names for directory and xattr names, so hoist the name obfuscation code into a separate file. Signed-off-by: Darrick J. Wong --- db/Makefile | 2 db/metadump.c | 343 ------------------------------------------------------- db/obfuscate.c | 348 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ db/obfuscate.h | 16 +++ 4 files changed, 366 insertions(+), 343 deletions(-) create mode 100644 db/obfuscate.c create mode 100644 db/obfuscate.h diff --git a/db/Makefile b/db/Makefile index b2e011745..2f95f6707 100644 --- a/db/Makefile +++ b/db/Makefile @@ -13,7 +13,7 @@ HFILES = addr.h agf.h agfl.h agi.h attr.h attrshort.h bit.h block.h bmap.h \ flist.h fprint.h frag.h freesp.h hash.h help.h init.h inode.h input.h \ io.h logformat.h malloc.h metadump.h output.h print.h quit.h sb.h \ sig.h strvec.h text.h type.h write.h attrset.h symlink.h fsmap.h \ - fuzz.h + fuzz.h obfuscate.h CFILES = $(HFILES:.h=.c) btdump.c btheight.c convert.c info.c namei.c \ timelimit.c LSRCFILES = xfs_admin.sh xfs_ncheck.sh xfs_metadump.sh diff --git a/db/metadump.c b/db/metadump.c index b413ef5b3..e1b707898 100644 --- a/db/metadump.c +++ b/db/metadump.c @@ -19,6 +19,7 @@ #include "faddr.h" #include "field.h" #include "dir2.h" +#include "obfuscate.h" #undef REMAP_DEBUG @@ -849,19 +850,6 @@ remaptable_add( return ent; } -#define is_invalid_char(c) ((c) == '/' || (c) == '\0') -#define rol32(x,y) (((x) << (y)) | ((x) >> (32 - (y)))) - -static inline unsigned char -random_filename_char(void) -{ - static unsigned char filename_alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz" - "0123456789-_"; - - return filename_alphabet[random() % (sizeof filename_alphabet - 1)]; -} - #define ORPHANAGE "lost+found" #define ORPHANAGE_LEN (sizeof (ORPHANAGE) - 1) @@ -921,335 +909,6 @@ in_lost_found( return slen == namelen && !memcmp(name, s, namelen); } -/* - * Given a name and its hash value, massage the name in such a way - * that the result is another name of equal length which shares the - * same hash value. - */ -static void -obfuscate_name( - xfs_dahash_t hash, - size_t name_len, - unsigned char *name) -{ - unsigned char *newp = name; - int i; - xfs_dahash_t new_hash = 0; - unsigned char *first; - unsigned char high_bit; - int shift; - - /* - * Our obfuscation algorithm requires at least 5-character - * names, so don't bother if the name is too short. We - * work backward from a hash value to determine the last - * five bytes in a name required to produce a new name - * with the same hash. - */ - if (name_len < 5) - return; - - /* - * The beginning of the obfuscated name can be pretty much - * anything, so fill it in with random characters. - * Accumulate its new hash value as we go. - */ - for (i = 0; i < name_len - 5; i++) { - *newp = random_filename_char(); - new_hash = *newp ^ rol32(new_hash, 7); - newp++; - } - - /* - * Compute which five bytes need to be used at the end of - * the name so the hash of the obfuscated name is the same - * as the hash of the original. If any result in an invalid - * character, flip a bit and arrange for a corresponding bit - * in a neighboring byte to be flipped as well. For the - * last byte, the "neighbor" to change is the first byte - * we're computing here. - */ - new_hash = rol32(new_hash, 3) ^ hash; - - first = newp; - high_bit = 0; - for (shift = 28; shift >= 0; shift -= 7) { - *newp = (new_hash >> shift & 0x7f) ^ high_bit; - if (is_invalid_char(*newp)) { - *newp ^= 1; - high_bit = 0x80; - } else - high_bit = 0; - ASSERT(!is_invalid_char(*newp)); - newp++; - } - - /* - * If we flipped a bit on the last byte, we need to fix up - * the matching bit in the first byte. The result will - * be a valid character, because we know that first byte - * has 0's in its upper four bits (it was produced by a - * 28-bit right-shift of a 32-bit unsigned value). - */ - if (high_bit) { - *first ^= 0x10; - ASSERT(!is_invalid_char(*first)); - } - ASSERT(libxfs_da_hashname(name, name_len) == hash); -} - -/* - * Flip a bit in each of two bytes at the end of the given name. - * This is used in generating a series of alternate names to be used - * in the event a duplicate is found. - * - * The bits flipped are selected such that they both affect the same - * bit in the name's computed hash value, so flipping them both will - * preserve the hash. - * - * The following diagram aims to show the portion of a computed - * hash that a given byte of a name affects. - * - * 31 28 24 21 14 8 7 3 0 - * +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+ - * hash: | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | - * +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+ - * last-4 ->| |<-- last-2 --->| |<--- last ---->| - * |<-- last-3 --->| |<-- last-1 --->| |<- last-4 - * |<-- last-7 --->| |<-- last-5 --->| - * |<-- last-8 --->| |<-- last-6 --->| - * . . . and so on - * - * The last byte of the name directly affects the low-order byte of - * the hash. The next-to-last affects bits 7-14, the next one back - * affects bits 14-21, and so on. The effect wraps around when it - * goes beyond the top of the hash (as happens for byte last-4). - * - * Bits that are flipped together "overlap" on the hash value. As - * an example of overlap, the last two bytes both affect bit 7 in - * the hash. That pair of bytes (and their overlapping bits) can be - * used for this "flip bit" operation (it's the first pair tried, - * actually). - * - * A table defines overlapping pairs--the bytes involved and bits - * within them--that can be used this way. The byte offset is - * relative to a starting point within the name, which will be set - * to affect the bytes at the end of the name. The function is - * called with a "bitseq" value which indicates which bit flip is - * desired, and this translates directly into selecting which entry - * in the bit_to_flip[] table to apply. - * - * The function returns 1 if the operation was successful. It - * returns 0 if the result produced a character that's not valid in - * a name (either '/' or a '\0'). Finally, it returns -1 if the bit - * sequence number is beyond what is supported for a name of this - * length. - * - * Discussion - * ---------- - * (Also see the discussion above find_alternate(), below.) - * - * In order to make this function work for any length name, the - * table is ordered by increasing byte offset, so that the earliest - * entries can apply to the shortest strings. This way all names - * are done consistently. - * - * When bit flips occur, they can convert printable characters - * into non-printable ones. In an effort to reduce the impact of - * this, the first bit flips are chosen to affect bytes the end of - * the name (and furthermore, toward the low bits of a byte). Those - * bytes are often non-printable anyway because of the way they are - * initially selected by obfuscate_name()). This is accomplished, - * using later table entries first. - * - * Each row in the table doubles the number of alternates that - * can be generated. A two-byte name is limited to using only - * the first row, so it's possible to generate two alternates - * (the original name, plus the alternate produced by flipping - * the one pair of bits). In a 5-byte name, the effect of the - * first byte overlaps the last by 4 its, and there are 8 bits - * to flip, allowing for 256 possible alternates. - * - * Short names (less than 5 bytes) are never even obfuscated, so for - * such names the relatively small number of alternates should never - * really be a problem. - * - * Long names (more than 6 bytes, say) are not likely to exhaust - * the number of available alternates. In fact, the table could - * probably have stopped at 8 entries, on the assumption that 256 - * alternates should be enough for most any situation. The entries - * beyond those are present mostly for demonstration of how it could - * be populated with more entries, should it ever be necessary to do - * so. - */ -static int -flip_bit( - size_t name_len, - unsigned char *name, - uint32_t bitseq) -{ - int index; - size_t offset; - unsigned char *p0, *p1; - unsigned char m0, m1; - struct { - int byte; /* Offset from start within name */ - unsigned char bit; /* Bit within that byte */ - } bit_to_flip[][2] = { /* Sorted by second entry's byte */ - { { 0, 0 }, { 1, 7 } }, /* Each row defines a pair */ - { { 1, 0 }, { 2, 7 } }, /* of bytes and a bit within */ - { { 2, 0 }, { 3, 7 } }, /* each byte. Each bit in */ - { { 0, 4 }, { 4, 0 } }, /* a pair affects the same */ - { { 0, 5 }, { 4, 1 } }, /* bit in the hash, so flipping */ - { { 0, 6 }, { 4, 2 } }, /* both will change the name */ - { { 0, 7 }, { 4, 3 } }, /* while preserving the hash. */ - { { 3, 0 }, { 4, 7 } }, - { { 0, 0 }, { 5, 3 } }, /* The first entry's byte offset */ - { { 0, 1 }, { 5, 4 } }, /* must be less than the second. */ - { { 0, 2 }, { 5, 5 } }, - { { 0, 3 }, { 5, 6 } }, /* The table can be extended to */ - { { 0, 4 }, { 5, 7 } }, /* an arbitrary number of entries */ - { { 4, 0 }, { 5, 7 } }, /* but there's not much point. */ - /* . . . */ - }; - - /* Find the first entry *not* usable for name of this length */ - - for (index = 0; index < ARRAY_SIZE(bit_to_flip); index++) - if (bit_to_flip[index][1].byte >= name_len) - break; - - /* - * Back up to the last usable entry. If that number is - * smaller than the bit sequence number, inform the caller - * that nothing this large (or larger) will work. - */ - if (bitseq > --index) - return -1; - - /* - * We will be switching bits at the end of name, with a - * preference for affecting the last bytes first. Compute - * where in the name we'll start applying the changes. - */ - offset = name_len - (bit_to_flip[index][1].byte + 1); - index -= bitseq; /* Use later table entries first */ - - p0 = name + offset + bit_to_flip[index][0].byte; - p1 = name + offset + bit_to_flip[index][1].byte; - m0 = 1 << bit_to_flip[index][0].bit; - m1 = 1 << bit_to_flip[index][1].bit; - - /* Only change the bytes if it produces valid characters */ - - if (is_invalid_char(*p0 ^ m0) || is_invalid_char(*p1 ^ m1)) - return 0; - - *p0 ^= m0; - *p1 ^= m1; - - return 1; -} - -/* - * This function generates a well-defined sequence of "alternate" - * names for a given name. An alternate is a name having the same - * length and same hash value as the original name. This is needed - * because the algorithm produces only one obfuscated name to use - * for a given original name, and it's possible that result matches - * a name already seen. This function checks for this, and if it - * occurs, finds another suitable obfuscated name to use. - * - * Each bit in the binary representation of the sequence number is - * used to select one possible "bit flip" operation to perform on - * the name. So for example: - * seq = 0: selects no bits to flip - * seq = 1: selects the 0th bit to flip - * seq = 2: selects the 1st bit to flip - * seq = 3: selects the 0th and 1st bit to flip - * ... and so on. - * - * The flip_bit() function takes care of the details of the bit - * flipping within the name. Note that the "1st bit" in this - * context is a bit sequence number; i.e. it doesn't necessarily - * mean bit 0x02 will be changed. - * - * If a valid name (one that contains no '/' or '\0' characters) is - * produced by this process for the given sequence number, this - * function returns 1. If the result is not valid, it returns 0. - * Returns -1 if the sequence number is beyond the the maximum for - * names of the given length. - * - * - * Discussion - * ---------- - * The number of alternates available for a given name is dependent - * on its length. A "bit flip" involves inverting two bits in - * a name--the two bits being selected such that their values - * affect the name's hash value in the same way. Alternates are - * thus generated by inverting the value of pairs of such - * "overlapping" bits in the original name. Each byte after the - * first in a name adds at least one bit of overlap to work with. - * (See comments above flip_bit() for more discussion on this.) - * - * So the number of alternates is dependent on the number of such - * overlapping bits in a name. If there are N bit overlaps, there - * 2^N alternates for that hash value. - * - * Here are the number of overlapping bits available for generating - * alternates for names of specific lengths: - * 1 0 (must have 2 bytes to have any overlap) - * 2 1 One bit overlaps--so 2 possible alternates - * 3 2 Two bits overlap--so 4 possible alternates - * 4 4 Three bits overlap, so 2^3 alternates - * 5 8 8 bits overlap (due to wrapping), 256 alternates - * 6 18 2^18 alternates - * 7 28 2^28 alternates - * ... - * It's clear that the number of alternates grows very quickly with - * the length of the name. But note that the set of alternates - * includes invalid names. And for certain (contrived) names, the - * number of valid names is a fairly small fraction of the total - * number of alternates. - * - * The main driver for this infrastructure for coming up with - * alternate names is really related to names 5 (or possibly 6) - * bytes in length. 5-byte obfuscated names contain no randomly- - * generated bytes in them, and the chance of an obfuscated name - * matching an already-seen name is too high to just ignore. This - * methodical selection of alternates ensures we don't produce - * duplicate names unless we have exhausted our options. - */ -static int -find_alternate( - size_t name_len, - unsigned char *name, - uint32_t seq) -{ - uint32_t bitseq = 0; - uint32_t bits = seq; - - if (!seq) - return 1; /* alternate 0 is the original name */ - if (name_len < 2) /* Must have 2 bytes to flip */ - return -1; - - for (bitseq = 0; bits; bitseq++) { - uint32_t mask = 1 << bitseq; - int fb; - - if (!(bits & mask)) - continue; - - fb = flip_bit(name_len, name, bitseq); - if (fb < 1) - return fb ? -1 : 0; - bits ^= mask; - } - - return 1; -} - /* * Look up the given name in the name table. If it is already * present, iterate through a well-defined sequence of alternate diff --git a/db/obfuscate.c b/db/obfuscate.c new file mode 100644 index 000000000..ae38cb9d0 --- /dev/null +++ b/db/obfuscate.c @@ -0,0 +1,348 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2007, 2011 SGI + * All Rights Reserved. + */ +#include "libxfs.h" +#include "obfuscate.h" + +static inline unsigned char +random_filename_char(void) +{ + static unsigned char filename_alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789-_"; + + return filename_alphabet[random() % (sizeof filename_alphabet - 1)]; +} + +#define rol32(x,y) (((x) << (y)) | ((x) >> (32 - (y)))) + +/* + * Given a name and its hash value, massage the name in such a way + * that the result is another name of equal length which shares the + * same hash value. + */ +void +obfuscate_name( + xfs_dahash_t hash, + size_t name_len, + unsigned char *name) +{ + unsigned char *newp = name; + int i; + xfs_dahash_t new_hash = 0; + unsigned char *first; + unsigned char high_bit; + int shift; + + /* + * Our obfuscation algorithm requires at least 5-character + * names, so don't bother if the name is too short. We + * work backward from a hash value to determine the last + * five bytes in a name required to produce a new name + * with the same hash. + */ + if (name_len < 5) + return; + + /* + * The beginning of the obfuscated name can be pretty much + * anything, so fill it in with random characters. + * Accumulate its new hash value as we go. + */ + for (i = 0; i < name_len - 5; i++) { + *newp = random_filename_char(); + new_hash = *newp ^ rol32(new_hash, 7); + newp++; + } + + /* + * Compute which five bytes need to be used at the end of + * the name so the hash of the obfuscated name is the same + * as the hash of the original. If any result in an invalid + * character, flip a bit and arrange for a corresponding bit + * in a neighboring byte to be flipped as well. For the + * last byte, the "neighbor" to change is the first byte + * we're computing here. + */ + new_hash = rol32(new_hash, 3) ^ hash; + + first = newp; + high_bit = 0; + for (shift = 28; shift >= 0; shift -= 7) { + *newp = (new_hash >> shift & 0x7f) ^ high_bit; + if (is_invalid_char(*newp)) { + *newp ^= 1; + high_bit = 0x80; + } else + high_bit = 0; + ASSERT(!is_invalid_char(*newp)); + newp++; + } + + /* + * If we flipped a bit on the last byte, we need to fix up + * the matching bit in the first byte. The result will + * be a valid character, because we know that first byte + * has 0's in its upper four bits (it was produced by a + * 28-bit right-shift of a 32-bit unsigned value). + */ + if (high_bit) { + *first ^= 0x10; + ASSERT(!is_invalid_char(*first)); + } + ASSERT(libxfs_da_hashname(name, name_len) == hash); +} + +/* + * Flip a bit in each of two bytes at the end of the given name. + * This is used in generating a series of alternate names to be used + * in the event a duplicate is found. + * + * The bits flipped are selected such that they both affect the same + * bit in the name's computed hash value, so flipping them both will + * preserve the hash. + * + * The following diagram aims to show the portion of a computed + * hash that a given byte of a name affects. + * + * 31 28 24 21 14 8 7 3 0 + * +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+ + * hash: | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | + * +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+ + * last-4 ->| |<-- last-2 --->| |<--- last ---->| + * |<-- last-3 --->| |<-- last-1 --->| |<- last-4 + * |<-- last-7 --->| |<-- last-5 --->| + * |<-- last-8 --->| |<-- last-6 --->| + * . . . and so on + * + * The last byte of the name directly affects the low-order byte of + * the hash. The next-to-last affects bits 7-14, the next one back + * affects bits 14-21, and so on. The effect wraps around when it + * goes beyond the top of the hash (as happens for byte last-4). + * + * Bits that are flipped together "overlap" on the hash value. As + * an example of overlap, the last two bytes both affect bit 7 in + * the hash. That pair of bytes (and their overlapping bits) can be + * used for this "flip bit" operation (it's the first pair tried, + * actually). + * + * A table defines overlapping pairs--the bytes involved and bits + * within them--that can be used this way. The byte offset is + * relative to a starting point within the name, which will be set + * to affect the bytes at the end of the name. The function is + * called with a "bitseq" value which indicates which bit flip is + * desired, and this translates directly into selecting which entry + * in the bit_to_flip[] table to apply. + * + * The function returns 1 if the operation was successful. It + * returns 0 if the result produced a character that's not valid in + * a name (either '/' or a '\0'). Finally, it returns -1 if the bit + * sequence number is beyond what is supported for a name of this + * length. + * + * Discussion + * ---------- + * (Also see the discussion above find_alternate(), below.) + * + * In order to make this function work for any length name, the + * table is ordered by increasing byte offset, so that the earliest + * entries can apply to the shortest strings. This way all names + * are done consistently. + * + * When bit flips occur, they can convert printable characters + * into non-printable ones. In an effort to reduce the impact of + * this, the first bit flips are chosen to affect bytes the end of + * the name (and furthermore, toward the low bits of a byte). Those + * bytes are often non-printable anyway because of the way they are + * initially selected by obfuscate_name()). This is accomplished, + * using later table entries first. + * + * Each row in the table doubles the number of alternates that + * can be generated. A two-byte name is limited to using only + * the first row, so it's possible to generate two alternates + * (the original name, plus the alternate produced by flipping + * the one pair of bits). In a 5-byte name, the effect of the + * first byte overlaps the last by 4 its, and there are 8 bits + * to flip, allowing for 256 possible alternates. + * + * Short names (less than 5 bytes) are never even obfuscated, so for + * such names the relatively small number of alternates should never + * really be a problem. + * + * Long names (more than 6 bytes, say) are not likely to exhaust + * the number of available alternates. In fact, the table could + * probably have stopped at 8 entries, on the assumption that 256 + * alternates should be enough for most any situation. The entries + * beyond those are present mostly for demonstration of how it could + * be populated with more entries, should it ever be necessary to do + * so. + */ +static int +flip_bit( + size_t name_len, + unsigned char *name, + uint32_t bitseq) +{ + int index; + size_t offset; + unsigned char *p0, *p1; + unsigned char m0, m1; + struct { + int byte; /* Offset from start within name */ + unsigned char bit; /* Bit within that byte */ + } bit_to_flip[][2] = { /* Sorted by second entry's byte */ + { { 0, 0 }, { 1, 7 } }, /* Each row defines a pair */ + { { 1, 0 }, { 2, 7 } }, /* of bytes and a bit within */ + { { 2, 0 }, { 3, 7 } }, /* each byte. Each bit in */ + { { 0, 4 }, { 4, 0 } }, /* a pair affects the same */ + { { 0, 5 }, { 4, 1 } }, /* bit in the hash, so flipping */ + { { 0, 6 }, { 4, 2 } }, /* both will change the name */ + { { 0, 7 }, { 4, 3 } }, /* while preserving the hash. */ + { { 3, 0 }, { 4, 7 } }, + { { 0, 0 }, { 5, 3 } }, /* The first entry's byte offset */ + { { 0, 1 }, { 5, 4 } }, /* must be less than the second. */ + { { 0, 2 }, { 5, 5 } }, + { { 0, 3 }, { 5, 6 } }, /* The table can be extended to */ + { { 0, 4 }, { 5, 7 } }, /* an arbitrary number of entries */ + { { 4, 0 }, { 5, 7 } }, /* but there's not much point. */ + /* . . . */ + }; + + /* Find the first entry *not* usable for name of this length */ + + for (index = 0; index < ARRAY_SIZE(bit_to_flip); index++) + if (bit_to_flip[index][1].byte >= name_len) + break; + + /* + * Back up to the last usable entry. If that number is + * smaller than the bit sequence number, inform the caller + * that nothing this large (or larger) will work. + */ + if (bitseq > --index) + return -1; + + /* + * We will be switching bits at the end of name, with a + * preference for affecting the last bytes first. Compute + * where in the name we'll start applying the changes. + */ + offset = name_len - (bit_to_flip[index][1].byte + 1); + index -= bitseq; /* Use later table entries first */ + + p0 = name + offset + bit_to_flip[index][0].byte; + p1 = name + offset + bit_to_flip[index][1].byte; + m0 = 1 << bit_to_flip[index][0].bit; + m1 = 1 << bit_to_flip[index][1].bit; + + /* Only change the bytes if it produces valid characters */ + + if (is_invalid_char(*p0 ^ m0) || is_invalid_char(*p1 ^ m1)) + return 0; + + *p0 ^= m0; + *p1 ^= m1; + + return 1; +} + +/* + * This function generates a well-defined sequence of "alternate" + * names for a given name. An alternate is a name having the same + * length and same hash value as the original name. This is needed + * because the algorithm produces only one obfuscated name to use + * for a given original name, and it's possible that result matches + * a name already seen. This function checks for this, and if it + * occurs, finds another suitable obfuscated name to use. + * + * Each bit in the binary representation of the sequence number is + * used to select one possible "bit flip" operation to perform on + * the name. So for example: + * seq = 0: selects no bits to flip + * seq = 1: selects the 0th bit to flip + * seq = 2: selects the 1st bit to flip + * seq = 3: selects the 0th and 1st bit to flip + * ... and so on. + * + * The flip_bit() function takes care of the details of the bit + * flipping within the name. Note that the "1st bit" in this + * context is a bit sequence number; i.e. it doesn't necessarily + * mean bit 0x02 will be changed. + * + * If a valid name (one that contains no '/' or '\0' characters) is + * produced by this process for the given sequence number, this + * function returns 1. If the result is not valid, it returns 0. + * Returns -1 if the sequence number is beyond the the maximum for + * names of the given length. + * + * + * Discussion + * ---------- + * The number of alternates available for a given name is dependent + * on its length. A "bit flip" involves inverting two bits in + * a name--the two bits being selected such that their values + * affect the name's hash value in the same way. Alternates are + * thus generated by inverting the value of pairs of such + * "overlapping" bits in the original name. Each byte after the + * first in a name adds at least one bit of overlap to work with. + * (See comments above flip_bit() for more discussion on this.) + * + * So the number of alternates is dependent on the number of such + * overlapping bits in a name. If there are N bit overlaps, there + * 2^N alternates for that hash value. + * + * Here are the number of overlapping bits available for generating + * alternates for names of specific lengths: + * 1 0 (must have 2 bytes to have any overlap) + * 2 1 One bit overlaps--so 2 possible alternates + * 3 2 Two bits overlap--so 4 possible alternates + * 4 4 Three bits overlap, so 2^3 alternates + * 5 8 8 bits overlap (due to wrapping), 256 alternates + * 6 18 2^18 alternates + * 7 28 2^28 alternates + * ... + * It's clear that the number of alternates grows very quickly with + * the length of the name. But note that the set of alternates + * includes invalid names. And for certain (contrived) names, the + * number of valid names is a fairly small fraction of the total + * number of alternates. + * + * The main driver for this infrastructure for coming up with + * alternate names is really related to names 5 (or possibly 6) + * bytes in length. 5-byte obfuscated names contain no randomly- + * generated bytes in them, and the chance of an obfuscated name + * matching an already-seen name is too high to just ignore. This + * methodical selection of alternates ensures we don't produce + * duplicate names unless we have exhausted our options. + */ +int +find_alternate( + size_t name_len, + unsigned char *name, + uint32_t seq) +{ + uint32_t bitseq = 0; + uint32_t bits = seq; + + if (!seq) + return 1; /* alternate 0 is the original name */ + if (name_len < 2) /* Must have 2 bytes to flip */ + return -1; + + for (bitseq = 0; bits; bitseq++) { + uint32_t mask = 1 << bitseq; + int fb; + + if (!(bits & mask)) + continue; + + fb = flip_bit(name_len, name, bitseq); + if (fb < 1) + return fb ? -1 : 0; + bits ^= mask; + } + + return 1; +} diff --git a/db/obfuscate.h b/db/obfuscate.h new file mode 100644 index 000000000..bba3c286b --- /dev/null +++ b/db/obfuscate.h @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2007, 2011 SGI + * All Rights Reserved. + */ +#ifndef __DB_OBFUSCATE_H__ +#define __DB_OBFUSCATE_H__ + +/* Routines to obfuscate directory filenames and xattr names. */ + +#define is_invalid_char(c) ((c) == '/' || (c) == '\0') + +void obfuscate_name(xfs_dahash_t hash, size_t name_len, unsigned char *name); +int find_alternate(size_t name_len, unsigned char *name, uint32_t seq); + +#endif /* __DB_OBFUSCATE_H__ */ From patchwork Thu Apr 6 19:38: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: 13203990 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 BC707C7618D for ; Thu, 6 Apr 2023 19:38:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229647AbjDFTir (ORCPT ); Thu, 6 Apr 2023 15:38:47 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40128 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230179AbjDFTii (ORCPT ); Thu, 6 Apr 2023 15:38:38 -0400 Received: from dfw.source.kernel.org (dfw.source.kernel.org [IPv6:2604:1380:4641:c500::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 28862E72 for ; Thu, 6 Apr 2023 12:38:37 -0700 (PDT) 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 dfw.source.kernel.org (Postfix) with ESMTPS id A62CA60FB3 for ; Thu, 6 Apr 2023 19:38:36 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 0A3AAC433EF; Thu, 6 Apr 2023 19:38:36 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1680809916; bh=btdN5h0anmxIVlufi8sRx4i64jwV+cw5uqfoiRD1bgI=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=e2kwf3HAAmyurcFT9ywkvBlADVteqvf7k5gaihC8xU2OOA9HbC6h5TTyvZr8Vo9s5 GFWT9ADF8WHfkOLWQH285JXWSJ0ccYO8YdjC4tp6B2J96mMtrNYxCj3kYjIaNSEugT cOtgvYDn0svhdPOyOq9ij4L2Kfskyfgh8X0BjciFXwX45bohlAEfi8T/7UHNt3LUkV frXygkyHk0PiUJAdTtdjbd98gXvejcVywBQyxeUabW00U7eCn3L61UyvUyaWW9hiiu xafM3d9MNpWOO+ekr5Y+vjzF78SPgtzlNq67HcvI+xuVAdAy+Qly5gM0jvODzoYcVS 1Hu+sBX7aLbJg== Date: Thu, 06 Apr 2023 12:38:35 -0700 Subject: [PATCH 27/32] xfs_db: create dirents and xattrs with colliding names From: "Darrick J. Wong" To: djwong@kernel.org Cc: allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <168080827912.616793.12711743622509100323.stgit@frogsfrogsfrogs> In-Reply-To: <168080827546.616793.7264157843231723676.stgit@frogsfrogsfrogs> References: <168080827546.616793.7264157843231723676.stgit@frogsfrogsfrogs> 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 Create a new debugger command that will create dirent and xattr names that induce dahash collisions. Signed-off-by: Darrick J. Wong --- db/hash.c | 374 +++++++++++++++++++++++++++++++++++++++++++++++++++++ man/man8/xfs_db.8 | 31 ++++ 2 files changed, 405 insertions(+) diff --git a/db/hash.c b/db/hash.c index 68c53e7f9..9fa5f054e 100644 --- a/db/hash.c +++ b/db/hash.c @@ -5,12 +5,15 @@ */ #include "libxfs.h" +#include "init.h" #include "addr.h" #include "command.h" #include "type.h" #include "io.h" #include "output.h" #include "hash.h" +#include "obfuscate.h" +#include static int hash_f(int argc, char **argv); static void hash_help(void); @@ -46,8 +49,379 @@ hash_f( return 0; } +static void +hashcoll_help(void) +{ + printf(_( +"\n" +" Generate obfuscated variants of the provided name. Each variant will have\n" +" the same dahash value. Names are written to stdout with a NULL separating\n" +" each name.\n" +"\n" +" -a -- create extended attributes.\n" +" -i -- read standard input for the name, up to %d bytes.\n" +" -n -- create this many names.\n" +" -p -- create directory entries or extended attributes in this file.\n" +" -s -- seed the rng with this value.\n" +"\n"), + MAXNAMELEN - 1); +} + +struct name_dup { + struct name_dup *next; + uint32_t crc; + uint8_t namelen; + uint8_t name[]; +}; + +static inline size_t +name_dup_sizeof( + unsigned int namelen) +{ + return sizeof(struct name_dup) + namelen; +} + +#define MAX_DUP_TABLE_BUCKETS (1048575) + +struct dup_table { + unsigned int nr_buckets; + struct name_dup *buckets[]; +}; + +static inline size_t +dup_table_sizeof( + unsigned int nr_buckets) +{ + return sizeof(struct dup_table) + + (nr_buckets * sizeof(struct name_dup *)); +} + +static int +dup_table_alloc( + unsigned long nr_names, + struct dup_table **tabp) +{ + struct dup_table *t; + + *tabp = NULL; + + if (nr_names == 1) + return 0; + + nr_names = min(MAX_DUP_TABLE_BUCKETS, nr_names); + t = calloc(1, dup_table_sizeof(nr_names)); + if (!t) + return ENOMEM; + + t->nr_buckets = nr_names; + *tabp = t; + return 0; +} + +static void +dup_table_free( + struct dup_table *tab) +{ + struct name_dup *ent, *next; + unsigned int i; + + if (!tab) + return; + + for (i = 0; i < tab->nr_buckets; i++) { + ent = tab->buckets[i]; + + while (ent) { + next = ent->next; + free(ent); + ent = next; + } + } + free(tab); +} + +static struct name_dup * +dup_table_find( + struct dup_table *tab, + unsigned char *name, + size_t namelen) +{ + struct name_dup *ent; + uint32_t crc = crc32c(~0, name, namelen); + + ent = tab->buckets[crc % tab->nr_buckets]; + while (ent) { + if (ent->crc == crc && + ent->namelen == namelen && + !memcmp(ent->name, name, namelen)) + return ent; + + ent = ent->next; + } + + return NULL; +} + +static int +dup_table_store( + struct dup_table *tab, + unsigned char *name, + size_t namelen) +{ + struct name_dup *dup; + uint32_t seq = 1; + + ASSERT(namelen < MAXNAMELEN); + + while ((dup = dup_table_find(tab, name, namelen)) != NULL) { + int ret; + + do { + ret = find_alternate(namelen, name, seq++); + } while (ret == 0); + if (ret < 0) + return EEXIST; + } + + dup = malloc(name_dup_sizeof(namelen)); + if (!dup) + return ENOMEM; + + dup->crc = crc32c(~0, name, namelen); + dup->namelen = namelen; + memcpy(dup->name, name, namelen); + dup->next = tab->buckets[dup->crc % tab->nr_buckets]; + + tab->buckets[dup->crc % tab->nr_buckets] = dup; + return 0; +} + +static int +collide_dirents( + unsigned long nr, + const unsigned char *name, + size_t namelen, + int fd) +{ + struct xfs_name dname = { + .name = name, + .len = namelen, + }; + unsigned char direntname[MAXNAMELEN + 1]; + struct dup_table *tab = NULL; + xfs_dahash_t old_hash; + unsigned long i; + int error = 0; + + old_hash = libxfs_dir2_hashname(mp, &dname); + + if (fd >= 0) { + int newfd; + + /* + * User passed in a fd, so we'll use the directory to detect + * duplicate names. First create the name that we are passed + * in; the new names will be hardlinks to the first file. + */ + newfd = openat(fd, name, O_CREAT, 0600); + if (newfd < 0) + return errno; + close(newfd); + } else if (nr > 1) { + /* + * Track every name we create so that we don't emit duplicates. + */ + error = dup_table_alloc(nr, &tab); + if (error) + return error; + } + + for (i = 0; i < nr; i++) { + strncpy(direntname, name, MAXNAMELEN); + obfuscate_name(old_hash, namelen, direntname); + + if (fd >= 0) { + error = linkat(fd, name, fd, direntname, 0); + if (error && errno != EEXIST) + return errno; + + /* don't print names to stdout */ + continue; + } else if (tab) { + error = dup_table_store(tab, direntname, namelen); + if (error) + break; + } + + printf("%s%c", direntname, 0); + } + + dup_table_free(tab); + return error; +} + +static int +collide_xattrs( + unsigned long nr, + const unsigned char *name, + size_t namelen, + int fd) +{ + unsigned char xattrname[MAXNAMELEN + 5]; + struct dup_table *tab = NULL; + xfs_dahash_t old_hash; + unsigned long i; + int error; + + old_hash = libxfs_da_hashname(name, namelen); + + if (fd >= 0) { + /* + * User passed in a fd, so we'll use the xattr structure to + * detect duplicate names. First create the attribute that we + * are passed in. + */ + snprintf(xattrname, MAXNAMELEN + 5, "user.%s", name); + error = fsetxattr(fd, xattrname, "1", 1, 0); + if (error) + return errno; + } else if (nr > 1) { + /* + * Track every name we create so that we don't emit duplicates. + */ + error = dup_table_alloc(nr, &tab); + if (error) + return error; + } + + for (i = 0; i < nr; i++) { + snprintf(xattrname, MAXNAMELEN + 5, "user.%s", name); + obfuscate_name(old_hash, namelen, xattrname + 5); + + if (fd >= 0) { + error = fsetxattr(fd, xattrname, "1", 1, 0); + if (error) + return errno; + + /* don't print names to stdout */ + continue; + } else if (tab) { + error = dup_table_store(tab, xattrname, namelen + 5); + if (error) + break; + } + + printf("%s%c", xattrname, 0); + } + + dup_table_free(tab); + return error; +} + +static int +hashcoll_f( + int argc, + char **argv) +{ + const char *path = NULL; + bool read_stdin = false; + bool create_xattr = false; + unsigned long nr = 1, seed = 0; + int fd = -1; + int c; + int error; + + while ((c = getopt(argc, argv, "ain:p:s:")) != EOF) { + switch (c) { + case 'a': + create_xattr = true; + break; + case 'i': + read_stdin = true; + break; + case 'n': + nr = strtoul(optarg, NULL, 10); + break; + case 'p': + path = optarg; + break; + case 's': + seed = strtoul(optarg, NULL, 10); + break; + default: + exitcode = 1; + hashcoll_help(); + return 0; + } + } + + if (path) { + int oflags = O_RDWR; + + if (!create_xattr) + oflags = O_RDONLY | O_DIRECTORY; + + fd = open(path, oflags); + if (fd < 0) { + perror(path); + exitcode = 1; + return 0; + } + } + + if (seed) + srandom(seed); + + if (read_stdin) { + char buf[MAXNAMELEN]; + size_t len; + + len = fread(buf, 1, MAXNAMELEN - 1, stdin); + + if (create_xattr) + error = collide_xattrs(nr, buf, len, fd); + else + error = collide_dirents(nr, buf, len, fd); + if (error) { + printf(_("hashcoll: %s\n"), strerror(error)); + exitcode = 1; + } + goto done; + } + + for (c = optind; c < argc; c++) { + size_t len = strlen(argv[c]); + + if (create_xattr) + error = collide_xattrs(nr, argv[c], len, fd); + else + error = collide_dirents(nr, argv[c], len, fd); + if (error) { + printf(_("hashcoll: %s\n"), strerror(error)); + exitcode = 1; + } + } + +done: + if (fd >= 0) + close(fd); + return 0; +} + +static cmdinfo_t hashcoll_cmd = { + .name = "hashcoll", + .cfunc = hashcoll_f, + .argmin = 0, + .argmax = -1, + .args = N_("[-a] [-s seed] [-n nr] [-p path] -i|names..."), + .oneline = N_("create names that produce dahash collisions"), + .help = hashcoll_help, +}; + void hash_init(void) { add_command(&hash_cmd); + add_command(&hashcoll_cmd); } + diff --git a/man/man8/xfs_db.8 b/man/man8/xfs_db.8 index 1a2bb7e98..fde1c5c6c 100644 --- a/man/man8/xfs_db.8 +++ b/man/man8/xfs_db.8 @@ -768,6 +768,37 @@ Prints the hash value of .I string using the hash function of the XFS directory and attribute implementation. .TP +.BI "hashcoll [-a] [-s seed] [-n " nr "] [-p " path "] -i | " names... +Create directory entries or extended attributes names that all have the same +hash value. +The metadump name obfuscation algorithm is used here. +Names are written to standard output, with a NULL between each name for use +with xargs -0. +.RS 1.0i +.PD 0 +.TP 0.4i +.TP 0.4i +.B \-a +Create extended attribute names. +.TP 0.4i +.B \-i +Read the first name to create from standard input. +Up to 255 bytes are read. +If this option is not specified, first names are taken from the command line. +.TP 0.4i +.BI \-n " nr" +Create this many duplicated names. +The default is to create one name. +.TP 0.4i +.BI \-p " path" +Create directory entries or extended attributes in this file instead of +writing the names to standard output. +.TP 0.4i +.BI \-s " seed" +Seed the random number generator with this value. +.PD +.RE +.TP .BI "help [" command ] Print help for one or all commands. .TP From patchwork Thu Apr 6 19:38:51 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: 13203991 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 0E643C7618D for ; Thu, 6 Apr 2023 19:38:56 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237261AbjDFTiz (ORCPT ); Thu, 6 Apr 2023 15:38:55 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:41150 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230179AbjDFTiy (ORCPT ); Thu, 6 Apr 2023 15:38:54 -0400 Received: from dfw.source.kernel.org (dfw.source.kernel.org [IPv6:2604:1380:4641:c500::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 9EEBC94 for ; Thu, 6 Apr 2023 12:38:52 -0700 (PDT) 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 dfw.source.kernel.org (Postfix) with ESMTPS id 3DBB360DED for ; Thu, 6 Apr 2023 19:38:52 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 9EBF1C4339B; Thu, 6 Apr 2023 19:38:51 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1680809931; bh=Vp9r3b3okPwN/zXVxvuEOGE0BDFNYKzsFMknEdN/8JY=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=s3HiuF9DMRMmIrJ86VYU5iqHkO8N2fixssbo2BGg72pVMGphXgLkRkcBe2c7P4e0J 3zaO2NR3jAyCy7Bp6SiVsQpe3HzNepaTVaHGft5TiETiSmKqF56lvo5EN81rlQb9oP aJ8sRbR8q09Zan9YVxt9y9mn7g3eKxsIqbuWUUbJHvI+p83VAJl80r7ivbvv9kFTTs 2TF1XN6IJD+3/E3HOiwpRHjECYIZKt9KpnDv/6yo+Z1+luS0jXEsuwr9UnDysI8Tjj Gq+wC8SrmCKjJRq+2+LOeu8jl+qmg32Bdy6pSZ7jXM21w12r8uNUDcWh5nHwzD1NpO ZSX3j46QbQE+w== Date: Thu, 06 Apr 2023 12:38:51 -0700 Subject: [PATCH 28/32] xfs_db: add a parents command to list the parents of a file From: "Darrick J. Wong" To: djwong@kernel.org Cc: allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <168080827925.616793.8896509199935689523.stgit@frogsfrogsfrogs> In-Reply-To: <168080827546.616793.7264157843231723676.stgit@frogsfrogsfrogs> References: <168080827546.616793.7264157843231723676.stgit@frogsfrogsfrogs> 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 Create a command to dump the parents of a file. Signed-off-by: Darrick J. Wong --- db/namei.c | 335 +++++++++++++++++++++++++++++++++++++++++++++++++++++ man/man8/xfs_db.8 | 9 + 2 files changed, 344 insertions(+) diff --git a/db/namei.c b/db/namei.c index 063721ca9..98a019d8f 100644 --- a/db/namei.c +++ b/db/namei.c @@ -596,6 +596,338 @@ static struct cmdinfo ls_cmd = { .help = ls_help, }; +static void +pptr_emit( + struct xfs_mount *mp, + const struct xfs_parent_name_irec *irec) +{ + struct xfs_name xname = { + .name = irec->p_name, + .len = irec->p_namelen, + }; + xfs_dahash_t hash; + bool good; + + hash = libxfs_dir2_hashname(mp, &xname); + good = hash == irec->p_namehash && + libxfs_dir2_namecheck(irec->p_name, irec->p_namelen); + + dbprintf("%18llu:0x%08x 0x%08x:0x%08x %3d %.*s %s\n", + irec->p_ino, irec->p_gen, irec->p_namehash, hash, + xname.len, xname.len, xname.name, + good ? _("(good)") : _("(corrupt)")); +} + +static int +list_sf_pptrs( + struct xfs_inode *ip) +{ + struct xfs_parent_name_irec irec; + struct xfs_attr_shortform *sf; + struct xfs_attr_sf_entry *sfe; + unsigned int i; + + sf = (struct xfs_attr_shortform *)ip->i_af.if_u1.if_data; + for (i = 0, sfe = &sf->list[0]; i < sf->hdr.count; i++) { + void *name = sfe->nameval; + void *value = &sfe->nameval[sfe->namelen]; + + if ((sfe->flags & XFS_ATTR_PARENT) && + libxfs_parent_namecheck(mp, name, sfe->namelen, sfe->flags) && + libxfs_parent_valuecheck(mp, value, sfe->valuelen)) { + libxfs_parent_irec_from_disk(&irec, name, value, + sfe->valuelen); + pptr_emit(mp, &irec); + } + + sfe = xfs_attr_sf_nextentry(sfe); + } + + return 0; +} + +static void +list_leaf_pptr_entries( + struct xfs_inode *ip, + struct xfs_buf *bp) +{ + struct xfs_parent_name_irec irec; + struct xfs_attr3_icleaf_hdr ichdr; + struct xfs_mount *mp = ip->i_mount; + struct xfs_attr_leafblock *leaf = bp->b_addr; + struct xfs_attr_leaf_entry *entry; + unsigned int i; + + libxfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &ichdr, leaf); + entry = xfs_attr3_leaf_entryp(leaf); + + for (i = 0; i < ichdr.count; entry++, i++) { + struct xfs_attr_leaf_name_local *name_loc; + void *value; + void *name; + unsigned int namelen, valuelen; + + if (!(entry->flags & XFS_ATTR_LOCAL) || + !(entry->flags & XFS_ATTR_PARENT)) + continue; + + name_loc = xfs_attr3_leaf_name_local(leaf, i); + name = name_loc->nameval; + namelen = name_loc->namelen; + value = &name_loc->nameval[name_loc->namelen]; + valuelen = be16_to_cpu(name_loc->valuelen); + + if (libxfs_parent_namecheck(mp, name, namelen, entry->flags) && + libxfs_parent_valuecheck(mp, value, valuelen)) { + libxfs_parent_irec_from_disk(&irec, name, value, + valuelen); + pptr_emit(mp, &irec); + } + } +} + +static int +list_leaf_pptrs( + struct xfs_inode *ip) +{ + struct xfs_buf *leaf_bp; + int error; + + error = -libxfs_attr3_leaf_read(NULL, ip, 0, &leaf_bp); + if (error) + return error; + + list_leaf_pptr_entries(ip, leaf_bp); + libxfs_trans_brelse(NULL, leaf_bp); + return 0; +} + +static int +find_leftmost_attr_leaf( + struct xfs_inode *ip, + struct xfs_buf **leaf_bpp) +{ + struct xfs_da3_icnode_hdr nodehdr; + struct xfs_mount *mp = ip->i_mount; + struct xfs_da_intnode *node; + struct xfs_da_node_entry *btree; + struct xfs_buf *bp; + xfs_dablk_t blkno = 0; + unsigned int expected_level = 0; + int error; + + for (;;) { + uint16_t magic; + + error = -libxfs_da3_node_read(NULL, ip, blkno, &bp, + XFS_ATTR_FORK); + if (error) + return error; + + node = bp->b_addr; + magic = be16_to_cpu(node->hdr.info.magic); + if (magic == XFS_ATTR_LEAF_MAGIC || + magic == XFS_ATTR3_LEAF_MAGIC) + break; + + error = EFSCORRUPTED; + if (magic != XFS_DA_NODE_MAGIC && + magic != XFS_DA3_NODE_MAGIC) + goto out_buf; + + libxfs_da3_node_hdr_from_disk(mp, &nodehdr, node); + + if (nodehdr.count == 0 || nodehdr.level >= XFS_DA_NODE_MAXDEPTH) + goto out_buf; + + /* Check the level from the root node. */ + if (blkno == 0) + expected_level = nodehdr.level - 1; + else if (expected_level != nodehdr.level) + goto out_buf; + else + expected_level--; + + /* Find the next level towards the leaves of the dabtree. */ + btree = nodehdr.btree; + blkno = be32_to_cpu(btree->before); + libxfs_trans_brelse(NULL, bp); + } + + error = EFSCORRUPTED; + if (expected_level != 0) + goto out_buf; + + *leaf_bpp = bp; + return 0; + +out_buf: + libxfs_trans_brelse(NULL, bp); + return error; +} + +static int +list_node_pptrs( + struct xfs_inode *ip) +{ + struct xfs_attr3_icleaf_hdr leafhdr; + struct xfs_mount *mp = ip->i_mount; + struct xfs_attr_leafblock *leaf; + struct xfs_buf *leaf_bp; + int error; + + error = find_leftmost_attr_leaf(ip, &leaf_bp); + if (error) + return error; + + for (;;) { + list_leaf_pptr_entries(ip, leaf_bp); + + /* Find the right sibling of this leaf block. */ + leaf = leaf_bp->b_addr; + libxfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &leafhdr, leaf); + if (leafhdr.forw == 0) + goto out_leaf; + + libxfs_trans_brelse(NULL, leaf_bp); + + error = -libxfs_attr3_leaf_read(NULL, ip, leafhdr.forw, + &leaf_bp); + if (error) + return error; + } + +out_leaf: + libxfs_trans_brelse(NULL, leaf_bp); + return error; +} + +static int +list_pptrs( + struct xfs_inode *ip) +{ + int error; + + if (!libxfs_inode_hasattr(ip)) + return 0; + + if (ip->i_af.if_format == XFS_DINODE_FMT_LOCAL) + return list_sf_pptrs(ip); + + /* attr functions require that the attr fork is loaded */ + error = -libxfs_iread_extents(NULL, ip, XFS_ATTR_FORK); + if (error) + return error; + + if (libxfs_attr_is_leaf(ip)) + return list_leaf_pptrs(ip); + + return list_node_pptrs(ip); +} + +/* If the io cursor points to a file, list its parents. */ +static int +parent_cur( + char *tag) +{ + struct xfs_inode *ip; + int error = 0; + + if (!xfs_has_parent(mp)) + return 0; + + if (iocur_top->typ != &typtab[TYP_INODE]) + return ENOTDIR; + + error = -libxfs_iget(mp, NULL, iocur_top->ino, 0, &ip); + if (error) + return error; + + /* List the parents of a file. */ + if (tag) + dbprintf(_("%s:\n"), tag); + + error = list_pptrs(ip); + if (error) + goto rele; + +rele: + libxfs_irele(ip); + return error; +} + +static void +parent_help(void) +{ + dbprintf(_( +"\n" +" List the parents of the currently selected file.\n" +"\n" +" Parent pointers will be listed in the format:\n" +" inode_number:inode_gen ondisk_namehash:namehash name_length name\n" + )); +} + +static int +parent_f( + int argc, + char **argv) +{ + int c; + int error = 0; + + while ((c = getopt(argc, argv, "")) != -1) { + switch (c) { + default: + ls_help(); + return 0; + } + } + + if (optind == argc) { + error = parent_cur(NULL); + if (error) { + dbprintf("%s\n", strerror(error)); + exitcode = 1; + } + + return 0; + } + + for (c = optind; c < argc; c++) { + push_cur(); + + error = path_walk(argv[c]); + if (error) + goto err_cur; + + error = parent_cur(argv[c]); + if (error) + goto err_cur; + + pop_cur(); + } + + return 0; +err_cur: + pop_cur(); + if (error) { + dbprintf("%s: %s\n", argv[c], strerror(error)); + exitcode = 1; + } + return 0; +} + +static struct cmdinfo parent_cmd = { + .name = "parent", + .altname = "pptr", + .cfunc = parent_f, + .argmin = 0, + .argmax = -1, + .canpush = 0, + .args = "[paths...]", + .help = parent_help, +}; void namei_init(void) { @@ -604,4 +936,7 @@ namei_init(void) ls_cmd.oneline = _("list directory contents"); add_command(&ls_cmd); + + parent_cmd.oneline = _("list parent pointers"); + add_command(&parent_cmd); } diff --git a/man/man8/xfs_db.8 b/man/man8/xfs_db.8 index fde1c5c6c..02351d1ec 100644 --- a/man/man8/xfs_db.8 +++ b/man/man8/xfs_db.8 @@ -884,6 +884,15 @@ See the .B print command. .TP +.BI "parent [" paths "]..." +List the parents of a file. +If a path resolves to a file, the parents of that file will be listed. +If no paths are supplied and the IO cursor points at an inode, the parents of +that file will be listed. + +The output format is: +inode number, inode generation, ondisk namehash, namehash, name length, name. +.TP .BI "path " dir_path Walk the directory tree to an inode using the supplied path. Absolute and relative paths are supported. From patchwork Thu Apr 6 19:39: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: 13203992 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 AF573C7618D for ; Thu, 6 Apr 2023 19:39:10 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230007AbjDFTjJ (ORCPT ); Thu, 6 Apr 2023 15:39:09 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:41480 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237250AbjDFTjJ (ORCPT ); Thu, 6 Apr 2023 15:39:09 -0400 Received: from dfw.source.kernel.org (dfw.source.kernel.org [IPv6:2604:1380:4641:c500::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3A3FEE50 for ; Thu, 6 Apr 2023 12:39:08 -0700 (PDT) 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 dfw.source.kernel.org (Postfix) with ESMTPS id CBD1060EFE for ; Thu, 6 Apr 2023 19:39:07 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 3E987C433D2; Thu, 6 Apr 2023 19:39:07 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1680809947; bh=1KEN42LiXPBKOY3IuYH/aqO+L+wW1zQtez9mGWda0vw=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=B1cjzVRYWeqwCZ0BllIA+H1hYJl7Kd0zoWoaUNlLdogBUQiJu3BqNkvWNq/DnUGpD e0CFvba4ob+5iPYxzxzjhn2j19hb04d4EKNFQUgwc+5Xa25nqINMEJyIJ5xHRHEn/p 7C6f27MhdsxN14V92EC0OwinPUYl46M1vfuuFpycDVx/p6qmlP80+RxO4forbou45R 0evStWDF1UW3XfdF390Eq/fB04Bbit/NBviETI/vZT/yVAIGQsSS9+jq6W5Qv10ehe pJ8+T+u5qoPbiAcwPXw469RqBfSbSC28Qa+IALN9DBfPBLXI54XCr0CMpllxZgJTXQ pkgpPcCiytmmw== Date: Thu, 06 Apr 2023 12:39:06 -0700 Subject: [PATCH 29/32] libxfs: create new files with attr forks if necessary From: "Darrick J. Wong" To: djwong@kernel.org Cc: allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <168080827939.616793.12522854598295807492.stgit@frogsfrogsfrogs> In-Reply-To: <168080827546.616793.7264157843231723676.stgit@frogsfrogsfrogs> References: <168080827546.616793.7264157843231723676.stgit@frogsfrogsfrogs> 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 Create new files with attr forks if they're going to have parent pointers. In the next patch we'll fix mkfs to use the same parent creation functions as the kernel, so we're going to need this. Signed-off-by: Darrick J. Wong --- libxfs/init.c | 4 ++++ libxfs/util.c | 14 ++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/libxfs/init.c b/libxfs/init.c index 59cd547d6..101b77602 100644 --- a/libxfs/init.c +++ b/libxfs/init.c @@ -746,14 +746,18 @@ void libxfs_compute_all_maxlevels( struct xfs_mount *mp) { + struct xfs_ino_geometry *igeo = M_IGEO(mp); + xfs_alloc_compute_maxlevels(mp); xfs_bmap_compute_maxlevels(mp, XFS_DATA_FORK); xfs_bmap_compute_maxlevels(mp, XFS_ATTR_FORK); + igeo->attr_fork_offset = xfs_bmap_compute_attr_offset(mp); xfs_ialloc_setup_geometry(mp); xfs_rmapbt_compute_maxlevels(mp); xfs_refcountbt_compute_maxlevels(mp); xfs_agbtree_compute_maxlevels(mp); + } /* diff --git a/libxfs/util.c b/libxfs/util.c index 6525f63de..bea5f1c71 100644 --- a/libxfs/util.c +++ b/libxfs/util.c @@ -322,6 +322,20 @@ libxfs_init_new_inode( ASSERT(0); } + /* + * If we need to create attributes immediately after allocating the + * inode, initialise an empty attribute fork right now. We use the + * default fork offset for attributes here as we don't know exactly what + * size or how many attributes we might be adding. We can do this + * safely here because we know the data fork is completely empty and + * this saves us from needing to run a separate transaction to set the + * fork offset in the immediate future. + */ + if (xfs_has_parent(tp->t_mountp) && xfs_has_attr(tp->t_mountp)) { + ip->i_forkoff = xfs_default_attroffset(ip) >> 3; + xfs_ifork_init_attr(ip, XFS_DINODE_FMT_EXTENTS, 0); + } + /* * Log the new values stuffed into the inode. */ From patchwork Thu Apr 6 19:39: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: 13203993 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 8568DC7618D for ; Thu, 6 Apr 2023 19:39:26 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229982AbjDFTjZ (ORCPT ); Thu, 6 Apr 2023 15:39:25 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:41540 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229518AbjDFTjY (ORCPT ); Thu, 6 Apr 2023 15:39:24 -0400 Received: from dfw.source.kernel.org (dfw.source.kernel.org [139.178.84.217]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id DD1669F for ; Thu, 6 Apr 2023 12:39:23 -0700 (PDT) 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 dfw.source.kernel.org (Postfix) with ESMTPS id 7776E60FA6 for ; Thu, 6 Apr 2023 19:39:23 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id CF47EC433D2; Thu, 6 Apr 2023 19:39:22 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1680809962; bh=MpAWHMDIwTiOZX99OMpmDuNaAR5q4sl6CzNjTnJhJtU=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=g67uAuJzRRFb5hfFQUG1C2Ac/mAWl1CsfhTZ7hV4V9KYjLsEYTnBZSjZOWCj9MII2 5BM2cClrQ5dy7qFHHtra243/1kk8B8YDqR3nNKGY+r+er6mcjdZheMOEfuzfYaWlC1 LGm8Dq2ezf5LBu52prvzm9ocwVUGRypa3TFbMOTTmQTg7BzJub4IQVFXiG18qMPbmM t0a6ym9kvY+mBQudTtaFifvWvmKTtdz1JH2vkEg9y9aRMiqRnjIxDQqTlSjIUinHxp ulmQHGrASeF/efh+psPAvFV5ozZQcBisOc4uMzbcLaS3PTgFWh0T+SfJUq0kwprgkH EBrUxEmZMGeoA== Date: Thu, 06 Apr 2023 12:39:22 -0700 Subject: [PATCH 30/32] xfsprogs: Fix default superblock attr bits From: "Darrick J. Wong" To: djwong@kernel.org Cc: Allison Henderson , allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <168080827952.616793.11727080637758218778.stgit@frogsfrogsfrogs> In-Reply-To: <168080827546.616793.7264157843231723676.stgit@frogsfrogsfrogs> References: <168080827546.616793.7264157843231723676.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-xfs@vger.kernel.org From: Allison Henderson Recent parent pointer testing discovered that the default attr configuration has XFS_SB_VERSION2_ATTR2BIT enabled but XFS_SB_VERSION_ATTRBIT disabled. This is incorrect since XFS_SB_VERSION2_ATTR2BIT describes the format of the attr where as XFS_SB_VERSION_ATTRBIT enables or disables attrs. Fix this by enableing XFS_SB_VERSION_ATTRBIT for either attr version 1 or 2 Signed-off-by: Allison Henderson Reviewed-by: Darrick J. Wong --- mkfs/xfs_mkfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c index 4399bf379..f2e683117 100644 --- a/mkfs/xfs_mkfs.c +++ b/mkfs/xfs_mkfs.c @@ -3266,7 +3266,7 @@ sb_set_features( sbp->sb_versionnum |= XFS_SB_VERSION_DALIGNBIT; if (fp->log_version == 2) sbp->sb_versionnum |= XFS_SB_VERSION_LOGV2BIT; - if (fp->attr_version == 1) + if (fp->attr_version >= 1) sbp->sb_versionnum |= XFS_SB_VERSION_ATTRBIT; if (fp->nci) sbp->sb_versionnum |= XFS_SB_VERSION_BORGBIT; From patchwork Thu Apr 6 19:39:38 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: 13203996 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 99E29C7618D for ; Thu, 6 Apr 2023 19:39:42 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230084AbjDFTjl (ORCPT ); Thu, 6 Apr 2023 15:39:41 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:41596 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229518AbjDFTjl (ORCPT ); Thu, 6 Apr 2023 15:39:41 -0400 Received: from dfw.source.kernel.org (dfw.source.kernel.org [139.178.84.217]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6D8D694 for ; Thu, 6 Apr 2023 12:39:39 -0700 (PDT) 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 dfw.source.kernel.org (Postfix) with ESMTPS id 0853860F9F for ; Thu, 6 Apr 2023 19:39:39 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 68BA7C4339B; Thu, 6 Apr 2023 19:39:38 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1680809978; bh=FxSAnXMplhguqw6nhGKRHNdCbDlQey16fCFDgudthUw=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=EF4xBTH2MVrSzExXnfbJjOAL0KoaOkPf1cPauc4EV2DZ39r/K1AOBPPbX0vmiR6lV W1wSYj/eDirnh+/ox3gOKU9Zy/juDv5fRMfJ00E5uOx//M3kLLP9G8Lydxk10BdD8e ZLTpZiN0tVjPLmM04ZHSkJaqZIq/fpZNW0gBaCVuuOtwLJHw6s0BMf0oi1FUEw7rUS rZkOyNtfWRXTRgjnrlweyLH+9oYon8JpINWoHZPNjQJHIAol0bkj1ev3cf63g7rWwM xKWH3XQSgkkyxTyhtSy+Hwd7rRoRC5XOegrfPRUKGMDdb5jJEvwcoafqkD7hf3wXoM yiOvzD2R0S8dg== Date: Thu, 06 Apr 2023 12:39:38 -0700 Subject: [PATCH 31/32] mkfs: Add parent pointers during protofile creation From: "Darrick J. Wong" To: djwong@kernel.org Cc: Allison Henderson , allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <168080827965.616793.17306235980370217756.stgit@frogsfrogsfrogs> In-Reply-To: <168080827546.616793.7264157843231723676.stgit@frogsfrogsfrogs> References: <168080827546.616793.7264157843231723676.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-xfs@vger.kernel.org From: Allison Henderson Inodes created from protofile parsing will also need to add the appropriate parent pointers. Signed-off-by: Allison Henderson Reviewed-by: Darrick J. Wong [djwong: use xfs_parent_add from libxfs instead of open-coding xfs_attr_set] Signed-off-by: Darrick J. Wong --- mkfs/proto.c | 48 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/mkfs/proto.c b/mkfs/proto.c index ea31cfe5c..d6999b850 100644 --- a/mkfs/proto.c +++ b/mkfs/proto.c @@ -378,6 +378,20 @@ newdirectory( fail(_("directory create error"), error); } +static struct xfs_parent_defer * +newpptr( + struct xfs_mount *mp) +{ + struct xfs_parent_defer *ret; + int error; + + error = -libxfs_parent_start(mp, &ret); + if (error) + fail(_("initializing parent pointer"), error); + + return ret; +} + static void parseproto( xfs_mount_t *mp, @@ -412,6 +426,7 @@ parseproto( struct cred creds; char *value; struct xfs_name xname; + struct xfs_parent_defer *parent = NULL; memset(&creds, 0, sizeof(creds)); mstr = getstr(pp); @@ -486,6 +501,7 @@ parseproto( case IF_REGULAR: buf = newregfile(pp, &len); tp = getres(mp, XFS_B_TO_FSB(mp, len)); + parent = newpptr(mp); error = -libxfs_dir_ialloc(&tp, pip, mode|S_IFREG, 1, 0, &creds, fsxp, &ip); if (error) @@ -509,7 +525,7 @@ parseproto( exit(1); } tp = getres(mp, XFS_B_TO_FSB(mp, llen)); - + parent = newpptr(mp); error = -libxfs_dir_ialloc(&tp, pip, mode|S_IFREG, 1, 0, &creds, fsxp, &ip); if (error) @@ -520,15 +536,24 @@ parseproto( xname.type = XFS_DIR3_FT_REG_FILE; newdirent(mp, tp, pip, &xname, ip->i_ino); libxfs_trans_log_inode(tp, ip, flags); + if (parent) { + error = -libxfs_parent_add(tp, parent, pip, &xname, + ip); + if (error) + fail(_("committing parent pointers failed."), + error); + } error = -libxfs_trans_commit(tp); if (error) fail(_("Space preallocation failed."), error); + libxfs_parent_finish(mp, parent); rsvfile(mp, ip, llen); libxfs_irele(ip); return; case IF_BLOCK: tp = getres(mp, 0); + parent = newpptr(mp); majdev = getnum(getstr(pp), 0, 0, false); mindev = getnum(getstr(pp), 0, 0, false); error = -libxfs_dir_ialloc(&tp, pip, mode|S_IFBLK, 1, @@ -544,6 +569,7 @@ parseproto( case IF_CHAR: tp = getres(mp, 0); + parent = newpptr(mp); majdev = getnum(getstr(pp), 0, 0, false); mindev = getnum(getstr(pp), 0, 0, false); error = -libxfs_dir_ialloc(&tp, pip, mode|S_IFCHR, 1, @@ -558,6 +584,7 @@ parseproto( case IF_FIFO: tp = getres(mp, 0); + parent = newpptr(mp); error = -libxfs_dir_ialloc(&tp, pip, mode|S_IFIFO, 1, 0, &creds, fsxp, &ip); if (error) @@ -570,6 +597,7 @@ parseproto( buf = getstr(pp); len = (int)strlen(buf); tp = getres(mp, XFS_B_TO_FSB(mp, len)); + parent = newpptr(mp); error = -libxfs_dir_ialloc(&tp, pip, mode|S_IFLNK, 1, 0, &creds, fsxp, &ip); if (error) @@ -592,6 +620,7 @@ parseproto( libxfs_log_sb(tp); isroot = 1; } else { + parent = newpptr(mp); libxfs_trans_ijoin(tp, pip, 0); xname.type = XFS_DIR3_FT_DIR; newdirent(mp, tp, pip, &xname, ip->i_ino); @@ -600,9 +629,19 @@ parseproto( } newdirectory(mp, tp, ip, pip); libxfs_trans_log_inode(tp, ip, flags); + if (parent) { + error = -libxfs_parent_add(tp, parent, pip, &xname, + ip); + if (error) + fail(_("committing parent pointers failed."), + error); + } error = -libxfs_trans_commit(tp); if (error) fail(_("Directory inode allocation failed."), error); + + libxfs_parent_finish(mp, parent); + /* * RT initialization. Do this here to ensure that * the RT inodes get placed after the root inode. @@ -625,11 +664,18 @@ parseproto( fail(_("Unknown format"), EINVAL); } libxfs_trans_log_inode(tp, ip, flags); + if (parent) { + error = -libxfs_parent_add(tp, parent, pip, &xname, ip); + if (error) + fail(_("committing parent pointers failed."), error); + } error = -libxfs_trans_commit(tp); if (error) { fail(_("Error encountered creating file from prototype file"), error); } + + libxfs_parent_finish(mp, parent); libxfs_irele(ip); } From patchwork Thu Apr 6 19:39: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: 13203997 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 8E516C76196 for ; Thu, 6 Apr 2023 19:39:59 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237442AbjDFTj6 (ORCPT ); Thu, 6 Apr 2023 15:39:58 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:41678 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237562AbjDFTjz (ORCPT ); Thu, 6 Apr 2023 15:39:55 -0400 Received: from dfw.source.kernel.org (dfw.source.kernel.org [IPv6:2604:1380:4641:c500::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 135AB9F for ; Thu, 6 Apr 2023 12:39:55 -0700 (PDT) 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 dfw.source.kernel.org (Postfix) with ESMTPS id 942B260CEB for ; Thu, 6 Apr 2023 19:39:54 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 08B44C433EF; Thu, 6 Apr 2023 19:39:53 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1680809994; bh=CgT6sZz/FZU1+AtZT8C8ViunruwKg5aARNjY4H+fzpo=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=H202gcDTBJTCAuEyHCgyei3Py8fEJ44nAMVad/KyY7ERVyADPMX6Ebk/gzAznKrdv g56w2N77DzlvqVaLcIC2cEs7lAV3bH4bs8IsOrlui/dcek+GZyso4/EY9iQQfsMN4S CqvWoon+/BGpBZE2iD6bSVGcNMnIIs/hF9K1NvvBx73J7aSO4wc4gvpaIO9P6SkzT3 V+cqVKylEuJT/POydCee3YiC6Er4Wapaj5S96rCAt1DeNslvu6lkeny7NBd1+cZs9q ntymBu9pTof3M8FWxykP3UXWfvWf99hcAHUIc3bXsmDxvRfWEpcLOT7C9r6vDjtWi9 6WRH52qqhsmcQ== Date: Thu, 06 Apr 2023 12:39:53 -0700 Subject: [PATCH 32/32] mkfs: enable formatting with parent pointers From: "Darrick J. Wong" To: djwong@kernel.org Cc: Allison Henderson , allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <168080827979.616793.4825719167031475284.stgit@frogsfrogsfrogs> In-Reply-To: <168080827546.616793.7264157843231723676.stgit@frogsfrogsfrogs> References: <168080827546.616793.7264157843231723676.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-xfs@vger.kernel.org From: Allison Henderson Enable parent pointer support in mkfs via the '-n parent' parameter. Signed-off-by: Allison Henderson Reviewed-by: Darrick J. Wong --- mkfs/xfs_mkfs.c | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c index f2e683117..c86f2bedf 100644 --- a/mkfs/xfs_mkfs.c +++ b/mkfs/xfs_mkfs.c @@ -110,6 +110,7 @@ enum { N_SIZE = 0, N_VERSION, N_FTYPE, + N_PARENT, N_MAX_OPTS, }; @@ -621,6 +622,7 @@ static struct opt_params nopts = { [N_SIZE] = "size", [N_VERSION] = "version", [N_FTYPE] = "ftype", + [N_PARENT] = "parent", [N_MAX_OPTS] = NULL, }, .subopt_params = { @@ -644,6 +646,14 @@ static struct opt_params nopts = { .maxval = 1, .defaultval = 1, }, + { .index = N_PARENT, + .conflicts = { { NULL, LAST_CONFLICT } }, + .minval = 0, + .maxval = 1, + .defaultval = 1, + }, + + }, }; @@ -1000,7 +1010,7 @@ usage( void ) /* log subvol */ [-l agnum=n,internal,size=num,logdev=xxx,version=n\n\ sunit=value|su=num,sectsize=num,lazy-count=0|1]\n\ /* label */ [-L label (maximum 12 characters)]\n\ -/* naming */ [-n size=num,version=2|ci,ftype=0|1]\n\ +/* naming */ [-n size=num,version=2|ci,ftype=0|1,parent=0|1]]\n\ /* no-op info only */ [-N]\n\ /* prototype file */ [-p fname]\n\ /* quiet */ [-q]\n\ @@ -1774,6 +1784,9 @@ naming_opts_parser( case N_FTYPE: cli->sb_feat.dirftype = getnum(value, opts, subopt); break; + case N_PARENT: + cli->sb_feat.parent_pointers = getnum(value, &nopts, N_PARENT); + break; default: return -EINVAL; } @@ -2286,6 +2299,14 @@ _("inode btree counters not supported without finobt support\n")); cli->sb_feat.inobtcnt = false; } + if ((cli->sb_feat.parent_pointers) && + cli->sb_feat.dir_version == 4) { + fprintf(stderr, +_("parent pointers not supported on v4 filesystems\n")); + usage(); + cli->sb_feat.parent_pointers = false; + } + if (cli->xi->rtname) { if (cli->sb_feat.reflink && cli_opt_set(&mopts, M_REFLINK)) { fprintf(stderr, @@ -3285,8 +3306,6 @@ sb_set_features( sbp->sb_features2 |= XFS_SB_VERSION2_LAZYSBCOUNTBIT; if (fp->projid32bit) sbp->sb_features2 |= XFS_SB_VERSION2_PROJID32BIT; - if (fp->parent_pointers) - sbp->sb_features2 |= XFS_SB_VERSION2_PARENTBIT; if (fp->crcs_enabled) sbp->sb_features2 |= XFS_SB_VERSION2_CRCBIT; if (fp->attr_version == 2) @@ -3327,6 +3346,10 @@ sb_set_features( sbp->sb_features_ro_compat |= XFS_SB_FEAT_RO_COMPAT_INOBTCNT; if (fp->bigtime) sbp->sb_features_incompat |= XFS_SB_FEAT_INCOMPAT_BIGTIME; + if (fp->parent_pointers) { + sbp->sb_features_incompat |= XFS_SB_FEAT_INCOMPAT_PARENT; + sbp->sb_versionnum |= XFS_SB_VERSION_ATTRBIT; + } /* * Sparse inode chunk support has two main inode alignment requirements.