From patchwork Wed Apr 10 00:53:46 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13623381 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E475B7460 for ; Wed, 10 Apr 2024 00:53:46 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712710427; cv=none; b=YkMY7fNHW2NIq1eycm1VrbmCO7ynC8OohIaOxPUAOVb5kGQXGwp5RdIqaiAjG91BM0YW9B7+NKlj4BOkynIO6h+M8IQ+3dz7/sfp10WT6Reaf6Ak4TOaqMCvIkXBOb8T3hLqEoRqNUxZUhWerm5mbSFrZfrrV7N+ifNRlVKhftQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712710427; c=relaxed/simple; bh=pHeRlcaAbjYMq9lUlNk5MQyBb52Y7GOZFy1TAYINrgU=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=jNF5cHTwsIImdJWccDSr5gXtX0VEWdrA95cN6GOlfBBIM53Ni3ClsaSKxAiEZVwDiXY4rT1pC4QUyYLB7jbPG9V1ISnOPYgcB9GW3ZaohDzNdx/cnlUvYs90MmjkXVfWyg58nvgYdr4bNiRa13yyRPS+bgCZ4sepwcSrzbhIcP8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=kfm6l+1O; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="kfm6l+1O" Received: by smtp.kernel.org (Postfix) with ESMTPSA id B9D00C433F1; Wed, 10 Apr 2024 00:53:46 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1712710426; bh=pHeRlcaAbjYMq9lUlNk5MQyBb52Y7GOZFy1TAYINrgU=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=kfm6l+1O+NoamviM5VqV7h2y0WCCrt05KQYLaTKvNHZpanN5K5hJyXhIt2cpF0mBb dp8iOGMQxasc8o7gY2J5nGiwaQVeyUmJdmdqQ6sFs1vc/Z/qPBsAmEXWzOC5UnTcJk hvXlnIpjbr/lHNiXR2r9mSf4EHXr4iwHMCQNIrbUKYj/jX8GuOY7YDZBBEiEXyASpN UYacrPrgKd2/YrFJATGRsvPcziFql+NL5oOgEiFX0YVuri4w7QZB8dejVK3wqcqGcK L8vIuE2ONzj5nE8BJTTbM6dB8XSt2lHzJ5RgL+uqqsgeOCE2vwFbEf3Tzo/2xzg7o4 mbRHAeaxSXCgg== Date: Tue, 09 Apr 2024 17:53:46 -0700 Subject: [PATCH 01/32] xfs: rearrange xfs_attr_match parameters From: "Darrick J. Wong" To: djwong@kernel.org Cc: catherine.hoang@oracle.com, hch@lst.de, allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <171270969575.3631889.6417849868606970393.stgit@frogsfrogsfrogs> In-Reply-To: <171270969477.3631889.12488500941186994317.stgit@frogsfrogsfrogs> References: <171270969477.3631889.12488500941186994317.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Rearrange the parameters to this function so that they match the order of attr listent: attr_flags -> name -> namelen -> value -> valuelen. Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig --- fs/xfs/libxfs/xfs_attr_leaf.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c index 7929caf2052f7..53ef784e3049e 100644 --- a/fs/xfs/libxfs/xfs_attr_leaf.c +++ b/fs/xfs/libxfs/xfs_attr_leaf.c @@ -509,9 +509,9 @@ xfs_attr3_leaf_read( static bool xfs_attr_match( struct xfs_da_args *args, - uint8_t namelen, - unsigned char *name, - int flags) + unsigned int attr_flags, + const unsigned char *name, + unsigned int namelen) { if (args->namelen != namelen) @@ -521,12 +521,12 @@ xfs_attr_match( /* Recovery ignores the INCOMPLETE flag. */ if ((args->op_flags & XFS_DA_OP_RECOVERY) && - args->attr_filter == (flags & XFS_ATTR_NSP_ONDISK_MASK)) + args->attr_filter == (attr_flags & XFS_ATTR_NSP_ONDISK_MASK)) return true; /* All remaining matches need to be filtered by INCOMPLETE state. */ if (args->attr_filter != - (flags & (XFS_ATTR_NSP_ONDISK_MASK | XFS_ATTR_INCOMPLETE))) + (attr_flags & (XFS_ATTR_NSP_ONDISK_MASK | XFS_ATTR_INCOMPLETE))) return false; return true; } @@ -745,8 +745,8 @@ xfs_attr_sf_findname( for (sfe = xfs_attr_sf_firstentry(sf); sfe < xfs_attr_sf_endptr(sf); sfe = xfs_attr_sf_nextentry(sfe)) { - if (xfs_attr_match(args, sfe->namelen, sfe->nameval, - sfe->flags)) + if (xfs_attr_match(args, sfe->flags, sfe->nameval, + sfe->namelen)) return sfe; } @@ -2442,15 +2442,16 @@ xfs_attr3_leaf_lookup_int( */ if (entry->flags & XFS_ATTR_LOCAL) { name_loc = xfs_attr3_leaf_name_local(leaf, probe); - if (!xfs_attr_match(args, name_loc->namelen, - name_loc->nameval, entry->flags)) + if (!xfs_attr_match(args, entry->flags, + name_loc->nameval, + name_loc->namelen)) continue; args->index = probe; return -EEXIST; } else { name_rmt = xfs_attr3_leaf_name_remote(leaf, probe); - if (!xfs_attr_match(args, name_rmt->namelen, - name_rmt->name, entry->flags)) + if (!xfs_attr_match(args, entry->flags, name_rmt->name, + name_rmt->namelen)) continue; args->index = probe; args->rmtvaluelen = be32_to_cpu(name_rmt->valuelen); From patchwork Wed Apr 10 00:54:01 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13623382 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 862C68BF7 for ; Wed, 10 Apr 2024 00:54:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712710442; cv=none; b=vGOEtEOrZMdb/zYmYwd+HZGodNpMBg/fOLcC11N59Ju8FDPSN+XyiJFeJa/bZClwYHR0bmc5LaYijNsMzrwnKmY5RQD8wuULrCBWiVPeiV0kdVb9//psnorArDgI/01rWSwjhFWNCiKYruH+ngeKUWHwfIKG5oUQrFDWGLRO6OY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712710442; c=relaxed/simple; bh=hA+yt9yN8VleVxIll9rThexLpWpT/2vrWsCtU9sMMPk=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=m6sTkKQBduU1yNJ/EPrkrRZbtkuotmC4BFP2Zd6yaU1D9+KFhsz4DvQf01hr69SePAT6lTwZzUboRirDQW4ZhiX76KLD4ISgz2EFmizoBn0JvW47Nu8dIDZPEFrVIg67TLYmkLGMpXjI8jWHAS3eagXg5QbzqWhVaQ2nfZLrxdU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Mh4rArRY; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Mh4rArRY" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 5E460C433C7; Wed, 10 Apr 2024 00:54:02 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1712710442; bh=hA+yt9yN8VleVxIll9rThexLpWpT/2vrWsCtU9sMMPk=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=Mh4rArRYGunWMHgcvdAVli6gkf3voZDDUmvXQ0/2jHsT9V7vxODuWhuG3yOMTiSwI Bi7eaSHlnHv1Q6a+01HPm95fi1ZEKN1MOn4bMoiHJzUwqHgcZTvOPrAyFCR7/NsdQK kC4VnPQNXjJH8/xBT+w7MftT4lNr9sK1HYZl9vWZvDnmCDZ0s5EmQQc/Z0C4TtlP6T tf8MqokcXusEochuS3NQksO0uRsBaM2AX0zKNhv7e0EPVUn1UgsA6dm/NoR6Mu/8KY 0C0GRq7ZW+eI2+gI5oI4pww37sdipS/77KDWe9A5b+bhx3ff//g1k2RDdsa5brERZd DZR69E9KNNzHw== Date: Tue, 09 Apr 2024 17:54:01 -0700 Subject: [PATCH 02/32] xfs: check the flags earlier in xfs_attr_match From: "Darrick J. Wong" To: djwong@kernel.org Cc: Christoph Hellwig , catherine.hoang@oracle.com, hch@lst.de, allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <171270969591.3631889.10114648429816387256.stgit@frogsfrogsfrogs> In-Reply-To: <171270969477.3631889.12488500941186994317.stgit@frogsfrogsfrogs> References: <171270969477.3631889.12488500941186994317.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Christoph Hellwig Checking the flags match is much cheaper than a memcmp, so do it early on in xfs_attr_match, and also add a little helper to calculate the match mask right under the comment explaining the logic for it. Signed-off-by: Christoph Hellwig Reviewed-by: Darrick J. Wong Signed-off-by: Darrick J. Wong --- fs/xfs/libxfs/xfs_attr_leaf.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c index 53ef784e3049e..9cb3a5d1c07d1 100644 --- a/fs/xfs/libxfs/xfs_attr_leaf.c +++ b/fs/xfs/libxfs/xfs_attr_leaf.c @@ -506,6 +506,13 @@ xfs_attr3_leaf_read( * INCOMPLETE flag will not be set in attr->attr_filter, but rather * XFS_DA_OP_RECOVERY will be set in args->op_flags. */ +static inline unsigned int xfs_attr_match_mask(const struct xfs_da_args *args) +{ + if (args->op_flags & XFS_DA_OP_RECOVERY) + return XFS_ATTR_NSP_ONDISK_MASK; + return XFS_ATTR_NSP_ONDISK_MASK | XFS_ATTR_INCOMPLETE; +} + static bool xfs_attr_match( struct xfs_da_args *args, @@ -513,21 +520,15 @@ xfs_attr_match( const unsigned char *name, unsigned int namelen) { + unsigned int mask = xfs_attr_match_mask(args); if (args->namelen != namelen) return false; + if ((args->attr_filter & mask) != (attr_flags & mask)) + return false; if (memcmp(args->name, name, namelen) != 0) return false; - /* Recovery ignores the INCOMPLETE flag. */ - if ((args->op_flags & XFS_DA_OP_RECOVERY) && - args->attr_filter == (attr_flags & XFS_ATTR_NSP_ONDISK_MASK)) - return true; - - /* All remaining matches need to be filtered by INCOMPLETE state. */ - if (args->attr_filter != - (attr_flags & (XFS_ATTR_NSP_ONDISK_MASK | XFS_ATTR_INCOMPLETE))) - return false; return true; } From patchwork Wed Apr 10 00:54:17 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13623383 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3A2138BE7 for ; Wed, 10 Apr 2024 00:54:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712710458; cv=none; b=CIDKJW9/z9TucNY9YEdIL80KXIqrpb3hcXYLQNAprcH9T6xEKuYSvERnNcRckqKPKiyryuTAAjlzIyVEoKpafz0/OIVOOxoJM/5/PZOLWTqeIKeMwivFMEXOjdCjbQpQCkXUJuoWB+IfsVYqhOwGVFbIF4HZC6QUPFEYkaRieok= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712710458; c=relaxed/simple; bh=OpcprZP6RXSQm4IUNQRIzYgFKBBCyZKWiMkMLOkQ18E=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=lnTo6MARSTlte0qewJB/lVMVwHVH+YH6GzM8RR6Gl28Ndx2hIf1TLgIyF5K7bFjGwjTnfLD8HtbJza+yEDp8UDF6NYS5SXK7jUhXTr5d2xgiYxSx0nJoSPWvAJqycgDB130umzLk6V2yOEYBEJ+K1eFO1/zXJMnaGX2Kds1V8sM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=R92dFnqN; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="R92dFnqN" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 065B3C433C7; Wed, 10 Apr 2024 00:54:18 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1712710458; bh=OpcprZP6RXSQm4IUNQRIzYgFKBBCyZKWiMkMLOkQ18E=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=R92dFnqN0N+en+IqmlSEkcTVyFzMNtEufixWDIlf6da8TtYYAxSLp/EHTP+qPhlx3 wZQP4IyGvrcXwDT0ghM3Ms1cfZ3T3FhmYc+ERL6v750SyRKbpb6BFyBvKEFV13KyoQ bWNk1QDYUGWwg43hjDl8eOeSvMcDVnyYjApjkv84EZywQNaNoq2bGEtF3nfLe7HzVB hZpLb2QXur53jEIG46ww7msMT3FYp8ISsfOEtuZkRWgsfXeYAp/v2dTlzUMoiO+Qrk EvDdI4f0xRExyFIeCZac3r68eYVA0DfljbtCHb554o0AGYgN56L6Prv9Yr92gIjMTS nwOMRQei9Bi0Q== Date: Tue, 09 Apr 2024 17:54:17 -0700 Subject: [PATCH 03/32] xfs: move xfs_attr_defer_add to xfs_attr_item.c From: "Darrick J. Wong" To: djwong@kernel.org Cc: catherine.hoang@oracle.com, hch@lst.de, allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <171270969608.3631889.469698599262996242.stgit@frogsfrogsfrogs> In-Reply-To: <171270969477.3631889.12488500941186994317.stgit@frogsfrogsfrogs> References: <171270969477.3631889.12488500941186994317.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Move the code that adds the incore xfs_attr_item deferred work data to a transaction live with the ATTRI log item code. This means that the upper level extended attribute code no longer has to know about the inner workings of the ATTRI log items. Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig --- fs/xfs/libxfs/xfs_attr.c | 37 +++---------------------------------- fs/xfs/xfs_attr_item.c | 30 ++++++++++++++++++++++++++++++ fs/xfs/xfs_attr_item.h | 8 ++++++++ 3 files changed, 41 insertions(+), 34 deletions(-) diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c index 426a41b43f641..03df79f63f674 100644 --- a/fs/xfs/libxfs/xfs_attr.c +++ b/fs/xfs/libxfs/xfs_attr.c @@ -903,37 +903,6 @@ xfs_attr_lookup( return error; } -static void -xfs_attr_defer_add( - struct xfs_da_args *args, - unsigned int op_flags) -{ - - struct xfs_attr_intent *new; - - new = kmem_cache_zalloc(xfs_attr_intent_cache, - GFP_KERNEL | __GFP_NOFAIL); - new->xattri_op_flags = op_flags; - new->xattri_da_args = args; - - switch (op_flags) { - case XFS_ATTRI_OP_FLAGS_SET: - new->xattri_dela_state = xfs_attr_init_add_state(args); - break; - case XFS_ATTRI_OP_FLAGS_REPLACE: - new->xattri_dela_state = xfs_attr_init_replace_state(args); - break; - case XFS_ATTRI_OP_FLAGS_REMOVE: - new->xattri_dela_state = xfs_attr_init_remove_state(args); - break; - default: - ASSERT(0); - } - - xfs_defer_add(args->trans, &new->xattri_list, &xfs_attr_defer_type); - trace_xfs_attr_defer_add(new->xattri_dela_state, args->dp); -} - /* * Note: If args->value is NULL the attribute will be removed, just like the * Linux ->setattr API. @@ -1023,14 +992,14 @@ xfs_attr_set( case -EEXIST: if (!args->value) { /* if no value, we are performing a remove operation */ - xfs_attr_defer_add(args, XFS_ATTRI_OP_FLAGS_REMOVE); + xfs_attr_defer_add(args, XFS_ATTR_DEFER_REMOVE); break; } /* Pure create fails if the attr already exists */ if (args->xattr_flags & XATTR_CREATE) goto out_trans_cancel; - xfs_attr_defer_add(args, XFS_ATTRI_OP_FLAGS_REPLACE); + xfs_attr_defer_add(args, XFS_ATTR_DEFER_REPLACE); break; case -ENOATTR: /* Can't remove what isn't there. */ @@ -1040,7 +1009,7 @@ xfs_attr_set( /* Pure replace fails if no existing attr to replace. */ if (args->xattr_flags & XATTR_REPLACE) goto out_trans_cancel; - xfs_attr_defer_add(args, XFS_ATTRI_OP_FLAGS_SET); + xfs_attr_defer_add(args, XFS_ATTR_DEFER_SET); break; default: goto out_trans_cancel; diff --git a/fs/xfs/xfs_attr_item.c b/fs/xfs/xfs_attr_item.c index 4d4fb804c0016..04aa2c68d5e56 100644 --- a/fs/xfs/xfs_attr_item.c +++ b/fs/xfs/xfs_attr_item.c @@ -723,6 +723,36 @@ xfs_attr_create_done( return &attrdp->attrd_item; } +void +xfs_attr_defer_add( + struct xfs_da_args *args, + enum xfs_attr_defer_op op) +{ + struct xfs_attr_intent *new; + + new = kmem_cache_zalloc(xfs_attr_intent_cache, + GFP_NOFS | __GFP_NOFAIL); + new->xattri_da_args = args; + + switch (op) { + case XFS_ATTR_DEFER_SET: + new->xattri_op_flags = XFS_ATTRI_OP_FLAGS_SET; + new->xattri_dela_state = xfs_attr_init_add_state(args); + break; + case XFS_ATTR_DEFER_REPLACE: + new->xattri_op_flags = XFS_ATTRI_OP_FLAGS_REPLACE; + new->xattri_dela_state = xfs_attr_init_replace_state(args); + break; + case XFS_ATTR_DEFER_REMOVE: + new->xattri_op_flags = XFS_ATTRI_OP_FLAGS_REMOVE; + new->xattri_dela_state = xfs_attr_init_remove_state(args); + break; + } + + xfs_defer_add(args->trans, &new->xattri_list, &xfs_attr_defer_type); + trace_xfs_attr_defer_add(new->xattri_dela_state, args->dp); +} + const struct xfs_defer_op_type xfs_attr_defer_type = { .name = "attr", .max_items = 1, diff --git a/fs/xfs/xfs_attr_item.h b/fs/xfs/xfs_attr_item.h index 3280a79302876..c32b669b0e16a 100644 --- a/fs/xfs/xfs_attr_item.h +++ b/fs/xfs/xfs_attr_item.h @@ -51,4 +51,12 @@ struct xfs_attrd_log_item { extern struct kmem_cache *xfs_attri_cache; extern struct kmem_cache *xfs_attrd_cache; +enum xfs_attr_defer_op { + XFS_ATTR_DEFER_SET, + XFS_ATTR_DEFER_REMOVE, + XFS_ATTR_DEFER_REPLACE, +}; + +void xfs_attr_defer_add(struct xfs_da_args *args, enum xfs_attr_defer_op op); + #endif /* __XFS_ATTR_ITEM_H__ */ From patchwork Wed Apr 10 00:54:33 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13623384 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E71308BF0 for ; Wed, 10 Apr 2024 00:54:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712710474; cv=none; b=mxO8TYE0szY+Umzciidnhtzm3W+kxJlGi36QiHj67BJSFK669D5YVGapilEoeTnzcbZ+AkCa/7ceNbipXKsoDqjcFc69GPhcg9BCgZrQqFiPrUyxvw8UqirB+CHZ0k2NrrIkAbBArL7V8RZNIvKklsTHDfadSKKN7dCOduYDEnQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712710474; c=relaxed/simple; bh=NcGt2vDXoWvdIvQulI3vvCgdtOp2uh3QZuQZ4mSa2Qc=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=Y/BNlbkiiC+Sj6xhDK9IwBw20aOtGatTSHpSO6Im++/AYoJ5B0HSCQlkkI2ROvLt31pTkK3qkgGrQeG2l0EaBG9vDg/tIiwQrZ3isQkxhrQcSsKooOFJ8bbDNfPy7vL6u802m6z/+z2Xi8WeLIa/Fmd1aKjNCosEwAc9bVqTR4I= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=WjM1KZbP; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="WjM1KZbP" Received: by smtp.kernel.org (Postfix) with ESMTPSA id C10F6C433F1; Wed, 10 Apr 2024 00:54:33 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1712710473; bh=NcGt2vDXoWvdIvQulI3vvCgdtOp2uh3QZuQZ4mSa2Qc=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=WjM1KZbP/fah/LJRst8TG+s2GkG/kYKmcPEl4tZqbeaTJnH61WaHwyfDPT+Tt7fFX iEdodYhw19uuEDlLvGdsJSSJOwOCJWkY6vt5s80E2rsejnjTnpAZrXUh8++zfHRlKy /dUSgpPPueL/R1iYv+D0fV0CIjzX6ZzObHZlRfpluJEjP7ciqGkDFEXfNx5R187c3M HthDxi5kocwqMdM7U56JM32dX1/SkdiihEd6jOYtJeUFz2bEs0U+yvncylureWrffF I5ZY7JJR1QhKdigoQLj69YGWgtgRC5zNY5nJEuw5Sq2gMiIM94NDf+NkXGTULvm9QR UECrO1zcrdS/A== Date: Tue, 09 Apr 2024 17:54:33 -0700 Subject: [PATCH 04/32] xfs: create a separate hashname function for extended attributes From: "Darrick J. Wong" To: djwong@kernel.org Cc: catherine.hoang@oracle.com, hch@lst.de, allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <171270969624.3631889.1427903658559985496.stgit@frogsfrogsfrogs> In-Reply-To: <171270969477.3631889.12488500941186994317.stgit@frogsfrogsfrogs> References: <171270969477.3631889.12488500941186994317.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Create a separate function to compute name hashvalues for extended attributes. When we get to parent pointers we'll be altering the rules so that metadump obfuscation doesn't turn heinous. Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig --- fs/xfs/libxfs/xfs_attr.c | 28 ++++++++++++++++++++++++++-- fs/xfs/libxfs/xfs_attr.h | 14 ++++++++++++++ fs/xfs/libxfs/xfs_attr_leaf.c | 3 +-- fs/xfs/scrub/attr.c | 11 ++++++++--- fs/xfs/xfs_attr_item.c | 2 +- fs/xfs/xfs_attr_list.c | 5 ++++- 6 files changed, 54 insertions(+), 9 deletions(-) diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c index 03df79f63f674..30988d60162c7 100644 --- a/fs/xfs/libxfs/xfs_attr.c +++ b/fs/xfs/libxfs/xfs_attr.c @@ -282,7 +282,7 @@ xfs_attr_get( args->owner = args->dp->i_ino; args->geo = args->dp->i_mount->m_attr_geo; args->whichfork = XFS_ATTR_FORK; - args->hashval = xfs_da_hashname(args->name, args->namelen); + xfs_attr_sethash(args); /* Entirely possible to look up a name which doesn't exist */ args->op_flags = XFS_DA_OP_OKNOENT; @@ -417,6 +417,30 @@ xfs_attr_sf_addname( return error; } +/* Compute the hash value for a user/root/secure extended attribute */ +xfs_dahash_t +xfs_attr_hashname( + const uint8_t *name, + int namelen) +{ + return xfs_da_hashname(name, namelen); +} + +/* Compute the hash value for any extended attribute from any namespace. */ +xfs_dahash_t +xfs_attr_hashval( + struct xfs_mount *mp, + unsigned int attr_flags, + const uint8_t *name, + int namelen, + const void *value, + int valuelen) +{ + ASSERT(xfs_attr_check_namespace(attr_flags)); + + return xfs_attr_hashname(name, namelen); +} + /* * Handle the state change on completion of a multi-state attr operation. * @@ -932,7 +956,7 @@ xfs_attr_set( args->owner = args->dp->i_ino; args->geo = mp->m_attr_geo; args->whichfork = XFS_ATTR_FORK; - args->hashval = xfs_da_hashname(args->name, args->namelen); + xfs_attr_sethash(args); /* * We have no control over the attribute names that userspace passes us diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h index 3813f7ae626a2..df91c94d5bf5c 100644 --- a/fs/xfs/libxfs/xfs_attr.h +++ b/fs/xfs/libxfs/xfs_attr.h @@ -620,6 +620,20 @@ xfs_attr_init_replace_state(struct xfs_da_args *args) return xfs_attr_init_add_state(args); } +xfs_dahash_t xfs_attr_hashname(const uint8_t *name, int namelen); + +xfs_dahash_t xfs_attr_hashval(struct xfs_mount *mp, unsigned int attr_flags, + const uint8_t *name, int namelen, const void *value, + int valuelen); + +/* Set the hash value for any extended attribute from any namespace. */ +static inline void xfs_attr_sethash(struct xfs_da_args *args) +{ + args->hashval = xfs_attr_hashval(args->dp->i_mount, args->attr_filter, + args->name, args->namelen, + args->value, args->valuelen); +} + extern struct kmem_cache *xfs_attr_intent_cache; int __init xfs_attr_intent_init_cache(void); void xfs_attr_intent_destroy_cache(void); diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c index 9cb3a5d1c07d1..490608bbed7ad 100644 --- a/fs/xfs/libxfs/xfs_attr_leaf.c +++ b/fs/xfs/libxfs/xfs_attr_leaf.c @@ -947,14 +947,13 @@ xfs_attr_shortform_to_leaf( nargs.namelen = sfe->namelen; nargs.value = &sfe->nameval[nargs.namelen]; nargs.valuelen = sfe->valuelen; - nargs.hashval = xfs_da_hashname(sfe->nameval, - sfe->namelen); nargs.attr_filter = sfe->flags & XFS_ATTR_NSP_ONDISK_MASK; if (!xfs_attr_check_namespace(sfe->flags)) { xfs_da_mark_sick(args); error = -EFSCORRUPTED; goto out; } + xfs_attr_sethash(&nargs); error = xfs_attr3_leaf_lookup_int(bp, &nargs); /* set a->index */ ASSERT(error == -ENOATTR); error = xfs_attr3_leaf_add(bp, &nargs); diff --git a/fs/xfs/scrub/attr.c b/fs/xfs/scrub/attr.c index fdff9be408186..d5c2e73be8623 100644 --- a/fs/xfs/scrub/attr.c +++ b/fs/xfs/scrub/attr.c @@ -179,7 +179,6 @@ xchk_xattr_actor( .dp = ip, .name = name, .namelen = namelen, - .hashval = xfs_da_hashname(name, namelen), .trans = sc->tp, .valuelen = valuelen, .owner = ip->i_ino, @@ -230,6 +229,7 @@ xchk_xattr_actor( args.value = ab->value; + xfs_attr_sethash(&args); error = xfs_attr_get_ilocked(&args); /* ENODATA means the hash lookup failed and the attr is bad */ if (error == -ENODATA) @@ -525,7 +525,10 @@ xchk_xattr_rec( xchk_da_set_corrupt(ds, level); goto out; } - calc_hash = xfs_da_hashname(lentry->nameval, lentry->namelen); + calc_hash = xfs_attr_hashval(mp, ent->flags, lentry->nameval, + lentry->namelen, + lentry->nameval + lentry->namelen, + be16_to_cpu(lentry->valuelen)); } else { rentry = (struct xfs_attr_leaf_name_remote *) (((char *)bp->b_addr) + nameidx); @@ -533,7 +536,9 @@ xchk_xattr_rec( xchk_da_set_corrupt(ds, level); goto out; } - calc_hash = xfs_da_hashname(rentry->name, rentry->namelen); + calc_hash = xfs_attr_hashval(mp, ent->flags, rentry->name, + rentry->namelen, NULL, + be32_to_cpu(rentry->valuelen)); } if (calc_hash != hash) xchk_da_set_corrupt(ds, level); diff --git a/fs/xfs/xfs_attr_item.c b/fs/xfs/xfs_attr_item.c index 04aa2c68d5e56..8f91016fc3cf8 100644 --- a/fs/xfs/xfs_attr_item.c +++ b/fs/xfs/xfs_attr_item.c @@ -578,13 +578,13 @@ xfs_attri_recover_work( args->whichfork = XFS_ATTR_FORK; args->name = nv->name.i_addr; args->namelen = nv->name.i_len; - args->hashval = xfs_da_hashname(args->name, args->namelen); args->value = nv->value.i_addr; args->valuelen = nv->value.i_len; args->attr_filter = attrp->alfi_attr_filter & XFS_ATTRI_FILTER_MASK; args->op_flags = XFS_DA_OP_RECOVERY | XFS_DA_OP_OKNOENT | XFS_DA_OP_LOGGED; args->owner = args->dp->i_ino; + xfs_attr_sethash(args); switch (xfs_attr_intent_op(attr)) { case XFS_ATTRI_OP_FLAGS_SET: diff --git a/fs/xfs/xfs_attr_list.c b/fs/xfs/xfs_attr_list.c index 903ed46c68872..9bc4b5322539a 100644 --- a/fs/xfs/xfs_attr_list.c +++ b/fs/xfs/xfs_attr_list.c @@ -135,12 +135,15 @@ xfs_attr_shortform_list( } sbp->entno = i; - sbp->hash = xfs_da_hashname(sfe->nameval, sfe->namelen); sbp->name = sfe->nameval; sbp->namelen = sfe->namelen; /* These are bytes, and both on-disk, don't endian-flip */ sbp->valuelen = sfe->valuelen; sbp->flags = sfe->flags; + sbp->hash = xfs_attr_hashval(dp->i_mount, sfe->flags, + sfe->nameval, sfe->namelen, + sfe->nameval + sfe->namelen, + sfe->valuelen); sfe = xfs_attr_sf_nextentry(sfe); sbp++; nsbuf++; From patchwork Wed Apr 10 00:54:48 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13623385 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8AC1E38B for ; Wed, 10 Apr 2024 00:54:49 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712710489; cv=none; b=WaV4pqZ4OXBy+unXHYaFV052MWUc1n3QOFglNZvW9iCduTsWypKxqodh8gLOTHKJbZmTeSVdpE2UY5gtOy/JIbca/7qYgcAJgTC7j+fHSCfMndKwi9uJq13JQaeQjLSlZNORY4vzsCqcjFaxy6PspuxevtcE9BK0meEeTGmKVl0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712710489; c=relaxed/simple; bh=Qxmo4xa8r5cbKZcxkRnMQ1YpKIrj6qYl0iF70Uh/IVM=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=m8LVum/xs6KkMbXAO4/cI/RlTgzy80kJlDtNUXMw71go9Ak2UQkgsXs51f0mTEixS67h5ujQ+4imeKD0y2smocT7o1bn+nqAZ9cZEbI5BQ+JaP0oSugblqQHk8wk1zCuPbTOptl3m1rXAICzCevC1qX/vbm893/zQ13t6J5fQDQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=R4edmQ2W; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="R4edmQ2W" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 665C0C433F1; Wed, 10 Apr 2024 00:54:49 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1712710489; bh=Qxmo4xa8r5cbKZcxkRnMQ1YpKIrj6qYl0iF70Uh/IVM=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=R4edmQ2WgZRnv/TNoRgCQH1Rf9JQCW/QPHov+5wfLjRDtZs5jWMDlgTTanK399jIM W8eFsDKNgrSRCN19lDCXpE09dydrR2LJ0tATtDBXm7wKrKpLHr9CBnl8hOzeE1EhMr /OpYUeOba0FNDrJMXrIJSxGzOSChzNi1RdNJpwlMlDM/FXsAYv5Ib4MFRV/vlTU3Ul K/f6wIOqJpv86dP23/EAChavYbIALKdg23bk4qOhBJV7QczgHLiOD+Bl/gpXv1QjhP FhvLo6s9Yc4X55IeO7piRV56DYbhrZwgpVjjob9UDnK1EgtOILRRreZWgGs+pHeU+L WAWdDDNTy9lvg== Date: Tue, 09 Apr 2024 17:54:48 -0700 Subject: [PATCH 05/32] xfs: add parent pointer support to attribute code From: "Darrick J. Wong" To: djwong@kernel.org Cc: Mark Tinguely , Dave Chinner , Allison Henderson , catherine.hoang@oracle.com, hch@lst.de, allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <171270969640.3631889.7554917757452786883.stgit@frogsfrogsfrogs> In-Reply-To: <171270969477.3631889.12488500941186994317.stgit@frogsfrogsfrogs> References: <171270969477.3631889.12488500941186994317.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Allison Henderson Add the new parent attribute type. XFS_ATTR_PARENT is used only for parent pointer entries; it uses reserved blocks like XFS_ATTR_ROOT. Signed-off-by: Mark Tinguely Signed-off-by: Dave Chinner Signed-off-by: Allison Henderson Reviewed-by: Darrick J. Wong Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig --- fs/xfs/libxfs/xfs_da_format.h | 9 +++++++-- fs/xfs/libxfs/xfs_log_format.h | 1 + fs/xfs/xfs_trace.h | 3 ++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/fs/xfs/libxfs/xfs_da_format.h b/fs/xfs/libxfs/xfs_da_format.h index ecd0616f5776a..0c80f7ab9475a 100644 --- a/fs/xfs/libxfs/xfs_da_format.h +++ b/fs/xfs/libxfs/xfs_da_format.h @@ -714,13 +714,17 @@ struct xfs_attr3_leafblock { #define XFS_ATTR_LOCAL_BIT 0 /* attr is stored locally */ #define XFS_ATTR_ROOT_BIT 1 /* limit access to trusted attrs */ #define XFS_ATTR_SECURE_BIT 2 /* limit access to secure attrs */ +#define XFS_ATTR_PARENT_BIT 3 /* parent pointer attrs */ #define XFS_ATTR_INCOMPLETE_BIT 7 /* attr in middle of create/delete */ #define XFS_ATTR_LOCAL (1u << XFS_ATTR_LOCAL_BIT) #define XFS_ATTR_ROOT (1u << XFS_ATTR_ROOT_BIT) #define XFS_ATTR_SECURE (1u << XFS_ATTR_SECURE_BIT) +#define XFS_ATTR_PARENT (1u << XFS_ATTR_PARENT_BIT) #define XFS_ATTR_INCOMPLETE (1u << XFS_ATTR_INCOMPLETE_BIT) -#define XFS_ATTR_NSP_ONDISK_MASK (XFS_ATTR_ROOT | XFS_ATTR_SECURE) +#define XFS_ATTR_NSP_ONDISK_MASK (XFS_ATTR_ROOT | \ + XFS_ATTR_SECURE | \ + XFS_ATTR_PARENT) #define XFS_ATTR_ONDISK_MASK (XFS_ATTR_NSP_ONDISK_MASK | \ XFS_ATTR_LOCAL | \ @@ -729,7 +733,8 @@ struct xfs_attr3_leafblock { #define XFS_ATTR_NAMESPACE_STR \ { XFS_ATTR_LOCAL, "local" }, \ { XFS_ATTR_ROOT, "root" }, \ - { XFS_ATTR_SECURE, "secure" } + { XFS_ATTR_SECURE, "secure" }, \ + { XFS_ATTR_PARENT, "parent" } /* * Alignment for namelist and valuelist entries (since they are mixed diff --git a/fs/xfs/libxfs/xfs_log_format.h b/fs/xfs/libxfs/xfs_log_format.h index accba2acd623d..020aebd101432 100644 --- a/fs/xfs/libxfs/xfs_log_format.h +++ b/fs/xfs/libxfs/xfs_log_format.h @@ -1034,6 +1034,7 @@ struct xfs_icreate_log { */ #define XFS_ATTRI_FILTER_MASK (XFS_ATTR_ROOT | \ XFS_ATTR_SECURE | \ + XFS_ATTR_PARENT | \ XFS_ATTR_INCOMPLETE) /* diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h index e9cf9430ce259..e6cbdffb14f64 100644 --- a/fs/xfs/xfs_trace.h +++ b/fs/xfs/xfs_trace.h @@ -91,7 +91,8 @@ struct xfs_exchrange; #define XFS_ATTR_FILTER_FLAGS \ { XFS_ATTR_ROOT, "ROOT" }, \ { XFS_ATTR_SECURE, "SECURE" }, \ - { XFS_ATTR_INCOMPLETE, "INCOMPLETE" } + { XFS_ATTR_INCOMPLETE, "INCOMPLETE" }, \ + { XFS_ATTR_PARENT, "PARENT" } DECLARE_EVENT_CLASS(xfs_attr_list_class, TP_PROTO(struct xfs_attr_list_context *ctx), From patchwork Wed Apr 10 00:55:04 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13623386 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 393F0621 for ; Wed, 10 Apr 2024 00:55:05 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712710505; cv=none; b=BOOSJnl2Ap/hFONa4Kgc21pcxTcq4dGUCE2Icgv8HaCowU+X7ylELj50m2wNaKGgVHxDxSEGd/8pTiQySKa8yUeCw3yaeS6IOpoKJ5n8RHgrVpnNrbdKJ/lAUntQg/dmC2L9+jRTVAJhfFTi2b/IEvnYQMlKPlJVXCMSqUxYMyc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712710505; c=relaxed/simple; bh=0kAtjWm7heyS4Y6iSVcGaMLgjbtGTpobvd2kXX7eiFU=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=S792MUKOpPq3tQtH0cG22XC0AN5mWPcFcahBRYi8eIDuKnK3oUWQ8LOwO2FFUHiPNqiExpyaCe1hAl76AwDIiDvr/Ld+2HI1PH2TOwEQg5D4idfncqmJNvBYHlg/JETkHvw/0z9o9VgUZcBgfWKcnbpn7bsxtvVLrVCEWwlZ6o0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=ZvTslu6S; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="ZvTslu6S" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 0CE3FC433C7; Wed, 10 Apr 2024 00:55:05 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1712710505; bh=0kAtjWm7heyS4Y6iSVcGaMLgjbtGTpobvd2kXX7eiFU=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=ZvTslu6So8B4tiofa8tL8r81whxeMcRew3PKyjvnKX9aMXXqi3C/aO0dvPMlNBaKk Q+UUKCD7YjuGGDsWjB/7fcdwJBpfzSJ/yfbQqhyeJPBFKlQOrSqN11itARP69rEb69 Jh7eOikaUHOJTaCoeldfs80UJRKrOtkOI1/SGaUXZgYX5hF1+DIhze6julg2xfGbKK Yoy5nA+yekE2vBX43PTan/e1HMk2IfFrMgTuNqAKbhwy43nWPQGnvET7/s0Vfi7iIT I8rox9YxityA4nCF0SFfy43RgzHKhIbwkowv8QpvKqG9xKFQKgrBfsIO/fEnkNTFxz isaV05OEIwagg== Date: Tue, 09 Apr 2024 17:55:04 -0700 Subject: [PATCH 06/32] xfs: define parent pointer ondisk extended attribute format From: "Darrick J. Wong" To: djwong@kernel.org Cc: Allison Henderson , catherine.hoang@oracle.com, hch@lst.de, allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <171270969657.3631889.9403759718168544689.stgit@frogsfrogsfrogs> In-Reply-To: <171270969477.3631889.12488500941186994317.stgit@frogsfrogsfrogs> References: <171270969477.3631889.12488500941186994317.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Allison Henderson We need to define the parent pointer attribute format before we start adding support for it into all the code that needs to use it. The EA format we will use encodes the following information: name={dirent name} value={parent inumber, parent inode generation} hash=xfs_dir2_hashname(dirent name) ^ (parent_inumber) 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. By using the name-value lookup 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: Allison Henderson Reviewed-by: Darrick J. Wong Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig --- fs/xfs/libxfs/xfs_da_format.h | 13 +++++++++++++ fs/xfs/libxfs/xfs_ondisk.h | 1 + 2 files changed, 14 insertions(+) diff --git a/fs/xfs/libxfs/xfs_da_format.h b/fs/xfs/libxfs/xfs_da_format.h index 0c80f7ab9475a..1395ad1937c53 100644 --- a/fs/xfs/libxfs/xfs_da_format.h +++ b/fs/xfs/libxfs/xfs_da_format.h @@ -890,4 +890,17 @@ 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 contains the dirent name. + * The xattr value encodes the parent inode number and generation to ease + * opening parents by handle. + * The xattr hashval is xfs_dir2_namehash() ^ p_ino + */ +struct xfs_parent_rec { + __be64 p_ino; + __be32 p_gen; +} __packed; + #endif /* __XFS_DA_FORMAT_H__ */ diff --git a/fs/xfs/libxfs/xfs_ondisk.h b/fs/xfs/libxfs/xfs_ondisk.h index 81885a6a028ed..25952ef584eee 100644 --- a/fs/xfs/libxfs/xfs_ondisk.h +++ b/fs/xfs/libxfs/xfs_ondisk.h @@ -119,6 +119,7 @@ xfs_check_ondisk_structs(void) XFS_CHECK_OFFSET(xfs_dir2_sf_entry_t, offset, 1); XFS_CHECK_OFFSET(xfs_dir2_sf_entry_t, name, 3); XFS_CHECK_STRUCT_SIZE(xfs_dir2_sf_hdr_t, 10); + XFS_CHECK_STRUCT_SIZE(struct xfs_parent_rec, 12); /* log structures */ XFS_CHECK_STRUCT_SIZE(struct xfs_buf_log_format, 88); From patchwork Wed Apr 10 00:55:20 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13623387 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D57AB38B for ; Wed, 10 Apr 2024 00:55:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712710520; cv=none; b=M/McnGxjzW5sWUzISrn/KgilFqiMyvQ8bNDdkDtg0BrDuNxOc6abhEiq8TlOLvjoJpBgQCBJh2Delvr8ISY1v4qRTJQ74490Vw1MbrZicvt6VX+bnS+GpBwFpo2F+CgL3lItM0ATeQsUJGmQiXmmutDGYPX+COd2mo3Ga0lMy/w= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712710520; c=relaxed/simple; bh=F59VcJpuVD2ZJpUXnJitBIxnWj6nZyd+6b4/PbddAgk=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=qcVhOJqOAicD07Oe/O6MZrNJrlh8AZ4VsLGpsdcjC/nnZfypyXVhk57fR56Ggba1j9KRRBdxFpLWhvZzinrV3nez54Kk89IcZ96iae7ZYjLNg/Sly7aFeZ/h2OsEaFvkc+60HlqBzQZRLX4fB2b/T+RTLrYGssGYWMeT5HytuY0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Gce4elga; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Gce4elga" Received: by smtp.kernel.org (Postfix) with ESMTPSA id A818AC433C7; Wed, 10 Apr 2024 00:55:20 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1712710520; bh=F59VcJpuVD2ZJpUXnJitBIxnWj6nZyd+6b4/PbddAgk=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=Gce4elgatfXx+sIPwHxVntHxgMZh5c6xuf2v1svFksOZeGkzol+PTPz4Z89fc98wk QMRi3B/8fSk76FPRYwh2GCEqm/4YU5RESo7n9j9Kv8PDW3ha3kvoTVOEijgeyismSk h995NpwXUwv6DvleSGyheia5Tyf1PtruK/mN0EmgMF41pU2C0KN5eGO2Cd5MmBRixu 1nc2z/Im36xRXBmmUc4Z349heQno5x37wYtvN96ytNCoYyeuMHJwWNOYNDa937r0I2 jeIDyGpX+Ft8gtEfoNFB4o0D6bXWTQc7A6Lm8ErqGnnutU2dIbWy2EfSCj0dFPEO/3 +F7+o35c/EICA== Date: Tue, 09 Apr 2024 17:55:20 -0700 Subject: [PATCH 07/32] xfs: allow xattr matching on name and value for local/sf attrs From: "Darrick J. Wong" To: djwong@kernel.org Cc: catherine.hoang@oracle.com, hch@lst.de, allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <171270969674.3631889.16669894985199358307.stgit@frogsfrogsfrogs> In-Reply-To: <171270969477.3631889.12488500941186994317.stgit@frogsfrogsfrogs> References: <171270969477.3631889.12488500941186994317.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Add a new XFS_DA_OP_PARENT flag to signal that the caller wants to look up a parent pointer extended attribute by name and value. This only works with shortform and local attributes. Only parent pointers need this functionality and parent pointers cannot be remote xattrs, so this limitation is ok for now. Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig --- fs/xfs/libxfs/xfs_attr_leaf.c | 44 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c index 490608bbed7ad..7d74ade47d8f1 100644 --- a/fs/xfs/libxfs/xfs_attr_leaf.c +++ b/fs/xfs/libxfs/xfs_attr_leaf.c @@ -513,12 +513,33 @@ static inline unsigned int xfs_attr_match_mask(const struct xfs_da_args *args) return XFS_ATTR_NSP_ONDISK_MASK | XFS_ATTR_INCOMPLETE; } +static inline bool +xfs_attr_parent_match( + const struct xfs_da_args *args, + const void *value, + unsigned int valuelen) +{ + ASSERT(args->value != NULL); + + /* Parent pointers do not use remote values */ + if (!value) + return false; + + /* The only value we support is a parent rec. */ + if (valuelen != sizeof(struct xfs_parent_rec)) + return false; + + return memcmp(args->value, value, valuelen) == 0; +} + static bool xfs_attr_match( struct xfs_da_args *args, unsigned int attr_flags, const unsigned char *name, - unsigned int namelen) + unsigned int namelen, + const void *value, + unsigned int valuelen) { unsigned int mask = xfs_attr_match_mask(args); @@ -529,6 +550,9 @@ xfs_attr_match( if (memcmp(args->name, name, namelen) != 0) return false; + if (attr_flags & XFS_ATTR_PARENT) + return xfs_attr_parent_match(args, value, valuelen); + return true; } @@ -538,6 +562,13 @@ xfs_attr_copy_value( unsigned char *value, int valuelen) { + /* + * Parent pointer lookups require the caller to specify the name and + * value, so don't copy anything. + */ + if (args->attr_filter & XFS_ATTR_PARENT) + return 0; + /* * No copy if all we have to do is get the length */ @@ -747,7 +778,9 @@ xfs_attr_sf_findname( sfe < xfs_attr_sf_endptr(sf); sfe = xfs_attr_sf_nextentry(sfe)) { if (xfs_attr_match(args, sfe->flags, sfe->nameval, - sfe->namelen)) + sfe->namelen, + &sfe->nameval[sfe->namelen], + sfe->valuelen)) return sfe; } @@ -2444,14 +2477,17 @@ xfs_attr3_leaf_lookup_int( name_loc = xfs_attr3_leaf_name_local(leaf, probe); if (!xfs_attr_match(args, entry->flags, name_loc->nameval, - name_loc->namelen)) + name_loc->namelen, + &name_loc->nameval[name_loc->namelen], + be16_to_cpu(name_loc->valuelen))) continue; args->index = probe; return -EEXIST; } else { name_rmt = xfs_attr3_leaf_name_remote(leaf, probe); if (!xfs_attr_match(args, entry->flags, name_rmt->name, - name_rmt->namelen)) + name_rmt->namelen, NULL, + be32_to_cpu(name_rmt->valuelen))) continue; args->index = probe; args->rmtvaluelen = be32_to_cpu(name_rmt->valuelen); From patchwork Wed Apr 10 00:55:35 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13623388 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7429E621 for ; Wed, 10 Apr 2024 00:55:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712710536; cv=none; b=M9uOZU7Lun4Ka69M1ksxNeD6OFyAWj5vR1CmsYKu9rCML/yrT2wv6RkCh/vnqoYzkKl1/X3LonopS0wC/45vw6kskPByVfRutOj/FG6m4uLbSn0+jQfkKTPPqWXxAc21WZPnhuJNEhZ463ZcD4EuIjJhGVPGhz8VA87u3czsZ6I= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712710536; c=relaxed/simple; bh=Rq3d4BieCM/c//9fMVm/pTz9Kd4VlppaVN+NHq1Mbp8=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=EXu3VkOhKaQWFnX053FTWfhViuYbMwPjyAIZAUJbdrEIV6m/uXkT3wFQh2AjLRJMd95GKwlErQub3+ZQBSvlk7HWiCKFIIEHj4OseC8WYNCVCvlLWyopj8+L74CtZVis7dNbGs9BGK4InTya8BNnGl9pGzgCaJSl1y8K+8gOSkA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=AEvUZDgb; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="AEvUZDgb" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 49D11C433C7; Wed, 10 Apr 2024 00:55:36 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1712710536; bh=Rq3d4BieCM/c//9fMVm/pTz9Kd4VlppaVN+NHq1Mbp8=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=AEvUZDgbQM3PQmEX26Z0f9xLilUbN+RT0FzbqtrpUhhmIHYXMw1vw9dmWaKGaNrG4 msVAKpWOg9ynLZDUiZ7PoaklcGWZZ8SRwOFM9ULZ3Sryxu6VIq7vEzifwTOJV7aG65 itLBrG1yvAyg43i50piYd4E/cLYobwYKQHq3pnXWs7khYLTUz8EDP6wj71OM9jKa0o +QjO4BuIKkM5MwLwzOSZRjYEEkgLP1BDjS6TUG9/qwjvVMMX0iiT7Kj0pZAITXRO9R jHGRRVjEML5tvcBQPdjdIhBfvQiAUzyPOFGzkZJwOeElNjdj9Xie3N26+0u5J9MwAj TCcyXO9wBkXnw== Date: Tue, 09 Apr 2024 17:55:35 -0700 Subject: [PATCH 08/32] xfs: allow logged xattr operations if parent pointers are enabled From: "Darrick J. Wong" To: djwong@kernel.org Cc: catherine.hoang@oracle.com, hch@lst.de, allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <171270969690.3631889.15408823864477343629.stgit@frogsfrogsfrogs> In-Reply-To: <171270969477.3631889.12488500941186994317.stgit@frogsfrogsfrogs> References: <171270969477.3631889.12488500941186994317.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Don't trip this assertion about attr log items if we have parent pointers enabled. Parent pointers are an incompat feature that doesn't use any of the functionality protected by XFS_SB_FEAT_INCOMPAT_LOG_XATTRS, which is why this is ok. Signed-off-by: Darrick J. Wong --- fs/xfs/xfs_attr_item.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/xfs/xfs_attr_item.c b/fs/xfs/xfs_attr_item.c index 8f91016fc3cf8..c509bf841949f 100644 --- a/fs/xfs/xfs_attr_item.c +++ b/fs/xfs/xfs_attr_item.c @@ -474,7 +474,7 @@ xfs_attri_validate( { unsigned int op = xfs_attr_log_item_op(attrp); - if (!xfs_is_using_logged_xattrs(mp)) + if (!xfs_is_using_logged_xattrs(mp) && !xfs_has_parent(mp)) return false; if (attrp->__pad != 0) From patchwork Wed Apr 10 00:55:51 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13623389 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1AD1E621 for ; Wed, 10 Apr 2024 00:55:52 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712710552; cv=none; b=kAEQt36aI77fo9B6BESaKEaEaD7w3IJMn7MR/IxG2X4PvJWwTGyXIu/xruWaODfOiNSyTHipYVMN8XMZgrkev9UsAeNamvMaYdWmEfIel70xdQ78kgrhtpV8APBCeHOWfUltuRrAWc3LQn/bqB1mV2UN2w/mxfPX8kfVv2vgjqc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712710552; c=relaxed/simple; bh=p9uE3cAjrG/nn65nIeZJup3hr53VH+SqUDXyiscFqLg=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=MO4Zkeq8QrP5RznZ9HiRh9rWiWlIVH+GOQWHrfjpNcE+965OqCOJclAcc/xWKv5DT0SEW99QRIhsWveqTtiE3aCRvbHg4VWS4tYQRBwl57sqRGa/wVPlg5wy5o1c9lHQuUEiKZvWJ9Plo3AQi6+KVeK8cA2XpyVmDtufqPPIDe8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Ww9OP0dq; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Ww9OP0dq" Received: by smtp.kernel.org (Postfix) with ESMTPSA id F0777C433F1; Wed, 10 Apr 2024 00:55:51 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1712710552; bh=p9uE3cAjrG/nn65nIeZJup3hr53VH+SqUDXyiscFqLg=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=Ww9OP0dq/iaEBkQ1edHG1KYGFXbbcBBqiz0Cxuues+FpvpvW25zIrN0k6N9RCJHcC JR0PCig3gtrVux3X6hcO+N8IsZGeCajcXPovILcALygwjU8fzCrBXa7lWRQwor/9WF PIY2Dd1LuB0BJrcjRXEQ8zcIn5K+hBmKk63JPJoFzjiB8EmbVqqf4Ka2v0Pknv07jf r9IXAdgpynA1SOgZ+9PEvRTJXz7zClJTe3BdERDcgoepfxUIjSchIUqiP4/QjIL1Iq wN7RCGoBCqV+PnNNPuPhZ9QvvBfPOFi0okXSQ16fIZ3jISRqNxmxWkRZhOaPcSA8EL K79Aj+zIAgfjQ== Date: Tue, 09 Apr 2024 17:55:51 -0700 Subject: [PATCH 09/32] xfs: log parent pointer xattr removal operations From: "Darrick J. Wong" To: djwong@kernel.org Cc: catherine.hoang@oracle.com, hch@lst.de, allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <171270969707.3631889.13730441376936994688.stgit@frogsfrogsfrogs> In-Reply-To: <171270969477.3631889.12488500941186994317.stgit@frogsfrogsfrogs> References: <171270969477.3631889.12488500941186994317.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong The parent pointer code needs to do a deferred parent pointer remove operation with the xattr log intent code. Declare a new logged xattr opcode and push it through the log. Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig --- fs/xfs/libxfs/xfs_log_format.h | 1 + fs/xfs/xfs_attr_item.c | 53 ++++++++++++++++++++++++++++++++++++++++ fs/xfs/xfs_attr_item.h | 2 ++ 3 files changed, 56 insertions(+) diff --git a/fs/xfs/libxfs/xfs_log_format.h b/fs/xfs/libxfs/xfs_log_format.h index 020aebd101432..52dcee4b3abe6 100644 --- a/fs/xfs/libxfs/xfs_log_format.h +++ b/fs/xfs/libxfs/xfs_log_format.h @@ -1026,6 +1026,7 @@ struct xfs_icreate_log { #define XFS_ATTRI_OP_FLAGS_SET 1 /* Set the attribute */ #define XFS_ATTRI_OP_FLAGS_REMOVE 2 /* Remove the attribute */ #define XFS_ATTRI_OP_FLAGS_REPLACE 3 /* Replace the attribute */ +#define XFS_ATTRI_OP_FLAGS_PPTR_REMOVE 5 /* Remove parent pointer */ #define XFS_ATTRI_OP_FLAGS_TYPE_MASK 0xFF /* Flags type mask */ /* diff --git a/fs/xfs/xfs_attr_item.c b/fs/xfs/xfs_attr_item.c index c509bf841949f..5cce8a9863862 100644 --- a/fs/xfs/xfs_attr_item.c +++ b/fs/xfs/xfs_attr_item.c @@ -491,6 +491,14 @@ xfs_attri_validate( return false; switch (op) { + case XFS_ATTRI_OP_FLAGS_PPTR_REMOVE: + if (!xfs_has_parent(mp)) + return false; + if (attrp->alfi_value_len == 0) + return false; + if (!(attrp->alfi_attr_filter & XFS_ATTR_PARENT)) + return false; + fallthrough; case XFS_ATTRI_OP_FLAGS_SET: case XFS_ATTRI_OP_FLAGS_REPLACE: if (attrp->alfi_value_len > XATTR_SIZE_MAX) @@ -595,6 +603,7 @@ xfs_attri_recover_work( else attr->xattri_dela_state = xfs_attr_init_add_state(args); break; + case XFS_ATTRI_OP_FLAGS_PPTR_REMOVE: case XFS_ATTRI_OP_FLAGS_REMOVE: attr->xattri_dela_state = xfs_attr_init_remove_state(args); break; @@ -753,6 +762,36 @@ xfs_attr_defer_add( trace_xfs_attr_defer_add(new->xattri_dela_state, args->dp); } +void +xfs_attr_defer_parent( + struct xfs_da_args *args, + enum xfs_attr_defer_op op) +{ + struct xfs_attr_intent *new; + + ASSERT(xfs_has_parent(args->dp->i_mount)); + ASSERT(args->attr_filter & XFS_ATTR_PARENT); + ASSERT(args->op_flags & XFS_DA_OP_LOGGED); + + new = kmem_cache_zalloc(xfs_attr_intent_cache, GFP_NOFS | __GFP_NOFAIL); + new->xattri_da_args = args; + + switch (op) { + case XFS_ATTR_DEFER_SET: + case XFS_ATTR_DEFER_REPLACE: + /* will be added in subsequent patches */ + ASSERT(0); + break; + case XFS_ATTR_DEFER_REMOVE: + new->xattri_op_flags = XFS_ATTRI_OP_FLAGS_PPTR_REMOVE; + new->xattri_dela_state = xfs_attr_init_remove_state(args); + break; + } + + xfs_defer_add(args->trans, &new->xattri_list, &xfs_attr_defer_type); + trace_xfs_attr_defer_add(new->xattri_dela_state, args->dp); +} + const struct xfs_defer_op_type xfs_attr_defer_type = { .name = "attr", .max_items = 1, @@ -801,6 +840,16 @@ xlog_recover_attri_commit_pass2( /* Check the number of log iovecs makes sense for the op code. */ op = xfs_attr_log_item_op(attri_formatp); switch (op) { + case XFS_ATTRI_OP_FLAGS_PPTR_REMOVE: + /* Log item, attr name, attr value */ + if (item->ri_total != 3) { + XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, + attri_formatp, len); + return -EFSCORRUPTED; + } + name_len = attri_formatp->alfi_name_len; + value_len = attri_formatp->alfi_value_len; + break; case XFS_ATTRI_OP_FLAGS_SET: case XFS_ATTRI_OP_FLAGS_REPLACE: /* Log item, attr name, attr value */ @@ -876,12 +925,16 @@ xlog_recover_attri_commit_pass2( return -EFSCORRUPTED; } fallthrough; + case XFS_ATTRI_OP_FLAGS_PPTR_REMOVE: case XFS_ATTRI_OP_FLAGS_SET: case XFS_ATTRI_OP_FLAGS_REPLACE: /* * Regular xattr set/remove/replace operations require a name * and do not take a newname. Values are optional for set and * replace. + * + * Name-value remove operations must have a name, do not + * take a newname, and can take a value. */ if (attr_name == NULL || name_len == 0) { XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, diff --git a/fs/xfs/xfs_attr_item.h b/fs/xfs/xfs_attr_item.h index c32b669b0e16a..f9efd674fd062 100644 --- a/fs/xfs/xfs_attr_item.h +++ b/fs/xfs/xfs_attr_item.h @@ -58,5 +58,7 @@ enum xfs_attr_defer_op { }; void xfs_attr_defer_add(struct xfs_da_args *args, enum xfs_attr_defer_op op); +void xfs_attr_defer_parent(struct xfs_da_args *args, + enum xfs_attr_defer_op op); #endif /* __XFS_ATTR_ITEM_H__ */ From patchwork Wed Apr 10 00:56:07 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13623390 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B14A3621 for ; Wed, 10 Apr 2024 00:56:07 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712710567; cv=none; b=PIrxi102Bd6Zj/Qt2AJMjw5yZ2GFF0B8UWxx21+1F+l+wgoc0niivHFFZDeiJURlecEaUp4uz7fh1N8nIHRlnJtPP7I9fxaDAQ8ytA6GFqt97T40LkYji2wIivTIlpiAwEtWlGk2rrrjmQCB53L8qioGSgrA0CGrAWbkHUFwcDs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712710567; c=relaxed/simple; bh=weXBb7r8Ai7mFkcTsOX1rsmLCTpFVMo9pPlnA30GiYQ=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=bL/NbPbeD3hvPfA5aeSE/PgRO0RNuk3UlM64YJCurIov5RAX0mGvFY7xhhoNNeSltSuBKFojU9vyUj7svBqPXgFY+wcA+mpwayLUwDnaNKHFoLQnavX8703gFYdAYiGSxrw2O0E/wZ+8KMKk8UNILOTX6I8FLrELGh/lpnARCEM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=GmF7tLM6; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="GmF7tLM6" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 88898C433F1; Wed, 10 Apr 2024 00:56:07 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1712710567; bh=weXBb7r8Ai7mFkcTsOX1rsmLCTpFVMo9pPlnA30GiYQ=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=GmF7tLM6IdU17DlH1vt68lwnbhd1BpU06/Lv/z13jhQ1kjpFKkN82aPya7qvBrqc1 KTR0wkPp2VF2sTsFWeupNRXlifZLHUza2FeilCKWQ6JapAsIgNj+JWa6shx/0gogPD o/U8AHtzLt3Vby8kBQAGAB2gs8IaaeDgBkMcCUjhb/BLNfexIjAHm7HkhFCSNObreq ES8/XZ/45v8sFFna19w8nraa8D1k3Ep+Ov9BC6Wy3FTJLqpU/dOJwRoKMXuicpjW37 ZUN/ifQQ9zcCPiwftAiMJGyAHJOYtaFt4Iafi4ejzzKvH/4+PfMy5xS/AMumhMpWN+ aanzMcYopwImA== Date: Tue, 09 Apr 2024 17:56:07 -0700 Subject: [PATCH 10/32] xfs: log parent pointer xattr setting operations From: "Darrick J. Wong" To: djwong@kernel.org Cc: catherine.hoang@oracle.com, hch@lst.de, allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <171270969723.3631889.12419473363106489444.stgit@frogsfrogsfrogs> In-Reply-To: <171270969477.3631889.12488500941186994317.stgit@frogsfrogsfrogs> References: <171270969477.3631889.12488500941186994317.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong The parent pointer code needs to do a deferred parent pointer set operation with the xattr log intent code. Declare a new logged xattr opcode and push it through the log. Signed-off-by: Darrick J. Wong --- fs/xfs/libxfs/xfs_log_format.h | 1 + fs/xfs/xfs_attr_item.c | 9 ++++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/fs/xfs/libxfs/xfs_log_format.h b/fs/xfs/libxfs/xfs_log_format.h index 52dcee4b3abe6..96732a212507e 100644 --- a/fs/xfs/libxfs/xfs_log_format.h +++ b/fs/xfs/libxfs/xfs_log_format.h @@ -1026,6 +1026,7 @@ struct xfs_icreate_log { #define XFS_ATTRI_OP_FLAGS_SET 1 /* Set the attribute */ #define XFS_ATTRI_OP_FLAGS_REMOVE 2 /* Remove the attribute */ #define XFS_ATTRI_OP_FLAGS_REPLACE 3 /* Replace the attribute */ +#define XFS_ATTRI_OP_FLAGS_PPTR_SET 4 /* Set parent pointer */ #define XFS_ATTRI_OP_FLAGS_PPTR_REMOVE 5 /* Remove parent pointer */ #define XFS_ATTRI_OP_FLAGS_TYPE_MASK 0xFF /* Flags type mask */ diff --git a/fs/xfs/xfs_attr_item.c b/fs/xfs/xfs_attr_item.c index 5cce8a9863862..d89495990f03b 100644 --- a/fs/xfs/xfs_attr_item.c +++ b/fs/xfs/xfs_attr_item.c @@ -491,6 +491,7 @@ xfs_attri_validate( return false; switch (op) { + case XFS_ATTRI_OP_FLAGS_PPTR_SET: case XFS_ATTRI_OP_FLAGS_PPTR_REMOVE: if (!xfs_has_parent(mp)) return false; @@ -595,6 +596,7 @@ xfs_attri_recover_work( xfs_attr_sethash(args); switch (xfs_attr_intent_op(attr)) { + case XFS_ATTRI_OP_FLAGS_PPTR_SET: case XFS_ATTRI_OP_FLAGS_SET: case XFS_ATTRI_OP_FLAGS_REPLACE: args->total = xfs_attr_calc_size(args, &local); @@ -778,6 +780,9 @@ xfs_attr_defer_parent( switch (op) { case XFS_ATTR_DEFER_SET: + new->xattri_op_flags = XFS_ATTRI_OP_FLAGS_PPTR_SET; + new->xattri_dela_state = xfs_attr_init_add_state(args); + break; case XFS_ATTR_DEFER_REPLACE: /* will be added in subsequent patches */ ASSERT(0); @@ -841,6 +846,7 @@ xlog_recover_attri_commit_pass2( op = xfs_attr_log_item_op(attri_formatp); switch (op) { case XFS_ATTRI_OP_FLAGS_PPTR_REMOVE: + case XFS_ATTRI_OP_FLAGS_PPTR_SET: /* Log item, attr name, attr value */ if (item->ri_total != 3) { XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, @@ -926,6 +932,7 @@ xlog_recover_attri_commit_pass2( } fallthrough; case XFS_ATTRI_OP_FLAGS_PPTR_REMOVE: + case XFS_ATTRI_OP_FLAGS_PPTR_SET: case XFS_ATTRI_OP_FLAGS_SET: case XFS_ATTRI_OP_FLAGS_REPLACE: /* @@ -933,7 +940,7 @@ xlog_recover_attri_commit_pass2( * and do not take a newname. Values are optional for set and * replace. * - * Name-value remove operations must have a name, do not + * Name-value set/remove operations must have a name, do not * take a newname, and can take a value. */ if (attr_name == NULL || name_len == 0) { From patchwork Wed Apr 10 00:56:22 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13623391 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 605A038B for ; Wed, 10 Apr 2024 00:56:23 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712710583; cv=none; b=Z+n3nPXrq6G8xGuEoYdJUNrGNx9liNnlpQYi6ztuWFDPDlloWB4OPJbCCwC8++Trn7gEuzOdRUznLNRlZp3hL75RsoP/s+EfaKUFXN/BtQRV/M8TEu3SQScYeUzja6RRz4un1BCCJoFX7Rx+FnEL4soCg4rbY6N4K/x8rycCvx0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712710583; c=relaxed/simple; bh=0Wx3n+wcu2Q+5SJl+nuakY56o/OcfkxIfnd3Wra5ymg=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=Z/8ksA81/u00t+WXJ+uB+KPIohq1DrRGkX1sDujc4JGLU8HlBpOZQQDljRR4yKkP+SARahZeaBFzCoCpQXgsiBZaeoMcPuvL59tec7Yv8CJBKVme9wAKu12qhhtbPkpiN1tRY13qjLUONfpo1kcwvPkyc1EMwTGOwn+CST3HZUQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=ubgvWTaH; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="ubgvWTaH" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 2C7C5C433C7; Wed, 10 Apr 2024 00:56:23 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1712710583; bh=0Wx3n+wcu2Q+5SJl+nuakY56o/OcfkxIfnd3Wra5ymg=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=ubgvWTaHBpXTraTSNjkjCEtC30MXkCmMXVM8mpgqtcKH7F+h/OvtCHkvDfaBIe4t5 2/rAIeHWEnn4fxSd37mYuqnvcP/fCmd673OA1PIOT9TZhDnnguIZqbuxRCjowaGLnM hrAIUyBAyISf2g14omVIEsbDn2KE0PMx2yJU2/lKAlFQPmbBAPpcy9cssOxLhjs/3a kvOUFRnnT3hn5SEYJdeikzBcjimqdCrYrXQum3TaMcuKV346f1J3WIP1JTogDyfcE5 kqBv0KC5HraDz3KKieb6v461FCuHR/EMHztRwP2LHpi8TUN2qB1G93209tWGVF/NXS gcXyEQSvr4pLg== Date: Tue, 09 Apr 2024 17:56:22 -0700 Subject: [PATCH 11/32] xfs: log parent pointer xattr replace operations From: "Darrick J. Wong" To: djwong@kernel.org Cc: Allison Henderson , catherine.hoang@oracle.com, hch@lst.de, allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <171270969740.3631889.12974902040083725812.stgit@frogsfrogsfrogs> In-Reply-To: <171270969477.3631889.12488500941186994317.stgit@frogsfrogsfrogs> References: <171270969477.3631889.12488500941186994317.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Allison Henderson The parent pointer code needs to do a deferred parent pointer replace operation with the xattr log intent code. Declare a new logged xattr opcode and push it through the log. (Formerly titled "xfs: Add new name to attri/d" and described as follows: This patch adds two new fields to the atti/d. They are nname and nnamelen. This will be used for parent pointer updates since a rename operation may cause the parent pointer to update both the name and value. So we need to carry both the new name as well as the target name in the attri/d.) Signed-off-by: Allison Henderson Reviewed-by: Darrick J. Wong [djwong: reworked to handle new disk format] Signed-off-by: Darrick J. Wong --- fs/xfs/libxfs/xfs_attr.c | 19 ++++ fs/xfs/libxfs/xfs_attr.h | 4 - fs/xfs/libxfs/xfs_da_btree.h | 4 + fs/xfs/libxfs/xfs_log_format.h | 20 ++++ fs/xfs/xfs_attr_item.c | 193 ++++++++++++++++++++++++++++++++++++---- fs/xfs/xfs_attr_item.h | 2 6 files changed, 218 insertions(+), 24 deletions(-) diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c index 30988d60162c7..6e47c493bf9e2 100644 --- a/fs/xfs/libxfs/xfs_attr.c +++ b/fs/xfs/libxfs/xfs_attr.c @@ -441,6 +441,23 @@ xfs_attr_hashval( return xfs_attr_hashname(name, namelen); } +/* + * PPTR_REPLACE operations require the caller to set the old and new names and + * values explicitly. Update the canonical fields to the new name and value + * here now that the removal phase has finished. + */ +static void +xfs_attr_update_pptr_replace_args( + struct xfs_da_args *args) +{ + ASSERT(args->new_namelen > 0); + args->name = args->new_name; + args->namelen = args->new_namelen; + args->value = args->new_value; + args->valuelen = args->new_valuelen; + xfs_attr_sethash(args); +} + /* * Handle the state change on completion of a multi-state attr operation. * @@ -461,6 +478,8 @@ xfs_attr_complete_op( if (!(args->op_flags & XFS_DA_OP_REPLACE)) replace_state = XFS_DAS_DONE; + else if (xfs_attr_intent_op(attr) == XFS_ATTRI_OP_FLAGS_PPTR_REPLACE) + xfs_attr_update_pptr_replace_args(args); args->op_flags &= ~XFS_DA_OP_REPLACE; args->attr_filter &= ~XFS_ATTR_INCOMPLETE; diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h index df91c94d5bf5c..d63305fc54155 100644 --- a/fs/xfs/libxfs/xfs_attr.h +++ b/fs/xfs/libxfs/xfs_attr.h @@ -510,8 +510,8 @@ struct xfs_attr_intent { struct xfs_da_args *xattri_da_args; /* - * Shared buffer containing the attr name and value so that the logging - * code can share large memory buffers between log items. + * Shared buffer containing the attr name, new name, and value so that + * the logging code can share large memory buffers between log items. */ struct xfs_attri_log_nameval *xattri_nameval; diff --git a/fs/xfs/libxfs/xfs_da_btree.h b/fs/xfs/libxfs/xfs_da_btree.h index 47485f5edae86..8d7a38fe2a5c0 100644 --- a/fs/xfs/libxfs/xfs_da_btree.h +++ b/fs/xfs/libxfs/xfs_da_btree.h @@ -55,7 +55,9 @@ enum xfs_dacmp { typedef struct xfs_da_args { struct xfs_da_geometry *geo; /* da block geometry */ const uint8_t *name; /* string (maybe not NULL terminated) */ + const uint8_t *new_name; /* new attr name */ void *value; /* set of bytes (maybe contain NULLs) */ + void *new_value; /* new xattr value (may contain NULLs) */ struct xfs_inode *dp; /* directory inode to manipulate */ struct xfs_trans *trans; /* current trans (changes over time) */ @@ -63,11 +65,13 @@ typedef struct xfs_da_args { xfs_ino_t owner; /* inode that owns the dir/attr data */ int valuelen; /* length of value */ + int new_valuelen; /* length of new_value */ uint8_t filetype; /* filetype of inode for directories */ uint8_t op_flags; /* operation flags */ uint8_t attr_filter; /* XFS_ATTR_{ROOT,SECURE,INCOMPLETE} */ uint8_t xattr_flags; /* XATTR_{CREATE,REPLACE} */ short namelen; /* length of string (maybe no NULL) */ + short new_namelen; /* length of new attr name */ xfs_dahash_t hashval; /* hash value of name */ xfs_extlen_t total; /* total blocks needed, for 1st bmap */ int whichfork; /* data or attribute fork */ diff --git a/fs/xfs/libxfs/xfs_log_format.h b/fs/xfs/libxfs/xfs_log_format.h index 96732a212507e..632dd97324557 100644 --- a/fs/xfs/libxfs/xfs_log_format.h +++ b/fs/xfs/libxfs/xfs_log_format.h @@ -115,11 +115,13 @@ struct xfs_unmount_log_format { #define XLOG_REG_TYPE_BUD_FORMAT 26 #define XLOG_REG_TYPE_ATTRI_FORMAT 27 #define XLOG_REG_TYPE_ATTRD_FORMAT 28 -#define XLOG_REG_TYPE_ATTR_NAME 29 +#define XLOG_REG_TYPE_ATTR_NAME 29 #define XLOG_REG_TYPE_ATTR_VALUE 30 #define XLOG_REG_TYPE_XMI_FORMAT 31 #define XLOG_REG_TYPE_XMD_FORMAT 32 -#define XLOG_REG_TYPE_MAX 32 +#define XLOG_REG_TYPE_ATTR_NEWNAME 33 +#define XLOG_REG_TYPE_ATTR_NEWVALUE 34 +#define XLOG_REG_TYPE_MAX 34 /* * Flags to log operation header @@ -1028,6 +1030,7 @@ struct xfs_icreate_log { #define XFS_ATTRI_OP_FLAGS_REPLACE 3 /* Replace the attribute */ #define XFS_ATTRI_OP_FLAGS_PPTR_SET 4 /* Set parent pointer */ #define XFS_ATTRI_OP_FLAGS_PPTR_REMOVE 5 /* Remove parent pointer */ +#define XFS_ATTRI_OP_FLAGS_PPTR_REPLACE 6 /* Replace parent pointer */ #define XFS_ATTRI_OP_FLAGS_TYPE_MASK 0xFF /* Flags type mask */ /* @@ -1050,7 +1053,18 @@ struct xfs_attri_log_format { uint64_t alfi_id; /* attri identifier */ uint64_t alfi_ino; /* the inode for this attr operation */ uint32_t alfi_op_flags; /* marks the op as a set or remove */ - uint32_t alfi_name_len; /* attr name length */ + union { + uint32_t alfi_name_len; /* attr name length */ + struct { + /* + * For PPTR_REPLACE, these are the lengths of the old + * and new attr names. The new and old values must + * have the same length. + */ + uint16_t alfi_old_name_len; + uint16_t alfi_new_name_len; + }; + }; uint32_t alfi_value_len; /* attr value length */ uint32_t alfi_attr_filter;/* attr filter flags */ }; diff --git a/fs/xfs/xfs_attr_item.c b/fs/xfs/xfs_attr_item.c index d89495990f03b..8d33294217aca 100644 --- a/fs/xfs/xfs_attr_item.c +++ b/fs/xfs/xfs_attr_item.c @@ -73,8 +73,12 @@ static inline struct xfs_attri_log_nameval * xfs_attri_log_nameval_alloc( const void *name, unsigned int name_len, + const void *new_name, + unsigned int new_name_len, const void *value, - unsigned int value_len) + unsigned int value_len, + const void *new_value, + unsigned int new_value_len) { struct xfs_attri_log_nameval *nv; @@ -83,15 +87,26 @@ xfs_attri_log_nameval_alloc( * this. But kvmalloc() utterly sucks, so we use our own version. */ nv = xlog_kvmalloc(sizeof(struct xfs_attri_log_nameval) + - name_len + value_len); + name_len + new_name_len + value_len + + new_value_len); nv->name.i_addr = nv + 1; nv->name.i_len = name_len; nv->name.i_type = XLOG_REG_TYPE_ATTR_NAME; memcpy(nv->name.i_addr, name, name_len); + if (new_name_len) { + nv->new_name.i_addr = nv->name.i_addr + name_len; + nv->new_name.i_len = new_name_len; + memcpy(nv->new_name.i_addr, new_name, new_name_len); + } else { + nv->new_name.i_addr = NULL; + nv->new_name.i_len = 0; + } + nv->new_name.i_type = XLOG_REG_TYPE_ATTR_NEWNAME; + if (value_len) { - nv->value.i_addr = nv->name.i_addr + name_len; + nv->value.i_addr = nv->name.i_addr + name_len + new_name_len; nv->value.i_len = value_len; memcpy(nv->value.i_addr, value, value_len); } else { @@ -100,6 +115,17 @@ xfs_attri_log_nameval_alloc( } nv->value.i_type = XLOG_REG_TYPE_ATTR_VALUE; + if (new_value_len) { + nv->new_value.i_addr = nv->name.i_addr + name_len + + new_name_len + value_len; + nv->new_value.i_len = new_value_len; + memcpy(nv->new_value.i_addr, new_value, new_value_len); + } else { + nv->new_value.i_addr = NULL; + nv->new_value.i_len = 0; + } + nv->new_value.i_type = XLOG_REG_TYPE_ATTR_NEWVALUE; + refcount_set(&nv->refcount, 1); return nv; } @@ -145,11 +171,20 @@ xfs_attri_item_size( *nbytes += sizeof(struct xfs_attri_log_format) + xlog_calc_iovec_len(nv->name.i_len); - if (!nv->value.i_len) - return; + if (nv->new_name.i_len) { + *nvecs += 1; + *nbytes += xlog_calc_iovec_len(nv->new_name.i_len); + } - *nvecs += 1; - *nbytes += xlog_calc_iovec_len(nv->value.i_len); + if (nv->value.i_len) { + *nvecs += 1; + *nbytes += xlog_calc_iovec_len(nv->value.i_len); + } + + if (nv->new_value.i_len) { + *nvecs += 1; + *nbytes += xlog_calc_iovec_len(nv->new_value.i_len); + } } /* @@ -179,15 +214,28 @@ xfs_attri_item_format( ASSERT(nv->name.i_len > 0); attrip->attri_format.alfi_size++; + if (nv->new_name.i_len > 0) + attrip->attri_format.alfi_size++; + if (nv->value.i_len > 0) attrip->attri_format.alfi_size++; + if (nv->new_value.i_len > 0) + attrip->attri_format.alfi_size++; + xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_ATTRI_FORMAT, &attrip->attri_format, sizeof(struct xfs_attri_log_format)); xlog_copy_from_iovec(lv, &vecp, &nv->name); + + if (nv->new_name.i_len > 0) + xlog_copy_from_iovec(lv, &vecp, &nv->new_name); + if (nv->value.i_len > 0) xlog_copy_from_iovec(lv, &vecp, &nv->value); + + if (nv->new_value.i_len > 0) + xlog_copy_from_iovec(lv, &vecp, &nv->new_value); } /* @@ -333,7 +381,17 @@ xfs_attr_log_item( ASSERT(!(attr->xattri_op_flags & ~XFS_ATTRI_OP_FLAGS_TYPE_MASK)); attrp->alfi_op_flags = attr->xattri_op_flags; attrp->alfi_value_len = attr->xattri_nameval->value.i_len; - attrp->alfi_name_len = attr->xattri_nameval->name.i_len; + + if (xfs_attr_log_item_op(attrp) == XFS_ATTRI_OP_FLAGS_PPTR_REPLACE) { + ASSERT(attr->xattri_nameval->value.i_len == + attr->xattri_nameval->new_value.i_len); + + attrp->alfi_old_name_len = attr->xattri_nameval->name.i_len; + attrp->alfi_new_name_len = attr->xattri_nameval->new_name.i_len; + } else { + attrp->alfi_name_len = attr->xattri_nameval->name.i_len; + } + ASSERT(!(attr->xattri_da_args->attr_filter & ~XFS_ATTRI_FILTER_MASK)); attrp->alfi_attr_filter = attr->xattri_da_args->attr_filter; } @@ -374,8 +432,11 @@ xfs_attr_create_intent( * Transfer our reference to the name/value buffer to the * deferred work state structure. */ - attr->xattri_nameval = xfs_attri_log_nameval_alloc(args->name, - args->namelen, args->value, args->valuelen); + attr->xattri_nameval = xfs_attri_log_nameval_alloc( + args->name, args->namelen, + args->new_name, args->new_namelen, + args->value, args->valuelen, + args->new_value, args->new_valuelen); } attrip = xfs_attri_init(mp, attr->xattri_nameval); @@ -477,9 +538,6 @@ xfs_attri_validate( if (!xfs_is_using_logged_xattrs(mp) && !xfs_has_parent(mp)) return false; - if (attrp->__pad != 0) - return false; - if (attrp->alfi_op_flags & ~XFS_ATTRI_OP_FLAGS_TYPE_MASK) return false; @@ -515,6 +573,21 @@ xfs_attri_validate( attrp->alfi_name_len > XATTR_NAME_MAX) return false; break; + case XFS_ATTRI_OP_FLAGS_PPTR_REPLACE: + if (!xfs_has_parent(mp)) + return false; + if (attrp->alfi_old_name_len == 0 || + attrp->alfi_old_name_len > XATTR_NAME_MAX) + return false; + if (attrp->alfi_new_name_len == 0 || + attrp->alfi_new_name_len > XATTR_NAME_MAX) + return false; + if (attrp->alfi_value_len == 0 || + attrp->alfi_value_len > XATTR_SIZE_MAX) + return false; + if (!(attrp->alfi_attr_filter & XFS_ATTR_PARENT)) + return false; + break; default: return false; } @@ -587,8 +660,12 @@ xfs_attri_recover_work( args->whichfork = XFS_ATTR_FORK; args->name = nv->name.i_addr; args->namelen = nv->name.i_len; + args->new_name = nv->new_name.i_addr; + args->new_namelen = nv->new_name.i_len; args->value = nv->value.i_addr; args->valuelen = nv->value.i_len; + args->new_value = nv->new_value.i_addr; + args->new_valuelen = nv->new_value.i_len; args->attr_filter = attrp->alfi_attr_filter & XFS_ATTRI_FILTER_MASK; args->op_flags = XFS_DA_OP_RECOVERY | XFS_DA_OP_OKNOENT | XFS_DA_OP_LOGGED; @@ -597,6 +674,7 @@ xfs_attri_recover_work( switch (xfs_attr_intent_op(attr)) { case XFS_ATTRI_OP_FLAGS_PPTR_SET: + case XFS_ATTRI_OP_FLAGS_PPTR_REPLACE: case XFS_ATTRI_OP_FLAGS_SET: case XFS_ATTRI_OP_FLAGS_REPLACE: args->total = xfs_attr_calc_size(args, &local); @@ -706,7 +784,14 @@ xfs_attr_relog_intent( new_attrp->alfi_ino = old_attrp->alfi_ino; new_attrp->alfi_op_flags = old_attrp->alfi_op_flags; new_attrp->alfi_value_len = old_attrp->alfi_value_len; - new_attrp->alfi_name_len = old_attrp->alfi_name_len; + + if (xfs_attr_log_item_op(old_attrp) == XFS_ATTRI_OP_FLAGS_PPTR_REPLACE) { + new_attrp->alfi_new_name_len = old_attrp->alfi_new_name_len; + new_attrp->alfi_old_name_len = old_attrp->alfi_old_name_len; + } else { + new_attrp->alfi_name_len = old_attrp->alfi_name_len; + } + new_attrp->alfi_attr_filter = old_attrp->alfi_attr_filter; return &new_attrip->attri_item; @@ -784,8 +869,10 @@ xfs_attr_defer_parent( new->xattri_dela_state = xfs_attr_init_add_state(args); break; case XFS_ATTR_DEFER_REPLACE: - /* will be added in subsequent patches */ - ASSERT(0); + ASSERT(args->new_valuelen == args->valuelen); + + new->xattri_op_flags = XFS_ATTRI_OP_FLAGS_PPTR_REPLACE; + new->xattri_dela_state = xfs_attr_init_replace_state(args); break; case XFS_ATTR_DEFER_REMOVE: new->xattri_op_flags = XFS_ATTRI_OP_FLAGS_PPTR_REMOVE; @@ -822,9 +909,13 @@ xlog_recover_attri_commit_pass2( struct xfs_attri_log_nameval *nv; const void *attr_name; const void *attr_value = NULL; + const void *attr_new_name = NULL; + const void *attr_new_value = NULL; size_t len; unsigned int name_len = 0; unsigned int value_len = 0; + unsigned int new_name_len = 0; + unsigned int new_value_len = 0; unsigned int op, i = 0; /* Validate xfs_attri_log_format before the large memory allocation */ @@ -876,6 +967,20 @@ xlog_recover_attri_commit_pass2( } name_len = attri_formatp->alfi_name_len; break; + case XFS_ATTRI_OP_FLAGS_PPTR_REPLACE: + /* + * Log item, attr name, new attr name, attr value, new attr + * value + */ + if (item->ri_total != 5) { + XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, + attri_formatp, len); + return -EFSCORRUPTED; + } + name_len = attri_formatp->alfi_old_name_len; + new_name_len = attri_formatp->alfi_new_name_len; + new_value_len = value_len = attri_formatp->alfi_value_len; + break; default: XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, attri_formatp, len); @@ -899,12 +1004,31 @@ xlog_recover_attri_commit_pass2( } i++; + /* Validate the new attr name */ + if (new_name_len > 0) { + if (item->ri_buf[i].i_len != xlog_calc_iovec_len(new_name_len)) { + XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, + item->ri_buf[i].i_addr, + item->ri_buf[i].i_len); + return -EFSCORRUPTED; + } + + attr_new_name = item->ri_buf[i].i_addr; + if (!xfs_attr_namecheck(attri_formatp->alfi_attr_filter, + attr_new_name, new_name_len)) { + XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, + item->ri_buf[i].i_addr, + item->ri_buf[i].i_len); + return -EFSCORRUPTED; + } + i++; + } + /* Validate the attr value, if present */ if (value_len != 0) { if (item->ri_buf[i].i_len != xlog_calc_iovec_len(value_len)) { XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, - item->ri_buf[0].i_addr, - item->ri_buf[0].i_len); + attri_formatp, len); return -EFSCORRUPTED; } @@ -912,6 +1036,18 @@ xlog_recover_attri_commit_pass2( i++; } + /* Validate the new attr value, if present */ + if (new_value_len != 0) { + if (item->ri_buf[i].i_len != xlog_calc_iovec_len(new_value_len)) { + XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, + attri_formatp, len); + return -EFSCORRUPTED; + } + + attr_new_value = item->ri_buf[i].i_addr; + i++; + } + /* * Make sure we got the correct number of buffers for the operation * that we just loaded. @@ -949,6 +1085,23 @@ xlog_recover_attri_commit_pass2( return -EFSCORRUPTED; } break; + case XFS_ATTRI_OP_FLAGS_PPTR_REPLACE: + /* + * Name-value replace operations require the caller to + * specify the old and new names and values explicitly. + * Values are optional. + */ + if (attr_name == NULL || name_len == 0) { + XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, + attri_formatp, len); + return -EFSCORRUPTED; + } + if (attr_new_name == NULL || new_name_len == 0) { + XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, + attri_formatp, len); + return -EFSCORRUPTED; + } + break; } /* @@ -957,7 +1110,9 @@ xlog_recover_attri_commit_pass2( * reference. */ nv = xfs_attri_log_nameval_alloc(attr_name, name_len, - attr_value, value_len); + attr_new_name, new_name_len, + attr_value, value_len, + attr_new_value, new_value_len); attrip = xfs_attri_init(mp, nv); memcpy(&attrip->attri_format, attri_formatp, len); diff --git a/fs/xfs/xfs_attr_item.h b/fs/xfs/xfs_attr_item.h index f9efd674fd062..d5e4658f711d1 100644 --- a/fs/xfs/xfs_attr_item.h +++ b/fs/xfs/xfs_attr_item.h @@ -13,7 +13,9 @@ struct kmem_zone; struct xfs_attri_log_nameval { struct xfs_log_iovec name; + struct xfs_log_iovec new_name; /* PPTR_REPLACE only */ struct xfs_log_iovec value; + struct xfs_log_iovec new_value; /* PPTR_REPLACE only */ refcount_t refcount; /* name and value follow the end of this struct */ From patchwork Wed Apr 10 00:56:38 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13623392 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3C216621 for ; Wed, 10 Apr 2024 00:56:38 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712710599; cv=none; b=lRyWGDOeuKGHW2HJiLUDv8gDtBfMiR/CMADbILiklIz9URPBUkPG1hf/tzE3E1LxKXCOTgSM4/kXKPM9SyCiSeWukqbQj2GISer5TGifC5bNoedk80p3QODlQO0docKYu4UNdsYaET+JSn5by0Q0cKxUHPdWC9JD0Udrsv7q4ew= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712710599; c=relaxed/simple; bh=RIepamdrzH8iQ0PwIfrhJ2WCE9DXdkvmpSXySQFTfrY=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=Ah0nYCJa6P+3MLN1SXbkgMCREaZlzPPXAoUakUsDFUn38Rpy2JmgjnMZxpk7cQWk3fa+o7fx7gnS5R4GS4A4jXeP7dnfgseqO9BK3oN/lEaZmLeIM9cLhAhgDcnh3fNgGlTwET3al6mvoAenMrsabOr6JixmkQrB6EfVT2+T7vs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=FGAmLOAX; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="FGAmLOAX" Received: by smtp.kernel.org (Postfix) with ESMTPSA id C3F48C433C7; Wed, 10 Apr 2024 00:56:38 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1712710598; bh=RIepamdrzH8iQ0PwIfrhJ2WCE9DXdkvmpSXySQFTfrY=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=FGAmLOAXJH93v6q1QiAXQ94rOxTtQN7YWrHBOebwFyVP9jkpeZvLe24epmAPxyNx/ TMulpJf217NwQY9v5d/W36SyqlwO3bPsoG1iK3UJZyT8dBAcBFor990yoM7AZw0k/H khHS0WbnoV9H4P44/9foyLzOEnxv3v3IYf5+B2RJPl16s1IzA9ECHspX3sf7vnC4yA bKyvJMGhZuI2E1SbbPJ77y3wFi85HSa2xhz2cgqqEAgtsHm9D8L7v3vimUdEbA6Ibx ZgwfyKCZocK5Et8FYwTaF0NCapLfEiqWoaz1xAmgCUK129UhYMPU2KnGkGkXfOLhwd w/xlG9RUoOHmg== Date: Tue, 09 Apr 2024 17:56:38 -0700 Subject: [PATCH 12/32] xfs: record inode generation in xattr update log intent items From: "Darrick J. Wong" To: djwong@kernel.org Cc: catherine.hoang@oracle.com, hch@lst.de, allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <171270969756.3631889.2291525923694183307.stgit@frogsfrogsfrogs> In-Reply-To: <171270969477.3631889.12488500941186994317.stgit@frogsfrogsfrogs> References: <171270969477.3631889.12488500941186994317.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong For parent pointer updates, record the i_generation of the file that is being updated so that we don't accidentally jump generations. Signed-off-by: Darrick J. Wong --- fs/xfs/libxfs/xfs_log_format.h | 2 +- fs/xfs/xfs_attr_item.c | 26 ++++++++++++++++++++++++-- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/fs/xfs/libxfs/xfs_log_format.h b/fs/xfs/libxfs/xfs_log_format.h index 632dd97324557..3e6682ed656b3 100644 --- a/fs/xfs/libxfs/xfs_log_format.h +++ b/fs/xfs/libxfs/xfs_log_format.h @@ -1049,7 +1049,7 @@ struct xfs_icreate_log { struct xfs_attri_log_format { uint16_t alfi_type; /* attri log item type */ uint16_t alfi_size; /* size of this item */ - uint32_t __pad; /* pad to 64 bit aligned */ + uint32_t alfi_igen; /* generation of alfi_ino for pptr ops */ uint64_t alfi_id; /* attri identifier */ uint64_t alfi_ino; /* the inode for this attr operation */ uint32_t alfi_op_flags; /* marks the op as a set or remove */ diff --git a/fs/xfs/xfs_attr_item.c b/fs/xfs/xfs_attr_item.c index 8d33294217aca..be8660a0b55ff 100644 --- a/fs/xfs/xfs_attr_item.c +++ b/fs/xfs/xfs_attr_item.c @@ -382,14 +382,22 @@ xfs_attr_log_item( attrp->alfi_op_flags = attr->xattri_op_flags; attrp->alfi_value_len = attr->xattri_nameval->value.i_len; - if (xfs_attr_log_item_op(attrp) == XFS_ATTRI_OP_FLAGS_PPTR_REPLACE) { + switch (xfs_attr_log_item_op(attrp)) { + case XFS_ATTRI_OP_FLAGS_PPTR_REPLACE: ASSERT(attr->xattri_nameval->value.i_len == attr->xattri_nameval->new_value.i_len); + attrp->alfi_igen = VFS_I(attr->xattri_da_args->dp)->i_generation; attrp->alfi_old_name_len = attr->xattri_nameval->name.i_len; attrp->alfi_new_name_len = attr->xattri_nameval->new_name.i_len; - } else { + break; + case XFS_ATTRI_OP_FLAGS_PPTR_REMOVE: + case XFS_ATTRI_OP_FLAGS_PPTR_SET: + attrp->alfi_igen = VFS_I(attr->xattri_da_args->dp)->i_generation; + fallthrough; + default: attrp->alfi_name_len = attr->xattri_nameval->name.i_len; + break; } ASSERT(!(attr->xattri_da_args->attr_filter & ~XFS_ATTRI_FILTER_MASK)); @@ -632,6 +640,19 @@ xfs_attri_recover_work( if (error) return ERR_PTR(error); + switch (xfs_attr_log_item_op(attrp)) { + case XFS_ATTRI_OP_FLAGS_PPTR_SET: + case XFS_ATTRI_OP_FLAGS_PPTR_REPLACE: + case XFS_ATTRI_OP_FLAGS_PPTR_REMOVE: + if (VFS_I(ip)->i_generation != attrp->alfi_igen) { + xfs_irele(ip); + XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, + attrp, sizeof(*attrp)); + return ERR_PTR(-EFSCORRUPTED); + } + break; + } + if (xfs_inode_has_attr_fork(ip)) { error = xfs_attri_iread_extents(ip); if (error) { @@ -782,6 +803,7 @@ xfs_attr_relog_intent( new_attrp = &new_attrip->attri_format; new_attrp->alfi_ino = old_attrp->alfi_ino; + new_attrp->alfi_igen = old_attrp->alfi_igen; new_attrp->alfi_op_flags = old_attrp->alfi_op_flags; new_attrp->alfi_value_len = old_attrp->alfi_value_len; From patchwork Wed Apr 10 00:56:53 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13623393 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 00357391 for ; Wed, 10 Apr 2024 00:56:54 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712710615; cv=none; b=NQj4qwrz0mpRlV7OaUlQr4F4fDT6yZAXqL3bhjvx4Iki6XPyyHIAkK19kbbT3NQKss7VaXmCbYuJ+H/Z0UjZIEAJM/hKrlkhiDjDzgh7l3sJzQOHcZg98KV4LBpZn5yf59XhMmcWD56EBhkYBWBJbrS36Fnl4Nn8BS2QkUutRG8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712710615; c=relaxed/simple; bh=W0kmeq3lB8TeOF/UVybWcg4I6AA2q4cJGxlOu5y19LE=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=Yw8Zr9noI7vM6myWKQfLspQk7XUn4QYKeiNNgZ35yW1SUdWVM1HGoqOWNTQbS6pKgg9JUMIpieIHt+dJSiYFfmngtq8ksDqR20jvx5YdH1AEii2D2mU6W3A9S/1AHXafrxSmY1/Pq8sGDNpFbjboRR02WKnZuI++iyTyfFYrHLM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=PJVNYlSA; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="PJVNYlSA" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 7A445C433C7; Wed, 10 Apr 2024 00:56:54 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1712710614; bh=W0kmeq3lB8TeOF/UVybWcg4I6AA2q4cJGxlOu5y19LE=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=PJVNYlSALY9vHS3TogcZ7To7dzXDB/80G6fdigqKM7XnUKOnWjflXePiBfOhUODKg VyA1PtkpsMHsF8EvtbyWbGfFKrw62nkO1ykoS8RItZlns253ABXoIGGr47raXkcJVq xZSFkDms66WW5iUQwYSPjFjqi7Dzn+3OiK4EuaNNcFTXVVN+txzabHRvyCFdGXp0js YIY6HqTjLUI8Ck064wujoGqA42S8e5xq3j0OETfWcSTgl/s4vVLHBOz+7Kgcd0rF6v yJj8xiy9rp8qOw65ydAbQqsYO+7RbhdLonGEqedqxYDTXtszDqvpvkDFumSCHlN6py TBEAVLTz4N/4A== Date: Tue, 09 Apr 2024 17:56:53 -0700 Subject: [PATCH 13/32] xfs: Expose init_xattrs in xfs_create_tmpfile From: "Darrick J. Wong" To: djwong@kernel.org Cc: Allison Henderson , catherine.hoang@oracle.com, hch@lst.de, allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <171270969773.3631889.2961452043600653365.stgit@frogsfrogsfrogs> In-Reply-To: <171270969477.3631889.12488500941186994317.stgit@frogsfrogsfrogs> References: <171270969477.3631889.12488500941186994317.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Allison Henderson Tmp files are used as part of rename operations and will need attr forks initialized for parent pointers. Expose the init_xattrs parameter to the calling function to initialize the fork. Signed-off-by: Allison Henderson Reviewed-by: Darrick J. Wong Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig --- fs/xfs/xfs_inode.c | 5 +++-- fs/xfs/xfs_inode.h | 2 +- fs/xfs/xfs_iops.c | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index 2aec7ab59aeb7..c079114b97ecf 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -1184,6 +1184,7 @@ xfs_create_tmpfile( struct mnt_idmap *idmap, struct xfs_inode *dp, umode_t mode, + bool init_xattrs, struct xfs_inode **ipp) { struct xfs_mount *mp = dp->i_mount; @@ -1224,7 +1225,7 @@ xfs_create_tmpfile( error = xfs_dialloc(&tp, dp->i_ino, mode, &ino); if (!error) error = xfs_init_new_inode(idmap, tp, dp, ino, mode, - 0, 0, prid, false, &ip); + 0, 0, prid, init_xattrs, &ip); if (error) goto out_trans_cancel; @@ -3036,7 +3037,7 @@ xfs_rename_alloc_whiteout( int error; error = xfs_create_tmpfile(idmap, dp, S_IFCHR | WHITEOUT_MODE, - &tmpfile); + false, &tmpfile); if (error) return error; diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h index a6da1ab8ab136..04a91e312993b 100644 --- a/fs/xfs/xfs_inode.h +++ b/fs/xfs/xfs_inode.h @@ -522,7 +522,7 @@ int xfs_create(struct mnt_idmap *idmap, umode_t mode, dev_t rdev, bool need_xattr, struct xfs_inode **ipp); int xfs_create_tmpfile(struct mnt_idmap *idmap, - struct xfs_inode *dp, umode_t mode, + struct xfs_inode *dp, umode_t mode, bool init_xattrs, struct xfs_inode **ipp); int xfs_remove(struct xfs_inode *dp, struct xfs_name *name, struct xfs_inode *ip); diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c index 7f0c840f0fd2f..273bc30fd2bad 100644 --- a/fs/xfs/xfs_iops.c +++ b/fs/xfs/xfs_iops.c @@ -201,7 +201,7 @@ xfs_generic_create( xfs_create_need_xattr(dir, default_acl, acl), &ip); } else { - error = xfs_create_tmpfile(idmap, XFS_I(dir), mode, &ip); + error = xfs_create_tmpfile(idmap, XFS_I(dir), mode, false, &ip); } if (unlikely(error)) goto out_free_acl; From patchwork Wed Apr 10 00:57:09 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13623394 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9B9DA621 for ; Wed, 10 Apr 2024 00:57:10 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712710630; cv=none; b=pjnuZ7Pk1RU8N1oStIseA9Y9pHkU+f6ICxy3f/2q7RL1Kzu2MjrXTjuCtUeIWT/MdwNI/dThIRgWXpusI03HpJWLvDB3WKCM9HoeaJ/6AdPvagmmv1RsUoy3fqMvfJ/H9jwtYrzxl6IL97YfdKg4cMJRYKn/JUO/DfeG/+1E1xU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712710630; c=relaxed/simple; bh=2bfXFWlsjbj/ImpomT59XFmKbdXrV0bnE0TJlxM9LLc=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=YnFpWQeEKUVCp8dtYEkHl+GtjB40Q4hBMEHOmb13nmcwB9Aliu1EJXDv4h5ECn0aeFDw9sfSqIA1c6gOA0kdUgXt1l6PNSH6xrVls/BKTnYSnsXGt6j51h6nZ9pYB8Ibp7a5UzvryXXGTrhiuxpABxvT83GjitlfRRih3T3hNdo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Db++LntY; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Db++LntY" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 247B1C433C7; Wed, 10 Apr 2024 00:57:10 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1712710630; bh=2bfXFWlsjbj/ImpomT59XFmKbdXrV0bnE0TJlxM9LLc=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=Db++LntYQ5fKpKW2TdS0GWClgydiH9m7bqRBo/nHFovfeKbdJXsn3sc5+rbMSnHXk QyexJVC7y2rux1DVkui+oMASHFpnMJFs6Uu+n0+c/zmLKXaayV7aXK7d2DULhXoWZf tKVVI7DzYQxpA1gBCTOuw+ZMZ0QiKqY3ju571qeuwTbfyq4Q09m+pYooAHV2akWJ02 Co58ldx9ZGH2zIrhjB0IbuSMHUstMu/okmU/WytwAx1Z3g7R/2Xycg3t+MKueX4qtX e6Sp6yVovAYNmD4+zej+Ic49KZ0ImQWZhvpY8eSUC5QmkBBx+LhxFAULhKecriIPWv YKsAivLvGOfkQ== Date: Tue, 09 Apr 2024 17:57:09 -0700 Subject: [PATCH 14/32] xfs: add parent pointer validator functions From: "Darrick J. Wong" To: djwong@kernel.org Cc: Allison Henderson , catherine.hoang@oracle.com, hch@lst.de, allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <171270969790.3631889.2339349798519269452.stgit@frogsfrogsfrogs> In-Reply-To: <171270969477.3631889.12488500941186994317.stgit@frogsfrogsfrogs> References: <171270969477.3631889.12488500941186994317.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Allison Henderson Attribute names of parent pointers are not strings. So we need to modify attr_namecheck to verify parent pointer records when the XFS_ATTR_PARENT flag is set. At the same time, we need to validate attr values during log recovery if the xattr is really a parent pointer. Signed-off-by: Allison Henderson Reviewed-by: Darrick J. Wong [djwong: move functions to xfs_parent.c, adjust for new disk format] Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig --- fs/xfs/Makefile | 1 fs/xfs/libxfs/xfs_attr.c | 5 ++ fs/xfs/libxfs/xfs_parent.c | 92 ++++++++++++++++++++++++++++++++++++++++++++ fs/xfs/libxfs/xfs_parent.h | 15 +++++++ fs/xfs/xfs_attr_item.c | 15 +++++++ 5 files changed, 128 insertions(+) create mode 100644 fs/xfs/libxfs/xfs_parent.c create mode 100644 fs/xfs/libxfs/xfs_parent.h diff --git a/fs/xfs/Makefile b/fs/xfs/Makefile index 4e1eb3b6dbc45..4956ea9a307b8 100644 --- a/fs/xfs/Makefile +++ b/fs/xfs/Makefile @@ -42,6 +42,7 @@ xfs-y += $(addprefix libxfs/, \ xfs_inode_buf.o \ xfs_log_rlimit.o \ xfs_ag_resv.o \ + xfs_parent.o \ xfs_rmap.o \ xfs_rmap_btree.o \ xfs_refcount.o \ diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c index 6e47c493bf9e2..41de6a135d907 100644 --- a/fs/xfs/libxfs/xfs_attr.c +++ b/fs/xfs/libxfs/xfs_attr.c @@ -26,6 +26,7 @@ #include "xfs_trace.h" #include "xfs_attr_item.h" #include "xfs_xattr.h" +#include "xfs_parent.h" struct kmem_cache *xfs_attr_intent_cache; @@ -1570,6 +1571,10 @@ xfs_attr_namecheck( if (length >= MAXNAMELEN) return false; + /* Parent pointers have their own validation. */ + if (attr_flags & XFS_ATTR_PARENT) + return xfs_parent_namecheck(attr_flags, name, length); + /* There shouldn't be any nulls here */ return !memchr(name, 0, length); } diff --git a/fs/xfs/libxfs/xfs_parent.c b/fs/xfs/libxfs/xfs_parent.c new file mode 100644 index 0000000000000..5961fa8c85615 --- /dev/null +++ b/fs/xfs/libxfs/xfs_parent.c @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2022-2024 Oracle. + * All rights reserved. + */ +#include "xfs.h" +#include "xfs_fs.h" +#include "xfs_format.h" +#include "xfs_da_format.h" +#include "xfs_log_format.h" +#include "xfs_shared.h" +#include "xfs_trans_resv.h" +#include "xfs_mount.h" +#include "xfs_bmap_btree.h" +#include "xfs_inode.h" +#include "xfs_error.h" +#include "xfs_trace.h" +#include "xfs_trans.h" +#include "xfs_da_btree.h" +#include "xfs_attr.h" +#include "xfs_dir2.h" +#include "xfs_dir2_priv.h" +#include "xfs_attr_sf.h" +#include "xfs_bmap.h" +#include "xfs_defer.h" +#include "xfs_log.h" +#include "xfs_xattr.h" +#include "xfs_parent.h" +#include "xfs_trans_space.h" + +/* + * Parent pointer attribute handling. + * + * Because the attribute name is a filename component, it will never be longer + * than 255 bytes and must not contain nulls or slashes. These are roughly the + * same constraints that apply to attribute names. + * + * The attribute value must always be a struct xfs_parent_rec. This means the + * attribute will never be in remote format because 12 bytes is nowhere near + * xfs_attr_leaf_entsize_local_max() (~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 attr name is valid. */ +bool +xfs_parent_namecheck( + unsigned int attr_flags, + const void *name, + size_t length) +{ + /* + * Parent pointers always use logged operations, so there should never + * be incomplete xattrs. + */ + if (attr_flags & XFS_ATTR_INCOMPLETE) + return false; + + return xfs_dir2_namecheck(name, length); +} + +/* Return true if parent pointer attr value is valid. */ +bool +xfs_parent_valuecheck( + struct xfs_mount *mp, + const void *value, + size_t valuelen) +{ + const struct xfs_parent_rec *rec = value; + + if (!xfs_has_parent(mp)) + return false; + + /* The xattr value must be a parent record. */ + if (valuelen != sizeof(struct xfs_parent_rec)) + return false; + + /* The parent record must be local. */ + if (value == NULL) + return false; + + /* The parent inumber must be valid. */ + if (!xfs_verify_dir_ino(mp, be64_to_cpu(rec->p_ino))) + return false; + + return true; +} diff --git a/fs/xfs/libxfs/xfs_parent.h b/fs/xfs/libxfs/xfs_parent.h new file mode 100644 index 0000000000000..ef8aff8607801 --- /dev/null +++ b/fs/xfs/libxfs/xfs_parent.h @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2022-2024 Oracle. + * All Rights Reserved. + */ +#ifndef __XFS_PARENT_H__ +#define __XFS_PARENT_H__ + +/* Metadata validators */ +bool xfs_parent_namecheck(unsigned int attr_flags, const void *name, + size_t length); +bool xfs_parent_valuecheck(struct xfs_mount *mp, const void *value, + size_t valuelen); + +#endif /* __XFS_PARENT_H__ */ diff --git a/fs/xfs/xfs_attr_item.c b/fs/xfs/xfs_attr_item.c index be8660a0b55ff..84c63b9668ad9 100644 --- a/fs/xfs/xfs_attr_item.c +++ b/fs/xfs/xfs_attr_item.c @@ -27,6 +27,7 @@ #include "xfs_error.h" #include "xfs_log_priv.h" #include "xfs_log_recover.h" +#include "xfs_parent.h" struct kmem_cache *xfs_attri_cache; struct kmem_cache *xfs_attrd_cache; @@ -1055,6 +1056,13 @@ xlog_recover_attri_commit_pass2( } attr_value = item->ri_buf[i].i_addr; + if ((attri_formatp->alfi_attr_filter & XFS_ATTR_PARENT) && + !xfs_parent_valuecheck(mp, attr_value, value_len)) { + XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, + item->ri_buf[i].i_addr, + item->ri_buf[i].i_len); + return -EFSCORRUPTED; + } i++; } @@ -1067,6 +1075,13 @@ xlog_recover_attri_commit_pass2( } attr_new_value = item->ri_buf[i].i_addr; + if ((attri_formatp->alfi_attr_filter & XFS_ATTR_PARENT) && + !xfs_parent_valuecheck(mp, attr_new_value, new_value_len)) { + XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, + item->ri_buf[i].i_addr, + item->ri_buf[i].i_len); + return -EFSCORRUPTED; + } i++; } From patchwork Wed Apr 10 00:57:25 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13623395 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4CEE7621 for ; Wed, 10 Apr 2024 00:57:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712710646; cv=none; b=smrRReAB+YAWhpr5fu6kGB80UwtOpMCUK8WUAALy/SRdz5920dA8ecpAK6ilRy/GKw73BLEeEGLe3zXkDvLkWpRptjCq/GqDthQhGYqAk/o07fD/0+CRbt8bB/VavHlL/r2LBdN+fKN3PYamGBYZ81G/ByRw+/t6GQN+5Fg7l4A= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712710646; c=relaxed/simple; bh=BpnapBEsLxFoKVQTzcexf9eySWa+9E6j34p3pOWrDy4=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=klhQ/A7eSTXl5x+QlsVuiLR5PbxxoJzlnIW/3+sp42i/EdO/yaj2MsCPcdx/hNxy9qGH74EZ/8uWhJinDCb1hB+kWk4VmKFEUnpkV80vjj3Y/fJbYWRvuyRvFwijEEstkEWSnyn86VkKvWfBcS4goR5MhJvVpPDLKUxRCzlTD+k= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=CGujNvCj; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="CGujNvCj" Received: by smtp.kernel.org (Postfix) with ESMTPSA id C8868C433C7; Wed, 10 Apr 2024 00:57:25 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1712710645; bh=BpnapBEsLxFoKVQTzcexf9eySWa+9E6j34p3pOWrDy4=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=CGujNvCjxDQ3g6/JnkAiZ+b5rtO72MnrDYUNJrpn4kneXvhCERxFnnjm85dN7uWDc ppDErMb/vQIRynHZs8I+TJx0oa/cWUYmR9lZWEJnZcyDmecWd7D6ZmQ7TWUmR6fp/u 5ICXGW6SsKl1ViSWQrxWtxvUdQuFSeQ+vl9Gxb0eWi/evP6uhPbjGLX1w4PSIbf/7y TRvoVWrJESy7wlzDchQ4/4m5jLDsCOF+WxteAxoSlRTSISMGaif8nPWqoHdMxOI+DS nnuBAaQaWl+tfvkFTFqQkUirRfFgmzppsLXZlp//YFmruOb7aoD4w2ukLxoQz9y1B6 Nv/Bd8omoCRWw== Date: Tue, 09 Apr 2024 17:57:25 -0700 Subject: [PATCH 15/32] xfs: extend transaction reservations for parent attributes From: "Darrick J. Wong" To: djwong@kernel.org Cc: Dave Chinner , Allison Henderson , catherine.hoang@oracle.com, hch@lst.de, allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <171270969807.3631889.124629951348206378.stgit@frogsfrogsfrogs> In-Reply-To: <171270969477.3631889.12488500941186994317.stgit@frogsfrogsfrogs> References: <171270969477.3631889.12488500941186994317.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Allison Henderson We need to add, remove or modify parent pointer attributes during create/link/unlink/rename operations atomically with the dirents in the parent directories being modified. This means they need to be modified in the same transaction as the parent directories, and so we need to add the required space for the attribute modifications to the transaction reservations. Signed-off-by: Dave Chinner Signed-off-by: Allison Henderson Reviewed-by: Darrick J. Wong [djwong: fix indenting errors, adjust for new log format] Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig --- fs/xfs/libxfs/xfs_trans_resv.c | 326 ++++++++++++++++++++++++++++++++++------ 1 file changed, 274 insertions(+), 52 deletions(-) diff --git a/fs/xfs/libxfs/xfs_trans_resv.c b/fs/xfs/libxfs/xfs_trans_resv.c index 6cd45e8c118da..6dbe6e7251e7c 100644 --- a/fs/xfs/libxfs/xfs_trans_resv.c +++ b/fs/xfs/libxfs/xfs_trans_resv.c @@ -20,6 +20,9 @@ #include "xfs_qm.h" #include "xfs_trans_space.h" #include "xfs_rtbitmap.h" +#include "xfs_attr_item.h" +#include "xfs_log.h" +#include "xfs_da_format.h" #define _ALLOC true #define _FREE false @@ -422,29 +425,110 @@ xfs_calc_itruncate_reservation_minlogsize( return xfs_calc_itruncate_reservation(mp, true); } +static inline unsigned int xfs_calc_pptr_link_overhead(void) +{ + return sizeof(struct xfs_attri_log_format) + + xlog_calc_iovec_len(sizeof(struct xfs_parent_rec)) + + xlog_calc_iovec_len(MAXNAMELEN - 1); +} +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_rec)) + + xlog_calc_iovec_len(MAXNAMELEN - 1); +} +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_rec)) + + xlog_calc_iovec_len(MAXNAMELEN - 1) + + xlog_calc_iovec_len(sizeof(struct xfs_parent_rec)) + + xlog_calc_iovec_len(MAXNAMELEN - 1); +} + /* * In renaming a files we can modify: * the five inodes involved: 5 * inode size * the two directory btrees: 2 * (max depth + v2) * dir block size * the two directory bmap btrees: 2 * max depth * block size * And the bmap_finish transaction can free dir and bmap blocks (two sets - * of bmap blocks) giving: + * of bmap blocks) giving (t2): * the agf for the ags in which the blocks live: 3 * sector size * the agfl for the ags in which the blocks live: 3 * sector size * the superblock for the free block count: sector size * the allocation btrees: 3 exts * 2 trees * (2 * max depth - 1) * block size + * If parent pointers are enabled (t3), then each transaction in the chain + * must be capable of setting or removing the extended attribute + * containing the parent information. It must also be able to handle + * the three xattr intent items that track the progress of the parent + * pointer update. */ STATIC uint xfs_calc_rename_reservation( struct xfs_mount *mp) { - return XFS_DQUOT_LOGRES(mp) + - max((xfs_calc_inode_res(mp, 5) + - xfs_calc_buf_res(2 * XFS_DIROP_LOG_COUNT(mp), - XFS_FSB_TO_B(mp, 1))), - (xfs_calc_buf_res(7, mp->m_sb.sb_sectsize) + - xfs_calc_buf_res(xfs_allocfree_block_count(mp, 3), - XFS_FSB_TO_B(mp, 1)))); + unsigned int overhead = XFS_DQUOT_LOGRES(mp); + struct xfs_trans_resv *resp = M_RES(mp); + unsigned int t1, t2, t3 = 0; + + t1 = xfs_calc_inode_res(mp, 5) + + xfs_calc_buf_res(2 * XFS_DIROP_LOG_COUNT(mp), + XFS_FSB_TO_B(mp, 1)); + + t2 = xfs_calc_buf_res(7, mp->m_sb.sb_sectsize) + + xfs_calc_buf_res(xfs_allocfree_block_count(mp, 3), + XFS_FSB_TO_B(mp, 1)); + + if (xfs_has_parent(mp)) { + unsigned int rename_overhead, exchange_overhead; + + t3 = max(resp->tr_attrsetm.tr_logres, + resp->tr_attrrm.tr_logres); + + /* + * For a standard rename, the three xattr intent log items + * are (1) replacing the pptr for the source file; (2) + * removing the pptr on the dest file; and (3) adding a + * pptr for the whiteout file in the src dir. + * + * For an RENAME_EXCHANGE, there are two xattr intent + * items to replace the pptr for both src and dest + * files. Link counts don't change and there is no + * whiteout. + * + * In the worst case we can end up relogging all log + * intent items to allow the log tail to move ahead, so + * they become overhead added to each transaction in a + * processing chain. + */ + rename_overhead = xfs_calc_pptr_replace_overhead() + + xfs_calc_pptr_unlink_overhead() + + xfs_calc_pptr_link_overhead(); + exchange_overhead = 2 * xfs_calc_pptr_replace_overhead(); + + overhead += max(rename_overhead, exchange_overhead); + } + + return overhead + max3(t1, t2, t3); +} + +static inline unsigned int +xfs_rename_log_count( + struct xfs_mount *mp, + struct xfs_trans_resv *resp) +{ + /* One for the rename, one more for freeing blocks */ + unsigned int ret = XFS_RENAME_LOG_COUNT; + + /* + * Pre-reserve enough log reservation to handle the transaction + * rolling needed to remove or add one parent pointer. + */ + if (xfs_has_parent(mp)) + ret += max(resp->tr_attrsetm.tr_logcount, + resp->tr_attrrm.tr_logcount); + + return ret; } /* @@ -461,6 +545,23 @@ xfs_calc_iunlink_remove_reservation( 2 * M_IGEO(mp)->inode_cluster_size; } +static inline unsigned int +xfs_link_log_count( + struct xfs_mount *mp, + struct xfs_trans_resv *resp) +{ + unsigned int ret = XFS_LINK_LOG_COUNT; + + /* + * Pre-reserve enough log reservation to handle the transaction + * rolling needed to add one parent pointer. + */ + if (xfs_has_parent(mp)) + ret += resp->tr_attrsetm.tr_logcount; + + return ret; +} + /* * For creating a link to an inode: * the parent directory inode: inode size @@ -477,14 +578,23 @@ STATIC uint xfs_calc_link_reservation( struct xfs_mount *mp) { - return XFS_DQUOT_LOGRES(mp) + - xfs_calc_iunlink_remove_reservation(mp) + - max((xfs_calc_inode_res(mp, 2) + - xfs_calc_buf_res(XFS_DIROP_LOG_COUNT(mp), - XFS_FSB_TO_B(mp, 1))), - (xfs_calc_buf_res(3, mp->m_sb.sb_sectsize) + - xfs_calc_buf_res(xfs_allocfree_block_count(mp, 1), - XFS_FSB_TO_B(mp, 1)))); + unsigned int overhead = XFS_DQUOT_LOGRES(mp); + struct xfs_trans_resv *resp = M_RES(mp); + unsigned int t1, t2, t3 = 0; + + overhead += xfs_calc_iunlink_remove_reservation(mp); + t1 = xfs_calc_inode_res(mp, 2) + + xfs_calc_buf_res(XFS_DIROP_LOG_COUNT(mp), XFS_FSB_TO_B(mp, 1)); + t2 = xfs_calc_buf_res(3, mp->m_sb.sb_sectsize) + + xfs_calc_buf_res(xfs_allocfree_block_count(mp, 1), + XFS_FSB_TO_B(mp, 1)); + + if (xfs_has_parent(mp)) { + t3 = resp->tr_attrsetm.tr_logres; + overhead += xfs_calc_pptr_link_overhead(); + } + + return overhead + max3(t1, t2, t3); } /* @@ -499,6 +609,23 @@ xfs_calc_iunlink_add_reservation(xfs_mount_t *mp) M_IGEO(mp)->inode_cluster_size; } +static inline unsigned int +xfs_remove_log_count( + struct xfs_mount *mp, + struct xfs_trans_resv *resp) +{ + unsigned int ret = XFS_REMOVE_LOG_COUNT; + + /* + * Pre-reserve enough log reservation to handle the transaction + * rolling needed to add one parent pointer. + */ + if (xfs_has_parent(mp)) + ret += resp->tr_attrrm.tr_logcount; + + return ret; +} + /* * For removing a directory entry we can modify: * the parent directory inode: inode size @@ -515,14 +642,24 @@ STATIC uint xfs_calc_remove_reservation( struct xfs_mount *mp) { - return XFS_DQUOT_LOGRES(mp) + - xfs_calc_iunlink_add_reservation(mp) + - max((xfs_calc_inode_res(mp, 2) + - xfs_calc_buf_res(XFS_DIROP_LOG_COUNT(mp), - XFS_FSB_TO_B(mp, 1))), - (xfs_calc_buf_res(4, mp->m_sb.sb_sectsize) + - xfs_calc_buf_res(xfs_allocfree_block_count(mp, 2), - XFS_FSB_TO_B(mp, 1)))); + unsigned int overhead = XFS_DQUOT_LOGRES(mp); + struct xfs_trans_resv *resp = M_RES(mp); + unsigned int t1, t2, t3 = 0; + + overhead += xfs_calc_iunlink_add_reservation(mp); + + t1 = xfs_calc_inode_res(mp, 2) + + xfs_calc_buf_res(XFS_DIROP_LOG_COUNT(mp), XFS_FSB_TO_B(mp, 1)); + t2 = xfs_calc_buf_res(4, mp->m_sb.sb_sectsize) + + xfs_calc_buf_res(xfs_allocfree_block_count(mp, 2), + XFS_FSB_TO_B(mp, 1)); + + if (xfs_has_parent(mp)) { + t3 = resp->tr_attrrm.tr_logres; + overhead += xfs_calc_pptr_unlink_overhead(); + } + + return overhead + max3(t1, t2, t3); } /* @@ -571,12 +708,40 @@ xfs_calc_icreate_resv_alloc( xfs_calc_finobt_res(mp); } +static inline unsigned int +xfs_icreate_log_count( + struct xfs_mount *mp, + struct xfs_trans_resv *resp) +{ + unsigned int ret = XFS_CREATE_LOG_COUNT; + + /* + * Pre-reserve enough log reservation to handle the transaction + * rolling needed to add one parent pointer. + */ + if (xfs_has_parent(mp)) + ret += resp->tr_attrsetm.tr_logcount; + + return ret; +} + STATIC uint -xfs_calc_icreate_reservation(xfs_mount_t *mp) +xfs_calc_icreate_reservation( + struct xfs_mount *mp) { - return XFS_DQUOT_LOGRES(mp) + - max(xfs_calc_icreate_resv_alloc(mp), - xfs_calc_create_resv_modify(mp)); + struct xfs_trans_resv *resp = M_RES(mp); + unsigned int overhead = XFS_DQUOT_LOGRES(mp); + unsigned int t1, t2, t3 = 0; + + t1 = xfs_calc_icreate_resv_alloc(mp); + t2 = xfs_calc_create_resv_modify(mp); + + if (xfs_has_parent(mp)) { + t3 = resp->tr_attrsetm.tr_logres; + overhead += xfs_calc_pptr_link_overhead(); + } + + return overhead + max3(t1, t2, t3); } STATIC uint @@ -589,6 +754,23 @@ xfs_calc_create_tmpfile_reservation( return res + xfs_calc_iunlink_add_reservation(mp); } +static inline unsigned int +xfs_mkdir_log_count( + struct xfs_mount *mp, + struct xfs_trans_resv *resp) +{ + unsigned int ret = XFS_MKDIR_LOG_COUNT; + + /* + * Pre-reserve enough log reservation to handle the transaction + * rolling needed to add one parent pointer. + */ + if (xfs_has_parent(mp)) + ret += resp->tr_attrsetm.tr_logcount; + + return ret; +} + /* * Making a new directory is the same as creating a new file. */ @@ -599,6 +781,22 @@ xfs_calc_mkdir_reservation( return xfs_calc_icreate_reservation(mp); } +static inline unsigned int +xfs_symlink_log_count( + struct xfs_mount *mp, + struct xfs_trans_resv *resp) +{ + unsigned int ret = XFS_SYMLINK_LOG_COUNT; + + /* + * Pre-reserve enough log reservation to handle the transaction + * rolling needed to add one parent pointer. + */ + if (xfs_has_parent(mp)) + ret += resp->tr_attrsetm.tr_logcount; + + return ret; +} /* * Making a new symplink is the same as creating a new file, but @@ -911,6 +1109,52 @@ xfs_calc_sb_reservation( return xfs_calc_buf_res(1, mp->m_sb.sb_sectsize); } +/* + * Namespace reservations. + * + * These get tricky when parent pointers are enabled as we have attribute + * modifications occurring from within these transactions. Rather than confuse + * each of these reservation calculations with the conditional attribute + * reservations, add them here in a clear and concise manner. This requires that + * the attribute reservations have already been calculated. + * + * Note that we only include the static attribute reservation here; the runtime + * reservation will have to be modified by the size of the attributes being + * added/removed/modified. See the comments on the attribute reservation + * calculations for more details. + */ +STATIC void +xfs_calc_namespace_reservations( + struct xfs_mount *mp, + struct xfs_trans_resv *resp) +{ + ASSERT(resp->tr_attrsetm.tr_logres > 0); + + resp->tr_rename.tr_logres = xfs_calc_rename_reservation(mp); + resp->tr_rename.tr_logcount = xfs_rename_log_count(mp, resp); + resp->tr_rename.tr_logflags |= XFS_TRANS_PERM_LOG_RES; + + resp->tr_link.tr_logres = xfs_calc_link_reservation(mp); + resp->tr_link.tr_logcount = xfs_link_log_count(mp, resp); + resp->tr_link.tr_logflags |= XFS_TRANS_PERM_LOG_RES; + + resp->tr_remove.tr_logres = xfs_calc_remove_reservation(mp); + resp->tr_remove.tr_logcount = xfs_remove_log_count(mp, resp); + resp->tr_remove.tr_logflags |= XFS_TRANS_PERM_LOG_RES; + + resp->tr_symlink.tr_logres = xfs_calc_symlink_reservation(mp); + resp->tr_symlink.tr_logcount = xfs_symlink_log_count(mp, resp); + resp->tr_symlink.tr_logflags |= XFS_TRANS_PERM_LOG_RES; + + resp->tr_create.tr_logres = xfs_calc_icreate_reservation(mp); + resp->tr_create.tr_logcount = xfs_icreate_log_count(mp, resp); + resp->tr_create.tr_logflags |= XFS_TRANS_PERM_LOG_RES; + + resp->tr_mkdir.tr_logres = xfs_calc_mkdir_reservation(mp); + resp->tr_mkdir.tr_logcount = xfs_mkdir_log_count(mp, resp); + resp->tr_mkdir.tr_logflags |= XFS_TRANS_PERM_LOG_RES; +} + void xfs_trans_resv_calc( struct xfs_mount *mp, @@ -930,35 +1174,11 @@ xfs_trans_resv_calc( resp->tr_itruncate.tr_logcount = XFS_ITRUNCATE_LOG_COUNT; resp->tr_itruncate.tr_logflags |= XFS_TRANS_PERM_LOG_RES; - resp->tr_rename.tr_logres = xfs_calc_rename_reservation(mp); - resp->tr_rename.tr_logcount = XFS_RENAME_LOG_COUNT; - resp->tr_rename.tr_logflags |= XFS_TRANS_PERM_LOG_RES; - - resp->tr_link.tr_logres = xfs_calc_link_reservation(mp); - resp->tr_link.tr_logcount = XFS_LINK_LOG_COUNT; - resp->tr_link.tr_logflags |= XFS_TRANS_PERM_LOG_RES; - - resp->tr_remove.tr_logres = xfs_calc_remove_reservation(mp); - resp->tr_remove.tr_logcount = XFS_REMOVE_LOG_COUNT; - resp->tr_remove.tr_logflags |= XFS_TRANS_PERM_LOG_RES; - - resp->tr_symlink.tr_logres = xfs_calc_symlink_reservation(mp); - resp->tr_symlink.tr_logcount = XFS_SYMLINK_LOG_COUNT; - resp->tr_symlink.tr_logflags |= XFS_TRANS_PERM_LOG_RES; - - resp->tr_create.tr_logres = xfs_calc_icreate_reservation(mp); - resp->tr_create.tr_logcount = XFS_CREATE_LOG_COUNT; - resp->tr_create.tr_logflags |= XFS_TRANS_PERM_LOG_RES; - resp->tr_create_tmpfile.tr_logres = xfs_calc_create_tmpfile_reservation(mp); resp->tr_create_tmpfile.tr_logcount = XFS_CREATE_TMPFILE_LOG_COUNT; resp->tr_create_tmpfile.tr_logflags |= XFS_TRANS_PERM_LOG_RES; - resp->tr_mkdir.tr_logres = xfs_calc_mkdir_reservation(mp); - resp->tr_mkdir.tr_logcount = XFS_MKDIR_LOG_COUNT; - resp->tr_mkdir.tr_logflags |= XFS_TRANS_PERM_LOG_RES; - resp->tr_ifree.tr_logres = xfs_calc_ifree_reservation(mp); resp->tr_ifree.tr_logcount = XFS_INACTIVE_LOG_COUNT; resp->tr_ifree.tr_logflags |= XFS_TRANS_PERM_LOG_RES; @@ -988,6 +1208,8 @@ xfs_trans_resv_calc( resp->tr_qm_dqalloc.tr_logcount = XFS_WRITE_LOG_COUNT; resp->tr_qm_dqalloc.tr_logflags |= XFS_TRANS_PERM_LOG_RES; + xfs_calc_namespace_reservations(mp, resp); + /* * The following transactions are logged in logical format with * a default log count. From patchwork Wed Apr 10 00:57:41 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13623396 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A9673391 for ; Wed, 10 Apr 2024 00:57:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712710661; cv=none; b=LCmun1dbkoTtZV6hUdQzly9fySW91VNLpKTz5uHaOnmrybP6qfPvp14XnbGrB5r8oQgQJmy2dfWZe3SBYBe2KJKTIa1JMEu6f8o6l3zQs/jPQeU8GsEi+qdCLDiXSdu0Kl6Qoj9vSbU0TXfVLJkG19kTHA88bj5qlzMthd2kbYE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712710661; c=relaxed/simple; bh=pvhy8RNP8qkvL0hwZFDEUElpq873FoEElycEoymQ9qw=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=LLwXQTs1l1kxGhfy3CZMRy9BS7CUB5WH/l/8ULWjKV8IKXztIROY6gsECJluNtwIUcxDDSWcMUG8VhFsydwHMxS2m19YLALItjsQ2ii35aUHQuM/GMD1zc+jgVqaB74ABbzzztQ5DN0Yyjw9wIsvprbHaXFkM4Bafx9yz9JGZsk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Y5L8y5kV; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Y5L8y5kV" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 7C54DC433C7; Wed, 10 Apr 2024 00:57:41 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1712710661; bh=pvhy8RNP8qkvL0hwZFDEUElpq873FoEElycEoymQ9qw=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=Y5L8y5kVOHdDIajDzbT7rYa5U6KyKRyhzkd7lYowrLb+LvVlGQq6bvScBap8eGNPU r4e5NWGyZXo6cm93kenvddEGZ1CATYvnr2Da5YWi1dxA4nK8O0K7Ugj27AsJqf2CvR cG6WgiJzFpPOKRD75AZ1M6D5kQpTNpdU5NBrSrzKiujbYwMdBlL96PHFEXDS0Cc0lC OqNXoQTIGieKwwpvpK4+ofzmXFlBEtLD+BDoIS0EmxDFOV+x3VWVaEmoazAM2aOtqT lm+ADC60+0FMmjcjBymHHLjjxCgPpw1bj/6PD81eO8h7cgZPTfhAgpLVB8yM2NvB5b 2pt6fN7o+Rxqg== Date: Tue, 09 Apr 2024 17:57:41 -0700 Subject: [PATCH 16/32] xfs: create a hashname function for parent pointers From: "Darrick J. Wong" To: djwong@kernel.org Cc: catherine.hoang@oracle.com, hch@lst.de, allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <171270969823.3631889.1348496929393481589.stgit@frogsfrogsfrogs> In-Reply-To: <171270969477.3631889.12488500941186994317.stgit@frogsfrogsfrogs> References: <171270969477.3631889.12488500941186994317.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Although directory entry and parent pointer recordsets look very similar (name -> ino), there's one major difference between them: a file can be hardlinked from multiple parent directories with the same filename. This is common in shared container environments where a base directory tree might be hardlink-copied multiple times. IOWs the same 'ls' program might be hardlinked to multiple /srv/*/bin/ls paths. We don't want parent pointer operations to bog down on hash collisions between the same dirent name, so create a special hash function that mixes in the parent directory inode number. Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig --- fs/xfs/libxfs/xfs_attr.c | 3 +++ fs/xfs/libxfs/xfs_parent.c | 49 ++++++++++++++++++++++++++++++++++++++++++++ fs/xfs/libxfs/xfs_parent.h | 5 ++++ fs/xfs/scrub/attr.c | 4 ++++ 4 files changed, 61 insertions(+) diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c index 41de6a135d907..99930472e59da 100644 --- a/fs/xfs/libxfs/xfs_attr.c +++ b/fs/xfs/libxfs/xfs_attr.c @@ -439,6 +439,9 @@ xfs_attr_hashval( { ASSERT(xfs_attr_check_namespace(attr_flags)); + if (attr_flags & XFS_ATTR_PARENT) + return xfs_parent_hashattr(mp, name, namelen, value, valuelen); + return xfs_attr_hashname(name, namelen); } diff --git a/fs/xfs/libxfs/xfs_parent.c b/fs/xfs/libxfs/xfs_parent.c index 5961fa8c85615..d24104821a090 100644 --- a/fs/xfs/libxfs/xfs_parent.c +++ b/fs/xfs/libxfs/xfs_parent.c @@ -90,3 +90,52 @@ xfs_parent_valuecheck( return true; } + +/* Compute the attribute name hash for a parent pointer. */ +xfs_dahash_t +xfs_parent_hashval( + struct xfs_mount *mp, + const uint8_t *name, + int namelen, + xfs_ino_t parent_ino) +{ + struct xfs_name xname = { + .name = name, + .len = namelen, + }; + xfs_dahash_t ret; + + /* + * Use the same dirent name hash as would be used on the directory, but + * mix in the parent inode number. + */ + ret = xfs_dir2_hashname(mp, &xname); + ret ^= upper_32_bits(parent_ino); + ret ^= lower_32_bits(parent_ino); + return ret; +} + +/* Compute the attribute name hash from the xattr components. */ +xfs_dahash_t +xfs_parent_hashattr( + struct xfs_mount *mp, + const uint8_t *name, + int namelen, + const void *value, + int valuelen) +{ + const struct xfs_parent_rec *rec = value; + + /* Requires a local attr value in xfs_parent_rec format */ + if (valuelen != sizeof(struct xfs_parent_rec)) { + ASSERT(valuelen == sizeof(struct xfs_parent_rec)); + return 0; + } + + if (!value) { + ASSERT(value != NULL); + return 0; + } + + return xfs_parent_hashval(mp, name, namelen, be64_to_cpu(rec->p_ino)); +} diff --git a/fs/xfs/libxfs/xfs_parent.h b/fs/xfs/libxfs/xfs_parent.h index ef8aff8607801..6a4028871b72a 100644 --- a/fs/xfs/libxfs/xfs_parent.h +++ b/fs/xfs/libxfs/xfs_parent.h @@ -12,4 +12,9 @@ bool xfs_parent_namecheck(unsigned int attr_flags, const void *name, bool xfs_parent_valuecheck(struct xfs_mount *mp, const void *value, size_t valuelen); +xfs_dahash_t xfs_parent_hashval(struct xfs_mount *mp, const uint8_t *name, + int namelen, xfs_ino_t parent_ino); +xfs_dahash_t xfs_parent_hashattr(struct xfs_mount *mp, const uint8_t *name, + int namelen, const void *value, int valuelen); + #endif /* __XFS_PARENT_H__ */ diff --git a/fs/xfs/scrub/attr.c b/fs/xfs/scrub/attr.c index d5c2e73be8623..fe51a17661831 100644 --- a/fs/xfs/scrub/attr.c +++ b/fs/xfs/scrub/attr.c @@ -536,6 +536,10 @@ xchk_xattr_rec( xchk_da_set_corrupt(ds, level); goto out; } + if (ent->flags & XFS_ATTR_PARENT) { + xchk_da_set_corrupt(ds, level); + goto out; + } calc_hash = xfs_attr_hashval(mp, ent->flags, rentry->name, rentry->namelen, NULL, be32_to_cpu(rentry->valuelen)); From patchwork Wed Apr 10 00:57:56 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13623397 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4ED2B621 for ; Wed, 10 Apr 2024 00:57:57 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712710677; cv=none; b=N1axBI9uvxdXMvS/sr77eX5lbkanM3wlkYm7vo97jMPCc/tEMBuAouC5hUyPOq9uKfP4LiaJUmcacNiMXxz4csNMy8txGy+6Lp3zRZatPbhJ+mWDRKCGkPncOi25meCR8apvsnhRtiATTksJ0SmUG/fYyHCgmIMHpaibLSAXTr8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712710677; c=relaxed/simple; bh=FzRj/BgfAuXLdYEUmIbdVnWsmK30dbtXmV3ZDIGhsTQ=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=RaTyuv8FKGikiaRydyx75HW7UhoPilGKX0fcKFW1JkvnI8O3keFo5GPQvLbNaGwBDhzElTFq75NnF+WTb/lPN1ipTqHMntB3G5HGBzdJxpr/tuFPOigeWUtUq9+d4KN1gADLg2ciCBWGhntb5T5jJVmThxYHtNbpzEMqfOucGY8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=d1X8PLhU; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="d1X8PLhU" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 2237AC433C7; Wed, 10 Apr 2024 00:57:57 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1712710677; bh=FzRj/BgfAuXLdYEUmIbdVnWsmK30dbtXmV3ZDIGhsTQ=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=d1X8PLhU3YEyZvWkks9xf97J4iscrnywA0gO7Vt2sNefuEFg1VRkiJxZO0Fijg52R duGAOGWudywCKJsMFX7JisgCXybPmgiThX+ZaFRZmJ2tDLbedmvmFrEi3TfEKVFhfd gbeQ6ymtyla7szloJ/cC5xwXrdQxxPHbFXOAD3VStBIjgH6AaUKrHxqGUTVB5QAjvK 0W7ncYgRcXme/ec3y7mKDEahwOdYVyF8Edx1WFCg3pf7PvgtVF044hR4m++/99apou oszqQvs0tcrW4Xuh0Bw49px6pHDvxgdPIplWw14LqsmE8RlyBjeCcoglaMS/P6GUfp IKoLLeNXUDF+g== Date: Tue, 09 Apr 2024 17:57:56 -0700 Subject: [PATCH 17/32] xfs: parent pointer attribute creation From: "Darrick J. Wong" To: djwong@kernel.org Cc: Dave Chinner , Allison Henderson , catherine.hoang@oracle.com, hch@lst.de, allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <171270969840.3631889.8747832684298773440.stgit@frogsfrogsfrogs> In-Reply-To: <171270969477.3631889.12488500941186994317.stgit@frogsfrogsfrogs> References: <171270969477.3631889.12488500941186994317.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Allison Henderson Add parent pointer attribute during xfs_create, and subroutines to initialize attributes Signed-off-by: Dave Chinner Signed-off-by: Allison Henderson Reviewed-by: Darrick J. Wong [djwong: shorten names, adjust to new format, set init_xattrs for parent pointers] Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig --- fs/xfs/Makefile | 1 + fs/xfs/libxfs/xfs_parent.c | 68 +++++++++++++++++++++++++++++++++++++++ fs/xfs/libxfs/xfs_parent.h | 65 +++++++++++++++++++++++++++++++++++++ fs/xfs/libxfs/xfs_trans_space.c | 52 ++++++++++++++++++++++++++++++ fs/xfs/libxfs/xfs_trans_space.h | 9 +++-- fs/xfs/scrub/tempfile.c | 2 + fs/xfs/xfs_inode.c | 32 +++++++++++++++--- fs/xfs/xfs_iops.c | 15 ++++++++- fs/xfs/xfs_super.c | 10 ++++++ fs/xfs/xfs_xattr.c | 2 + fs/xfs/xfs_xattr.h | 2 + 11 files changed, 245 insertions(+), 13 deletions(-) create mode 100644 fs/xfs/libxfs/xfs_trans_space.c diff --git a/fs/xfs/Makefile b/fs/xfs/Makefile index 4956ea9a307b8..0c1a0b67af93c 100644 --- a/fs/xfs/Makefile +++ b/fs/xfs/Makefile @@ -51,6 +51,7 @@ xfs-y += $(addprefix libxfs/, \ xfs_symlink_remote.o \ xfs_trans_inode.o \ xfs_trans_resv.o \ + xfs_trans_space.o \ xfs_types.o \ ) # xfs_rtbitmap is shared with libxfs diff --git a/fs/xfs/libxfs/xfs_parent.c b/fs/xfs/libxfs/xfs_parent.c index d24104821a090..8875b4790112e 100644 --- a/fs/xfs/libxfs/xfs_parent.c +++ b/fs/xfs/libxfs/xfs_parent.c @@ -27,6 +27,10 @@ #include "xfs_xattr.h" #include "xfs_parent.h" #include "xfs_trans_space.h" +#include "xfs_attr_item.h" +#include "xfs_health.h" + +struct kmem_cache *xfs_parent_args_cache; /* * Parent pointer attribute handling. @@ -139,3 +143,67 @@ xfs_parent_hashattr( return xfs_parent_hashval(mp, name, namelen, be64_to_cpu(rec->p_ino)); } + +/* + * Initialize the parent pointer arguments structure. Caller must have zeroed + * the contents of @args. @tp is only required for updates. + */ +static void +xfs_parent_da_args_init( + struct xfs_da_args *args, + struct xfs_trans *tp, + struct xfs_parent_rec *rec, + struct xfs_inode *child, + xfs_ino_t owner, + const struct xfs_name *parent_name) +{ + args->geo = child->i_mount->m_attr_geo; + args->whichfork = XFS_ATTR_FORK; + args->attr_filter = XFS_ATTR_PARENT; + args->op_flags = XFS_DA_OP_LOGGED | XFS_DA_OP_OKNOENT; + args->trans = tp; + args->dp = child; + args->owner = owner; + args->name = parent_name->name; + args->namelen = parent_name->len; + args->value = rec; + args->valuelen = sizeof(struct xfs_parent_rec); + xfs_attr_sethash(args); +} + +/* Make sure the incore state is ready for a parent pointer query/update. */ +static inline int +xfs_parent_iread_extents( + struct xfs_trans *tp, + struct xfs_inode *child) +{ + /* Parent pointers require that the attr fork must exist. */ + if (XFS_IS_CORRUPT(child->i_mount, !xfs_inode_has_attr_fork(child))) { + xfs_inode_mark_sick(child, XFS_SICK_INO_PARENT); + return -EFSCORRUPTED; + } + + return xfs_iread_extents(tp, child, XFS_ATTR_FORK); +} + +/* Add a parent pointer to reflect a dirent addition. */ +int +xfs_parent_addname( + struct xfs_trans *tp, + struct xfs_parent_args *ppargs, + struct xfs_inode *dp, + const struct xfs_name *parent_name, + struct xfs_inode *child) +{ + int error; + + error = xfs_parent_iread_extents(tp, child); + if (error) + return error; + + xfs_inode_to_parent_rec(&ppargs->rec, dp); + xfs_parent_da_args_init(&ppargs->args, tp, &ppargs->rec, child, + child->i_ino, parent_name); + xfs_attr_defer_parent(&ppargs->args, XFS_ATTR_DEFER_SET); + return 0; +} diff --git a/fs/xfs/libxfs/xfs_parent.h b/fs/xfs/libxfs/xfs_parent.h index 6a4028871b72a..6de24e3ef318c 100644 --- a/fs/xfs/libxfs/xfs_parent.h +++ b/fs/xfs/libxfs/xfs_parent.h @@ -17,4 +17,69 @@ xfs_dahash_t xfs_parent_hashval(struct xfs_mount *mp, const uint8_t *name, xfs_dahash_t xfs_parent_hashattr(struct xfs_mount *mp, const uint8_t *name, int namelen, const void *value, int valuelen); +/* Initializes a xfs_parent_rec to be stored as an attribute name. */ +static inline void +xfs_parent_rec_init( + struct xfs_parent_rec *rec, + xfs_ino_t ino, + uint32_t gen) +{ + rec->p_ino = cpu_to_be64(ino); + rec->p_gen = cpu_to_be32(gen); +} + +/* Initializes a xfs_parent_rec to be stored as an attribute name. */ +static inline void +xfs_inode_to_parent_rec( + struct xfs_parent_rec *rec, + const struct xfs_inode *dp) +{ + xfs_parent_rec_init(rec, dp->i_ino, VFS_IC(dp)->i_generation); +} + +extern struct kmem_cache *xfs_parent_args_cache; + +/* + * Parent pointer information needed to pass around the deferred xattr update + * machinery. + */ +struct xfs_parent_args { + struct xfs_parent_rec rec; + struct xfs_da_args args; +}; + +/* + * Start a parent pointer update by allocating the context object we need to + * perform a parent pointer update. + */ +static inline int +xfs_parent_start( + struct xfs_mount *mp, + struct xfs_parent_args **ppargsp) +{ + if (!xfs_has_parent(mp)) { + *ppargsp = NULL; + return 0; + } + + *ppargsp = kmem_cache_zalloc(xfs_parent_args_cache, GFP_KERNEL); + if (!*ppargsp) + return -ENOMEM; + return 0; +} + +/* Finish a parent pointer update by freeing the context object. */ +static inline void +xfs_parent_finish( + struct xfs_mount *mp, + struct xfs_parent_args *ppargs) +{ + if (ppargs) + kmem_cache_free(xfs_parent_args_cache, ppargs); +} + +int xfs_parent_addname(struct xfs_trans *tp, struct xfs_parent_args *ppargs, + struct xfs_inode *dp, const struct xfs_name *parent_name, + struct xfs_inode *child); + #endif /* __XFS_PARENT_H__ */ diff --git a/fs/xfs/libxfs/xfs_trans_space.c b/fs/xfs/libxfs/xfs_trans_space.c new file mode 100644 index 0000000000000..90532c3fa2053 --- /dev/null +++ b/fs/xfs/libxfs/xfs_trans_space.c @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2000,2005 Silicon Graphics, Inc. + * All Rights Reserved. + */ +#include "xfs.h" +#include "xfs_fs.h" +#include "xfs_shared.h" +#include "xfs_format.h" +#include "xfs_da_format.h" +#include "xfs_log_format.h" +#include "xfs_trans_resv.h" +#include "xfs_mount.h" +#include "xfs_da_btree.h" +#include "xfs_bmap_btree.h" +#include "xfs_trans_space.h" + +/* Calculate the disk space required to add a parent pointer. */ +unsigned int +xfs_parent_calc_space_res( + struct xfs_mount *mp, + unsigned int namelen) +{ + /* + * Parent pointers are always the first attr in an attr tree, and never + * larger than a block + */ + return XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK) + + XFS_NEXTENTADD_SPACE_RES(mp, namelen, XFS_ATTR_FORK); +} + +unsigned int +xfs_create_space_res( + struct xfs_mount *mp, + unsigned int namelen) +{ + unsigned int ret; + + ret = XFS_IALLOC_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp, namelen); + if (xfs_has_parent(mp)) + ret += xfs_parent_calc_space_res(mp, namelen); + + return ret; +} + +unsigned int +xfs_mkdir_space_res( + struct xfs_mount *mp, + unsigned int namelen) +{ + return xfs_create_space_res(mp, namelen); +} diff --git a/fs/xfs/libxfs/xfs_trans_space.h b/fs/xfs/libxfs/xfs_trans_space.h index 9640fc232c147..6cda87153b38c 100644 --- a/fs/xfs/libxfs/xfs_trans_space.h +++ b/fs/xfs/libxfs/xfs_trans_space.h @@ -80,8 +80,6 @@ /* This macro is not used - see inline code in xfs_attr_set */ #define XFS_ATTRSET_SPACE_RES(mp, v) \ (XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK) + XFS_B_TO_FSB(mp, v)) -#define XFS_CREATE_SPACE_RES(mp,nl) \ - (XFS_IALLOC_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp,nl)) #define XFS_DIOSTRAT_SPACE_RES(mp, v) \ (XFS_EXTENTADD_SPACE_RES(mp, XFS_DATA_FORK) + (v)) #define XFS_GROWFS_SPACE_RES(mp) \ @@ -90,8 +88,6 @@ ((b) + XFS_EXTENTADD_SPACE_RES(mp, XFS_DATA_FORK)) #define XFS_LINK_SPACE_RES(mp,nl) \ XFS_DIRENTER_SPACE_RES(mp,nl) -#define XFS_MKDIR_SPACE_RES(mp,nl) \ - (XFS_IALLOC_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp,nl)) #define XFS_QM_DQALLOC_SPACE_RES(mp) \ (XFS_EXTENTADD_SPACE_RES(mp, XFS_DATA_FORK) + \ XFS_DQUOT_CLUSTER_SIZE_FSB) @@ -106,5 +102,10 @@ #define XFS_IFREE_SPACE_RES(mp) \ (xfs_has_finobt(mp) ? M_IGEO(mp)->inobt_maxlevels : 0) +unsigned int xfs_parent_calc_space_res(struct xfs_mount *mp, + unsigned int namelen); + +unsigned int xfs_create_space_res(struct xfs_mount *mp, unsigned int namelen); +unsigned int xfs_mkdir_space_res(struct xfs_mount *mp, unsigned int namelen); #endif /* __XFS_TRANS_SPACE_H__ */ diff --git a/fs/xfs/scrub/tempfile.c b/fs/xfs/scrub/tempfile.c index 6f39504a216ea..ddbcccb3dba13 100644 --- a/fs/xfs/scrub/tempfile.c +++ b/fs/xfs/scrub/tempfile.c @@ -71,7 +71,7 @@ xrep_tempfile_create( return error; if (is_dir) { - resblks = XFS_MKDIR_SPACE_RES(mp, 0); + resblks = xfs_mkdir_space_res(mp, 0); tres = &M_RES(mp)->tr_mkdir; } else { resblks = XFS_IALLOC_SPACE_RES(mp); diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index c079114b97ecf..ebef2767a86bd 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -40,6 +40,8 @@ #include "xfs_log_priv.h" #include "xfs_health.h" #include "xfs_pnfs.h" +#include "xfs_parent.h" +#include "xfs_xattr.h" struct kmem_cache *xfs_inode_cache; @@ -1016,7 +1018,7 @@ xfs_dir_hook_setup( int xfs_create( struct mnt_idmap *idmap, - xfs_inode_t *dp, + struct xfs_inode *dp, struct xfs_name *name, umode_t mode, dev_t rdev, @@ -1028,7 +1030,7 @@ xfs_create( struct xfs_inode *ip = NULL; struct xfs_trans *tp = NULL; int error; - bool unlock_dp_on_error = false; + bool unlock_dp_on_error = false; prid_t prid; struct xfs_dquot *udqp = NULL; struct xfs_dquot *gdqp = NULL; @@ -1036,6 +1038,7 @@ xfs_create( struct xfs_trans_res *tres; uint resblks; xfs_ino_t ino; + struct xfs_parent_args *ppargs; trace_xfs_create(dp, name); @@ -1057,13 +1060,17 @@ xfs_create( return error; if (is_dir) { - resblks = XFS_MKDIR_SPACE_RES(mp, name->len); + resblks = xfs_mkdir_space_res(mp, name->len); tres = &M_RES(mp)->tr_mkdir; } else { - resblks = XFS_CREATE_SPACE_RES(mp, name->len); + resblks = xfs_create_space_res(mp, name->len); tres = &M_RES(mp)->tr_create; } + error = xfs_parent_start(mp, &ppargs); + if (error) + goto out_release_dquots; + /* * Initially assume that the file does not exist and * reserve the resources for that case. If that is not @@ -1079,7 +1086,7 @@ xfs_create( resblks, &tp); } if (error) - goto out_release_dquots; + goto out_parent; xfs_ilock(dp, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT); unlock_dp_on_error = true; @@ -1122,6 +1129,16 @@ xfs_create( xfs_bumplink(tp, dp); } + /* + * If we have parent pointers, we need to add the attribute containing + * the parent information now. + */ + if (ppargs) { + error = xfs_parent_addname(tp, ppargs, dp, name, ip); + if (error) + goto out_trans_cancel; + } + /* * Create ip with a reference from dp, and add '.' and '..' references * if it's a directory. @@ -1154,6 +1171,7 @@ xfs_create( *ipp = ip; xfs_iunlock(ip, XFS_ILOCK_EXCL); xfs_iunlock(dp, XFS_ILOCK_EXCL); + xfs_parent_finish(mp, ppargs); return 0; out_trans_cancel: @@ -1169,6 +1187,8 @@ xfs_create( xfs_finish_inode_setup(ip); xfs_irele(ip); } + out_parent: + xfs_parent_finish(mp, ppargs); out_release_dquots: xfs_qm_dqrele(udqp); xfs_qm_dqrele(gdqp); @@ -3037,7 +3057,7 @@ xfs_rename_alloc_whiteout( int error; error = xfs_create_tmpfile(idmap, dp, S_IFCHR | WHITEOUT_MODE, - false, &tmpfile); + xfs_has_parent(dp->i_mount), &tmpfile); if (error) return error; diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c index 273bc30fd2bad..a363af4d0bead 100644 --- a/fs/xfs/xfs_iops.c +++ b/fs/xfs/xfs_iops.c @@ -157,6 +157,8 @@ xfs_create_need_xattr( if (dir->i_sb->s_security) return true; #endif + if (xfs_has_parent(XFS_I(dir)->i_mount)) + return true; return false; } @@ -201,7 +203,18 @@ xfs_generic_create( xfs_create_need_xattr(dir, default_acl, acl), &ip); } else { - error = xfs_create_tmpfile(idmap, XFS_I(dir), mode, false, &ip); + bool init_xattrs = false; + + /* + * If this temporary file will be linkable, set up the file + * with an attr fork to receive a parent pointer. + */ + if (!(tmpfile->f_flags & O_EXCL) && + xfs_has_parent(XFS_I(dir)->i_mount)) + init_xattrs = true; + + error = xfs_create_tmpfile(idmap, XFS_I(dir), mode, + init_xattrs, &ip); } if (unlikely(error)) goto out_free_acl; diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c index 5c9ba974252d1..84f37e8474da2 100644 --- a/fs/xfs/xfs_super.c +++ b/fs/xfs/xfs_super.c @@ -44,6 +44,7 @@ #include "xfs_dahash_test.h" #include "xfs_rtbitmap.h" #include "xfs_exchmaps_item.h" +#include "xfs_parent.h" #include "scrub/stats.h" #include "scrub/rcbag_btree.h" @@ -2202,8 +2203,16 @@ xfs_init_caches(void) if (!xfs_xmi_cache) goto out_destroy_xmd_cache; + xfs_parent_args_cache = kmem_cache_create("xfs_parent_args", + sizeof(struct xfs_parent_args), + 0, 0, NULL); + if (!xfs_parent_args_cache) + goto out_destroy_xmi_cache; + return 0; + out_destroy_xmi_cache: + kmem_cache_destroy(xfs_xmi_cache); out_destroy_xmd_cache: kmem_cache_destroy(xfs_xmd_cache); out_destroy_iul_cache: @@ -2264,6 +2273,7 @@ xfs_destroy_caches(void) * destroy caches. */ rcu_barrier(); + kmem_cache_destroy(xfs_parent_args_cache); kmem_cache_destroy(xfs_xmd_cache); kmem_cache_destroy(xfs_xmi_cache); kmem_cache_destroy(xfs_iunlink_cache); diff --git a/fs/xfs/xfs_xattr.c b/fs/xfs/xfs_xattr.c index 514179a8d2a7f..85e886ee20e03 100644 --- a/fs/xfs/xfs_xattr.c +++ b/fs/xfs/xfs_xattr.c @@ -24,7 +24,7 @@ * Get permission to use log-assisted atomic exchange of file extents. * Callers must not be running any transactions or hold any ILOCKs. */ -static inline int +int xfs_attr_grab_log_assist( struct xfs_mount *mp) { diff --git a/fs/xfs/xfs_xattr.h b/fs/xfs/xfs_xattr.h index cec766cad26cd..f097002d06571 100644 --- a/fs/xfs/xfs_xattr.h +++ b/fs/xfs/xfs_xattr.h @@ -7,6 +7,8 @@ #define __XFS_XATTR_H__ int xfs_attr_change(struct xfs_da_args *args); +int xfs_attr_grab_log_assist(struct xfs_mount *mp); +void xfs_attr_rele_log_assist(struct xfs_mount *mp); extern const struct xattr_handler * const xfs_xattr_handlers[]; From patchwork Wed Apr 10 00:58:12 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13623398 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DF275391 for ; Wed, 10 Apr 2024 00:58:12 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712710693; cv=none; b=oQczqoeHHs14gmidvbF6Y0XX57SEB2vcL90MYkLU5uGcBlcjtQVER1pAlzmoYmqWk+6gLikN240a5ZMvwMfBiyiBEKITDaGtZXNO+qYDByfzm/UF344ngjrhyhG7+FhcJlgbCq+OazZvZICuJQ0OdRoX5bTuiyuMoalkh62pnLs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712710693; c=relaxed/simple; bh=TJ5CebvlXGF/gdhU0FLIOFqwBFK13n3ZzDyWhRZSx5g=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=Ebgilx8Hv/ssGcjv/etZ7bXq7JDY7/Q4flXKQn9Q5BBmicuK5L3M+Mk64jLVLvR92skWpyyUZpcMK7SuZLuuZeIyfJpgALKFUobZSFS78RtnxECa/jrS8fzwAKNAColdBOqCf1F0ftmTRIKrBZWZCQIa0/p1IbtSIjEg3NnHZ9A= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=K3n7zxys; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="K3n7zxys" Received: by smtp.kernel.org (Postfix) with ESMTPSA id B7208C433F1; Wed, 10 Apr 2024 00:58:12 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1712710692; bh=TJ5CebvlXGF/gdhU0FLIOFqwBFK13n3ZzDyWhRZSx5g=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=K3n7zxysruzsfuu6Iz1icjPtswWzJF+wna7k5qZYfqPKYMHJrQPplNZxflulv+nT8 2L4j/jPxktZ7cMRZGBaO1Rf60hol7ccQDyCLceQ165PI3wf3/6JlWS7x01up+vGLo9 pxRnEHqKd6phxqzLEaZmp/tbo0DyxoGOgaxUXQXW+CJZhM6w6DCKNkcZQTkeulU263 B957R+HX+ohJ+/b+QIwpb7qIL9yZfzL5Od92pul4lariQjuX7xDTO18sUx1lVz2o+y HcT3dNavyBA6AeXL33cEe/HXuX9Zq8ct0H0Xc0mYsjBk4X174DXjOAoZJo186uGZdh JjRQ1F0iY7ESQ== Date: Tue, 09 Apr 2024 17:58:12 -0700 Subject: [PATCH 18/32] xfs: add parent attributes to link From: "Darrick J. Wong" To: djwong@kernel.org Cc: Dave Chinner , Allison Henderson , catherine.hoang@oracle.com, hch@lst.de, allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <171270969857.3631889.10116561090490715564.stgit@frogsfrogsfrogs> In-Reply-To: <171270969477.3631889.12488500941186994317.stgit@frogsfrogsfrogs> References: <171270969477.3631889.12488500941186994317.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Allison Henderson This patch modifies xfs_link to add a parent pointer to the inode. Signed-off-by: Dave Chinner Signed-off-by: Allison Henderson Reviewed-by: Darrick J. Wong [djwong: minor rebase fixes] Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig --- fs/xfs/libxfs/xfs_trans_space.c | 14 +++++++++++++ fs/xfs/libxfs/xfs_trans_space.h | 3 +-- fs/xfs/scrub/dir_repair.c | 2 +- fs/xfs/scrub/orphanage.c | 2 +- fs/xfs/xfs_inode.c | 43 ++++++++++++++++++++++++++++++++++----- 5 files changed, 54 insertions(+), 10 deletions(-) diff --git a/fs/xfs/libxfs/xfs_trans_space.c b/fs/xfs/libxfs/xfs_trans_space.c index 90532c3fa2053..cf775750120e8 100644 --- a/fs/xfs/libxfs/xfs_trans_space.c +++ b/fs/xfs/libxfs/xfs_trans_space.c @@ -50,3 +50,17 @@ xfs_mkdir_space_res( { return xfs_create_space_res(mp, namelen); } + +unsigned int +xfs_link_space_res( + struct xfs_mount *mp, + unsigned int namelen) +{ + unsigned int ret; + + ret = XFS_DIRENTER_SPACE_RES(mp, namelen); + if (xfs_has_parent(mp)) + ret += xfs_parent_calc_space_res(mp, namelen); + + return ret; +} diff --git a/fs/xfs/libxfs/xfs_trans_space.h b/fs/xfs/libxfs/xfs_trans_space.h index 6cda87153b38c..5539634009fb2 100644 --- a/fs/xfs/libxfs/xfs_trans_space.h +++ b/fs/xfs/libxfs/xfs_trans_space.h @@ -86,8 +86,6 @@ (2 * (mp)->m_alloc_maxlevels) #define XFS_GROWFSRT_SPACE_RES(mp,b) \ ((b) + XFS_EXTENTADD_SPACE_RES(mp, XFS_DATA_FORK)) -#define XFS_LINK_SPACE_RES(mp,nl) \ - XFS_DIRENTER_SPACE_RES(mp,nl) #define XFS_QM_DQALLOC_SPACE_RES(mp) \ (XFS_EXTENTADD_SPACE_RES(mp, XFS_DATA_FORK) + \ XFS_DQUOT_CLUSTER_SIZE_FSB) @@ -107,5 +105,6 @@ unsigned int xfs_parent_calc_space_res(struct xfs_mount *mp, unsigned int xfs_create_space_res(struct xfs_mount *mp, unsigned int namelen); unsigned int xfs_mkdir_space_res(struct xfs_mount *mp, unsigned int namelen); +unsigned int xfs_link_space_res(struct xfs_mount *mp, unsigned int namelen); #endif /* __XFS_TRANS_SPACE_H__ */ diff --git a/fs/xfs/scrub/dir_repair.c b/fs/xfs/scrub/dir_repair.c index 38957da26b94a..575397aef1f7a 100644 --- a/fs/xfs/scrub/dir_repair.c +++ b/fs/xfs/scrub/dir_repair.c @@ -704,7 +704,7 @@ xrep_dir_replay_update( uint resblks; int error; - resblks = XFS_LINK_SPACE_RES(mp, xname->len); + resblks = xfs_link_space_res(mp, xname->len); error = xchk_trans_alloc(rd->sc, resblks); if (error) return error; diff --git a/fs/xfs/scrub/orphanage.c b/fs/xfs/scrub/orphanage.c index 885b7d478a0ab..5e2c3546f2e95 100644 --- a/fs/xfs/scrub/orphanage.c +++ b/fs/xfs/scrub/orphanage.c @@ -326,7 +326,7 @@ xrep_adoption_trans_alloc( /* Compute the worst case space reservation that we need. */ adopt->sc = sc; - adopt->orphanage_blkres = XFS_LINK_SPACE_RES(mp, MAXNAMELEN); + adopt->orphanage_blkres = xfs_link_space_res(mp, MAXNAMELEN); if (S_ISDIR(VFS_I(sc->ip)->i_mode)) child_blkres = XFS_RENAME_SPACE_RES(mp, xfs_name_dotdot.len); adopt->child_blkres = child_blkres; diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index ebef2767a86bd..4a3fbd8d33099 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -1298,14 +1298,15 @@ xfs_create_tmpfile( int xfs_link( - xfs_inode_t *tdp, - xfs_inode_t *sip, + struct xfs_inode *tdp, + struct xfs_inode *sip, struct xfs_name *target_name) { - xfs_mount_t *mp = tdp->i_mount; - xfs_trans_t *tp; + struct xfs_mount *mp = tdp->i_mount; + struct xfs_trans *tp; int error, nospace_error = 0; int resblks; + struct xfs_parent_args *ppargs; trace_xfs_link(tdp, target_name); @@ -1324,11 +1325,25 @@ xfs_link( if (error) goto std_return; - resblks = XFS_LINK_SPACE_RES(mp, target_name->len); + error = xfs_parent_start(mp, &ppargs); + if (error) + goto std_return; + + resblks = xfs_link_space_res(mp, target_name->len); error = xfs_trans_alloc_dir(tdp, &M_RES(mp)->tr_link, sip, &resblks, &tp, &nospace_error); if (error) - goto std_return; + goto out_parent; + + /* + * We don't allow reservationless or quotaless hardlinking when parent + * pointers are enabled because we can't back out if the xattrs must + * grow. + */ + if (ppargs && nospace_error) { + error = nospace_error; + goto error_return; + } /* * If we are using project inheritance, we only allow hard link @@ -1379,6 +1394,19 @@ xfs_link( xfs_trans_log_inode(tp, tdp, XFS_ILOG_CORE); xfs_bumplink(tp, sip); + + /* + * If we have parent pointers, we now need to add the parent record to + * the attribute fork of the inode. If this is the initial parent + * attribute, we need to create it correctly, otherwise we can just add + * the parent to the inode. + */ + if (ppargs) { + error = xfs_parent_addname(tp, ppargs, tdp, target_name, sip); + if (error) + goto error_return; + } + xfs_dir_update_hook(tdp, sip, 1, target_name); /* @@ -1392,12 +1420,15 @@ xfs_link( error = xfs_trans_commit(tp); xfs_iunlock(tdp, XFS_ILOCK_EXCL); xfs_iunlock(sip, XFS_ILOCK_EXCL); + xfs_parent_finish(mp, ppargs); return error; error_return: xfs_trans_cancel(tp); xfs_iunlock(tdp, XFS_ILOCK_EXCL); xfs_iunlock(sip, XFS_ILOCK_EXCL); + out_parent: + xfs_parent_finish(mp, ppargs); std_return: if (error == -ENOSPC && nospace_error) error = nospace_error; From patchwork Wed Apr 10 00:58:27 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13623399 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8D0CF391 for ; Wed, 10 Apr 2024 00:58:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712710708; cv=none; b=HxEFJi9BncBIlyawfEIEb+gIaAXVCEDHNl9gUuqMe+cgeCXOmUya1NiBjNJ3nfYG9BU3UZaihaTINJrVo+wgvyck4DLDpIA5FWLgSf/4ROr78dFH62tIn/pY0nss/g84W6l+V9G1jgagbOs/6+gUFHzzERPX8hUvAyUFgyLy9Tg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712710708; c=relaxed/simple; bh=TVydHWtXq6Q6OU+3GkfIj9OuyyBwzMEgrY4PidRB89w=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=ttIpl/1brCNwTMZlzoUl9iXisQCHH6TSmB9obj35tOGGixZ+nma0+DveIC+Sga4VZP6uPv4ct2OPGw8muH42U/zcPfBsuWXSDmFZddsILwG5On2BYISfBXu4VA9LkAIDymbmYwjjFVlyvV2VyTuje1FvRfTjkwFyFqTJ3TcW7/U= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=b18NHfYQ; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="b18NHfYQ" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 6294BC433F1; Wed, 10 Apr 2024 00:58:28 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1712710708; bh=TVydHWtXq6Q6OU+3GkfIj9OuyyBwzMEgrY4PidRB89w=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=b18NHfYQWReAjK16yegJa306tYQs9HSkLItIpp+vofKsv2hqCIj0BJeVVQpJgyXzz 7OmcTReK6UiPGji/khvuM6BbfOWNHxVzKBJkhNHDEgau91Vnb4LOVzTDpl+Obz5nFn /a0mn3RskdA9zkbO+ttdpSDYs4JjIeay8dAk9siL58jmGin+KP/i9F1fWN2L1TQlhm uPz+cglIz4Fr/GdncTlW5jeugnE5i0sNVU4FTsQSc6sVzapu9wOoLyK6Jg2XCVZine AEjFhOyDYKBdE5O1/bWR/MlOVDVQz98vPRmP17TVuECnq9VybXhV6I/UQIW7HdeQxf n/AbzlrqxRIDQ== Date: Tue, 09 Apr 2024 17:58:27 -0700 Subject: [PATCH 19/32] xfs: add parent attributes to symlink From: "Darrick J. Wong" To: djwong@kernel.org Cc: Allison Henderson , catherine.hoang@oracle.com, hch@lst.de, allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <171270969874.3631889.4172660414607095925.stgit@frogsfrogsfrogs> In-Reply-To: <171270969477.3631889.12488500941186994317.stgit@frogsfrogsfrogs> References: <171270969477.3631889.12488500941186994317.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Allison Henderson This patch modifies xfs_symlink to add a parent pointer to the inode. Signed-off-by: Allison Henderson Reviewed-by: Darrick J. Wong [djwong: minor rebase fixups] Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig --- fs/xfs/libxfs/xfs_trans_space.c | 17 +++++++++++++++++ fs/xfs/libxfs/xfs_trans_space.h | 4 ++-- fs/xfs/scrub/symlink_repair.c | 2 +- fs/xfs/xfs_symlink.c | 30 +++++++++++++++++++++++++----- 4 files changed, 45 insertions(+), 8 deletions(-) diff --git a/fs/xfs/libxfs/xfs_trans_space.c b/fs/xfs/libxfs/xfs_trans_space.c index cf775750120e8..c8adda82debe0 100644 --- a/fs/xfs/libxfs/xfs_trans_space.c +++ b/fs/xfs/libxfs/xfs_trans_space.c @@ -64,3 +64,20 @@ xfs_link_space_res( return ret; } + +unsigned int +xfs_symlink_space_res( + struct xfs_mount *mp, + unsigned int namelen, + unsigned int fsblocks) +{ + unsigned int ret; + + ret = XFS_IALLOC_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp, namelen) + + fsblocks; + + if (xfs_has_parent(mp)) + ret += xfs_parent_calc_space_res(mp, namelen); + + return ret; +} diff --git a/fs/xfs/libxfs/xfs_trans_space.h b/fs/xfs/libxfs/xfs_trans_space.h index 5539634009fb2..354ad1d6e18d6 100644 --- a/fs/xfs/libxfs/xfs_trans_space.h +++ b/fs/xfs/libxfs/xfs_trans_space.h @@ -95,8 +95,6 @@ XFS_DIRREMOVE_SPACE_RES(mp) #define XFS_RENAME_SPACE_RES(mp,nl) \ (XFS_DIRREMOVE_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp,nl)) -#define XFS_SYMLINK_SPACE_RES(mp,nl,b) \ - (XFS_IALLOC_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp,nl) + (b)) #define XFS_IFREE_SPACE_RES(mp) \ (xfs_has_finobt(mp) ? M_IGEO(mp)->inobt_maxlevels : 0) @@ -106,5 +104,7 @@ unsigned int xfs_parent_calc_space_res(struct xfs_mount *mp, unsigned int xfs_create_space_res(struct xfs_mount *mp, unsigned int namelen); unsigned int xfs_mkdir_space_res(struct xfs_mount *mp, unsigned int namelen); unsigned int xfs_link_space_res(struct xfs_mount *mp, unsigned int namelen); +unsigned int xfs_symlink_space_res(struct xfs_mount *mp, unsigned int namelen, + unsigned int fsblocks); #endif /* __XFS_TRANS_SPACE_H__ */ diff --git a/fs/xfs/scrub/symlink_repair.c b/fs/xfs/scrub/symlink_repair.c index 178304959535a..c8b5a5b878ac9 100644 --- a/fs/xfs/scrub/symlink_repair.c +++ b/fs/xfs/scrub/symlink_repair.c @@ -421,7 +421,7 @@ xrep_symlink_rebuild( * unlikely. */ fs_blocks = xfs_symlink_blocks(sc->mp, target_len); - resblks = XFS_SYMLINK_SPACE_RES(sc->mp, target_len, fs_blocks); + resblks = xfs_symlink_space_res(sc->mp, target_len, fs_blocks); error = xfs_trans_reserve_quota_nblks(sc->tp, sc->tempip, resblks, 0, true); if (error) diff --git a/fs/xfs/xfs_symlink.c b/fs/xfs/xfs_symlink.c index 85ef56fdd7dfe..17aee806ec2e1 100644 --- a/fs/xfs/xfs_symlink.c +++ b/fs/xfs/xfs_symlink.c @@ -25,6 +25,8 @@ #include "xfs_error.h" #include "xfs_health.h" #include "xfs_symlink_remote.h" +#include "xfs_parent.h" +#include "xfs_defer.h" int xfs_readlink( @@ -100,6 +102,7 @@ xfs_symlink( struct xfs_dquot *pdqp = NULL; uint resblks; xfs_ino_t ino; + struct xfs_parent_args *ppargs; *ipp = NULL; @@ -130,18 +133,24 @@ xfs_symlink( /* * The symlink will fit into the inode data fork? - * There can't be any attributes so we get the whole variable part. + * If there are no parent pointers, then there wont't be any attributes. + * So we get the whole variable part, and do not need to reserve extra + * blocks. Otherwise, we need to reserve the blocks. */ - if (pathlen <= XFS_LITINO(mp)) + if (pathlen <= XFS_LITINO(mp) && !xfs_has_parent(mp)) fs_blocks = 0; else fs_blocks = xfs_symlink_blocks(mp, pathlen); - resblks = XFS_SYMLINK_SPACE_RES(mp, link_name->len, fs_blocks); + resblks = xfs_symlink_space_res(mp, link_name->len, fs_blocks); + + error = xfs_parent_start(mp, &ppargs); + if (error) + goto out_release_dquots; error = xfs_trans_alloc_icreate(mp, &M_RES(mp)->tr_symlink, udqp, gdqp, pdqp, resblks, &tp); if (error) - goto out_release_dquots; + goto out_parent; xfs_ilock(dp, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT); unlock_dp_on_error = true; @@ -161,7 +170,7 @@ xfs_symlink( if (!error) error = xfs_init_new_inode(idmap, tp, dp, ino, S_IFLNK | (mode & ~S_IFMT), 1, 0, prid, - false, &ip); + xfs_has_parent(mp), &ip); if (error) goto out_trans_cancel; @@ -195,6 +204,14 @@ xfs_symlink( goto out_trans_cancel; xfs_trans_ichgtime(tp, dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE); + + /* Add parent pointer for the new symlink. */ + if (ppargs) { + error = xfs_parent_addname(tp, ppargs, dp, link_name, ip); + if (error) + goto out_trans_cancel; + } + xfs_dir_update_hook(dp, ip, 1, link_name); /* @@ -216,6 +233,7 @@ xfs_symlink( *ipp = ip; xfs_iunlock(ip, XFS_ILOCK_EXCL); xfs_iunlock(dp, XFS_ILOCK_EXCL); + xfs_parent_finish(mp, ppargs); return 0; out_trans_cancel: @@ -231,6 +249,8 @@ xfs_symlink( xfs_finish_inode_setup(ip); xfs_irele(ip); } +out_parent: + xfs_parent_finish(mp, ppargs); out_release_dquots: xfs_qm_dqrele(udqp); xfs_qm_dqrele(gdqp); From patchwork Wed Apr 10 00:58:43 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13623400 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 47F57621 for ; Wed, 10 Apr 2024 00:58:44 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712710724; cv=none; b=HG/Of4+kdnukAPg7Z/0LFchjsCFEiD0oiTWkPu+Lfr2cDT6/eE2xlq9JpCr7A1qPxvcHaK1vGyrElGFMbzpQoU9kyBvE6NCWg5jzNLw7CGoIKP3s382bNITCPD848kQ4UaenrmS+WPAG5BeqTy/cd/f65wbhqKPqgI/32fZQkLI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712710724; c=relaxed/simple; bh=+WK8nOi3k3SvRJn42cVqCXQx9xBBMTqcFoGv8sV1Fpk=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=D9Rb/Rn6ypjdJjiUq+0ElULkYX1pqP46KCLAuHtNWLHuUlv1X2W3xzuCI0itmfvXVnHUCUQR8TcSR6GFdQ2Gg+kYyDB+srQWLEzC/YJ8Ghr24etafVzlN2wMUktFMBLWKEgy19ocKWnKXIDD8A9kXi6r87nNvpKqp1IFB8CyGYY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=MFbhUx8M; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="MFbhUx8M" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 21938C433F1; Wed, 10 Apr 2024 00:58:44 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1712710724; bh=+WK8nOi3k3SvRJn42cVqCXQx9xBBMTqcFoGv8sV1Fpk=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=MFbhUx8MV5G6TqYelmi470Fu0nk+qNye80oWWKowyU08IRuo4X+Qkqxk32N58AjGW YswxiJOA+BBjbY25YrVNsskXzFLKZVbtZlubDUiiylVP4TLfSwgmGUSRA4ox37d/yl 2SkdtTkvNtFLS7h2Yw59Cn2UaP0yIdH0gcw2npaBZepOVM82YrZM6ns82TKWp7M/rX hfFJKRNqlArJViusanSYgHXxp5Y8F5JInUIEPJPqYWM4lrqHLUIip/VHyYGfRAS5j0 vO64BM7/ixliqoAUO970t+kpQhuKsVyJWa/zIm9MjQAK3t7jTMVlghIgZxJQZ4A/dT mguRuBgNgdxEQ== Date: Tue, 09 Apr 2024 17:58:43 -0700 Subject: [PATCH 20/32] xfs: remove parent pointers in unlink From: "Darrick J. Wong" To: djwong@kernel.org Cc: Dave Chinner , Allison Henderson , catherine.hoang@oracle.com, hch@lst.de, allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <171270969891.3631889.16415446774447161383.stgit@frogsfrogsfrogs> In-Reply-To: <171270969477.3631889.12488500941186994317.stgit@frogsfrogsfrogs> References: <171270969477.3631889.12488500941186994317.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Allison Henderson This patch removes the parent pointer attribute during unlink Signed-off-by: Dave Chinner Signed-off-by: Allison Henderson Reviewed-by: Darrick J. Wong [djwong: adjust to new ondisk format, minor rebase fixes] Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig --- fs/xfs/libxfs/xfs_parent.c | 22 ++++++++++++++++++++++ fs/xfs/libxfs/xfs_parent.h | 3 +++ fs/xfs/libxfs/xfs_trans_space.c | 13 +++++++++++++ fs/xfs/libxfs/xfs_trans_space.h | 3 +-- fs/xfs/xfs_inode.c | 27 +++++++++++++++++++++------ 5 files changed, 60 insertions(+), 8 deletions(-) diff --git a/fs/xfs/libxfs/xfs_parent.c b/fs/xfs/libxfs/xfs_parent.c index 8875b4790112e..0ddaab08d722d 100644 --- a/fs/xfs/libxfs/xfs_parent.c +++ b/fs/xfs/libxfs/xfs_parent.c @@ -207,3 +207,25 @@ xfs_parent_addname( xfs_attr_defer_parent(&ppargs->args, XFS_ATTR_DEFER_SET); return 0; } + +/* Remove a parent pointer to reflect a dirent removal. */ +int +xfs_parent_removename( + struct xfs_trans *tp, + struct xfs_parent_args *ppargs, + struct xfs_inode *dp, + const struct xfs_name *parent_name, + struct xfs_inode *child) +{ + int error; + + error = xfs_parent_iread_extents(tp, child); + if (error) + return error; + + xfs_inode_to_parent_rec(&ppargs->rec, dp); + xfs_parent_da_args_init(&ppargs->args, tp, &ppargs->rec, child, + child->i_ino, parent_name); + xfs_attr_defer_parent(&ppargs->args, XFS_ATTR_DEFER_REMOVE); + return 0; +} diff --git a/fs/xfs/libxfs/xfs_parent.h b/fs/xfs/libxfs/xfs_parent.h index 6de24e3ef318c..4a7fd48c226a4 100644 --- a/fs/xfs/libxfs/xfs_parent.h +++ b/fs/xfs/libxfs/xfs_parent.h @@ -81,5 +81,8 @@ xfs_parent_finish( int xfs_parent_addname(struct xfs_trans *tp, struct xfs_parent_args *ppargs, struct xfs_inode *dp, const struct xfs_name *parent_name, struct xfs_inode *child); +int xfs_parent_removename(struct xfs_trans *tp, struct xfs_parent_args *ppargs, + struct xfs_inode *dp, const struct xfs_name *parent_name, + struct xfs_inode *child); #endif /* __XFS_PARENT_H__ */ diff --git a/fs/xfs/libxfs/xfs_trans_space.c b/fs/xfs/libxfs/xfs_trans_space.c index c8adda82debe0..df729e4f1a4c9 100644 --- a/fs/xfs/libxfs/xfs_trans_space.c +++ b/fs/xfs/libxfs/xfs_trans_space.c @@ -81,3 +81,16 @@ xfs_symlink_space_res( return ret; } + +unsigned int +xfs_remove_space_res( + struct xfs_mount *mp, + unsigned int namelen) +{ + unsigned int ret = XFS_DIRREMOVE_SPACE_RES(mp); + + if (xfs_has_parent(mp)) + ret += xfs_parent_calc_space_res(mp, namelen); + + return ret; +} diff --git a/fs/xfs/libxfs/xfs_trans_space.h b/fs/xfs/libxfs/xfs_trans_space.h index 354ad1d6e18d6..a4490813c56f1 100644 --- a/fs/xfs/libxfs/xfs_trans_space.h +++ b/fs/xfs/libxfs/xfs_trans_space.h @@ -91,8 +91,6 @@ XFS_DQUOT_CLUSTER_SIZE_FSB) #define XFS_QM_QINOCREATE_SPACE_RES(mp) \ XFS_IALLOC_SPACE_RES(mp) -#define XFS_REMOVE_SPACE_RES(mp) \ - XFS_DIRREMOVE_SPACE_RES(mp) #define XFS_RENAME_SPACE_RES(mp,nl) \ (XFS_DIRREMOVE_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp,nl)) #define XFS_IFREE_SPACE_RES(mp) \ @@ -106,5 +104,6 @@ unsigned int xfs_mkdir_space_res(struct xfs_mount *mp, unsigned int namelen); unsigned int xfs_link_space_res(struct xfs_mount *mp, unsigned int namelen); unsigned int xfs_symlink_space_res(struct xfs_mount *mp, unsigned int namelen, unsigned int fsblocks); +unsigned int xfs_remove_space_res(struct xfs_mount *mp, unsigned int namelen); #endif /* __XFS_TRANS_SPACE_H__ */ diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index 4a3fbd8d33099..492d8d1055e9e 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -2720,16 +2720,17 @@ xfs_iunpin_wait( */ int xfs_remove( - xfs_inode_t *dp, + struct xfs_inode *dp, struct xfs_name *name, - xfs_inode_t *ip) + struct xfs_inode *ip) { - xfs_mount_t *mp = dp->i_mount; - xfs_trans_t *tp = NULL; + struct xfs_mount *mp = dp->i_mount; + struct xfs_trans *tp = NULL; int is_dir = S_ISDIR(VFS_I(ip)->i_mode); int dontcare; int error = 0; uint resblks; + struct xfs_parent_args *ppargs; trace_xfs_remove(dp, name); @@ -2746,6 +2747,10 @@ xfs_remove( if (error) goto std_return; + error = xfs_parent_start(mp, &ppargs); + if (error) + goto std_return; + /* * We try to get the real space reservation first, allowing for * directory btree deletion(s) implying possible bmap insert(s). If we @@ -2757,12 +2762,12 @@ xfs_remove( * the directory code can handle a reservationless update and we don't * want to prevent a user from trying to free space by deleting things. */ - resblks = XFS_REMOVE_SPACE_RES(mp); + resblks = xfs_remove_space_res(mp, name->len); error = xfs_trans_alloc_dir(dp, &M_RES(mp)->tr_remove, ip, &resblks, &tp, &dontcare); if (error) { ASSERT(error != -ENOSPC); - goto std_return; + goto out_parent; } /* @@ -2822,6 +2827,13 @@ xfs_remove( goto out_trans_cancel; } + /* Remove parent pointer. */ + if (ppargs) { + error = xfs_parent_removename(tp, ppargs, dp, name, ip); + if (error) + goto out_trans_cancel; + } + /* * Drop the link from dp to ip, and if ip was a directory, remove the * '.' and '..' references since we freed the directory. @@ -2845,6 +2857,7 @@ xfs_remove( xfs_iunlock(ip, XFS_ILOCK_EXCL); xfs_iunlock(dp, XFS_ILOCK_EXCL); + xfs_parent_finish(mp, ppargs); return 0; out_trans_cancel: @@ -2852,6 +2865,8 @@ xfs_remove( out_unlock: xfs_iunlock(ip, XFS_ILOCK_EXCL); xfs_iunlock(dp, XFS_ILOCK_EXCL); + out_parent: + xfs_parent_finish(mp, ppargs); std_return: return error; } From patchwork Wed Apr 10 00:58:59 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13623401 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4357F391 for ; Wed, 10 Apr 2024 00:58:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712710740; cv=none; b=ipEJvCb+wt7lbK0O2tXtg4NOPItIRQFqzu1MS+VEGBB5XN8Le+v3+Tmz5LAElR9xkw206RAiY37EyD166hrxQwev14WyuosaHBLrLF+5lmcsBKPRalJsdpy5lHLiYS4AXRcRxKEfQ37cEoDqVDFvLU/BTJBkC5QUPv8EhSYx5DU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712710740; c=relaxed/simple; bh=h0Fugom/5Sr1RqYd5VvAvSK1SwjDhny6lMYpagUFPRU=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=ADwNdBbU3osQ9bTyLfVVGM5AMVuy3Nyj21qN6m7776e+pwKtW0aawFedErQw9Jclo+IBL7JMgW62LCCpCGTSepXr/7g5BS7cQKgaGLCNZGK4rgsVXlyYPv48Dx2jhCue5dEps22i1m33Twd0JnPUTY63m5hAjlndbuzBNLVnVLY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=JlWtPS9G; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="JlWtPS9G" Received: by smtp.kernel.org (Postfix) with ESMTPSA id C6D2CC433C7; Wed, 10 Apr 2024 00:58:59 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1712710739; bh=h0Fugom/5Sr1RqYd5VvAvSK1SwjDhny6lMYpagUFPRU=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=JlWtPS9GOsX053vZipl6wzqtUnMlOJSbVLjFQJYaSEhXnG1ZVFu+nP+zROwq5L2un suM4igpU1qVT6EIhx6UK70Ei40349o9A3GEBekxazDmGhMYlaBMqEGt9l24gDbC+OG PS8YwpRDPR2bbRMGtDhDoqV41cTzjLJDyCETmbVxVTuhv/IYYHi43JAeGKk75FueYA z0s1FyML++cm/JI8d+/4u1kyCkW+LuGaAUAxnKLo4qlnZCJKMmfLGZqvvE0mB3UIez negPcLaoSzfn+/Y8hdbRkenhf+AhySkI/y3njkcS23c+SNEl4kvF1n7UWoyu4pCDTJ oApPAaJ7jZSXA== Date: Tue, 09 Apr 2024 17:58:59 -0700 Subject: [PATCH 21/32] xfs: Add parent pointers to rename From: "Darrick J. Wong" To: djwong@kernel.org Cc: Allison Henderson , catherine.hoang@oracle.com, hch@lst.de, allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <171270969908.3631889.12708632891559407279.stgit@frogsfrogsfrogs> In-Reply-To: <171270969477.3631889.12488500941186994317.stgit@frogsfrogsfrogs> References: <171270969477.3631889.12488500941186994317.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Allison Henderson This patch removes the old parent pointer attribute during the rename operation, and re-adds the updated parent pointer. Signed-off-by: Allison Henderson Reviewed-by: Darrick J. Wong [djwong: adjust to new ondisk format] Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig --- fs/xfs/libxfs/xfs_parent.c | 30 +++++++++++++++ fs/xfs/libxfs/xfs_parent.h | 6 +++ fs/xfs/libxfs/xfs_trans_space.c | 25 ++++++++++++ fs/xfs/libxfs/xfs_trans_space.h | 6 ++- fs/xfs/scrub/orphanage.c | 3 + fs/xfs/scrub/parent_repair.c | 3 + fs/xfs/xfs_inode.c | 80 ++++++++++++++++++++++++++++++++++++--- 7 files changed, 142 insertions(+), 11 deletions(-) diff --git a/fs/xfs/libxfs/xfs_parent.c b/fs/xfs/libxfs/xfs_parent.c index 0ddaab08d722d..86c808157294e 100644 --- a/fs/xfs/libxfs/xfs_parent.c +++ b/fs/xfs/libxfs/xfs_parent.c @@ -229,3 +229,33 @@ xfs_parent_removename( xfs_attr_defer_parent(&ppargs->args, XFS_ATTR_DEFER_REMOVE); return 0; } + +/* Replace one parent pointer with another to reflect a rename. */ +int +xfs_parent_replacename( + struct xfs_trans *tp, + struct xfs_parent_args *ppargs, + struct xfs_inode *old_dp, + const struct xfs_name *old_name, + struct xfs_inode *new_dp, + const struct xfs_name *new_name, + struct xfs_inode *child) +{ + int error; + + error = xfs_parent_iread_extents(tp, child); + if (error) + return error; + + xfs_inode_to_parent_rec(&ppargs->rec, old_dp); + xfs_parent_da_args_init(&ppargs->args, tp, &ppargs->rec, child, + child->i_ino, old_name); + + xfs_inode_to_parent_rec(&ppargs->new_rec, new_dp); + ppargs->args.new_name = new_name->name; + ppargs->args.new_namelen = new_name->len; + ppargs->args.new_value = &ppargs->new_rec; + ppargs->args.new_valuelen = sizeof(struct xfs_parent_rec); + xfs_attr_defer_parent(&ppargs->args, XFS_ATTR_DEFER_REPLACE); + return 0; +} diff --git a/fs/xfs/libxfs/xfs_parent.h b/fs/xfs/libxfs/xfs_parent.h index 4a7fd48c226a4..768633b313671 100644 --- a/fs/xfs/libxfs/xfs_parent.h +++ b/fs/xfs/libxfs/xfs_parent.h @@ -45,6 +45,7 @@ extern struct kmem_cache *xfs_parent_args_cache; */ struct xfs_parent_args { struct xfs_parent_rec rec; + struct xfs_parent_rec new_rec; struct xfs_da_args args; }; @@ -84,5 +85,10 @@ int xfs_parent_addname(struct xfs_trans *tp, struct xfs_parent_args *ppargs, int xfs_parent_removename(struct xfs_trans *tp, struct xfs_parent_args *ppargs, struct xfs_inode *dp, const struct xfs_name *parent_name, struct xfs_inode *child); +int xfs_parent_replacename(struct xfs_trans *tp, + struct xfs_parent_args *ppargs, + struct xfs_inode *old_dp, const struct xfs_name *old_name, + struct xfs_inode *new_dp, const struct xfs_name *new_name, + struct xfs_inode *child); #endif /* __XFS_PARENT_H__ */ diff --git a/fs/xfs/libxfs/xfs_trans_space.c b/fs/xfs/libxfs/xfs_trans_space.c index df729e4f1a4c9..b9dc3752f702c 100644 --- a/fs/xfs/libxfs/xfs_trans_space.c +++ b/fs/xfs/libxfs/xfs_trans_space.c @@ -94,3 +94,28 @@ xfs_remove_space_res( return ret; } + +unsigned int +xfs_rename_space_res( + struct xfs_mount *mp, + unsigned int src_namelen, + bool target_exists, + unsigned int target_namelen, + bool has_whiteout) +{ + unsigned int ret; + + ret = XFS_DIRREMOVE_SPACE_RES(mp) + + XFS_DIRENTER_SPACE_RES(mp, target_namelen); + + if (xfs_has_parent(mp)) { + if (has_whiteout) + ret += xfs_parent_calc_space_res(mp, src_namelen); + ret += 2 * xfs_parent_calc_space_res(mp, target_namelen); + } + + if (target_exists) + ret += xfs_parent_calc_space_res(mp, target_namelen); + + return ret; +} diff --git a/fs/xfs/libxfs/xfs_trans_space.h b/fs/xfs/libxfs/xfs_trans_space.h index a4490813c56f1..1155ff2d37e29 100644 --- a/fs/xfs/libxfs/xfs_trans_space.h +++ b/fs/xfs/libxfs/xfs_trans_space.h @@ -91,8 +91,6 @@ XFS_DQUOT_CLUSTER_SIZE_FSB) #define XFS_QM_QINOCREATE_SPACE_RES(mp) \ XFS_IALLOC_SPACE_RES(mp) -#define XFS_RENAME_SPACE_RES(mp,nl) \ - (XFS_DIRREMOVE_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp,nl)) #define XFS_IFREE_SPACE_RES(mp) \ (xfs_has_finobt(mp) ? M_IGEO(mp)->inobt_maxlevels : 0) @@ -106,4 +104,8 @@ unsigned int xfs_symlink_space_res(struct xfs_mount *mp, unsigned int namelen, unsigned int fsblocks); unsigned int xfs_remove_space_res(struct xfs_mount *mp, unsigned int namelen); +unsigned int xfs_rename_space_res(struct xfs_mount *mp, + unsigned int src_namelen, bool target_exists, + unsigned int target_namelen, bool has_whiteout); + #endif /* __XFS_TRANS_SPACE_H__ */ diff --git a/fs/xfs/scrub/orphanage.c b/fs/xfs/scrub/orphanage.c index 5e2c3546f2e95..94bcc2799188f 100644 --- a/fs/xfs/scrub/orphanage.c +++ b/fs/xfs/scrub/orphanage.c @@ -328,7 +328,8 @@ xrep_adoption_trans_alloc( adopt->sc = sc; adopt->orphanage_blkres = xfs_link_space_res(mp, MAXNAMELEN); if (S_ISDIR(VFS_I(sc->ip)->i_mode)) - child_blkres = XFS_RENAME_SPACE_RES(mp, xfs_name_dotdot.len); + child_blkres = xfs_rename_space_res(mp, 0, false, + xfs_name_dotdot.len, false); adopt->child_blkres = child_blkres; /* diff --git a/fs/xfs/scrub/parent_repair.c b/fs/xfs/scrub/parent_repair.c index ebb5791bf839e..63590e1b35060 100644 --- a/fs/xfs/scrub/parent_repair.c +++ b/fs/xfs/scrub/parent_repair.c @@ -171,7 +171,8 @@ xrep_parent_reset_dotdot( * Reserve more space just in case we have to expand the dir. We're * allowed to exceed quota to repair inconsistent metadata. */ - spaceres = XFS_RENAME_SPACE_RES(sc->mp, xfs_name_dotdot.len); + spaceres = xfs_rename_space_res(sc->mp, 0, false, xfs_name_dotdot.len, + false); error = xfs_trans_reserve_more_inode(sc->tp, sc->ip, spaceres, 0, true); if (error) diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index 492d8d1055e9e..ea619f5140739 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -3147,6 +3147,9 @@ xfs_rename( struct xfs_trans *tp; struct xfs_inode *wip = NULL; /* whiteout inode */ struct xfs_inode *inodes[__XFS_SORT_INODES]; + struct xfs_parent_args *src_ppargs = NULL; + struct xfs_parent_args *tgt_ppargs = NULL; + struct xfs_parent_args *wip_ppargs = NULL; int i; int num_inodes = __XFS_SORT_INODES; bool new_parent = (src_dp != target_dp); @@ -3178,9 +3181,26 @@ xfs_rename( xfs_sort_for_rename(src_dp, target_dp, src_ip, target_ip, wip, inodes, &num_inodes); + error = xfs_parent_start(mp, &src_ppargs); + if (error) + goto out_release_wip; + + if (wip) { + error = xfs_parent_start(mp, &wip_ppargs); + if (error) + goto out_src_ppargs; + } + + if (target_ip) { + error = xfs_parent_start(mp, &tgt_ppargs); + if (error) + goto out_wip_ppargs; + } + retry: nospace_error = 0; - spaceres = XFS_RENAME_SPACE_RES(mp, target_name->len); + spaceres = xfs_rename_space_res(mp, src_name->len, target_ip != NULL, + target_name->len, wip != NULL); error = xfs_trans_alloc(mp, &M_RES(mp)->tr_rename, spaceres, 0, 0, &tp); if (error == -ENOSPC) { nospace_error = error; @@ -3189,7 +3209,17 @@ xfs_rename( &tp); } if (error) - goto out_release_wip; + goto out_tgt_ppargs; + + /* + * We don't allow reservationless renaming when parent pointers are + * enabled because we can't back out if the xattrs must grow. + */ + if (src_ppargs && nospace_error) { + error = nospace_error; + xfs_trans_cancel(tp); + goto out_tgt_ppargs; + } /* * Attach the dquots to the inodes @@ -3197,7 +3227,7 @@ xfs_rename( error = xfs_qm_vop_rename_dqattach(inodes); if (error) { xfs_trans_cancel(tp); - goto out_release_wip; + goto out_tgt_ppargs; } /* @@ -3266,6 +3296,15 @@ xfs_rename( goto out_trans_cancel; } + /* + * We don't allow quotaless renaming when parent pointers are enabled + * because we can't back out if the xattrs must grow. + */ + if (src_ppargs && nospace_error) { + error = nospace_error; + goto out_trans_cancel; + } + /* * Check for expected errors before we dirty the transaction * so we can return an error without a transaction abort. @@ -3458,6 +3497,28 @@ xfs_rename( if (error) goto out_trans_cancel; + /* Schedule parent pointer updates. */ + if (wip_ppargs) { + error = xfs_parent_addname(tp, wip_ppargs, src_dp, src_name, + wip); + if (error) + goto out_trans_cancel; + } + + if (src_ppargs) { + error = xfs_parent_replacename(tp, src_ppargs, src_dp, + src_name, target_dp, target_name, src_ip); + if (error) + goto out_trans_cancel; + } + + if (tgt_ppargs) { + error = xfs_parent_removename(tp, tgt_ppargs, target_dp, + target_name, target_ip); + if (error) + goto out_trans_cancel; + } + xfs_trans_ichgtime(tp, src_dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); xfs_trans_log_inode(tp, src_dp, XFS_ILOG_CORE); if (new_parent) @@ -3479,14 +3540,19 @@ xfs_rename( xfs_dir_update_hook(src_dp, wip, 1, src_name); error = xfs_finish_rename(tp); - xfs_iunlock_rename(inodes, num_inodes); - if (wip) - xfs_irele(wip); - return error; + nospace_error = 0; + goto out_unlock; out_trans_cancel: xfs_trans_cancel(tp); +out_unlock: xfs_iunlock_rename(inodes, num_inodes); +out_tgt_ppargs: + xfs_parent_finish(mp, tgt_ppargs); +out_wip_ppargs: + xfs_parent_finish(mp, wip_ppargs); +out_src_ppargs: + xfs_parent_finish(mp, src_ppargs); out_release_wip: if (wip) xfs_irele(wip); From patchwork Wed Apr 10 00:59:14 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13623402 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DF801621 for ; Wed, 10 Apr 2024 00:59:15 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712710756; cv=none; b=NfvkmmLt7hwBVJCNo+aFB2rZHyTnw8WBUEcC4cbFbqD+mzfzTmOspkCfYOOWogou8WB4lNevCHlEaXBLboKFQY5jrzFKFl5HeeeDhvxJe97DS9PGVteQfB1mzpik3bLHfFdU2RCpgirP8XT7wngIcK46RyY9xqK3PAi/VDCyYBM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712710756; c=relaxed/simple; bh=uP9kK6nFxA96HcRh/zy6QMTVhXnROs8f97p5JfgWKpI=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=VTKth5IqrwGZPkQEts8l/dhC6GITEDmz3xTchm0h9M8+uJrVVc+Ogk7cON5PssWscah7WjlWNbBQ91Nf8Mm1T8cmA0qJFotvvFoxM57fkTwMVuRFxEQY2NzetKUpZdTz8z4qJNWLB3kTtJ/pfeiM6lxRk/SH1cZFPCj7z+kMLUg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=eqQNmOWV; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="eqQNmOWV" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 709DFC433C7; Wed, 10 Apr 2024 00:59:15 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1712710755; bh=uP9kK6nFxA96HcRh/zy6QMTVhXnROs8f97p5JfgWKpI=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=eqQNmOWV2DKy9DdtTS981d5LM2H5TqBhTwrzn9FLOJl4Bb3zB0qpaQ+NUlIiS2WMv ukIEXRTEZ+GR2KCYC30eD5QSHq1J/Gnt44GpNPb4jA4hOKe5lfsMt9g2kzLX3S9AIf 8h6K2Rej1HelV4FWi3SWJEEgaS3un73ch5ZPLumFnbC672hzqWc4oXU35/wIvbCC17 xcJtMllyW49RB8fGum1iP9z3CSvskp8DgTJv+kXHIZ/rZZRpHpGl+2e9rhjTumIm8n SKpc8VCuxmqyGBWAS9Qf3wzQ6rMNIlogakp3AgapTIysCYEnEGimayidaFnJmY8816 9tuf1BcrrO5bw== Date: Tue, 09 Apr 2024 17:59:14 -0700 Subject: [PATCH 22/32] xfs: Add parent pointers to xfs_cross_rename From: "Darrick J. Wong" To: djwong@kernel.org Cc: Allison Henderson , catherine.hoang@oracle.com, hch@lst.de, allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <171270969925.3631889.2928122008436370702.stgit@frogsfrogsfrogs> In-Reply-To: <171270969477.3631889.12488500941186994317.stgit@frogsfrogsfrogs> References: <171270969477.3631889.12488500941186994317.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Allison Henderson Cross renames are handled separately from standard renames, and need different handling to update the parent attributes correctly. Signed-off-by: Allison Henderson Reviewed-by: Darrick J. Wong Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig --- fs/xfs/xfs_inode.c | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index ea619f5140739..766cbb8b7be51 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -2971,15 +2971,17 @@ xfs_cross_rename( struct xfs_inode *dp1, struct xfs_name *name1, struct xfs_inode *ip1, + struct xfs_parent_args *ip1_ppargs, struct xfs_inode *dp2, struct xfs_name *name2, struct xfs_inode *ip2, + struct xfs_parent_args *ip2_ppargs, int spaceres) { - int error = 0; - int ip1_flags = 0; - int ip2_flags = 0; - int dp2_flags = 0; + int error = 0; + int ip1_flags = 0; + int ip2_flags = 0; + int dp2_flags = 0; /* Swap inode number for dirent in first parent */ error = xfs_dir_replace(tp, dp1, name1, ip2->i_ino, spaceres); @@ -3048,6 +3050,21 @@ xfs_cross_rename( } } + /* Schedule parent pointer replacements */ + if (ip1_ppargs) { + error = xfs_parent_replacename(tp, ip1_ppargs, dp1, name1, dp2, + name2, ip1); + if (error) + goto out_trans_abort; + } + + if (ip2_ppargs) { + error = xfs_parent_replacename(tp, ip2_ppargs, dp2, name2, dp1, + name1, ip2); + if (error) + goto out_trans_abort; + } + if (ip1_flags) { xfs_trans_ichgtime(tp, ip1, ip1_flags); xfs_trans_log_inode(tp, ip1, XFS_ILOG_CORE); @@ -3264,10 +3281,10 @@ xfs_rename( /* RENAME_EXCHANGE is unique from here on. */ if (flags & RENAME_EXCHANGE) { error = xfs_cross_rename(tp, src_dp, src_name, src_ip, - target_dp, target_name, target_ip, - spaceres); - xfs_iunlock_rename(inodes, num_inodes); - return error; + src_ppargs, target_dp, target_name, target_ip, + tgt_ppargs, spaceres); + nospace_error = 0; + goto out_unlock; } /* From patchwork Wed Apr 10 00:59:30 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13623403 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9FDB310E5 for ; Wed, 10 Apr 2024 00:59:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712710771; cv=none; b=RUGshXlYs5mCvSoqV3cOhKljXJr9d0/VQpg77RxTmV5LMChHj21rjYyxgPyS387VyL88kmhsg8inFDUA4Zk5wOiA3/emRpEDfnwJDVg76xkCi9ShCRwp7Cz/afkHjfvqF/SkIBgaHzG/ntp/pjnOD7QuISvadtww96KHo1SMskE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712710771; c=relaxed/simple; bh=MlDxcx6B+kdPtyHNHKCenukc1g0DrPF78rAVldA1PNg=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=TeLitKOf6Hc7Io0f6OmJldvO4adSWrNf5RFLNW+wVZcMmPzZYAQ15GqrJ0myAksXY+aoGv3taQlpXZT3EDPibO+buRslXCfpb+tXw+JDiu1snjs1+QgTvyLnttxGidW9Qfmf08enNFeOYUvzl95QFBS+VeULj+5eaxcoVHuJtdc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=i4wibwz7; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="i4wibwz7" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 1F15CC433A6; Wed, 10 Apr 2024 00:59:31 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1712710771; bh=MlDxcx6B+kdPtyHNHKCenukc1g0DrPF78rAVldA1PNg=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=i4wibwz7GkOxzvcsY+vV7jMtrSDILAmNQxJX+t/LXSiegR7xN3TPW65vJuyrxMxEw +xFrRaIRS1IEqiUqhKbdXFsmCfzFK+9VoedHg8uS6J8EoSPlY+Y7uuCdP6ZfEveKyG oQOlnE8Z2CVsuQmCbzeFC4qFbBOjEw/OzSZc6xfFbkH96+9O0eTbhWy5rPZ6kwxa2s d8OWdzsMVIFdRBckIm56VDW7nHiG4uLSBtQUx/B8Ld0LwLyfMd0TvqEY3A3OgUKzCe NJzgvNT7h3r+DOmdyzXPUE3cXKStDtrI9fgkFA3xeSWiWXpIXVzxowhMQwAiu/e7Rg kbMe+cdRDpc2Q== Date: Tue, 09 Apr 2024 17:59:30 -0700 Subject: [PATCH 23/32] xfs: Filter XFS_ATTR_PARENT for getfattr From: "Darrick J. Wong" To: djwong@kernel.org Cc: Allison Henderson , catherine.hoang@oracle.com, hch@lst.de, allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <171270969941.3631889.11060276222007768999.stgit@frogsfrogsfrogs> In-Reply-To: <171270969477.3631889.12488500941186994317.stgit@frogsfrogsfrogs> References: <171270969477.3631889.12488500941186994317.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Allison Henderson Parent pointers returned to the get_fattr tool cause errors since the tool cannot parse parent pointers. Fix this by filtering parent parent pointers from xfs_xattr_put_listent. Signed-off-by: Allison Henderson Inspired-by: Andrey Albershteyn Reviewed-by: Darrick J. Wong [djwong: change this to XFS_ATTR_PRIVATE_NSP_MASK per fsverity patchset] Signed-off-by: Darrick J. Wong --- fs/xfs/libxfs/xfs_da_format.h | 3 +++ fs/xfs/xfs_xattr.c | 10 ++++++++++ 2 files changed, 13 insertions(+) diff --git a/fs/xfs/libxfs/xfs_da_format.h b/fs/xfs/libxfs/xfs_da_format.h index 1395ad1937c53..ebde6eb1da65d 100644 --- a/fs/xfs/libxfs/xfs_da_format.h +++ b/fs/xfs/libxfs/xfs_da_format.h @@ -726,6 +726,9 @@ struct xfs_attr3_leafblock { XFS_ATTR_SECURE | \ XFS_ATTR_PARENT) +/* Private attr namespaces not exposed to userspace */ +#define XFS_ATTR_PRIVATE_NSP_MASK (XFS_ATTR_PARENT) + #define XFS_ATTR_ONDISK_MASK (XFS_ATTR_NSP_ONDISK_MASK | \ XFS_ATTR_LOCAL | \ XFS_ATTR_INCOMPLETE) diff --git a/fs/xfs/xfs_xattr.c b/fs/xfs/xfs_xattr.c index 85e886ee20e03..00b591f6c5ca1 100644 --- a/fs/xfs/xfs_xattr.c +++ b/fs/xfs/xfs_xattr.c @@ -20,6 +20,12 @@ #include +/* + * This file defines functions to work with externally visible extended + * attributes, such as those in user, system, or security namespaces. They + * should not be used for internally used attributes. Consider xfs_attr.c. + */ + /* * Get permission to use log-assisted atomic exchange of file extents. * Callers must not be running any transactions or hold any ILOCKs. @@ -215,6 +221,10 @@ xfs_xattr_put_listent( ASSERT(context->count >= 0); + /* Don't expose private xattr namespaces. */ + if (flags & XFS_ATTR_PRIVATE_NSP_MASK) + return; + if (flags & XFS_ATTR_ROOT) { #ifdef CONFIG_XFS_POSIX_ACL if (namelen == SGI_ACL_FILE_SIZE && From patchwork Wed Apr 10 00:59:46 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13623404 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3E06C391 for ; Wed, 10 Apr 2024 00:59:46 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712710787; cv=none; b=gQqVjnf1g58l6jk8U4B/iQfYUcMwAwCRrx/NsoqSASvPev0jxfCoHtkdw9HvLO1lsosoSh6Uec97+wxIKIquNjVrwDxcMvTDRJzK87MWmrbLkLG4RJIatVjpXUNWW7i2WDOobhV+n6KAHxjjSpVZeeobVYOP7YX1BkGT6pmJWlA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712710787; c=relaxed/simple; bh=bowjWDD/QOEvUSxk0hlxVuspKIpC3UPkUWr1Ta3j5io=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=D+bPoBWPniRa5pgzLZSAt2BuBuMO9lzwXt6O9Tv4CfylJitkcYbrPqPnitPOzO0y5Mb2c05YLay/l1fcKOJ32+s/nMHOkOCDuMaKzLKDSEZfMPfKR1Uvh9VovWFlqJHWgZqNNm2Q4zx6fskLY3puX/H0O2NKZJYbTFWQ3y+CLls= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=p9oS1Bkv; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="p9oS1Bkv" Received: by smtp.kernel.org (Postfix) with ESMTPSA id B64BDC433F1; Wed, 10 Apr 2024 00:59:46 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1712710786; bh=bowjWDD/QOEvUSxk0hlxVuspKIpC3UPkUWr1Ta3j5io=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=p9oS1Bkv4MMH+lMfNihBSVw0vB4IBQCXFH8uO3kdJdzr0dvFjx3Of/hsZqMVl7i2T +hJcY/Lc1MrqGjaPN8JgDMxgD5w2pXkOKbyzaMSKyfIBe11AUDEVWVwfxg7J2vKuTc UWYY+HGs64VKSYeTp0QWguRJpHXJ2yqHZzB85qs8prhaBr/qgj66M4Go155yKbnQh6 1g5aSN5Ua4TbmYro0FBBmK23YxUgK3XZSVJoyOevJ0cHt/PmN/Z9/FNzNq+3LS2tQA BSYQErYe9MwysZy6hYfa1wpBZnTcSuXx9ELeOmDPftsGZqz74rFz+ZzhCa+x/Iebaq dz8FmzHS9nA5Q== Date: Tue, 09 Apr 2024 17:59:46 -0700 Subject: [PATCH 24/32] xfs: pass the attr value to put_listent when possible From: "Darrick J. Wong" To: djwong@kernel.org Cc: Allison Henderson , catherine.hoang@oracle.com, hch@lst.de, allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <171270969957.3631889.6582034396609138645.stgit@frogsfrogsfrogs> In-Reply-To: <171270969477.3631889.12488500941186994317.stgit@frogsfrogsfrogs> References: <171270969477.3631889.12488500941186994317.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Allison Henderson Pass the attr value to put_listent when we have local xattrs or shortform xattrs. Signed-off-by: Allison Henderson Reviewed-by: Darrick J. Wong Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig --- fs/xfs/libxfs/xfs_attr.h | 5 +++-- fs/xfs/libxfs/xfs_attr_sf.h | 1 + fs/xfs/xfs_attr_list.c | 8 +++++++- fs/xfs/xfs_ioctl.c | 1 + fs/xfs/xfs_xattr.c | 1 + 5 files changed, 13 insertions(+), 3 deletions(-) diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h index d63305fc54155..cb5ca37000848 100644 --- a/fs/xfs/libxfs/xfs_attr.h +++ b/fs/xfs/libxfs/xfs_attr.h @@ -47,8 +47,9 @@ struct xfs_attrlist_cursor_kern { /* void; state communicated via *context */ -typedef void (*put_listent_func_t)(struct xfs_attr_list_context *, int, - unsigned char *, int, int); +typedef void (*put_listent_func_t)(struct xfs_attr_list_context *context, + int flags, unsigned char *name, int namelen, void *value, + int valuelen); struct xfs_attr_list_context { struct xfs_trans *tp; diff --git a/fs/xfs/libxfs/xfs_attr_sf.h b/fs/xfs/libxfs/xfs_attr_sf.h index bc44222230248..73bdc0e556825 100644 --- a/fs/xfs/libxfs/xfs_attr_sf.h +++ b/fs/xfs/libxfs/xfs_attr_sf.h @@ -16,6 +16,7 @@ typedef struct xfs_attr_sf_sort { uint8_t flags; /* flags bits (see xfs_attr_leaf.h) */ xfs_dahash_t hash; /* this entry's hash value */ unsigned char *name; /* name value, pointer into buffer */ + void *value; } xfs_attr_sf_sort_t; #define XFS_ATTR_SF_ENTSIZE_MAX /* max space for name&value */ \ diff --git a/fs/xfs/xfs_attr_list.c b/fs/xfs/xfs_attr_list.c index 9bc4b5322539a..5c947e5ce8b88 100644 --- a/fs/xfs/xfs_attr_list.c +++ b/fs/xfs/xfs_attr_list.c @@ -92,6 +92,7 @@ xfs_attr_shortform_list( sfe->flags, sfe->nameval, (int)sfe->namelen, + &sfe->nameval[sfe->namelen], (int)sfe->valuelen); /* * Either search callback finished early or @@ -138,6 +139,7 @@ xfs_attr_shortform_list( sbp->name = sfe->nameval; sbp->namelen = sfe->namelen; /* These are bytes, and both on-disk, don't endian-flip */ + sbp->value = &sfe->nameval[sfe->namelen], sbp->valuelen = sfe->valuelen; sbp->flags = sfe->flags; sbp->hash = xfs_attr_hashval(dp->i_mount, sfe->flags, @@ -192,6 +194,7 @@ xfs_attr_shortform_list( sbp->flags, sbp->name, sbp->namelen, + sbp->value, sbp->valuelen); if (context->seen_enough) break; @@ -479,6 +482,7 @@ xfs_attr3_leaf_list_int( */ for (; i < ichdr.count; entry++, i++) { char *name; + void *value; int namelen, valuelen; if (be32_to_cpu(entry->hashval) != cursor->hashval) { @@ -496,6 +500,7 @@ xfs_attr3_leaf_list_int( name_loc = xfs_attr3_leaf_name_local(leaf, i); name = name_loc->nameval; namelen = name_loc->namelen; + value = &name_loc->nameval[name_loc->namelen]; valuelen = be16_to_cpu(name_loc->valuelen); } else { xfs_attr_leaf_name_remote_t *name_rmt; @@ -503,6 +508,7 @@ xfs_attr3_leaf_list_int( name_rmt = xfs_attr3_leaf_name_remote(leaf, i); name = name_rmt->name; namelen = name_rmt->namelen; + value = NULL; valuelen = be32_to_cpu(name_rmt->valuelen); } @@ -513,7 +519,7 @@ xfs_attr3_leaf_list_int( return -EFSCORRUPTED; } context->put_listent(context, entry->flags, - name, namelen, valuelen); + name, namelen, value, valuelen); if (context->seen_enough) break; cursor->offset++; diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c index 39bdd1034ffab..d56e5c6876eee 100644 --- a/fs/xfs/xfs_ioctl.c +++ b/fs/xfs/xfs_ioctl.c @@ -310,6 +310,7 @@ xfs_ioc_attr_put_listent( int flags, unsigned char *name, int namelen, + void *value, int valuelen) { struct xfs_attrlist *alist = context->buffer; diff --git a/fs/xfs/xfs_xattr.c b/fs/xfs/xfs_xattr.c index 00b591f6c5ca1..1d57e204c850f 100644 --- a/fs/xfs/xfs_xattr.c +++ b/fs/xfs/xfs_xattr.c @@ -214,6 +214,7 @@ xfs_xattr_put_listent( int flags, unsigned char *name, int namelen, + void *value, int valuelen) { char *prefix; From patchwork Wed Apr 10 01:00:01 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13623405 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id EB09410E5 for ; Wed, 10 Apr 2024 01:00:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712710803; cv=none; b=UpnoB7wYSeNh4/YD3wrTId4gkuSYh/G3+Y6LbdXXukeUkpp2tpYxfWUZQRGEN8BStnxxqBpTUUcdWM4A+HVTU3cAOMtmrbUs4FcMld0TnVNbbySKkci7CnPsY1FwDmYzTiuzJ2TaZmQtoMponWzq7AhKfghzeZXFtOKLC4vUgXo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712710803; c=relaxed/simple; bh=MejuNcP3pgSV4/hLRJmQaLVm3hkOP9fUNOpKm8t7UTE=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=EWA5IzvTyRTjMPHNaRbdWDbCMv6bZA6nOr2N/PQuHrXmXeWoIMxzKDsB+FgbrHpBHJVF0Y3MWPGtlRmc6qlh8U3TI3Tt6wRwzQaV7UCJ+6SitOHuAqE11ieB0f+XAq0Zzvlr9Ie943Uc1ejDNz5df68NuELP6s3+HlXQ342fBOE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=gGm7L1mv; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="gGm7L1mv" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 681C0C43390; Wed, 10 Apr 2024 01:00:02 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1712710802; bh=MejuNcP3pgSV4/hLRJmQaLVm3hkOP9fUNOpKm8t7UTE=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=gGm7L1mvGHN1zSet5he1v6jAYl6oCgW697KswFtDngUOHT1jTOyEzezLngPdkobbx wvmMAY/NeSCDhcobnME+dgOgI2G9C0oxwM6mmFDGChjPLfMtR7YxqNDNuHNg0jbp3p vcBORPKgOBqmfle/P6tBUoVVZwwshCVJcRiskvowE8tNmbPEJfSLRH9LnBKqDCYEXE 62OHM5KjF2SJf5QaU0SmOk0irw0cIYNy+eSBElE9Yq4uVNJx87g3IWrGLr0s9ohb28 Ug+lVT9Gmg+ZezcT9D4/QD+xOdXbOkeirq06d/Dx4gB/Lg0tbuq4KLLjTSYU4EeUWD vXNkXpurct2Lg== Date: Tue, 09 Apr 2024 18:00:01 -0700 Subject: [PATCH 25/32] xfs: move handle ioctl code to xfs_handle.c From: "Darrick J. Wong" To: djwong@kernel.org Cc: catherine.hoang@oracle.com, hch@lst.de, allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <171270969974.3631889.581031520799249475.stgit@frogsfrogsfrogs> In-Reply-To: <171270969477.3631889.12488500941186994317.stgit@frogsfrogsfrogs> References: <171270969477.3631889.12488500941186994317.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Move the handle managemnet code (and the attrmulti code that uses it) to xfs_handle.c. Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig --- fs/xfs/Makefile | 1 fs/xfs/xfs_handle.c | 617 ++++++++++++++++++++++++++++++++++++++++++++++++++ fs/xfs/xfs_handle.h | 28 ++ fs/xfs/xfs_ioctl.c | 591 ------------------------------------------------ fs/xfs/xfs_ioctl.h | 28 -- fs/xfs/xfs_ioctl32.c | 1 6 files changed, 648 insertions(+), 618 deletions(-) create mode 100644 fs/xfs/xfs_handle.c create mode 100644 fs/xfs/xfs_handle.h diff --git a/fs/xfs/Makefile b/fs/xfs/Makefile index 0c1a0b67af93c..c969b11ce0f47 100644 --- a/fs/xfs/Makefile +++ b/fs/xfs/Makefile @@ -78,6 +78,7 @@ xfs-y += xfs_aops.o \ xfs_fsmap.o \ xfs_fsops.o \ xfs_globals.o \ + xfs_handle.o \ xfs_health.o \ xfs_icache.o \ xfs_ioctl.o \ diff --git a/fs/xfs/xfs_handle.c b/fs/xfs/xfs_handle.c new file mode 100644 index 0000000000000..a0015dc8cff1a --- /dev/null +++ b/fs/xfs/xfs_handle.c @@ -0,0 +1,617 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2000-2005 Silicon Graphics, Inc. + * All rights reserved. + */ +#include "xfs.h" +#include "xfs_fs.h" +#include "xfs_format.h" +#include "xfs_log_format.h" +#include "xfs_shared.h" +#include "xfs_trans_resv.h" +#include "xfs_mount.h" +#include "xfs_bmap_btree.h" +#include "xfs_inode.h" +#include "xfs_error.h" +#include "xfs_trace.h" +#include "xfs_trans.h" +#include "xfs_da_format.h" +#include "xfs_da_btree.h" +#include "xfs_attr.h" +#include "xfs_ioctl.h" +#include "xfs_parent.h" +#include "xfs_da_btree.h" +#include "xfs_handle.h" +#include "xfs_health.h" +#include "xfs_icache.h" +#include "xfs_export.h" +#include "xfs_xattr.h" +#include "xfs_acl.h" + +#include + +/* + * xfs_find_handle maps from userspace xfs_fsop_handlereq structure to + * a file or fs handle. + * + * XFS_IOC_PATH_TO_FSHANDLE + * returns fs handle for a mount point or path within that mount point + * XFS_IOC_FD_TO_HANDLE + * returns full handle for a FD opened in user space + * XFS_IOC_PATH_TO_HANDLE + * returns full handle for a path + */ +int +xfs_find_handle( + unsigned int cmd, + xfs_fsop_handlereq_t *hreq) +{ + int hsize; + xfs_handle_t handle; + struct inode *inode; + struct fd f = {NULL}; + struct path path; + int error; + struct xfs_inode *ip; + + if (cmd == XFS_IOC_FD_TO_HANDLE) { + f = fdget(hreq->fd); + if (!f.file) + return -EBADF; + inode = file_inode(f.file); + } else { + error = user_path_at(AT_FDCWD, hreq->path, 0, &path); + if (error) + return error; + inode = d_inode(path.dentry); + } + ip = XFS_I(inode); + + /* + * We can only generate handles for inodes residing on a XFS filesystem, + * and only for regular files, directories or symbolic links. + */ + error = -EINVAL; + if (inode->i_sb->s_magic != XFS_SB_MAGIC) + goto out_put; + + error = -EBADF; + if (!S_ISREG(inode->i_mode) && + !S_ISDIR(inode->i_mode) && + !S_ISLNK(inode->i_mode)) + goto out_put; + + + memcpy(&handle.ha_fsid, ip->i_mount->m_fixedfsid, sizeof(xfs_fsid_t)); + + if (cmd == XFS_IOC_PATH_TO_FSHANDLE) { + /* + * This handle only contains an fsid, zero the rest. + */ + memset(&handle.ha_fid, 0, sizeof(handle.ha_fid)); + hsize = sizeof(xfs_fsid_t); + } else { + 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_gen = inode->i_generation; + handle.ha_fid.fid_ino = ip->i_ino; + hsize = sizeof(xfs_handle_t); + } + + error = -EFAULT; + if (copy_to_user(hreq->ohandle, &handle, hsize) || + copy_to_user(hreq->ohandlen, &hsize, sizeof(__s32))) + goto out_put; + + error = 0; + + out_put: + if (cmd == XFS_IOC_FD_TO_HANDLE) + fdput(f); + else + path_put(&path); + return error; +} + +/* + * No need to do permission checks on the various pathname components + * as the handle operations are privileged. + */ +STATIC int +xfs_handle_acceptable( + void *context, + struct dentry *dentry) +{ + return 1; +} + +/* + * Convert userspace handle data into a dentry. + */ +struct dentry * +xfs_handle_to_dentry( + struct file *parfilp, + void __user *uhandle, + u32 hlen) +{ + xfs_handle_t handle; + struct xfs_fid64 fid; + + /* + * Only allow handle opens under a directory. + */ + if (!S_ISDIR(file_inode(parfilp)->i_mode)) + return ERR_PTR(-ENOTDIR); + + if (hlen != sizeof(xfs_handle_t)) + return ERR_PTR(-EINVAL); + if (copy_from_user(&handle, uhandle, hlen)) + return ERR_PTR(-EFAULT); + if (handle.ha_fid.fid_len != + sizeof(handle.ha_fid) - sizeof(handle.ha_fid.fid_len)) + return ERR_PTR(-EINVAL); + + memset(&fid, 0, sizeof(struct fid)); + fid.ino = handle.ha_fid.fid_ino; + fid.gen = handle.ha_fid.fid_gen; + + return exportfs_decode_fh(parfilp->f_path.mnt, (struct fid *)&fid, 3, + FILEID_INO32_GEN | XFS_FILEID_TYPE_64FLAG, + xfs_handle_acceptable, NULL); +} + +STATIC struct dentry * +xfs_handlereq_to_dentry( + struct file *parfilp, + xfs_fsop_handlereq_t *hreq) +{ + return xfs_handle_to_dentry(parfilp, hreq->ihandle, hreq->ihandlen); +} + +int +xfs_open_by_handle( + struct file *parfilp, + xfs_fsop_handlereq_t *hreq) +{ + const struct cred *cred = current_cred(); + int error; + int fd; + int permflag; + struct file *filp; + struct inode *inode; + struct dentry *dentry; + fmode_t fmode; + struct path path; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + dentry = xfs_handlereq_to_dentry(parfilp, hreq); + if (IS_ERR(dentry)) + return PTR_ERR(dentry); + inode = d_inode(dentry); + + /* Restrict xfs_open_by_handle to directories & regular files. */ + if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode))) { + error = -EPERM; + goto out_dput; + } + +#if BITS_PER_LONG != 32 + hreq->oflags |= O_LARGEFILE; +#endif + + permflag = hreq->oflags; + fmode = OPEN_FMODE(permflag); + if ((!(permflag & O_APPEND) || (permflag & O_TRUNC)) && + (fmode & FMODE_WRITE) && IS_APPEND(inode)) { + error = -EPERM; + goto out_dput; + } + + if ((fmode & FMODE_WRITE) && IS_IMMUTABLE(inode)) { + error = -EPERM; + goto out_dput; + } + + /* Can't write directories. */ + if (S_ISDIR(inode->i_mode) && (fmode & FMODE_WRITE)) { + error = -EISDIR; + goto out_dput; + } + + fd = get_unused_fd_flags(0); + if (fd < 0) { + error = fd; + goto out_dput; + } + + path.mnt = parfilp->f_path.mnt; + path.dentry = dentry; + filp = dentry_open(&path, hreq->oflags, cred); + dput(dentry); + if (IS_ERR(filp)) { + put_unused_fd(fd); + return PTR_ERR(filp); + } + + if (S_ISREG(inode->i_mode)) { + filp->f_flags |= O_NOATIME; + filp->f_mode |= FMODE_NOCMTIME; + } + + fd_install(fd, filp); + return fd; + + out_dput: + dput(dentry); + return error; +} + +int +xfs_readlink_by_handle( + struct file *parfilp, + xfs_fsop_handlereq_t *hreq) +{ + struct dentry *dentry; + __u32 olen; + int error; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + dentry = xfs_handlereq_to_dentry(parfilp, hreq); + if (IS_ERR(dentry)) + return PTR_ERR(dentry); + + /* Restrict this handle operation to symlinks only. */ + if (!d_is_symlink(dentry)) { + error = -EINVAL; + goto out_dput; + } + + if (copy_from_user(&olen, hreq->ohandlen, sizeof(__u32))) { + error = -EFAULT; + goto out_dput; + } + + error = vfs_readlink(dentry, hreq->ohandle, olen); + + out_dput: + dput(dentry); + return error; +} + +/* + * Format an attribute and copy it out to the user's buffer. + * Take care to check values and protect against them changing later, + * we may be reading them directly out of a user buffer. + */ +static void +xfs_ioc_attr_put_listent( + struct xfs_attr_list_context *context, + int flags, + unsigned char *name, + int namelen, + void *value, + int valuelen) +{ + struct xfs_attrlist *alist = context->buffer; + struct xfs_attrlist_ent *aep; + int arraytop; + + ASSERT(!context->seen_enough); + ASSERT(context->count >= 0); + ASSERT(context->count < (ATTR_MAX_VALUELEN/8)); + ASSERT(context->firstu >= sizeof(*alist)); + ASSERT(context->firstu <= context->bufsize); + + /* + * Only list entries in the right namespace. + */ + if (context->attr_filter != (flags & XFS_ATTR_NSP_ONDISK_MASK)) + return; + + arraytop = sizeof(*alist) + + context->count * sizeof(alist->al_offset[0]); + + /* decrement by the actual bytes used by the attr */ + context->firstu -= round_up(offsetof(struct xfs_attrlist_ent, a_name) + + namelen + 1, sizeof(uint32_t)); + if (context->firstu < arraytop) { + trace_xfs_attr_list_full(context); + alist->al_more = 1; + context->seen_enough = 1; + return; + } + + aep = context->buffer + context->firstu; + aep->a_valuelen = valuelen; + memcpy(aep->a_name, name, namelen); + aep->a_name[namelen] = 0; + alist->al_offset[context->count++] = context->firstu; + alist->al_count = context->count; + trace_xfs_attr_list_add(context); +} + +static unsigned int +xfs_attr_filter( + u32 ioc_flags) +{ + if (ioc_flags & XFS_IOC_ATTR_ROOT) + return XFS_ATTR_ROOT; + if (ioc_flags & XFS_IOC_ATTR_SECURE) + return XFS_ATTR_SECURE; + return 0; +} + +static unsigned int +xfs_xattr_flags( + u32 ioc_flags) +{ + if (ioc_flags & XFS_IOC_ATTR_CREATE) + return XATTR_CREATE; + if (ioc_flags & XFS_IOC_ATTR_REPLACE) + return XATTR_REPLACE; + return 0; +} + +int +xfs_ioc_attr_list( + struct xfs_inode *dp, + void __user *ubuf, + size_t bufsize, + int flags, + struct xfs_attrlist_cursor __user *ucursor) +{ + struct xfs_attr_list_context context = { }; + struct xfs_attrlist *alist; + void *buffer; + int error; + + if (bufsize < sizeof(struct xfs_attrlist) || + bufsize > XFS_XATTR_LIST_MAX) + return -EINVAL; + + /* + * Reject flags, only allow namespaces. + */ + if (flags & ~(XFS_IOC_ATTR_ROOT | XFS_IOC_ATTR_SECURE)) + return -EINVAL; + if (flags == (XFS_IOC_ATTR_ROOT | XFS_IOC_ATTR_SECURE)) + return -EINVAL; + + /* + * Validate the cursor. + */ + if (copy_from_user(&context.cursor, ucursor, sizeof(context.cursor))) + return -EFAULT; + if (context.cursor.pad1 || context.cursor.pad2) + return -EINVAL; + if (!context.cursor.initted && + (context.cursor.hashval || context.cursor.blkno || + context.cursor.offset)) + return -EINVAL; + + buffer = kvzalloc(bufsize, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + /* + * Initialize the output buffer. + */ + context.dp = dp; + context.resynch = 1; + context.attr_filter = xfs_attr_filter(flags); + context.buffer = buffer; + context.bufsize = round_down(bufsize, sizeof(uint32_t)); + context.firstu = context.bufsize; + context.put_listent = xfs_ioc_attr_put_listent; + + alist = context.buffer; + alist->al_count = 0; + alist->al_more = 0; + alist->al_offset[0] = context.bufsize; + + error = xfs_attr_list(&context); + if (error) + goto out_free; + + if (copy_to_user(ubuf, buffer, bufsize) || + copy_to_user(ucursor, &context.cursor, sizeof(context.cursor))) + error = -EFAULT; +out_free: + kvfree(buffer); + return error; +} + +int +xfs_attrlist_by_handle( + struct file *parfilp, + struct xfs_fsop_attrlist_handlereq __user *p) +{ + struct xfs_fsop_attrlist_handlereq al_hreq; + struct dentry *dentry; + int error = -ENOMEM; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (copy_from_user(&al_hreq, p, sizeof(al_hreq))) + return -EFAULT; + + dentry = xfs_handlereq_to_dentry(parfilp, &al_hreq.hreq); + if (IS_ERR(dentry)) + return PTR_ERR(dentry); + + error = xfs_ioc_attr_list(XFS_I(d_inode(dentry)), al_hreq.buffer, + al_hreq.buflen, al_hreq.flags, &p->pos); + dput(dentry); + return error; +} + +static int +xfs_attrmulti_attr_get( + struct inode *inode, + unsigned char *name, + unsigned char __user *ubuf, + uint32_t *len, + uint32_t flags) +{ + struct xfs_da_args args = { + .dp = XFS_I(inode), + .attr_filter = xfs_attr_filter(flags), + .xattr_flags = xfs_xattr_flags(flags), + .name = name, + .namelen = strlen(name), + .valuelen = *len, + }; + int error; + + if (*len > XFS_XATTR_SIZE_MAX) + return -EINVAL; + + error = xfs_attr_get(&args); + if (error) + goto out_kfree; + + *len = args.valuelen; + if (copy_to_user(ubuf, args.value, args.valuelen)) + error = -EFAULT; + +out_kfree: + kvfree(args.value); + return error; +} + +static int +xfs_attrmulti_attr_set( + struct inode *inode, + unsigned char *name, + const unsigned char __user *ubuf, + uint32_t len, + uint32_t flags) +{ + struct xfs_da_args args = { + .dp = XFS_I(inode), + .attr_filter = xfs_attr_filter(flags), + .xattr_flags = xfs_xattr_flags(flags), + .name = name, + .namelen = strlen(name), + }; + int error; + + if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) + return -EPERM; + + if (ubuf) { + if (len > XFS_XATTR_SIZE_MAX) + return -EINVAL; + args.value = memdup_user(ubuf, len); + if (IS_ERR(args.value)) + return PTR_ERR(args.value); + args.valuelen = len; + } + + error = xfs_attr_change(&args); + if (!error && (flags & XFS_IOC_ATTR_ROOT)) + xfs_forget_acl(inode, name); + kfree(args.value); + return error; +} + +int +xfs_ioc_attrmulti_one( + struct file *parfilp, + struct inode *inode, + uint32_t opcode, + void __user *uname, + void __user *value, + uint32_t *len, + uint32_t flags) +{ + unsigned char *name; + int error; + + if ((flags & XFS_IOC_ATTR_ROOT) && (flags & XFS_IOC_ATTR_SECURE)) + return -EINVAL; + + name = strndup_user(uname, MAXNAMELEN); + if (IS_ERR(name)) + return PTR_ERR(name); + + switch (opcode) { + case ATTR_OP_GET: + error = xfs_attrmulti_attr_get(inode, name, value, len, flags); + break; + case ATTR_OP_REMOVE: + value = NULL; + *len = 0; + fallthrough; + case ATTR_OP_SET: + error = mnt_want_write_file(parfilp); + if (error) + break; + error = xfs_attrmulti_attr_set(inode, name, value, *len, flags); + mnt_drop_write_file(parfilp); + break; + default: + error = -EINVAL; + break; + } + + kfree(name); + return error; +} + +int +xfs_attrmulti_by_handle( + struct file *parfilp, + void __user *arg) +{ + int error; + xfs_attr_multiop_t *ops; + xfs_fsop_attrmulti_handlereq_t am_hreq; + struct dentry *dentry; + unsigned int i, size; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (copy_from_user(&am_hreq, arg, sizeof(xfs_fsop_attrmulti_handlereq_t))) + return -EFAULT; + + /* overflow check */ + if (am_hreq.opcount >= INT_MAX / sizeof(xfs_attr_multiop_t)) + return -E2BIG; + + dentry = xfs_handlereq_to_dentry(parfilp, &am_hreq.hreq); + if (IS_ERR(dentry)) + return PTR_ERR(dentry); + + error = -E2BIG; + size = am_hreq.opcount * sizeof(xfs_attr_multiop_t); + if (!size || size > 16 * PAGE_SIZE) + goto out_dput; + + ops = memdup_user(am_hreq.ops, size); + if (IS_ERR(ops)) { + error = PTR_ERR(ops); + goto out_dput; + } + + error = 0; + for (i = 0; i < am_hreq.opcount; i++) { + ops[i].am_error = xfs_ioc_attrmulti_one(parfilp, + d_inode(dentry), ops[i].am_opcode, + ops[i].am_attrname, ops[i].am_attrvalue, + &ops[i].am_length, ops[i].am_flags); + } + + if (copy_to_user(am_hreq.ops, ops, size)) + error = -EFAULT; + + kfree(ops); + out_dput: + dput(dentry); + return error; +} diff --git a/fs/xfs/xfs_handle.h b/fs/xfs/xfs_handle.h new file mode 100644 index 0000000000000..e39eaf4689da9 --- /dev/null +++ b/fs/xfs/xfs_handle.h @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2000-2005 Silicon Graphics, Inc. + * All rights reserved. + */ +#ifndef __XFS_HANDLE_H__ +#define __XFS_HANDLE_H__ + +int xfs_attrlist_by_handle(struct file *parfilp, + struct xfs_fsop_attrlist_handlereq __user *p); +int xfs_attrmulti_by_handle(struct file *parfilp, void __user *arg); + +int xfs_find_handle(unsigned int cmd, struct xfs_fsop_handlereq *hreq); +int xfs_open_by_handle(struct file *parfilp, struct xfs_fsop_handlereq *hreq); +int xfs_readlink_by_handle(struct file *parfilp, + struct xfs_fsop_handlereq *hreq); + +int xfs_ioc_attrmulti_one(struct file *parfilp, struct inode *inode, + uint32_t opcode, void __user *uname, void __user *value, + uint32_t *len, uint32_t flags); +int xfs_ioc_attr_list(struct xfs_inode *dp, void __user *ubuf, + size_t bufsize, int flags, + struct xfs_attrlist_cursor __user *ucursor); + +struct dentry *xfs_handle_to_dentry(struct file *parfilp, void __user *uhandle, + u32 hlen); + +#endif /* __XFS_HANDLE_H__ */ diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c index d56e5c6876eee..7b347cdd28785 100644 --- a/fs/xfs/xfs_ioctl.c +++ b/fs/xfs/xfs_ioctl.c @@ -23,11 +23,9 @@ #include "xfs_fsops.h" #include "xfs_discard.h" #include "xfs_quota.h" -#include "xfs_export.h" #include "xfs_trace.h" #include "xfs_icache.h" #include "xfs_trans.h" -#include "xfs_acl.h" #include "xfs_btree.h" #include #include "xfs_fsmap.h" @@ -37,601 +35,14 @@ #include "xfs_health.h" #include "xfs_reflink.h" #include "xfs_ioctl.h" -#include "xfs_xattr.h" #include "xfs_rtbitmap.h" #include "xfs_file.h" #include "xfs_exchrange.h" +#include "xfs_handle.h" #include -#include #include -/* - * xfs_find_handle maps from userspace xfs_fsop_handlereq structure to - * a file or fs handle. - * - * XFS_IOC_PATH_TO_FSHANDLE - * returns fs handle for a mount point or path within that mount point - * XFS_IOC_FD_TO_HANDLE - * returns full handle for a FD opened in user space - * XFS_IOC_PATH_TO_HANDLE - * returns full handle for a path - */ -int -xfs_find_handle( - unsigned int cmd, - xfs_fsop_handlereq_t *hreq) -{ - int hsize; - xfs_handle_t handle; - struct inode *inode; - struct fd f = {NULL}; - struct path path; - int error; - struct xfs_inode *ip; - - if (cmd == XFS_IOC_FD_TO_HANDLE) { - f = fdget(hreq->fd); - if (!f.file) - return -EBADF; - inode = file_inode(f.file); - } else { - error = user_path_at(AT_FDCWD, hreq->path, 0, &path); - if (error) - return error; - inode = d_inode(path.dentry); - } - ip = XFS_I(inode); - - /* - * We can only generate handles for inodes residing on a XFS filesystem, - * and only for regular files, directories or symbolic links. - */ - error = -EINVAL; - if (inode->i_sb->s_magic != XFS_SB_MAGIC) - goto out_put; - - error = -EBADF; - if (!S_ISREG(inode->i_mode) && - !S_ISDIR(inode->i_mode) && - !S_ISLNK(inode->i_mode)) - goto out_put; - - - memcpy(&handle.ha_fsid, ip->i_mount->m_fixedfsid, sizeof(xfs_fsid_t)); - - if (cmd == XFS_IOC_PATH_TO_FSHANDLE) { - /* - * This handle only contains an fsid, zero the rest. - */ - memset(&handle.ha_fid, 0, sizeof(handle.ha_fid)); - hsize = sizeof(xfs_fsid_t); - } else { - 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_gen = inode->i_generation; - handle.ha_fid.fid_ino = ip->i_ino; - hsize = sizeof(xfs_handle_t); - } - - error = -EFAULT; - if (copy_to_user(hreq->ohandle, &handle, hsize) || - copy_to_user(hreq->ohandlen, &hsize, sizeof(__s32))) - goto out_put; - - error = 0; - - out_put: - if (cmd == XFS_IOC_FD_TO_HANDLE) - fdput(f); - else - path_put(&path); - return error; -} - -/* - * No need to do permission checks on the various pathname components - * as the handle operations are privileged. - */ -STATIC int -xfs_handle_acceptable( - void *context, - struct dentry *dentry) -{ - return 1; -} - -/* - * Convert userspace handle data into a dentry. - */ -struct dentry * -xfs_handle_to_dentry( - struct file *parfilp, - void __user *uhandle, - u32 hlen) -{ - xfs_handle_t handle; - struct xfs_fid64 fid; - - /* - * Only allow handle opens under a directory. - */ - if (!S_ISDIR(file_inode(parfilp)->i_mode)) - return ERR_PTR(-ENOTDIR); - - if (hlen != sizeof(xfs_handle_t)) - return ERR_PTR(-EINVAL); - if (copy_from_user(&handle, uhandle, hlen)) - return ERR_PTR(-EFAULT); - if (handle.ha_fid.fid_len != - sizeof(handle.ha_fid) - sizeof(handle.ha_fid.fid_len)) - return ERR_PTR(-EINVAL); - - memset(&fid, 0, sizeof(struct fid)); - fid.ino = handle.ha_fid.fid_ino; - fid.gen = handle.ha_fid.fid_gen; - - return exportfs_decode_fh(parfilp->f_path.mnt, (struct fid *)&fid, 3, - FILEID_INO32_GEN | XFS_FILEID_TYPE_64FLAG, - xfs_handle_acceptable, NULL); -} - -STATIC struct dentry * -xfs_handlereq_to_dentry( - struct file *parfilp, - xfs_fsop_handlereq_t *hreq) -{ - return xfs_handle_to_dentry(parfilp, hreq->ihandle, hreq->ihandlen); -} - -int -xfs_open_by_handle( - struct file *parfilp, - xfs_fsop_handlereq_t *hreq) -{ - const struct cred *cred = current_cred(); - int error; - int fd; - int permflag; - struct file *filp; - struct inode *inode; - struct dentry *dentry; - fmode_t fmode; - struct path path; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - dentry = xfs_handlereq_to_dentry(parfilp, hreq); - if (IS_ERR(dentry)) - return PTR_ERR(dentry); - inode = d_inode(dentry); - - /* Restrict xfs_open_by_handle to directories & regular files. */ - if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode))) { - error = -EPERM; - goto out_dput; - } - -#if BITS_PER_LONG != 32 - hreq->oflags |= O_LARGEFILE; -#endif - - permflag = hreq->oflags; - fmode = OPEN_FMODE(permflag); - if ((!(permflag & O_APPEND) || (permflag & O_TRUNC)) && - (fmode & FMODE_WRITE) && IS_APPEND(inode)) { - error = -EPERM; - goto out_dput; - } - - if ((fmode & FMODE_WRITE) && IS_IMMUTABLE(inode)) { - error = -EPERM; - goto out_dput; - } - - /* Can't write directories. */ - if (S_ISDIR(inode->i_mode) && (fmode & FMODE_WRITE)) { - error = -EISDIR; - goto out_dput; - } - - fd = get_unused_fd_flags(0); - if (fd < 0) { - error = fd; - goto out_dput; - } - - path.mnt = parfilp->f_path.mnt; - path.dentry = dentry; - filp = dentry_open(&path, hreq->oflags, cred); - dput(dentry); - if (IS_ERR(filp)) { - put_unused_fd(fd); - return PTR_ERR(filp); - } - - if (S_ISREG(inode->i_mode)) { - filp->f_flags |= O_NOATIME; - filp->f_mode |= FMODE_NOCMTIME; - } - - fd_install(fd, filp); - return fd; - - out_dput: - dput(dentry); - return error; -} - -int -xfs_readlink_by_handle( - struct file *parfilp, - xfs_fsop_handlereq_t *hreq) -{ - struct dentry *dentry; - __u32 olen; - int error; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - dentry = xfs_handlereq_to_dentry(parfilp, hreq); - if (IS_ERR(dentry)) - return PTR_ERR(dentry); - - /* Restrict this handle operation to symlinks only. */ - if (!d_is_symlink(dentry)) { - error = -EINVAL; - goto out_dput; - } - - if (copy_from_user(&olen, hreq->ohandlen, sizeof(__u32))) { - error = -EFAULT; - goto out_dput; - } - - error = vfs_readlink(dentry, hreq->ohandle, olen); - - out_dput: - dput(dentry); - return error; -} - -/* - * Format an attribute and copy it out to the user's buffer. - * Take care to check values and protect against them changing later, - * we may be reading them directly out of a user buffer. - */ -static void -xfs_ioc_attr_put_listent( - struct xfs_attr_list_context *context, - int flags, - unsigned char *name, - int namelen, - void *value, - int valuelen) -{ - struct xfs_attrlist *alist = context->buffer; - struct xfs_attrlist_ent *aep; - int arraytop; - - ASSERT(!context->seen_enough); - ASSERT(context->count >= 0); - ASSERT(context->count < (ATTR_MAX_VALUELEN/8)); - ASSERT(context->firstu >= sizeof(*alist)); - ASSERT(context->firstu <= context->bufsize); - - /* - * Only list entries in the right namespace. - */ - if (context->attr_filter != (flags & XFS_ATTR_NSP_ONDISK_MASK)) - return; - - arraytop = sizeof(*alist) + - context->count * sizeof(alist->al_offset[0]); - - /* decrement by the actual bytes used by the attr */ - context->firstu -= round_up(offsetof(struct xfs_attrlist_ent, a_name) + - namelen + 1, sizeof(uint32_t)); - if (context->firstu < arraytop) { - trace_xfs_attr_list_full(context); - alist->al_more = 1; - context->seen_enough = 1; - return; - } - - aep = context->buffer + context->firstu; - aep->a_valuelen = valuelen; - memcpy(aep->a_name, name, namelen); - aep->a_name[namelen] = 0; - alist->al_offset[context->count++] = context->firstu; - alist->al_count = context->count; - trace_xfs_attr_list_add(context); -} - -static unsigned int -xfs_attr_filter( - u32 ioc_flags) -{ - if (ioc_flags & XFS_IOC_ATTR_ROOT) - return XFS_ATTR_ROOT; - if (ioc_flags & XFS_IOC_ATTR_SECURE) - return XFS_ATTR_SECURE; - return 0; -} - -static unsigned int -xfs_xattr_flags( - u32 ioc_flags) -{ - if (ioc_flags & XFS_IOC_ATTR_CREATE) - return XATTR_CREATE; - if (ioc_flags & XFS_IOC_ATTR_REPLACE) - return XATTR_REPLACE; - return 0; -} - -int -xfs_ioc_attr_list( - struct xfs_inode *dp, - void __user *ubuf, - size_t bufsize, - int flags, - struct xfs_attrlist_cursor __user *ucursor) -{ - struct xfs_attr_list_context context = { }; - struct xfs_attrlist *alist; - void *buffer; - int error; - - if (bufsize < sizeof(struct xfs_attrlist) || - bufsize > XFS_XATTR_LIST_MAX) - return -EINVAL; - - /* - * Reject flags, only allow namespaces. - */ - if (flags & ~(XFS_IOC_ATTR_ROOT | XFS_IOC_ATTR_SECURE)) - return -EINVAL; - if (flags == (XFS_IOC_ATTR_ROOT | XFS_IOC_ATTR_SECURE)) - return -EINVAL; - - /* - * Validate the cursor. - */ - if (copy_from_user(&context.cursor, ucursor, sizeof(context.cursor))) - return -EFAULT; - if (context.cursor.pad1 || context.cursor.pad2) - return -EINVAL; - if (!context.cursor.initted && - (context.cursor.hashval || context.cursor.blkno || - context.cursor.offset)) - return -EINVAL; - - buffer = kvzalloc(bufsize, GFP_KERNEL); - if (!buffer) - return -ENOMEM; - - /* - * Initialize the output buffer. - */ - context.dp = dp; - context.resynch = 1; - context.attr_filter = xfs_attr_filter(flags); - context.buffer = buffer; - context.bufsize = round_down(bufsize, sizeof(uint32_t)); - context.firstu = context.bufsize; - context.put_listent = xfs_ioc_attr_put_listent; - - alist = context.buffer; - alist->al_count = 0; - alist->al_more = 0; - alist->al_offset[0] = context.bufsize; - - error = xfs_attr_list(&context); - if (error) - goto out_free; - - if (copy_to_user(ubuf, buffer, bufsize) || - copy_to_user(ucursor, &context.cursor, sizeof(context.cursor))) - error = -EFAULT; -out_free: - kvfree(buffer); - return error; -} - -STATIC int -xfs_attrlist_by_handle( - struct file *parfilp, - struct xfs_fsop_attrlist_handlereq __user *p) -{ - struct xfs_fsop_attrlist_handlereq al_hreq; - struct dentry *dentry; - int error = -ENOMEM; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - if (copy_from_user(&al_hreq, p, sizeof(al_hreq))) - return -EFAULT; - - dentry = xfs_handlereq_to_dentry(parfilp, &al_hreq.hreq); - if (IS_ERR(dentry)) - return PTR_ERR(dentry); - - error = xfs_ioc_attr_list(XFS_I(d_inode(dentry)), al_hreq.buffer, - al_hreq.buflen, al_hreq.flags, &p->pos); - dput(dentry); - return error; -} - -static int -xfs_attrmulti_attr_get( - struct inode *inode, - unsigned char *name, - unsigned char __user *ubuf, - uint32_t *len, - uint32_t flags) -{ - struct xfs_da_args args = { - .dp = XFS_I(inode), - .attr_filter = xfs_attr_filter(flags), - .xattr_flags = xfs_xattr_flags(flags), - .name = name, - .namelen = strlen(name), - .valuelen = *len, - }; - int error; - - if (*len > XFS_XATTR_SIZE_MAX) - return -EINVAL; - - error = xfs_attr_get(&args); - if (error) - goto out_kfree; - - *len = args.valuelen; - if (copy_to_user(ubuf, args.value, args.valuelen)) - error = -EFAULT; - -out_kfree: - kvfree(args.value); - return error; -} - -static int -xfs_attrmulti_attr_set( - struct inode *inode, - unsigned char *name, - const unsigned char __user *ubuf, - uint32_t len, - uint32_t flags) -{ - struct xfs_da_args args = { - .dp = XFS_I(inode), - .attr_filter = xfs_attr_filter(flags), - .xattr_flags = xfs_xattr_flags(flags), - .name = name, - .namelen = strlen(name), - }; - int error; - - if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) - return -EPERM; - - if (ubuf) { - if (len > XFS_XATTR_SIZE_MAX) - return -EINVAL; - args.value = memdup_user(ubuf, len); - if (IS_ERR(args.value)) - return PTR_ERR(args.value); - args.valuelen = len; - } - - error = xfs_attr_change(&args); - if (!error && (flags & XFS_IOC_ATTR_ROOT)) - xfs_forget_acl(inode, name); - kfree(args.value); - return error; -} - -int -xfs_ioc_attrmulti_one( - struct file *parfilp, - struct inode *inode, - uint32_t opcode, - void __user *uname, - void __user *value, - uint32_t *len, - uint32_t flags) -{ - unsigned char *name; - int error; - - if ((flags & XFS_IOC_ATTR_ROOT) && (flags & XFS_IOC_ATTR_SECURE)) - return -EINVAL; - - name = strndup_user(uname, MAXNAMELEN); - if (IS_ERR(name)) - return PTR_ERR(name); - - switch (opcode) { - case ATTR_OP_GET: - error = xfs_attrmulti_attr_get(inode, name, value, len, flags); - break; - case ATTR_OP_REMOVE: - value = NULL; - *len = 0; - fallthrough; - case ATTR_OP_SET: - error = mnt_want_write_file(parfilp); - if (error) - break; - error = xfs_attrmulti_attr_set(inode, name, value, *len, flags); - mnt_drop_write_file(parfilp); - break; - default: - error = -EINVAL; - break; - } - - kfree(name); - return error; -} - -STATIC int -xfs_attrmulti_by_handle( - struct file *parfilp, - void __user *arg) -{ - int error; - xfs_attr_multiop_t *ops; - xfs_fsop_attrmulti_handlereq_t am_hreq; - struct dentry *dentry; - unsigned int i, size; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - if (copy_from_user(&am_hreq, arg, sizeof(xfs_fsop_attrmulti_handlereq_t))) - return -EFAULT; - - /* overflow check */ - if (am_hreq.opcount >= INT_MAX / sizeof(xfs_attr_multiop_t)) - return -E2BIG; - - dentry = xfs_handlereq_to_dentry(parfilp, &am_hreq.hreq); - if (IS_ERR(dentry)) - return PTR_ERR(dentry); - - error = -E2BIG; - size = am_hreq.opcount * sizeof(xfs_attr_multiop_t); - if (!size || size > 16 * PAGE_SIZE) - goto out_dput; - - ops = memdup_user(am_hreq.ops, size); - if (IS_ERR(ops)) { - error = PTR_ERR(ops); - goto out_dput; - } - - error = 0; - for (i = 0; i < am_hreq.opcount; i++) { - ops[i].am_error = xfs_ioc_attrmulti_one(parfilp, - d_inode(dentry), ops[i].am_opcode, - ops[i].am_attrname, ops[i].am_attrvalue, - &ops[i].am_length, ops[i].am_flags); - } - - if (copy_to_user(am_hreq.ops, ops, size)) - error = -EFAULT; - - kfree(ops); - out_dput: - dput(dentry); - return error; -} - /* Return 0 on success or positive error */ int xfs_fsbulkstat_one_fmt( diff --git a/fs/xfs/xfs_ioctl.h b/fs/xfs/xfs_ioctl.h index 38be600b5e1e8..12124946f347e 100644 --- a/fs/xfs/xfs_ioctl.h +++ b/fs/xfs/xfs_ioctl.h @@ -14,34 +14,6 @@ int xfs_ioc_swapext( xfs_swapext_t *sxp); -extern int -xfs_find_handle( - unsigned int cmd, - xfs_fsop_handlereq_t *hreq); - -extern int -xfs_open_by_handle( - struct file *parfilp, - xfs_fsop_handlereq_t *hreq); - -extern int -xfs_readlink_by_handle( - struct file *parfilp, - xfs_fsop_handlereq_t *hreq); - -int xfs_ioc_attrmulti_one(struct file *parfilp, struct inode *inode, - uint32_t opcode, void __user *uname, void __user *value, - uint32_t *len, uint32_t flags); -int xfs_ioc_attr_list(struct xfs_inode *dp, void __user *ubuf, - size_t bufsize, int flags, - struct xfs_attrlist_cursor __user *ucursor); - -extern struct dentry * -xfs_handle_to_dentry( - struct file *parfilp, - void __user *uhandle, - u32 hlen); - extern int xfs_fileattr_get( struct dentry *dentry, diff --git a/fs/xfs/xfs_ioctl32.c b/fs/xfs/xfs_ioctl32.c index ee35eea1ecce6..b64785dc4354e 100644 --- a/fs/xfs/xfs_ioctl32.c +++ b/fs/xfs/xfs_ioctl32.c @@ -24,6 +24,7 @@ #include "xfs_ioctl32.h" #include "xfs_trace.h" #include "xfs_sb.h" +#include "xfs_handle.h" #define _NATIVE_IOC(cmd, type) \ _IOC(_IOC_DIR(cmd), _IOC_TYPE(cmd), _IOC_NR(cmd), sizeof(type)) From patchwork Wed Apr 10 01:00:17 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13623406 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 41D77391 for ; Wed, 10 Apr 2024 01:00:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712710818; cv=none; b=Vsjss4L6ZE1qUHm7vwdUYMkobtERk4CBAyLb1zdq5LH+08+tqNUDr5NRm6GLaMhi0qupOJGBoxe9RPxuJ4VVB0Ioy+J8RLWFZdW6WL68eOxpJRwTJCDSZlIGyzSlfFBtuSxro3YCPhJbY3XSUP4W+KyVj5HUQ+8Ih0Qrc/8u+IA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712710818; c=relaxed/simple; bh=zKKfDBA/1+ra28LA2fpJU4pkWTO04QB/Sc0Gyve5JfU=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=h9xeKukKM0WSYItw7qcFs7/WIhZf3W4r2iRaZSVRm4thEvvLrSGe896bZC4fIvA3E5igd2PznHl0DH6eSbAqfMghuKHVuEs23Qa+IZcBu06+tEbPFysUpOOhOrlsalUOLahqQVG9hrDS8y5ISeXChWTxChaTTZ5ucjqNJJRicyM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=fpUfAxzj; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="fpUfAxzj" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 18DF0C433C7; Wed, 10 Apr 2024 01:00:18 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1712710818; bh=zKKfDBA/1+ra28LA2fpJU4pkWTO04QB/Sc0Gyve5JfU=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=fpUfAxzj1rMgugcyOOEOmknD/LFp1ynh2JutFtmQMIT515l1baVXuAnYLr2Nxf3wU OODxwwQxUe4SiQ+YoZGg9CZ9l2IR6OWNgBXtqvTzcKn7mAvpHB6zuR+utxV9EuQHl+ Akucg9Vky8BLwRIqDxi5rUVSUzU3CpxdybxXDOnADEKkxU1HI+XT6US6JriPKSCvhA nVPQGJFvzKRD9ofpXuvCo42w8U/VI4tj58inkINwcNP287PxV7s81Co70XDMXhh4Bw lPbwhIcAI1ZO59A3AsJrd96R/jwfzHi/dJTpIgtkoyI5Ojd8477JSkw97OOzSzCgfy 4emtD7YpqcuSg== Date: Tue, 09 Apr 2024 18:00:17 -0700 Subject: [PATCH 26/32] xfs: split out handle management helpers a bit From: "Darrick J. Wong" To: djwong@kernel.org Cc: catherine.hoang@oracle.com, hch@lst.de, allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <171270969991.3631889.18004647832726113704.stgit@frogsfrogsfrogs> In-Reply-To: <171270969477.3631889.12488500941186994317.stgit@frogsfrogsfrogs> References: <171270969477.3631889.12488500941186994317.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Split out the functions that generate file/fs handles and map them back into dentries in preparation for the GETPARENTS ioctl next. Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig --- fs/xfs/libxfs/xfs_fs.h | 4 ++ fs/xfs/xfs_handle.c | 92 ++++++++++++++++++++++++++++++++---------------- 2 files changed, 64 insertions(+), 32 deletions(-) diff --git a/fs/xfs/libxfs/xfs_fs.h b/fs/xfs/libxfs/xfs_fs.h index 7486dcba8c218..51aa4774f57a2 100644 --- a/fs/xfs/libxfs/xfs_fs.h +++ b/fs/xfs/libxfs/xfs_fs.h @@ -633,7 +633,9 @@ typedef struct xfs_fsop_attrmulti_handlereq { /* * per machine unique filesystem identifier types. */ -typedef struct { __u32 val[2]; } xfs_fsid_t; /* file system id type */ +typedef struct xfs_fsid { + __u32 val[2]; /* file system id type */ +} xfs_fsid_t; typedef struct xfs_fid { __u16 fid_len; /* length of remainder */ diff --git a/fs/xfs/xfs_handle.c b/fs/xfs/xfs_handle.c index a0015dc8cff1a..abeca486a2c91 100644 --- a/fs/xfs/xfs_handle.c +++ b/fs/xfs/xfs_handle.c @@ -30,6 +30,35 @@ #include +static size_t +xfs_filehandle_init( + struct xfs_mount *mp, + xfs_ino_t ino, + uint32_t gen, + struct xfs_handle *handle) +{ + memcpy(&handle->ha_fsid, mp->m_fixedfsid, sizeof(struct xfs_fsid)); + + handle->ha_fid.fid_len = sizeof(struct xfs_fid) - + sizeof(handle->ha_fid.fid_len); + handle->ha_fid.fid_pad = 0; + handle->ha_fid.fid_gen = gen; + handle->ha_fid.fid_ino = ino; + + return sizeof(struct xfs_handle); +} + +static size_t +xfs_fshandle_init( + struct xfs_mount *mp, + struct xfs_handle *handle) +{ + memcpy(&handle->ha_fsid, mp->m_fixedfsid, sizeof(struct xfs_fsid)); + memset(&handle->ha_fid, 0, sizeof(handle->ha_fid)); + + return sizeof(struct xfs_fsid); +} + /* * xfs_find_handle maps from userspace xfs_fsop_handlereq structure to * a file or fs handle. @@ -84,20 +113,11 @@ xfs_find_handle( memcpy(&handle.ha_fsid, ip->i_mount->m_fixedfsid, sizeof(xfs_fsid_t)); - if (cmd == XFS_IOC_PATH_TO_FSHANDLE) { - /* - * This handle only contains an fsid, zero the rest. - */ - memset(&handle.ha_fid, 0, sizeof(handle.ha_fid)); - hsize = sizeof(xfs_fsid_t); - } else { - 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_gen = inode->i_generation; - handle.ha_fid.fid_ino = ip->i_ino; - hsize = sizeof(xfs_handle_t); - } + if (cmd == XFS_IOC_PATH_TO_FSHANDLE) + hsize = xfs_fshandle_init(ip->i_mount, &handle); + else + hsize = xfs_filehandle_init(ip->i_mount, ip->i_ino, + inode->i_generation, &handle); error = -EFAULT; if (copy_to_user(hreq->ohandle, &handle, hsize) || @@ -126,6 +146,32 @@ xfs_handle_acceptable( return 1; } +/* Convert handle already copied to kernel space into a dentry. */ +static struct dentry * +xfs_khandle_to_dentry( + struct file *file, + struct xfs_handle *handle) +{ + struct xfs_fid64 fid = { + .ino = handle->ha_fid.fid_ino, + .gen = handle->ha_fid.fid_gen, + }; + + /* + * Only allow handle opens under a directory. + */ + if (!S_ISDIR(file_inode(file)->i_mode)) + return ERR_PTR(-ENOTDIR); + + if (handle->ha_fid.fid_len != + sizeof(handle->ha_fid) - sizeof(handle->ha_fid.fid_len)) + return ERR_PTR(-EINVAL); + + return exportfs_decode_fh(file->f_path.mnt, (struct fid *)&fid, 3, + FILEID_INO32_GEN | XFS_FILEID_TYPE_64FLAG, + xfs_handle_acceptable, NULL); +} + /* * Convert userspace handle data into a dentry. */ @@ -136,29 +182,13 @@ xfs_handle_to_dentry( u32 hlen) { xfs_handle_t handle; - struct xfs_fid64 fid; - - /* - * Only allow handle opens under a directory. - */ - if (!S_ISDIR(file_inode(parfilp)->i_mode)) - return ERR_PTR(-ENOTDIR); if (hlen != sizeof(xfs_handle_t)) return ERR_PTR(-EINVAL); if (copy_from_user(&handle, uhandle, hlen)) return ERR_PTR(-EFAULT); - if (handle.ha_fid.fid_len != - sizeof(handle.ha_fid) - sizeof(handle.ha_fid.fid_len)) - return ERR_PTR(-EINVAL); - memset(&fid, 0, sizeof(struct fid)); - fid.ino = handle.ha_fid.fid_ino; - fid.gen = handle.ha_fid.fid_gen; - - return exportfs_decode_fh(parfilp->f_path.mnt, (struct fid *)&fid, 3, - FILEID_INO32_GEN | XFS_FILEID_TYPE_64FLAG, - xfs_handle_acceptable, NULL); + return xfs_khandle_to_dentry(parfilp, &handle); } STATIC struct dentry * From patchwork Wed Apr 10 01:00:33 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13623407 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DB204391 for ; Wed, 10 Apr 2024 01:00:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712710833; cv=none; b=Wgo+CSKnDN3dFrg5G9nl7h7xYAz57k7rtCEdbUUQq817V3LkfrGX4RYFHOP9FgkMONk6ET4HIWs/7HwnnmQGa42sIxl3kvFHtXACcYlsIlIFkjZe3FJy3cE9sAd6K+zxsQBV5BLGjctN/WdJgg3y4E6LWWuYihx4Y8Pf7r8wDRM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712710833; c=relaxed/simple; bh=GmkNCYJ2fnpJnqgvWP9Oe93IiywJHswsMDN4tNOLvW0=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=KKDTCEcXrW/va1OAA0NLD9ZdgdoHZxCXc48GdQIWyTxe0L07RNJ5j9pWtp1s3Lw/VOKnL7ljK6uYUt+Vm6iGQxykiB/LBuatnQZiJUXq8u10LpySFt2aCb8i9zgt+gQrisWA+FAf0Z9HB8pAt+j3+lBMC/cyG7zT4pPanHoYLGA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Ek03vucg; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Ek03vucg" Received: by smtp.kernel.org (Postfix) with ESMTPSA id B097AC433C7; Wed, 10 Apr 2024 01:00:33 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1712710833; bh=GmkNCYJ2fnpJnqgvWP9Oe93IiywJHswsMDN4tNOLvW0=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=Ek03vucgMW9WvXTbg0SHG/MYWokzCi05xoTqJbRk2kiMfZGM9gnhEkyijg19YVCu3 /oGpQdA5SiDg/kKcWRVeV0/xabiK0nKXugojCpGbekexPH4yRs0c8ovM4nrHtLR20T J325oemZQA2XRLVKqkD1EVCHAgk1447dcqyPWnUlBKuURanzSbbS8UcLTTq3gqOoiy oagDpOK7DY2z/zldUzG6wiCqWDH0Uuw+QWOX/3Rcl9G82zm4vxNJWe7mYvrz4xH/v9 BgpGgDEZ6zgpR1D/r3cowdAa7x7TJspXJLR2AfvP6R4mmFU8Yt3HpHW/oIbigYEJVx 5QlcHuzTSoKTw== Date: Tue, 09 Apr 2024 18:00:33 -0700 Subject: [PATCH 27/32] xfs: Add parent pointer ioctls From: "Darrick J. Wong" To: djwong@kernel.org Cc: Allison Henderson , catherine.hoang@oracle.com, hch@lst.de, allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <171270970008.3631889.8274576756376203769.stgit@frogsfrogsfrogs> In-Reply-To: <171270969477.3631889.12488500941186994317.stgit@frogsfrogsfrogs> References: <171270969477.3631889.12488500941186994317.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong This patch adds a pair of new file ioctls to retrieve the parent pointer of a given inode. They both return the same results, but one operates on the file descriptor passed to ioctl() whereas the other allows the caller to specify a file handle for which the caller wants results. Signed-off-by: Allison Henderson Reviewed-by: Darrick J. Wong [djwong: adjust to new ondisk format, split ioctls] Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig --- fs/xfs/libxfs/xfs_fs.h | 73 ++++++++++++ fs/xfs/libxfs/xfs_ondisk.h | 5 + fs/xfs/libxfs/xfs_parent.c | 35 ++++++ fs/xfs/libxfs/xfs_parent.h | 5 + fs/xfs/xfs_handle.c | 259 ++++++++++++++++++++++++++++++++++++++++++++ fs/xfs/xfs_handle.h | 5 + fs/xfs/xfs_ioctl.c | 6 + fs/xfs/xfs_trace.c | 1 fs/xfs/xfs_trace.h | 92 ++++++++++++++++ 9 files changed, 480 insertions(+), 1 deletion(-) diff --git a/fs/xfs/libxfs/xfs_fs.h b/fs/xfs/libxfs/xfs_fs.h index 51aa4774f57a2..fa28c18e521bf 100644 --- a/fs/xfs/libxfs/xfs_fs.h +++ b/fs/xfs/libxfs/xfs_fs.h @@ -840,6 +840,77 @@ struct xfs_commit_range { XFS_EXCHANGE_RANGE_DRY_RUN | \ XFS_EXCHANGE_RANGE_FILE1_WRITTEN) +/* Iterating parent pointers of files. */ + +/* target was the root directory */ +#define XFS_GETPARENTS_OFLAG_ROOT (1U << 0) + +/* Cursor is done iterating pptrs */ +#define XFS_GETPARENTS_OFLAG_DONE (1U << 1) + +#define XFS_GETPARENTS_OFLAGS_ALL (XFS_GETPARENTS_OFLAG_ROOT | \ + XFS_GETPARENTS_OFLAG_DONE) + +#define XFS_GETPARENTS_IFLAGS_ALL (0) + +struct xfs_getparents_rec { + struct xfs_handle gpr_parent; /* Handle to parent */ + __u16 gpr_reclen; /* Length of entire record */ + char gpr_name[]; /* Null-terminated filename */ +} __packed; + +/* Iterate through this file's directory parent pointers */ +struct xfs_getparents { + /* + * 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; + + /* Input flags: XFS_GETPARENTS_IFLAG* */ + __u16 gp_iflags; + + /* Output flags: XFS_GETPARENTS_OFLAG* */ + __u16 gp_oflags; + + /* Size of the gp_buffer in bytes */ + __u32 gp_bufsize; + + /* Must be set to zero */ + __u64 __pad; + + /* Pointer to a buffer in which to place xfs_getparents_rec */ + __u64 gp_buffer; +}; + +static inline struct xfs_getparents_rec * +xfs_getparents_first_rec(struct xfs_getparents *gp) +{ + return (struct xfs_getparents_rec *)(uintptr_t)gp->gp_buffer; +} + +static inline struct xfs_getparents_rec * +xfs_getparents_next_rec(struct xfs_getparents *gp, + struct xfs_getparents_rec *gpr) +{ + char *next = ((char *)gpr + gpr->gpr_reclen); + char *end = (char *)(uintptr_t)(gp->gp_buffer + gp->gp_bufsize); + + if (next >= end) + return NULL; + + return (struct xfs_getparents_rec *)next; +} + +/* Iterate through this file handle's directory parent pointers. */ +struct xfs_getparents_by_handle { + /* Handle to file whose parents we want. */ + struct xfs_handle gph_handle; + + struct xfs_getparents gph_request; +}; + /* * ioctl commands that are used by Linux filesystems */ @@ -875,6 +946,8 @@ struct xfs_commit_range { /* 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) +#define XFS_IOC_GETPARENTS _IOWR('X', 62, struct xfs_getparents) +#define XFS_IOC_GETPARENTS_BY_HANDLE _IOWR('X', 63, struct xfs_getparents_by_handle) /* * ioctl commands that replace IRIX syssgi()'s diff --git a/fs/xfs/libxfs/xfs_ondisk.h b/fs/xfs/libxfs/xfs_ondisk.h index 25952ef584eee..34c972113d997 100644 --- a/fs/xfs/libxfs/xfs_ondisk.h +++ b/fs/xfs/libxfs/xfs_ondisk.h @@ -156,6 +156,11 @@ xfs_check_ondisk_structs(void) XFS_CHECK_OFFSET(struct xfs_efi_log_format_32, efi_extents, 16); XFS_CHECK_OFFSET(struct xfs_efi_log_format_64, efi_extents, 16); + /* parent pointer ioctls */ + XFS_CHECK_STRUCT_SIZE(struct xfs_getparents_rec, 26); + XFS_CHECK_STRUCT_SIZE(struct xfs_getparents, 40); + XFS_CHECK_STRUCT_SIZE(struct xfs_getparents_by_handle, 64); + /* * The v5 superblock format extended several v4 header structures with * additional data. While new fields are only accessible on v5 diff --git a/fs/xfs/libxfs/xfs_parent.c b/fs/xfs/libxfs/xfs_parent.c index 86c808157294e..db8cfad0b968e 100644 --- a/fs/xfs/libxfs/xfs_parent.c +++ b/fs/xfs/libxfs/xfs_parent.c @@ -259,3 +259,38 @@ xfs_parent_replacename( xfs_attr_defer_parent(&ppargs->args, XFS_ATTR_DEFER_REPLACE); return 0; } + +/* + * Extract parent pointer information from any xattr into @parent_ino/gen. + * The last two parameters can be NULL pointers. + * + * Returns 1 if this is a valid parent pointer; 0 if this is not a parent + * pointer xattr at all; or -EFSCORRUPTED for garbage. + */ +int +xfs_parent_from_xattr( + struct xfs_mount *mp, + unsigned int attr_flags, + const unsigned char *name, + unsigned int namelen, + const void *value, + unsigned int valuelen, + xfs_ino_t *parent_ino, + uint32_t *parent_gen) +{ + const struct xfs_parent_rec *rec = value; + + if (!(attr_flags & XFS_ATTR_PARENT)) + return 0; + + if (!xfs_parent_namecheck(attr_flags, name, namelen)) + return -EFSCORRUPTED; + if (!xfs_parent_valuecheck(mp, value, valuelen)) + return -EFSCORRUPTED; + + if (parent_ino) + *parent_ino = be64_to_cpu(rec->p_ino); + if (parent_gen) + *parent_gen = be32_to_cpu(rec->p_gen); + return 1; +} diff --git a/fs/xfs/libxfs/xfs_parent.h b/fs/xfs/libxfs/xfs_parent.h index 768633b313671..3003ab496f854 100644 --- a/fs/xfs/libxfs/xfs_parent.h +++ b/fs/xfs/libxfs/xfs_parent.h @@ -91,4 +91,9 @@ int xfs_parent_replacename(struct xfs_trans *tp, struct xfs_inode *new_dp, const struct xfs_name *new_name, struct xfs_inode *child); +int xfs_parent_from_xattr(struct xfs_mount *mp, unsigned int attr_flags, + const unsigned char *name, unsigned int namelen, + const void *value, unsigned int valuelen, + xfs_ino_t *parent_ino, uint32_t *parent_gen); + #endif /* __XFS_PARENT_H__ */ diff --git a/fs/xfs/xfs_handle.c b/fs/xfs/xfs_handle.c index abeca486a2c91..833b0d7d8bea1 100644 --- a/fs/xfs/xfs_handle.c +++ b/fs/xfs/xfs_handle.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2005 Silicon Graphics, Inc. + * Copyright (c) 2022-2024 Oracle. * All rights reserved. */ #include "xfs.h" @@ -645,3 +646,261 @@ xfs_attrmulti_by_handle( dput(dentry); return error; } + +struct xfs_getparents_ctx { + struct xfs_attr_list_context context; + struct xfs_getparents_by_handle gph; + + /* File to target */ + struct xfs_inode *ip; + + /* Internal buffer where we format records */ + void *krecords; + + /* Last record filled out */ + struct xfs_getparents_rec *lastrec; + + unsigned int count; +}; + +static inline unsigned int +xfs_getparents_rec_sizeof( + unsigned int namelen) +{ + return round_up(sizeof(struct xfs_getparents_rec) + namelen + 1, + sizeof(uint32_t)); +} + +static void +xfs_getparents_put_listent( + struct xfs_attr_list_context *context, + int flags, + unsigned char *name, + int namelen, + void *value, + int valuelen) +{ + struct xfs_getparents_ctx *gpx = + container_of(context, struct xfs_getparents_ctx, context); + struct xfs_inode *ip = context->dp; + struct xfs_mount *mp = ip->i_mount; + struct xfs_getparents *gp = &gpx->gph.gph_request; + struct xfs_getparents_rec *gpr = gpx->krecords + context->firstu; + unsigned short reclen = xfs_getparents_rec_sizeof(namelen); + xfs_ino_t ino; + uint32_t gen; + int ret; + + ret = xfs_parent_from_xattr(mp, flags, name, namelen, value, valuelen, + &ino, &gen); + if (ret < 0) { + xfs_inode_mark_sick(ip, XFS_SICK_INO_PARENT); + context->seen_enough = -EFSCORRUPTED; + return; + } + if (ret != 1) + return; + + /* + * We found a parent pointer, but we've filled up the buffer. Signal + * to the caller that we did /not/ reach the end of the parent pointer + * recordset. + */ + if (context->firstu > context->bufsize - reclen) { + context->seen_enough = 1; + return; + } + + /* Format the parent pointer directly into the caller buffer. */ + gpr->gpr_reclen = reclen; + xfs_filehandle_init(mp, ino, gen, &gpr->gpr_parent); + memcpy(gpr->gpr_name, name, namelen); + gpr->gpr_name[namelen] = 0; + + trace_xfs_getparents_put_listent(ip, gp, context, gpr); + + context->firstu += reclen; + gpx->count++; + gpx->lastrec = gpr; +} + +/* Expand the last record to fill the rest of the caller's buffer. */ +static inline void +xfs_getparents_expand_lastrec( + struct xfs_getparents_ctx *gpx) +{ + struct xfs_getparents *gp = &gpx->gph.gph_request; + struct xfs_getparents_rec *gpr = gpx->lastrec; + + if (!gpx->lastrec) + gpr = gpx->krecords; + + gpr->gpr_reclen = gp->gp_bufsize - ((void *)gpr - gpx->krecords); + + trace_xfs_getparents_expand_lastrec(gpx->ip, gp, &gpx->context, gpr); +} + +static inline void __user *u64_to_uptr(u64 val) +{ + return (void __user *)(uintptr_t)val; +} + +/* Retrieve the parent pointers for a given inode. */ +STATIC int +xfs_getparents( + struct xfs_getparents_ctx *gpx) +{ + struct xfs_getparents *gp = &gpx->gph.gph_request; + struct xfs_inode *ip = gpx->ip; + struct xfs_mount *mp = ip->i_mount; + size_t bufsize; + int error; + + /* Check size of buffer requested by user */ + if (gp->gp_bufsize > XFS_XATTR_LIST_MAX) + return -ENOMEM; + if (gp->gp_bufsize < xfs_getparents_rec_sizeof(1)) + return -EINVAL; + + if (gp->gp_iflags & ~XFS_GETPARENTS_IFLAGS_ALL) + return -EINVAL; + if (gp->__pad) + return -EINVAL; + + bufsize = round_down(gp->gp_bufsize, sizeof(uint32_t)); + gpx->krecords = kvzalloc(bufsize, GFP_KERNEL); + if (!gpx->krecords) { + bufsize = min(bufsize, PAGE_SIZE); + gpx->krecords = kvzalloc(bufsize, GFP_KERNEL); + if (!gpx->krecords) + return -ENOMEM; + } + + gpx->context.dp = ip; + gpx->context.resynch = 1; + gpx->context.put_listent = xfs_getparents_put_listent; + gpx->context.bufsize = bufsize; + /* firstu is used to track the bytes filled in the buffer */ + gpx->context.firstu = 0; + + /* Copy the cursor provided by caller */ + memcpy(&gpx->context.cursor, &gp->gp_cursor, + sizeof(struct xfs_attrlist_cursor)); + gpx->count = 0; + gp->gp_oflags = 0; + + trace_xfs_getparents_begin(ip, gp, &gpx->context.cursor); + + error = xfs_attr_list(&gpx->context); + if (error) + goto out_free_buf; + if (gpx->context.seen_enough < 0) { + error = gpx->context.seen_enough; + goto out_free_buf; + } + xfs_getparents_expand_lastrec(gpx); + + /* Update the caller with the current cursor position */ + memcpy(&gp->gp_cursor, &gpx->context.cursor, + sizeof(struct xfs_attrlist_cursor)); + + /* Is this the root directory? */ + if (ip->i_ino == mp->m_sb.sb_rootino) + gp->gp_oflags |= XFS_GETPARENTS_OFLAG_ROOT; + + if (gpx->context.seen_enough == 0) { + /* + * If we did not run out of buffer space, then we reached the + * end of the pptr recordset, so set the DONE flag. + */ + gp->gp_oflags |= XFS_GETPARENTS_OFLAG_DONE; + } else if (gpx->count == 0) { + /* + * If we ran out of buffer space before copying any parent + * pointers at all, the caller's buffer was too short. Tell + * userspace that, erm, the message is too long. + */ + error = -EMSGSIZE; + goto out_free_buf; + } + + trace_xfs_getparents_end(ip, gp, &gpx->context.cursor); + + ASSERT(gpx->context.firstu <= gpx->gph.gph_request.gp_bufsize); + + /* Copy the records to userspace. */ + if (copy_to_user(u64_to_uptr(gpx->gph.gph_request.gp_buffer), + gpx->krecords, gpx->context.firstu)) + error = -EFAULT; + +out_free_buf: + kvfree(gpx->krecords); + gpx->krecords = NULL; + return error; +} + +/* Retrieve the parents of this file and pass them back to userspace. */ +int +xfs_ioc_getparents( + struct file *file, + struct xfs_getparents __user *ureq) +{ + struct xfs_getparents_ctx gpx = { + .ip = XFS_I(file_inode(file)), + }; + struct xfs_getparents *kreq = &gpx.gph.gph_request; + struct xfs_mount *mp = gpx.ip->i_mount; + int error; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (!xfs_has_parent(mp)) + return -EOPNOTSUPP; + if (copy_from_user(kreq, ureq, sizeof(*kreq))) + return -EFAULT; + + error = xfs_getparents(&gpx); + if (error) + return error; + + if (copy_to_user(ureq, kreq, sizeof(*kreq))) + return -EFAULT; + + return 0; +} + +/* Retrieve the parents of this file handle and pass them back to userspace. */ +int +xfs_ioc_getparents_by_handle( + struct file *file, + struct xfs_getparents_by_handle __user *ureq) +{ + struct xfs_getparents_ctx gpx = { }; + struct xfs_inode *ip = XFS_I(file_inode(file)); + struct xfs_mount *mp = ip->i_mount; + struct xfs_getparents_by_handle *kreq = &gpx.gph; + struct dentry *dentry; + int error; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (!xfs_has_parent(mp)) + return -EOPNOTSUPP; + if (copy_from_user(kreq, ureq, sizeof(*kreq))) + return -EFAULT; + + dentry = xfs_khandle_to_dentry(file, &kreq->gph_handle); + if (IS_ERR(dentry)) + return PTR_ERR(dentry); + + gpx.ip = XFS_I(dentry->d_inode); + error = xfs_getparents(&gpx); + dput(dentry); + if (error) + return error; + + if (copy_to_user(ureq, kreq, sizeof(*kreq))) + return -EFAULT; + + return 0; +} diff --git a/fs/xfs/xfs_handle.h b/fs/xfs/xfs_handle.h index e39eaf4689da9..6799a86d8565c 100644 --- a/fs/xfs/xfs_handle.h +++ b/fs/xfs/xfs_handle.h @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2005 Silicon Graphics, Inc. + * Copyright (c) 2022-2024 Oracle. * All rights reserved. */ #ifndef __XFS_HANDLE_H__ @@ -25,4 +26,8 @@ int xfs_ioc_attr_list(struct xfs_inode *dp, void __user *ubuf, struct dentry *xfs_handle_to_dentry(struct file *parfilp, void __user *uhandle, u32 hlen); +int xfs_ioc_getparents(struct file *file, struct xfs_getparents __user *arg); +int xfs_ioc_getparents_by_handle(struct file *file, + struct xfs_getparents_by_handle __user *arg); + #endif /* __XFS_HANDLE_H__ */ diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c index 7b347cdd28785..c7a15b5f33aa4 100644 --- a/fs/xfs/xfs_ioctl.c +++ b/fs/xfs/xfs_ioctl.c @@ -35,6 +35,7 @@ #include "xfs_health.h" #include "xfs_reflink.h" #include "xfs_ioctl.h" +#include "xfs_xattr.h" #include "xfs_rtbitmap.h" #include "xfs_file.h" #include "xfs_exchrange.h" @@ -1542,7 +1543,10 @@ xfs_file_ioctl( case XFS_IOC_FSGETXATTRA: return xfs_ioc_fsgetxattra(ip, arg); - + case XFS_IOC_GETPARENTS: + return xfs_ioc_getparents(filp, arg); + case XFS_IOC_GETPARENTS_BY_HANDLE: + return xfs_ioc_getparents_by_handle(filp, arg); case XFS_IOC_GETBMAP: case XFS_IOC_GETBMAPA: case XFS_IOC_GETBMAPX: diff --git a/fs/xfs/xfs_trace.c b/fs/xfs/xfs_trace.c index cf92a3bd56c79..9c7fbaae2717d 100644 --- a/fs/xfs/xfs_trace.c +++ b/fs/xfs/xfs_trace.c @@ -41,6 +41,7 @@ #include "xfs_bmap.h" #include "xfs_exchmaps.h" #include "xfs_exchrange.h" +#include "xfs_parent.h" /* * We include this last to have the helpers above available for the trace diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h index e6cbdffb14f64..4438b62a8c562 100644 --- a/fs/xfs/xfs_trace.h +++ b/fs/xfs/xfs_trace.h @@ -87,6 +87,9 @@ struct xfs_bmap_intent; struct xfs_exchmaps_intent; struct xfs_exchmaps_req; struct xfs_exchrange; +struct xfs_getparents; +struct xfs_parent_irec; +struct xfs_attrlist_cursor_kern; #define XFS_ATTR_FILTER_FLAGS \ { XFS_ATTR_ROOT, "ROOT" }, \ @@ -5158,6 +5161,95 @@ TRACE_EVENT(xfs_exchmaps_delta_nextents, __entry->d_nexts1, __entry->d_nexts2) ); +DECLARE_EVENT_CLASS(xfs_getparents_rec_class, + TP_PROTO(struct xfs_inode *ip, const struct xfs_getparents *ppi, + const struct xfs_attr_list_context *context, + const struct xfs_getparents_rec *pptr), + TP_ARGS(ip, ppi, context, pptr), + TP_STRUCT__entry( + __field(dev_t, dev) + __field(xfs_ino_t, ino) + __field(unsigned int, firstu) + __field(unsigned short, reclen) + __field(unsigned int, bufsize) + __field(xfs_ino_t, parent_ino) + __field(unsigned int, parent_gen) + __string(name, pptr->gpr_name) + ), + TP_fast_assign( + __entry->dev = ip->i_mount->m_super->s_dev; + __entry->ino = ip->i_ino; + __entry->firstu = context->firstu; + __entry->reclen = pptr->gpr_reclen; + __entry->bufsize = ppi->gp_bufsize; + __entry->parent_ino = pptr->gpr_parent.ha_fid.fid_ino; + __entry->parent_gen = pptr->gpr_parent.ha_fid.fid_gen; + __assign_str(name, pptr->gpr_name); + ), + TP_printk("dev %d:%d ino 0x%llx firstu %u reclen %u bufsize %u parent_ino 0x%llx parent_gen 0x%x name '%s'", + MAJOR(__entry->dev), MINOR(__entry->dev), + __entry->ino, + __entry->firstu, + __entry->reclen, + __entry->bufsize, + __entry->parent_ino, + __entry->parent_gen, + __get_str(name)) +) +#define DEFINE_XFS_GETPARENTS_REC_EVENT(name) \ +DEFINE_EVENT(xfs_getparents_rec_class, name, \ + TP_PROTO(struct xfs_inode *ip, const struct xfs_getparents *ppi, \ + const struct xfs_attr_list_context *context, \ + const struct xfs_getparents_rec *pptr), \ + TP_ARGS(ip, ppi, context, pptr)) +DEFINE_XFS_GETPARENTS_REC_EVENT(xfs_getparents_put_listent); +DEFINE_XFS_GETPARENTS_REC_EVENT(xfs_getparents_expand_lastrec); + +DECLARE_EVENT_CLASS(xfs_getparents_class, + TP_PROTO(struct xfs_inode *ip, const struct xfs_getparents *ppi, + const struct xfs_attrlist_cursor_kern *cur), + TP_ARGS(ip, ppi, cur), + TP_STRUCT__entry( + __field(dev_t, dev) + __field(xfs_ino_t, ino) + __field(unsigned short, iflags) + __field(unsigned short, oflags) + __field(unsigned int, bufsize) + __field(unsigned int, hashval) + __field(unsigned int, blkno) + __field(unsigned int, offset) + __field(int, initted) + ), + TP_fast_assign( + __entry->dev = ip->i_mount->m_super->s_dev; + __entry->ino = ip->i_ino; + __entry->iflags = ppi->gp_iflags; + __entry->oflags = ppi->gp_oflags; + __entry->bufsize = ppi->gp_bufsize; + __entry->hashval = cur->hashval; + __entry->blkno = cur->blkno; + __entry->offset = cur->offset; + __entry->initted = cur->initted; + ), + TP_printk("dev %d:%d ino 0x%llx iflags 0x%x oflags 0x%x bufsize %u cur_init? %d hashval 0x%x blkno %u offset %u", + MAJOR(__entry->dev), MINOR(__entry->dev), + __entry->ino, + __entry->iflags, + __entry->oflags, + __entry->bufsize, + __entry->initted, + __entry->hashval, + __entry->blkno, + __entry->offset) +) +#define DEFINE_XFS_GETPARENTS_EVENT(name) \ +DEFINE_EVENT(xfs_getparents_class, name, \ + TP_PROTO(struct xfs_inode *ip, const struct xfs_getparents *ppi, \ + const struct xfs_attrlist_cursor_kern *cur), \ + TP_ARGS(ip, ppi, cur)) +DEFINE_XFS_GETPARENTS_EVENT(xfs_getparents_begin); +DEFINE_XFS_GETPARENTS_EVENT(xfs_getparents_end); + #endif /* _TRACE_XFS_H */ #undef TRACE_INCLUDE_PATH From patchwork Wed Apr 10 01:00:48 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13623408 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 87D17621 for ; Wed, 10 Apr 2024 01:00:49 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712710849; cv=none; b=lH7H8cKwlrlFuRN/XiCJKEZkooSaBubs3/3bYjrQd8pxqssNJHRLsq3poX5xjSfqOGhKT3wyvFCIFYq/6aKIN0/hvSv/1xCzVCgR4sYwyp9tGHTqRkxJ57NvBXIBXRrOIg3qwcGo0i+4ZIVhx7AjtmRWYAqofdHHEf6N4vmuAL8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712710849; c=relaxed/simple; bh=sRGy5TXm0DI8xYkUG5BchEFCO1aUNgmK43P3tXWw4UI=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=eUMd3lUhtUR9JPBO3qhdQj3rPXu1+orj08NJtiI519yyNzQJJtD6rARwOqAgX8nmpX7Is/Ddv0F9QDfpcQbRayhJn8Ty9Jf0hW/XzqdXzVMG8Mpn1vTNje1GmZmANoL2bpwv08Z2e+wzGqLnFEqoe5OrFxxnRQ4vS8RKCegd7mQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=I6WzOLsD; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="I6WzOLsD" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 55464C433F1; Wed, 10 Apr 2024 01:00:49 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1712710849; bh=sRGy5TXm0DI8xYkUG5BchEFCO1aUNgmK43P3tXWw4UI=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=I6WzOLsDZ32jZ3fcxB1u9MU4fyGr0O9f3PGHmZsvWSq05N5pSjscJF2Im/alaFsxU JMveCczERNCssC7wGUD8C0szZYn70SMm/EL5XxOcyJmuVW1lCdBr0qMtbeNaIMwZiH KdDf4dRRKq/tnvWAZPYB4EYijIwLaufPyYelXYCoFENcov5yI8i5UOfKhyup8FtQW+ q3Z6xxzg+0fUa7JU886l40j9NBc0BolbzRrvjw1fpYxLDv8sWd5MCKN2pX4ecIr7aL 8q38Ru+TjfCOOT1jS3IQXjIHZOFkUorITSgtHYI/a8sVval+U94LYEqqUvnm2RplEW +EG4A8TiW0dmA== Date: Tue, 09 Apr 2024 18:00:48 -0700 Subject: [PATCH 28/32] xfs: don't remove the attr fork when parent pointers are enabled From: "Darrick J. Wong" To: djwong@kernel.org Cc: Allison Henderson , catherine.hoang@oracle.com, hch@lst.de, allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <171270970025.3631889.12207478353485734181.stgit@frogsfrogsfrogs> In-Reply-To: <171270969477.3631889.12488500941186994317.stgit@frogsfrogsfrogs> References: <171270969477.3631889.12488500941186994317.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Allison Henderson When an inode is removed, it may also cause the attribute fork to be removed if it is the last attribute. This transaction gets flushed to the log, but if the system goes down before we could inactivate the symlink, the log recovery tries to inactivate this inode (since it is on the unlinked list) but the verifier trips over the remote value and leaks it. Hence we ended up with a file in this odd state on a "clean" mount. The "obvious" fix is to prohibit erasure of the attr fork to avoid tripping over the verifiers when pptrs are enabled. Signed-off-by: Allison Henderson Reviewed-by: Darrick J. Wong Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig --- fs/xfs/libxfs/xfs_attr_leaf.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c index 7d74ade47d8f1..6eacf3cb7ca0b 100644 --- a/fs/xfs/libxfs/xfs_attr_leaf.c +++ b/fs/xfs/libxfs/xfs_attr_leaf.c @@ -887,7 +887,8 @@ xfs_attr_sf_removename( */ if (totsize == sizeof(struct xfs_attr_sf_hdr) && 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); @@ -896,7 +897,8 @@ xfs_attr_sf_removename( ASSERT(totsize > sizeof(struct xfs_attr_sf_hdr) || (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 Wed Apr 10 01:01:04 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13623409 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2FC07621 for ; Wed, 10 Apr 2024 01:01:05 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712710865; cv=none; b=E8uckZserhLyrUeI706Xuzg4Qeto6hYFgaCEI6f4pAO+e/bSzIGxBvOI+h0tgqIyvTMNBFO3mxnvw5cac04y9h7Yk9JO6w4N/a52LN/yJVKBKLNRv9GI26G17oYbgkwWKLA7o/lS6dqD+fNQ+6En9sudhAcK2FabHQ88Zt2BPXc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712710865; c=relaxed/simple; bh=Djm1otwGDlSzthgpwdLVXi+/17+f5iG8zxcHmKst0DE=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=uWdsJc6OQl27PpaLaAI0tz/oWantzZjkucihRRIpQQjdFWcY65hxNs3YMKA5kNtlkZpNIQUlw8CDvaxCZlR9ZS34W93M7o5yrhaStK2ITCQDYR2eebXQZq+vR6TUBQ2EzsXJHhhEvdYyozl71PTbdhWzC90LtSF5NufGBNGg7w4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=MKeJA1df; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="MKeJA1df" Received: by smtp.kernel.org (Postfix) with ESMTPSA id EF25DC433F1; Wed, 10 Apr 2024 01:01:04 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1712710865; bh=Djm1otwGDlSzthgpwdLVXi+/17+f5iG8zxcHmKst0DE=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=MKeJA1dfOlu1uLM42nV2+6qDPbOT07ZCtMM1RvHge+ufvRZEOJBk9OOwOnbCXCPYk av+xDMlZx0gtyUuemDj6DKL6/abIjWGNwN19TzFfJRCLOnJgYMpw7zzRCW0MI+EH8+ BIdcPuGZ0dyrfjC96vgdxUNsj00cJDyyfgUizlCOEpEcCozf/Kueo3/mFssl6PwkP1 3d02zaatSiVUu8Z7MYeKUwlJFCJa2uWhh5SpdXSR9fII3dFqY5MaCAW2t/ZKcRT9Mj 0VwxjB79jDSYOy40bGRg3qK/KBFDGZiQxWSMu5GzwvkM4RB9VSa1Hs+sH7zE/CgKj2 RQlzHbVADp8yQ== Date: Tue, 09 Apr 2024 18:01:04 -0700 Subject: [PATCH 29/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" , catherine.hoang@oracle.com, hch@lst.de, allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <171270970042.3631889.15727225239821945588.stgit@frogsfrogsfrogs> In-Reply-To: <171270969477.3631889.12488500941186994317.stgit@frogsfrogsfrogs> References: <171270969477.3631889.12488500941186994317.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Allison Henderson Add the parent pointer superblock flag so that we can actually mount filesystems with this feature enabled. Signed-off-by: Mark Tinguely Signed-off-by: Dave Chinner Signed-off-by: Allison Henderson Reviewed-by: Darrick J. Wong Reviewed-by: Darrick J. Wong Signed-off-by: Darrick J. Wong --- fs/xfs/libxfs/xfs_format.h | 1 + fs/xfs/libxfs/xfs_fs.h | 2 ++ fs/xfs/libxfs/xfs_sb.c | 4 ++++ fs/xfs/xfs_super.c | 4 ++++ 4 files changed, 11 insertions(+) diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h index f1818c54af6f8..b457e457e1f71 100644 --- a/fs/xfs/libxfs/xfs_format.h +++ b/fs/xfs/libxfs/xfs_format.h @@ -374,6 +374,7 @@ xfs_sb_has_ro_compat_feature( #define XFS_SB_FEAT_INCOMPAT_NEEDSREPAIR (1 << 4) /* needs xfs_repair */ #define XFS_SB_FEAT_INCOMPAT_NREXT64 (1 << 5) /* large extent counters */ #define XFS_SB_FEAT_INCOMPAT_EXCHRANGE (1 << 6) /* exchangerange supported */ +#define XFS_SB_FEAT_INCOMPAT_PARENT (1 << 7) /* parent pointers */ #define XFS_SB_FEAT_INCOMPAT_ALL \ (XFS_SB_FEAT_INCOMPAT_FTYPE | \ XFS_SB_FEAT_INCOMPAT_SPINODES | \ diff --git a/fs/xfs/libxfs/xfs_fs.h b/fs/xfs/libxfs/xfs_fs.h index fa28c18e521bf..90e1d0cc04e4b 100644 --- a/fs/xfs/libxfs/xfs_fs.h +++ b/fs/xfs/libxfs/xfs_fs.h @@ -241,6 +241,8 @@ typedef struct xfs_fsop_resblks { #define XFS_FSOP_GEOM_FLAGS_NREXT64 (1 << 23) /* large extent counters */ #define XFS_FSOP_GEOM_FLAGS_EXCHANGE_RANGE (1 << 24) /* exchange range */ +#define XFS_FSOP_GEOM_FLAGS_PARENT (1U << 30) /* parent pointers */ + /* * Minimum and maximum sizes need for growth checks. * diff --git a/fs/xfs/libxfs/xfs_sb.c b/fs/xfs/libxfs/xfs_sb.c index c350e259b6855..09e4bf949bf88 100644 --- a/fs/xfs/libxfs/xfs_sb.c +++ b/fs/xfs/libxfs/xfs_sb.c @@ -178,6 +178,8 @@ xfs_sb_version_to_features( features |= XFS_FEAT_NREXT64; if (sbp->sb_features_incompat & XFS_SB_FEAT_INCOMPAT_EXCHRANGE) features |= XFS_FEAT_EXCHANGE_RANGE; + if (sbp->sb_features_incompat & XFS_SB_FEAT_INCOMPAT_PARENT) + features |= XFS_FEAT_PARENT; return features; } @@ -1254,6 +1256,8 @@ xfs_fs_geometry( geo->flags |= XFS_FSOP_GEOM_FLAGS_BIGTIME; if (xfs_has_inobtcounts(mp)) geo->flags |= XFS_FSOP_GEOM_FLAGS_INOBTCNT; + if (xfs_has_parent(mp)) + geo->flags |= XFS_FSOP_GEOM_FLAGS_PARENT; if (xfs_has_sector(mp)) { geo->flags |= XFS_FSOP_GEOM_FLAGS_SECTOR; geo->logsectsize = sbp->sb_logsectsize; diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c index 84f37e8474da2..14a7f74b20dbb 100644 --- a/fs/xfs/xfs_super.c +++ b/fs/xfs/xfs_super.c @@ -1733,6 +1733,10 @@ xfs_fs_fill_super( xfs_warn(mp, "EXPERIMENTAL exchange-range feature enabled. Use at your own risk!"); + if (xfs_has_parent(mp)) + xfs_warn(mp, + "EXPERIMENTAL parent pointer feature enabled. Use at your own risk!"); + error = xfs_mountfs(mp); if (error) goto out_filestream_unmount; From patchwork Wed Apr 10 01:01:20 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13623410 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id CE7F5391 for ; Wed, 10 Apr 2024 01:01:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712710880; cv=none; b=FnoksPq0tiKwUe10mBDEDDXUK7nIcH2DHIIdWDhK7QU9y9XPBNVQ2VRThLnsCMSkxsrZYS4oEd98m7siGE4kfJXi0uGUveGCkBaZ3GOuvkeHiOd2W4jB0vQc1sGqUCMaX2JWDBY89o/rgh2e7KF2PWqmNsWw0q0X4+7G14sXpgM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712710880; c=relaxed/simple; bh=Ci3ye8+//spnZAj5yLmQKmqoR4qum3iR3QM8tRmpREE=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=CFKoWnU27lFs5NZDgFtcwSNNe2e9nezgYlXeWPn23yrIK4Qx69BbWAbw5R5ElbnE9YCbhhzsvDJGnuVaVk/v6Aqp9Zd5FgM+DDiy2fus76/DZe/1+lr5bCCquy2lJ5rnyyw0C3x83/wWBkQLJOyDRZjgqORtyyf0OhbMfPHyATw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=ouaMzqFt; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="ouaMzqFt" Received: by smtp.kernel.org (Postfix) with ESMTPSA id A0662C433F1; Wed, 10 Apr 2024 01:01:20 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1712710880; bh=Ci3ye8+//spnZAj5yLmQKmqoR4qum3iR3QM8tRmpREE=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=ouaMzqFt8Spsd7Dv4WfPpJb9cBAMjG7CbCvpBh1efLq5dR8Yu3juDC/+ohuPnOl86 2ea778lUEeN73XFbVuucjWLa/knER64ncU3VLTZmrD26rc4EL3QU6/VVPqdfBay+vU MPF1BdDz+yLQI0c7fyoihtA7RsnMEAaUm2qxF+flk2vrQrtMeMF05Jdh19HNs79CMd ppHc4YtNfunzqruc47EsXhqo22UvjHw8i2N73LOC1du5jawimMXgYXtpAuGE+cDO+U o1sJOjx8Ch67beCmg/ePATSUw5CFhxGXc9GIvGU6gNmHt4N7torCno4OhOiQucSDpj sFYXDSvDXlM1w== Date: Tue, 09 Apr 2024 18:01:20 -0700 Subject: [PATCH 30/32] xfs: fix unit conversion error in xfs_log_calc_max_attrsetm_res From: "Darrick J. Wong" To: djwong@kernel.org Cc: Allison Henderson , catherine.hoang@oracle.com, hch@lst.de, allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <171270970059.3631889.4894608923555781612.stgit@frogsfrogsfrogs> In-Reply-To: <171270969477.3631889.12488500941186994317.stgit@frogsfrogsfrogs> References: <171270969477.3631889.12488500941186994317.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Dave and I were discussing some recent test regressions as a result of me turning on nrext64=1 on realtime filesystems, when we noticed that the minimum log size of a 32M filesystem jumped from 954 blocks to 4287 blocks. Digging through xfs_log_calc_max_attrsetm_res, Dave noticed that @size contains the maximum estimated amount of space needed for a local format xattr, in bytes, but we feed this quantity to XFS_NEXTENTADD_SPACE_RES, which requires units of blocks. This has resulted in an overestimation of the minimum log size over the years. We should nominally correct this, but there's a backwards compatibility problem -- if we enable it now, the minimum log size will decrease. If a corrected mkfs formats a filesystem with this new smaller log size, a user will encounter mount failures on an uncorrected kernel due to the larger minimum log size computations there. Therefore, turn this on for parent pointers because it wasn't merged at all upstream when this issue was discovered. Signed-off-by: Darrick J. Wong Reviewed-by: Allison Henderson Reviewed-by: Christoph Hellwig --- fs/xfs/libxfs/xfs_log_rlimit.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/fs/xfs/libxfs/xfs_log_rlimit.c b/fs/xfs/libxfs/xfs_log_rlimit.c index 9975b93a7412d..3518d5e21df03 100644 --- a/fs/xfs/libxfs/xfs_log_rlimit.c +++ b/fs/xfs/libxfs/xfs_log_rlimit.c @@ -16,6 +16,29 @@ #include "xfs_bmap_btree.h" #include "xfs_trace.h" +/* + * Shortly after enabling the large extents count feature in 2023, longstanding + * bugs were found in the code that computes the minimum log size. Luckily, + * the bugs resulted in over-estimates of that size, so there's no impact to + * existing users. However, we don't want to reduce the minimum log size + * because that can create the situation where a newer mkfs writes a new + * filesystem that an older kernel won't mount. + * + * Therefore, we only may correct the computation starting with filesystem + * features that didn't exist in 2023. In other words, only turn this on if + * the filesystem has parent pointers. + * + * This function can be called before the XFS_HAS_* flags have been set up, + * (e.g. mkfs) so we must check the ondisk superblock. + */ +static inline bool +xfs_want_minlogsize_fixes( + struct xfs_sb *sb) +{ + return xfs_sb_is_v5(sb) && + xfs_sb_has_incompat_feature(sb, XFS_SB_FEAT_INCOMPAT_PARENT); +} + /* * Calculate the maximum length in bytes that would be required for a local * attribute value as large attributes out of line are not logged. @@ -31,6 +54,15 @@ xfs_log_calc_max_attrsetm_res( MAXNAMELEN - 1; nblks = XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK); nblks += XFS_B_TO_FSB(mp, size); + + /* + * If the feature set is new enough, correct a unit conversion error in + * the xattr transaction reservation code that resulted in oversized + * minimum log size computations. + */ + if (xfs_want_minlogsize_fixes(&mp->m_sb)) + 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 Wed Apr 10 01:01:35 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13623411 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6F340621 for ; Wed, 10 Apr 2024 01:01:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712710896; cv=none; b=RC+WjEdAm4uOWaHcl2ajdJvz6tFESc0GK3FlAYEOv7oHsSKcxA+zjg07uWnJlIQUVtAilHtCwvNe9WoCDR4H+V10t2GmjviK4d1ga0nJGVwXAfpa/beev2oOSTH4HF9wIVTcjTZgM0pV5FjohPozXdGLp3m5YvYBrjp0bAEEt2Q= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712710896; c=relaxed/simple; bh=a44EIScXpHqAYmMge+z4VGTetNu72SJqVZnLBAQHNAM=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=LDi4FLBNGNoIlJBcUydLAE9fHzKBuyYM6uDPootLaye4e6TjD4BNOLqHotEVxuWvZ/dATdCJRLHxI5QlUuDZPktmBKz0NIgcF+nJ03sKNG6DPJSpEuLybf1MiO0xS7mK3YaANwqi0VBNktnn+bSrtCvFbweDpvtDYlpz9Lz+Hz8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=YK+rTSEC; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="YK+rTSEC" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 44305C433F1; Wed, 10 Apr 2024 01:01:36 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1712710896; bh=a44EIScXpHqAYmMge+z4VGTetNu72SJqVZnLBAQHNAM=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=YK+rTSEC4yIcmkO7j1iVolkFW9Zmklxe0Ps0+hudZg0HElDr+xAtYnqDtjlAW48QG mNwxAG6zt0MirV5rw/uSM+8HwFUzK2dVCW9iDDJFrtbJi3RD4SmQnrrZ/uwFvi2hXV ePSU18c0tlInZQzCXjjo+15IyMCRIF3G7jc5XSLHw9C0QCRZVtxixMLEfvyy+JDasc mkgMwOH8kHExF+dZN6RTTdwNZTyzGocNYSkaEDabnRCCkL7pP1o1k0AHRLArtQGviQ X0qnlGTfZwNBlSG8zfeHMkOwJaBRf6FVFmQIWL5OmdKmOMdLw/AGHABAWcDJ/ImN+3 jkb7OgiXvQA0A== Date: Tue, 09 Apr 2024 18:01:35 -0700 Subject: [PATCH 31/32] xfs: drop compatibility minimum log size computations for reflink From: "Darrick J. Wong" To: djwong@kernel.org Cc: Allison Henderson , catherine.hoang@oracle.com, hch@lst.de, allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <171270970075.3631889.13494808585016033882.stgit@frogsfrogsfrogs> In-Reply-To: <171270969477.3631889.12488500941186994317.stgit@frogsfrogsfrogs> References: <171270969477.3631889.12488500941186994317.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Let's also drop the oversized minimum log computations for reflink and rmap that were the result of bugs introduced many years ago. Signed-off-by: Darrick J. Wong Reviewed-by: Allison Henderson Reviewed-by: Christoph Hellwig --- fs/xfs/libxfs/xfs_log_rlimit.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/fs/xfs/libxfs/xfs_log_rlimit.c b/fs/xfs/libxfs/xfs_log_rlimit.c index 3518d5e21df03..d3bd6a86c8fe9 100644 --- a/fs/xfs/libxfs/xfs_log_rlimit.c +++ b/fs/xfs/libxfs/xfs_log_rlimit.c @@ -24,6 +24,11 @@ * because that can create the situation where a newer mkfs writes a new * filesystem that an older kernel won't mount. * + * Several years prior, we also discovered that the transaction reservations + * for rmap and reflink operations were unnecessarily large. That was fixed, + * but the minimum log size computation was left alone to avoid the + * compatibility problems noted above. Fix that too. + * * Therefore, we only may correct the computation starting with filesystem * features that didn't exist in 2023. In other words, only turn this on if * the filesystem has parent pointers. @@ -80,6 +85,15 @@ xfs_log_calc_trans_resv_for_minlogblocks( { unsigned int rmap_maxlevels = mp->m_rmap_maxlevels; + /* + * If the feature set is new enough, drop the oversized minimum log + * size computation introduced by the original reflink code. + */ + if (xfs_want_minlogsize_fixes(&mp->m_sb)) { + 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 Wed Apr 10 01:01:51 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13623412 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 231DF818 for ; Wed, 10 Apr 2024 01:01:52 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712710912; cv=none; b=c6EX/qbqRhf0A3DbFeFsJWceGjJJWDsQoC4QXjPja7smY1hTUf50lmVAbCxHZaWy9c9F0rHofiqvzisgP6HvHWmdXB3FWr1TAA1016WiWpFG+QvD8H/ISxTFPdgQJCRvH6yXX9tZvG4qhRdGjNjh9ystewirsW3V4Bxc0GAY+l8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712710912; c=relaxed/simple; bh=Vh0g21My62IAb/SmyG4ANLlu3Q/qVbU4YFw4EOLqXmo=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=GkO/ZTvb86G+YHh3AdxeRTlMJc9Jixafti+seUa0f42OvwCeuCeKRiEmra7mSKcyov8hCXKhizD+rnkW15bJAWnWSt+KwPCXf1/b2LrbSiE0fOC15uzukXniKjAfQhzaTsPsHFHLXEwxnGjDHWpwr6G1MbaLLl/oI/4UQmsY3vQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=ZWOZzyQZ; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="ZWOZzyQZ" Received: by smtp.kernel.org (Postfix) with ESMTPSA id EAE62C433C7; Wed, 10 Apr 2024 01:01:51 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1712710912; bh=Vh0g21My62IAb/SmyG4ANLlu3Q/qVbU4YFw4EOLqXmo=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=ZWOZzyQZzUxASFbPM2cxKGdq8dmGPoVKjI7qOc8ghVyffw4DR4SiKfThNAlMYP5fZ pBxIixVfJt8s9WeYDEgA76hLJZ6wxweozZg4Vk58oCADwe3Wxc1r/bT+4HdJE3+toH ZBP/+agJqXqZbL8Z06mDOw1xv6ipv5zts/b2oTp9359jjRR/cekkgv5a2xuinE/Tva uTDDt58BBsJ8YAr4KxMyTr6AAUz/TJx1eO6kKtjHo9jn3824AcQmlM390YSFQjifvq xW8sUVxpc77S9NuStzlWEWzKucVZWhFcoP6MIkveM9ypFZaGG4Iybfl6pqEZs0i0hi CcA4NjCKsGPFA== Date: Tue, 09 Apr 2024 18:01:51 -0700 Subject: [PATCH 32/32] xfs: enable parent pointers From: "Darrick J. Wong" To: djwong@kernel.org Cc: catherine.hoang@oracle.com, hch@lst.de, allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <171270970091.3631889.3723065069358160559.stgit@frogsfrogsfrogs> In-Reply-To: <171270969477.3631889.12488500941186994317.stgit@frogsfrogsfrogs> References: <171270969477.3631889.12488500941186994317.stgit@frogsfrogsfrogs> User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Add parent pointers to the list of supported features. Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig --- fs/xfs/libxfs/xfs_format.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h index b457e457e1f71..61f51becff4f7 100644 --- a/fs/xfs/libxfs/xfs_format.h +++ b/fs/xfs/libxfs/xfs_format.h @@ -382,7 +382,8 @@ xfs_sb_has_ro_compat_feature( XFS_SB_FEAT_INCOMPAT_BIGTIME | \ XFS_SB_FEAT_INCOMPAT_NEEDSREPAIR | \ XFS_SB_FEAT_INCOMPAT_NREXT64 | \ - XFS_SB_FEAT_INCOMPAT_EXCHRANGE) + XFS_SB_FEAT_INCOMPAT_EXCHRANGE | \ + XFS_SB_FEAT_INCOMPAT_PARENT) #define XFS_SB_FEAT_INCOMPAT_UNKNOWN ~XFS_SB_FEAT_INCOMPAT_ALL static inline bool