From nobody Sat Jul 25 04:54:16 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (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 78B71344D92; Fri, 17 Jul 2026 16:53:06 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784307187; cv=none; b=S02RuQHegBLDGkouxTvA5OfEme2BxEPPQDrH/pyDPCP2k2DSJBFlhoAnLZGyIIi5H+rOmyAlvhAitpbtrgeg/WOl6YoYuoOlJRr7UIWm71wSgAj1jYJd7Ua74bIpf7MoeRZxrFDNEM/otjJ5bfOQ8t37FU0bKb8HNpnn6ZhhiRI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784307187; c=relaxed/simple; bh=NdKAuaLuNewy/k63oi5OEDmdnoEMQaYx06SVbYpFGMs=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=mAkw7VhP5UIs7NWo6ItL0dRbF7MfRgeDDuOCbw6U29qLOsndabsKwY6bwFikpw2fuSxzEC2r82+FzQk7qVYlWht3cNbRuyJ9WiKbkMHZe8iuZilDQBiQcmdlRffvWZN8abIfojM+HQsG6Ij1LUBemfTWrBerw0CotH7Ua6hYFrw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=VHy4Gst6; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="VHy4Gst6" Received: by smtp.kernel.org (Postfix) with ESMTPSA id E176C1F00A3D; Fri, 17 Jul 2026 16:53:05 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1784307186; bh=chNnEUS4ou1ewRr5tiT5ffA/oK+d9tifbMacz+ARlPk=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=VHy4Gst6qim3PoxXrlkcQdv8iWEI+CusiRKKwfSlfYoFTJADPluWZJgku9QUd25RC NU4b+RKNSF8Va+qCTLaFpKWu3GeJzEDLBenMLMkRMn7qaek841qELSrB75W9+C5rsp oBPIhv74YRu2HE8cbVppPdeMhZJAecythOxT1omH/P0zxmLy03t16wCTZWlaim6cT9 H6yaMInFUS9KaW9vBDTtcAzB6rPtozGpP8PcI715MXxP8rcH3Op7vYYVEoUZdCpwuv EUcsadqaXtUA8bg383nn5LPz7iuNqFb+0laZB1iRUMyA7i22zYPPj6QaLe0eRDMkDs qsebzJ20TadPA== From: Jeff Layton Date: Fri, 17 Jul 2026 12:52:36 -0400 Subject: [PATCH 1/4] btrfs: split btrfs_insert_delayed_dir_index() into prealloc and commit phases Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260717-btrfs-enomem-v1-1-cdc9c0e265d0@kernel.org> References: <20260717-btrfs-enomem-v1-0-cdc9c0e265d0@kernel.org> In-Reply-To: <20260717-btrfs-enomem-v1-0-cdc9c0e265d0@kernel.org> To: Chris Mason , David Sterba Cc: linux-btrfs@vger.kernel.org, linux-kernel@vger.kernel.org, kernel-team@fb.com, Jeff Layton X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=8189; i=jlayton@kernel.org; h=from:subject:message-id; bh=NdKAuaLuNewy/k63oi5OEDmdnoEMQaYx06SVbYpFGMs=; b=owEBbQKS/ZANAwAKAQAOaEEZVoIVAcsmYgBqWl3v52jA/vgS/n1Zp/BrUG7LRkB+sl0A1/Sux tNzRRNxxOGJAjMEAAEKAB0WIQRLwNeyRHGyoYTq9dMADmhBGVaCFQUCalpd7wAKCRAADmhBGVaC FUPgD/sE0B06KoUGFgIf1v3+epAUTW+I77MhDtYEQG+9+4Lhg2570qhxGOm0TkHInX3VuM+vV7V PkPxaDKdq8/WarpnPx3v2tLdYf4TDlo8W1pBASqn24E1bUzzME05eOnT0uidbEiuNkIJ4nnI0as 9YBTzs8uXPrNGzM6sWzDnW8E2Bn8mijePQls/yOpa38izfJMWwIuTSDpBNCWMme8arGC613y6EO AaXpoF3Jn7D40EiRDMC/1/c438LyqsX154ssywq+GpySiBshAPXq92ZiF8LgiV4qSrB6wEWMX44 o9mkz3bLpRA8v3BqsrPkpFwJ80TEa90iWVUl7zss7ZQqoVX5WWjdvwI5MIVD4n3qEKH29y6SJre XA8rGPHBV+PXf/rjF/1ybMSMT/HbbP0XJN31dx0CXAKLVumMb12NkucROfuyqkR3o2Rdk8BQJEh Omdli/hRxpHQLy7zdPGgDkaj4UrR0wVmrNxLx6llKriC4IIh4Ls19Bkq1tXO1/mo0xjW8npMZ1r M9Wkbd6t5wH04icpF0lBHuoQ0MFNZwf/KzN0RtcQtusStUgGw/lFfV9cYi/d4/GoVsnIpb0Lf39 nartylHWS91Kaxlzr72AGdqVL3vKkb2ssAkSu6sR7GUa2c07or3JeFTZK/GlEZotZN5L9aOa0jl /0rYlVk+csJ5GUg== X-Developer-Key: i=jlayton@kernel.org; a=openpgp; fpr=4BC0D7B24471B2A184EAF5D3000E684119568215 Split btrfs_insert_delayed_dir_index() into three functions using a new btrfs_dir_index_prealloc struct to bundle the pre-allocated resources: - btrfs_prealloc_delayed_dir_index(): performs the two GFP_NOFS allocations (delayed node + delayed item) that can fail with -ENOMEM. - btrfs_insert_delayed_dir_index_prealloc(): populates the item data, inserts into the rb-tree, and reserves metadata space. Cannot fail with -ENOMEM since all allocations were done in the prealloc step. - btrfs_free_delayed_dir_index_prealloc(): frees pre-allocated resources when the caller's btree insertion fails. The original btrfs_insert_delayed_dir_index() is refactored into a thin wrapper that calls the prealloc and commit functions. This split allows callers to move the fallible memory allocations before the point of no return (the DIR_ITEM btree insertion), so that -ENOMEM can be returned cleanly without aborting the transaction. Assisted-by: LLM Signed-off-by: Jeff Layton --- fs/btrfs/delayed-inode.c | 109 ++++++++++++++++++++++++++++++++++++-------= ---- fs/btrfs/delayed-inode.h | 17 ++++++++ 2 files changed, 102 insertions(+), 24 deletions(-) diff --git a/fs/btrfs/delayed-inode.c b/fs/btrfs/delayed-inode.c index 09795439b9fb..9d7343934eea 100644 --- a/fs/btrfs/delayed-inode.c +++ b/fs/btrfs/delayed-inode.c @@ -1469,35 +1469,73 @@ static void btrfs_release_dir_index_item_space(stru= ct btrfs_trans_handle *trans) trans->bytes_reserved -=3D bytes; } =20 -/* Will return 0, -ENOMEM or -EEXIST (index number collision, unexpected).= */ -int btrfs_insert_delayed_dir_index(struct btrfs_trans_handle *trans, - const char *name, int name_len, - struct btrfs_inode *dir, - const struct btrfs_disk_key *disk_key, u8 flags, - u64 index) +/* + * Pre-allocate a delayed node and delayed item for a dir index insertion. + * Call this before modifying the btree so that ENOMEM can be returned + * before any on-disk state has changed. + * + * Returns 0 on success, -ENOMEM on allocation failure. + */ +int btrfs_prealloc_delayed_dir_index(struct btrfs_inode *dir, + const char *name, int name_len, + struct btrfs_dir_index_prealloc *prealloc) +{ + struct btrfs_delayed_node *node; + struct btrfs_delayed_item *item; + + node =3D btrfs_get_or_create_delayed_node(dir, &prealloc->tracker); + if (IS_ERR(node)) + return PTR_ERR(node); + + item =3D btrfs_alloc_delayed_item(sizeof(struct btrfs_dir_item) + name_le= n, + node, BTRFS_DELAYED_INSERTION_ITEM); + if (!item) { + btrfs_release_delayed_node(node, &prealloc->tracker); + return -ENOMEM; + } + + prealloc->node =3D node; + prealloc->item =3D item; + return 0; +} + +/* + * Free resources from btrfs_prealloc_delayed_dir_index() when the btree + * insertion failed and we will not commit the delayed dir index. + */ +void btrfs_free_delayed_dir_index_prealloc(struct btrfs_trans_handle *tran= s, + struct btrfs_dir_index_prealloc *prealloc) { + btrfs_release_delayed_item(prealloc->item); + btrfs_release_dir_index_item_space(trans); + btrfs_release_delayed_node(prealloc->node, &prealloc->tracker); +} + +/* + * Commit a pre-allocated delayed dir index item. The delayed node and item + * must have been returned by btrfs_prealloc_delayed_dir_index(). This + * populates the item, adds it to the delayed node's rb-tree, and reserves + * metadata space. It cannot fail with ENOMEM. + * + * Will return 0 or -EEXIST (index number collision, unexpected). + */ +int btrfs_insert_delayed_dir_index_prealloc(struct btrfs_trans_handle *tra= ns, + struct btrfs_inode *dir, + struct btrfs_dir_index_prealloc *prealloc, + const struct btrfs_disk_key *disk_key, + u8 flags, u64 index) +{ + struct btrfs_delayed_node *delayed_node =3D prealloc->node; + struct btrfs_ref_tracker *tracker =3D &prealloc->tracker; + struct btrfs_delayed_item *delayed_item =3D prealloc->item; struct btrfs_fs_info *fs_info =3D trans->fs_info; const unsigned int leaf_data_size =3D BTRFS_LEAF_DATA_SIZE(fs_info); - struct btrfs_delayed_node *delayed_node; - struct btrfs_ref_tracker delayed_node_tracker; - struct btrfs_delayed_item *delayed_item; + const int name_len =3D delayed_item->data_len - sizeof(struct btrfs_dir_i= tem); struct btrfs_dir_item *dir_item; bool reserve_leaf_space; u32 data_len; int ret; =20 - delayed_node =3D btrfs_get_or_create_delayed_node(dir, &delayed_node_trac= ker); - if (IS_ERR(delayed_node)) - return PTR_ERR(delayed_node); - - delayed_item =3D btrfs_alloc_delayed_item(sizeof(*dir_item) + name_len, - delayed_node, - BTRFS_DELAYED_INSERTION_ITEM); - if (!delayed_item) { - ret =3D -ENOMEM; - goto release_node; - } - delayed_item->index =3D index; =20 dir_item =3D (struct btrfs_dir_item *)delayed_item->data; @@ -1506,7 +1544,7 @@ int btrfs_insert_delayed_dir_index(struct btrfs_trans= _handle *trans, btrfs_set_stack_dir_data_len(dir_item, 0); btrfs_set_stack_dir_name_len(dir_item, name_len); btrfs_set_stack_dir_flags(dir_item, flags); - memcpy((char *)(dir_item + 1), name, name_len); + /* Name was already copied into delayed_item->data by the caller. */ =20 data_len =3D delayed_item->data_len + sizeof(struct btrfs_item); =20 @@ -1524,7 +1562,9 @@ int btrfs_insert_delayed_dir_index(struct btrfs_trans= _handle *trans, if (unlikely(ret)) { btrfs_err(trans->fs_info, "error adding delayed dir index item, name: %.*s, index: %llu, root: %llu,= dir: %llu, dir->index_cnt: %llu, delayed_node->index_cnt: %llu, error: %d", - name_len, name, index, btrfs_root_id(delayed_node->root), + name_len, + (const char *)(dir_item + 1), + index, btrfs_root_id(delayed_node->root), delayed_node->inode_id, dir->index_cnt, delayed_node->index_cnt, ret); btrfs_release_delayed_item(delayed_item); @@ -1562,10 +1602,31 @@ int btrfs_insert_delayed_dir_index(struct btrfs_tra= ns_handle *trans, mutex_unlock(&delayed_node->mutex); =20 release_node: - btrfs_release_delayed_node(delayed_node, &delayed_node_tracker); + btrfs_release_delayed_node(delayed_node, tracker); return ret; } =20 +/* Will return 0, -ENOMEM or -EEXIST (index number collision, unexpected).= */ +int btrfs_insert_delayed_dir_index(struct btrfs_trans_handle *trans, + const char *name, int name_len, + struct btrfs_inode *dir, + const struct btrfs_disk_key *disk_key, u8 flags, + u64 index) +{ + struct btrfs_dir_index_prealloc prealloc; + int ret; + + ret =3D btrfs_prealloc_delayed_dir_index(dir, name, name_len, &prealloc); + if (ret) + return ret; + + memcpy(prealloc.item->data + sizeof(struct btrfs_dir_item), name, + name_len); + + return btrfs_insert_delayed_dir_index_prealloc(trans, dir, &prealloc, + disk_key, flags, index); +} + static bool btrfs_delete_delayed_insertion_item(struct btrfs_delayed_node = *node, u64 index) { diff --git a/fs/btrfs/delayed-inode.h b/fs/btrfs/delayed-inode.h index fc752863f89b..e310a257c9a6 100644 --- a/fs/btrfs/delayed-inode.h +++ b/fs/btrfs/delayed-inode.h @@ -121,6 +121,23 @@ int btrfs_insert_delayed_dir_index(struct btrfs_trans_= handle *trans, const struct btrfs_disk_key *disk_key, u8 flags, u64 index); =20 +struct btrfs_dir_index_prealloc { + struct btrfs_delayed_node *node; + struct btrfs_ref_tracker tracker; + struct btrfs_delayed_item *item; +}; + +int btrfs_prealloc_delayed_dir_index(struct btrfs_inode *dir, + const char *name, int name_len, + struct btrfs_dir_index_prealloc *prealloc); +void btrfs_free_delayed_dir_index_prealloc(struct btrfs_trans_handle *tran= s, + struct btrfs_dir_index_prealloc *prealloc); +int btrfs_insert_delayed_dir_index_prealloc(struct btrfs_trans_handle *tra= ns, + struct btrfs_inode *dir, + struct btrfs_dir_index_prealloc *prealloc, + const struct btrfs_disk_key *disk_key, + u8 flags, u64 index); + int btrfs_delete_delayed_dir_index(struct btrfs_trans_handle *trans, struct btrfs_inode *dir, u64 index); =20 --=20 2.55.0 From nobody Sat Jul 25 04:54:16 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (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 6C9323ECBE2; Fri, 17 Jul 2026 16:53:07 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784307188; cv=none; b=Y6FaIht5P5xymUatAFuoNHWFECXN85WIkBTd8T6VRup6St7Knk5TSG07r1JXlS0Mop22bRq2ljeOcnf5V6szpjzwzYKmYrYnbT+WPAjluQn4QV4XKycpuXlH2H8oVOmIl+FrmrVTeaEU9jEo1y9m101dwG+h4rKdjS0jF61XqYk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784307188; c=relaxed/simple; bh=MxdERwye36AER3QylwxpVQ26/YFmLLKDtHNFy+corwE=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=hrXRQBP/8fINFCqTfM5cayynVUYDLejeUC1Lv52sPhTP+OOwfs/IGTiQcAxBlPSHTVhMG6MhP7RsmL379vhL9YmOzP8q9T4i1xJSXyADGZX42aSB5FSCC2ZoykeFnfMPIpm2A/vJwUccUj6BbZ4vGitCrJ70sY/UbHxcJKRa3tY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=X6K8boQS; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="X6K8boQS" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 93C7D1F00A3E; Fri, 17 Jul 2026 16:53:06 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1784307187; bh=Mwqk2zH3wC+9JE29CQ0H0khHk9v+glGkYTbNuXjg0S8=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=X6K8boQScxsUTPAw1G7TpAovoSVvTwuF3fGR6o4WqEEdBk89VOydJm6hRCuQbZTAx YRGrgyIaNVt3oEpI0zDaRGC/QX694rUK6UqTCEawQR1WcM/NjO3XUc+lNb97z4Gckw DCD6Fftxregf4PdFY/nmNgBqWIvd7O2IQnSEPZiT2ekPbbN5c4tz2jKa8yt4Xv6PkO eI06y5hcWVYMYLAsmKUb0dQnRrC+KFvuzB65keas6cuDDmsQSSPeZDVxgYCR2NbNce 1pHAgmmUWN0A58ZrLhGpBVhduW09clkZGN9dlKR+3uXCNESzjX/119uXqYQ3x2rY69 qX8gRwNqgJyKQ== From: Jeff Layton Date: Fri, 17 Jul 2026 12:52:37 -0400 Subject: [PATCH 2/4] btrfs: pre-allocate delayed dir index before btree modification Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260717-btrfs-enomem-v1-2-cdc9c0e265d0@kernel.org> References: <20260717-btrfs-enomem-v1-0-cdc9c0e265d0@kernel.org> In-Reply-To: <20260717-btrfs-enomem-v1-0-cdc9c0e265d0@kernel.org> To: Chris Mason , David Sterba Cc: linux-btrfs@vger.kernel.org, linux-kernel@vger.kernel.org, kernel-team@fb.com, Jeff Layton X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=5752; i=jlayton@kernel.org; h=from:subject:message-id; bh=MxdERwye36AER3QylwxpVQ26/YFmLLKDtHNFy+corwE=; b=owEBbQKS/ZANAwAKAQAOaEEZVoIVAcsmYgBqWl3wJBm3N3WjqyDid9ZEKOCShalFw2BlyS4+O kHfjg7n5P2JAjMEAAEKAB0WIQRLwNeyRHGyoYTq9dMADmhBGVaCFQUCalpd8AAKCRAADmhBGVaC FQvpEACwfjBz7GjPlfiP4hkrjsU0yl3JelC0Yebq25XfpCFw7qyEzMGoYDZ6RE5K+764/5kDG/x XT9AUNDNgDqw1MJWhBMjVr0OgBXOBC29sXiQ7vGfB2FIKUDFdKEryX/zsXpDaRIre5qVmkprJJx 453AP0pigkELHsSuU42Gp7CqYPgbeYcfNFx3vhmF22pON1G/YOEiOsTDjMP/GY/spzjXu+vE2R5 V9GadaiUMS3Y6fEVfuPHeMwQZJJgtldTlLTevDYyb/hW35HEj+9HAeUH1iOu0YbsG6OtAWYj2dF ww9BVTxyaC4BKFH6r8ffShzMPhvugChtW1dhDOO5pW8CQrFca1klbYYmUQIFPNceEAquBR89Ygl RBFKSeK+FoiyeV2OJ3mgiQy1GWDoyTgtoALinsvwTT1898ougqS/m4SNsTzHjVX+7xvUPEfn2KH tmp5shaa4MUGpaxQ9jwbsyODWh2E+7dTujo5m9eF7ThXBHkv6BZBwBfuVn70wwjtC+YJ/AVxe70 +LZ7aIOGlU4Cp5VpQIcazSMfrBiiEg46TODxzP9xsIyYoIGIASJIlMjG4rDWzwCjp2C5gMA3KUQ Le92NLXq5Vf0tdNT/Yqx9D9V7As8twp+KN2PRk8HFcNstkgZYUAlUYQILv2VCkiC+LeDW8h0ljI 3GQBt65s6lKcKjg== X-Developer-Key: i=jlayton@kernel.org; a=openpgp; fpr=4BC0D7B24471B2A184EAF5D3000E684119568215 Move the delayed dir index allocation in btrfs_insert_dir_item() before the insert_with_overflow() call that modifies the btree. Previously, the allocations happened after the DIR_ITEM was already inserted, meaning an ENOMEM failure left the btree in a partially-modified state that could only be resolved by aborting the transaction. With the pre-allocation, if the GFP_NOFS allocations fail, -ENOMEM is returned before any on-disk state has changed. The caller can then handle the error gracefully. If the btree insertion itself fails, the pre-allocated resources are freed. Add an optional caller-provided btrfs_dir_index_prealloc parameter to btrfs_insert_dir_item(). When non-NULL, ownership of the prealloc transfers to btrfs_insert_dir_item(). When NULL, it allocates internally. All existing callers pass NULL to preserve the current behavior. Assisted-by: LLM Signed-off-by: Jeff Layton --- fs/btrfs/dir-item.c | 30 ++++++++++++++++++++++++------ fs/btrfs/dir-item.h | 5 +++-- fs/btrfs/inode.c | 2 +- fs/btrfs/transaction.c | 2 +- 4 files changed, 29 insertions(+), 10 deletions(-) diff --git a/fs/btrfs/dir-item.c b/fs/btrfs/dir-item.c index 84f1c64423d3..1b956df2c571 100644 --- a/fs/btrfs/dir-item.c +++ b/fs/btrfs/dir-item.c @@ -106,8 +106,11 @@ int btrfs_insert_xattr_item(struct btrfs_trans_handle = *trans, * Will return 0 or -ENOMEM */ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, - const struct fscrypt_str *name, struct btrfs_inode *dir, - const struct btrfs_key *location, u8 type, u64 index) + const struct fscrypt_str *name, + struct btrfs_inode *dir, + const struct btrfs_key *location, u8 type, + u64 index, + struct btrfs_dir_index_prealloc *prealloc) { int ret =3D 0; int ret2 =3D 0; @@ -119,6 +122,8 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *tr= ans, struct btrfs_key key; struct btrfs_disk_key disk_key; u32 data_size; + const bool need_delayed_index =3D (root !=3D root->fs_info->tree_root); + struct btrfs_dir_index_prealloc local_prealloc; =20 key.objectid =3D btrfs_ino(dir); key.type =3D BTRFS_DIR_ITEM_KEY; @@ -130,6 +135,18 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *t= rans, =20 btrfs_cpu_key_to_disk(&disk_key, location); =20 + /* Pre-allocate the delayed dir index before modifying the btree. */ + if (need_delayed_index && !prealloc) { + ret =3D btrfs_prealloc_delayed_dir_index(dir, name->name, + name->len, + &local_prealloc); + if (ret) + return ret; + memcpy(local_prealloc.item->data + sizeof(struct btrfs_dir_item), + name->name, name->len); + prealloc =3D &local_prealloc; + } + data_size =3D sizeof(*dir_item) + name->len; dir_item =3D insert_with_overflow(trans, root, path, &key, data_size, name->name, name->len); @@ -137,6 +154,8 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *tr= ans, ret =3D PTR_ERR(dir_item); if (ret =3D=3D -EEXIST) goto second_insert; + if (need_delayed_index) + btrfs_free_delayed_dir_index_prealloc(trans, prealloc); goto out_free; } =20 @@ -154,15 +173,14 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *= trans, write_extent_buffer(leaf, name->name, name_ptr, name->len); =20 second_insert: - /* FIXME, use some real flag for selecting the extra index */ - if (root =3D=3D root->fs_info->tree_root) { + if (!need_delayed_index) { ret =3D 0; goto out_free; } btrfs_release_path(path); =20 - ret2 =3D btrfs_insert_delayed_dir_index(trans, name->name, name->len, dir, - &disk_key, type, index); + ret2 =3D btrfs_insert_delayed_dir_index_prealloc(trans, dir, prealloc, + &disk_key, type, index); out_free: if (ret) return ret; diff --git a/fs/btrfs/dir-item.h b/fs/btrfs/dir-item.h index e52174a8baf9..d7a7d0b66f37 100644 --- a/fs/btrfs/dir-item.h +++ b/fs/btrfs/dir-item.h @@ -16,9 +16,11 @@ struct btrfs_trans_handle; =20 int btrfs_check_dir_item_collision(struct btrfs_root *root, u64 dir_ino, const struct fscrypt_str *name); +struct btrfs_dir_index_prealloc; int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, const struct fscrypt_str *name, struct btrfs_inode *dir, - const struct btrfs_key *location, u8 type, u64 index); + const struct btrfs_key *location, u8 type, u64 index, + struct btrfs_dir_index_prealloc *prealloc); struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *tr= ans, struct btrfs_root *root, struct btrfs_path *path, u64 dir, @@ -53,5 +55,4 @@ static inline u64 btrfs_name_hash(const char *name, int l= en) { return crc32c((u32)~1, name, len); } - #endif diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 272598f6ae77..b7b4e6177135 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -6737,7 +6737,7 @@ int btrfs_add_link(struct btrfs_trans_handle *trans, return ret; =20 ret =3D btrfs_insert_dir_item(trans, name, parent_inode, &key, - btrfs_inode_type(inode), index); + btrfs_inode_type(inode), index, NULL); if (ret =3D=3D -EEXIST || ret =3D=3D -EOVERFLOW) goto fail_dir_item; else if (unlikely(ret)) { diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 8f9419728100..3a2d4520c79a 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c @@ -1886,7 +1886,7 @@ static noinline int create_pending_snapshot(struct bt= rfs_trans_handle *trans, =20 ret =3D btrfs_insert_dir_item(trans, &fname.disk_name, parent_inode, &key, BTRFS_FT_DIR, - index); + index, NULL); if (unlikely(ret)) { btrfs_abort_transaction(trans, ret); goto fail; --=20 2.55.0 From nobody Sat Jul 25 04:54:16 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (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 CEED442BC53; Fri, 17 Jul 2026 16:53:07 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784307188; cv=none; b=SOu/PlmQPZqdDVWYvgWPlz5+lrNqDWI2+VnXB+NBb+i70GwhHAhSwzlnhTCP+vs5ZyjyoYdIevuNpoKB34EnHL0Ya1ecNgTAgTwiglK5ZMutTb4in2iNZ+Tfjr60tQapCrwYqmRRAsfMcwq9iY+z3bJ1LxQWLPOhbPI3yGcIL/I= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784307188; c=relaxed/simple; bh=KxUpBjE7GkEdx2Qqgqyitbvr6gIa/qqxQ25dhmZMRY0=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=BIJ77gOLeRD7XI0HZCGAmgnV9QuUF4wg45dnPsMCOfiNFaFmPlBpoWIqcJk2KrOyWJbrqfWvPwBvBgQGB52q0+/9schqFap8ePmzax+ypn/5UdJhE4vyN35Yew22/6TsqlEgOjHPrPa5hp14W2ItbQZgapHhQmAaEU+yMQWOCmE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=EtNheuhu; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="EtNheuhu" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 462421F000E9; Fri, 17 Jul 2026 16:53:07 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1784307187; bh=+otu3tSxhx7AZpD7m5U/RbIcK04drt8wAOdP9GSvoSs=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=EtNheuhuZMmqYglBAN0iU6nyOudntdYJ1yikXm8U0lOhPe3wfl6yKeuYrA5D7jFW5 VU6ZLxX8FVVheeThSRHjS2BBuQLi9gD/opiuCsvdYeECCReSRE4CpxJhXIkLjf/+27 aXTLO0/EpXtd+B9Yr4l5JS6NPewYHSH26Hz7Da3eb0AD5/tBvPIK8x/zD1/9Mhp5Bm c/jszlugYKIB/l82s+m7Pyy4tPtk8xEF2rU2OF/axomcniQRpYroIIYr9iLrXyDekm 1u2T2e/NPor+bYG64PEh16A2181IiHt3GhQZ+cU8GMmzPeJNohv+kDWYSMCo4+yh7U idrn7Fzkbi6/g== From: Jeff Layton Date: Fri, 17 Jul 2026 12:52:38 -0400 Subject: [PATCH 3/4] btrfs: handle ENOMEM from btrfs_insert_dir_item() without aborting Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260717-btrfs-enomem-v1-3-cdc9c0e265d0@kernel.org> References: <20260717-btrfs-enomem-v1-0-cdc9c0e265d0@kernel.org> In-Reply-To: <20260717-btrfs-enomem-v1-0-cdc9c0e265d0@kernel.org> To: Chris Mason , David Sterba Cc: linux-btrfs@vger.kernel.org, linux-kernel@vger.kernel.org, kernel-team@fb.com, Jeff Layton X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=2498; i=jlayton@kernel.org; h=from:subject:message-id; bh=KxUpBjE7GkEdx2Qqgqyitbvr6gIa/qqxQ25dhmZMRY0=; b=owEBbQKS/ZANAwAKAQAOaEEZVoIVAcsmYgBqWl3wFMnxMX9gtEODcJiDSiLSbOh3LgWKm8foA ctbUjf50BeJAjMEAAEKAB0WIQRLwNeyRHGyoYTq9dMADmhBGVaCFQUCalpd8AAKCRAADmhBGVaC Fa9pD/0aZwcuPu7skU6agqHaXRHF0Cn2L5XbbiSyDpdeJtnFOcGxKGuJTp1OyyWnbHHH3+AzajY RHgaWZ3/y3HhK5KZ+uCguJ2QcZkLJL03ngEQBdJ6QnRETc39Zyumc/FohLhEMPZ3l2DHcvDJgUb RQYUBLTMFN9abBEb8K2eU9oddAMrTI3Tgi3NX1p0bRqqswjxgww3j8R93luGrCaEzyuls7grriM oARYta3FBXPtDMhzfPXo93dXP5fuoZe7aVnj5GuYzUwy7ubMWIt5fIOC0RfaL0TKoxmzm8W9kt9 Dl/34rw/Gdzc+OwYa182hjKCV7AjIxeeH9zX1cgZv4vygZUBL2nGiIHrrPU9348AY7c3oJ0KuY1 /stvub2TnF3XLHFYfkffK8DQ/6vF7LcG292z5qsuU+wh7ofO86AogaQ0tcPL1p1Mch6fiRm0dl2 0d8otYnLp17d5j20zHdxVgPdR6CoimeAB3x8wG421bAKnawCsekUj+VRZ6JAo6eQr+qxMd7unK2 HRDJp4Ug2/50Th40PsC0yjPI38yNdOYK4z64rkkVTlci1RrXWO5QBjjBtjCsB64knBdS0QRNLgH QI/OXcn5GY+vWQoiJQD/EJzPqWrOK50tpiNeFHyCusi6Xntg5+rFiSB1T1kvoWbBkAWZM8LSNnA S9blFEjXmzjK9Pw== X-Developer-Key: i=jlayton@kernel.org; a=openpgp; fpr=4BC0D7B24471B2A184EAF5D3000E684119568215 Now that btrfs_insert_dir_item() returns -ENOMEM before modifying the btree (thanks to delayed dir index pre-allocation), callers can handle ENOMEM gracefully instead of aborting the transaction. In btrfs_add_link(), add -ENOMEM to the set of recoverable errors alongside -EEXIST and -EOVERFLOW. The fail_dir_item cleanup path unwinds the inode_ref/root_ref and returns the error to userspace. In btrfs_create_new_inode(), when btrfs_add_link() fails with -ENOMEM, convert the newly-created inode into an orphan instead of aborting. This is done by clearing nlink and adding an orphan item, which ensures btrfs_evict_inode() will delete the INODE_ITEM and INODE_REF, and crash-recovery will clean it up via orphan processing. If btrfs_orphan_add() itself fails, we fall back to aborting. This turns a filesystem-killing transaction abort into a graceful -ENOMEM return to userspace for create(), mkdir(), mknod(), symlink(), and link() operations under memory pressure. Assisted-by: LLM Signed-off-by: Jeff Layton --- fs/btrfs/inode.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index b7b4e6177135..4d9947ae08f7 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -6676,7 +6676,20 @@ int btrfs_create_new_inode(struct btrfs_trans_handle= *trans, } else { ret =3D btrfs_add_link(trans, BTRFS_I(dir), BTRFS_I(inode), name, false, BTRFS_I(inode)->dir_index); - if (unlikely(ret)) { + if (ret =3D=3D -ENOMEM) { + /* + * The ENOMEM came before the DIR_ITEM was inserted, + * so the btree has our INODE_ITEM + INODE_REF but no + * directory entry. Convert this into an orphan so + * eviction (or crash-recovery) cleans up the inode. + */ + clear_nlink(inode); + ret =3D btrfs_orphan_add(trans, BTRFS_I(inode)); + if (unlikely(ret)) + btrfs_abort_transaction(trans, ret); + ret =3D -ENOMEM; + goto discard; + } else if (unlikely(ret)) { btrfs_abort_transaction(trans, ret); goto discard; } @@ -6738,7 +6751,7 @@ int btrfs_add_link(struct btrfs_trans_handle *trans, =20 ret =3D btrfs_insert_dir_item(trans, name, parent_inode, &key, btrfs_inode_type(inode), index, NULL); - if (ret =3D=3D -EEXIST || ret =3D=3D -EOVERFLOW) + if (ret =3D=3D -EEXIST || ret =3D=3D -EOVERFLOW || ret =3D=3D -ENOMEM) goto fail_dir_item; else if (unlikely(ret)) { btrfs_abort_transaction(trans, ret); --=20 2.55.0 From nobody Sat Jul 25 04:54:16 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (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 BF98E42DA5F; Fri, 17 Jul 2026 16:53:08 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784307190; cv=none; b=hOQ7QNxNBOWQYiEaa66DKNkgLCalZbwF/j7Mdtu5dEPPN0lxFcYMGpDlW8NLwfoXdgfCSLFf5U2N3DSvU5KyAF11fNMdH2BkW+hRXRFVIsOTn7uKK1X2V9qfAXE4htrvgyhiSEC8Zir5f1VKpXwfZZkDKlF1Mi0F3+v/T4sAeos= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784307190; c=relaxed/simple; bh=GiFkt3z4iWkrkW0beJu+hXDQGatXHi0Pk0MMlGkGZbg=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=L0uru1Cvsj0j8JE9btP8oAL5yHVbgCzrgvoaXVD6Rr24nrlpGcp2mI9iK53fbtBsNiOHiciGHdkE2wZyL3XHvBNcwHTlO0Wi1m5UgB1nEtPl5I0ZXLIdnvxkhjPUj0rrnS9Bzb/tP1R6a7M/6OvSKr1hjumK8ucU9ktRqaBRJ+8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=fvCv+b0r; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="fvCv+b0r" Received: by smtp.kernel.org (Postfix) with ESMTPSA id EC55A1F00A3D; Fri, 17 Jul 2026 16:53:07 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1784307188; bh=PCojI2O4xN+3K0m+1+ou+NHnFebGObdzYZMuDTbziz8=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=fvCv+b0rqLE8v/sWBt9PYNJbeCckhNd7AIiiRNarSUOfcq0Cl4xD5mU+ncj4Vs/md rMc8Zu7tuuYwHQg/KUANvlfUrpPYUQob0RClnQJotJT/zqCofofITSgwOBXojEF6yx FtqE/smsSiALGwkDkjDM7xJWUZbpgl/ZqauTQSmE/QdWF6bnT1OM7z6M6TokY7CbK6 2yLkXf+6wZFTYRnse442Ns7yZ0UHB+NG+hQcISXwKjXV1lncxTOeGeGbH6O9QrSKEN 0860f57yiFYM7YH5EBxBptlRRPagcqUAeEhoQbZyKBWw8JQ/PxbUC/bQJv1pKek9Hy ETKvz/1Z4zqEA== From: Jeff Layton Date: Fri, 17 Jul 2026 12:52:39 -0400 Subject: [PATCH 4/4] btrfs: pre-allocate delayed dir index for non-overwrite rename Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260717-btrfs-enomem-v1-4-cdc9c0e265d0@kernel.org> References: <20260717-btrfs-enomem-v1-0-cdc9c0e265d0@kernel.org> In-Reply-To: <20260717-btrfs-enomem-v1-0-cdc9c0e265d0@kernel.org> To: Chris Mason , David Sterba Cc: linux-btrfs@vger.kernel.org, linux-kernel@vger.kernel.org, kernel-team@fb.com, Jeff Layton X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=7257; i=jlayton@kernel.org; h=from:subject:message-id; bh=GiFkt3z4iWkrkW0beJu+hXDQGatXHi0Pk0MMlGkGZbg=; b=owEBbQKS/ZANAwAKAQAOaEEZVoIVAcsmYgBqWl3wFsdn2Yvj+T+zTE/iLBeX/f+ys/hHqr1JR kwb+oaD9YiJAjMEAAEKAB0WIQRLwNeyRHGyoYTq9dMADmhBGVaCFQUCalpd8AAKCRAADmhBGVaC FRuDD/wK6+Q9n8eW02QzFdLbK8nn3MNSIFdecU+fLX5CMuZrANw04yjxzlZfd4k/z/D3kzBX4Kw 1LGloCxb0yUDi8ZKYVgembPsDS5n/HAywikQKXy4XGrhiD5biC/Zfuz3bZBdPTse0Readf3qcEp FYRR34wD1le4I+NiTM1YIZDRu5J4XV/UOaza5onDGMgzFBZTnpP3aZL3SN/APXhVseZXi7UDNpT lnjFLBOYuBjBQB2rtBtVvxCum2MJqYC0pOEzwOsJyKevsnE8KZQ8hL8UAA7/X8W8gg/U+j6aSgv WqZm6/dr4NFP8+G8x9Nz1ZPQu6u5bmI5gUG/aH4gdyXc7wgzL1otDJ1eACBmrglYSEVgoieJa31 YhrvbWTSVdFJa5VH7qUTbkTckfa2xndTIyjfEHJpuxkLJA0JnnJaGv5qzFdwrIJ78R0fPR6F9tQ vJL1qxDHlxx/P+WyGYh0kzpgugZODhRuplet2m48z/FPB880OWVNMzFR3OD4SDlq/QxzCYOGag3 HQL5ZgXoykeF+kkZa3s4xmcCiNVyr9ATiQmI9yu+x0+dU/8jtApraogM55ihiX88/b5lWcPqmBc djcZhVr98fMpQQTHFoOhO+o7vHPeRtCdF4FLJbxy/kKSvhMEsvWyIx9GFYFNIB9p9KoM2EO8PUk ivEd6h4y5lcv+/g== X-Developer-Key: i=jlayton@kernel.org; a=openpgp; fpr=4BC0D7B24471B2A184EAF5D3000E684119568215 For rename() without an overwrite target, pre-allocate the delayed dir index before any btree modifications so that ENOMEM can be returned before the source is unlinked from the old directory. Add a prealloc parameter to btrfs_add_link() that allows callers to pass pre-allocated delayed dir index resources. When provided, btrfs_add_link() takes ownership: it either passes the prealloc to btrfs_insert_dir_item() (which commits or frees it), or frees it on early error. All existing callers pass NULL to preserve the current behavior. In btrfs_rename(), when new_inode is NULL (no overwrite), call btrfs_prealloc_delayed_dir_index() before the first btree modification and pass the result through to btrfs_add_link(). If the prealloc fails, -ENOMEM is returned before any btree state has changed. For overwrite rename (new_inode !=3D NULL), the transaction still aborts on ENOMEM since earlier unlink operations have already made irreversible btree modifications. Assisted-by: LLM Signed-off-by: Jeff Layton --- fs/btrfs/btrfs_inode.h | 4 +++- fs/btrfs/inode.c | 43 +++++++++++++++++++++++++++++++++++-------- fs/btrfs/tree-log.c | 4 ++-- 3 files changed, 40 insertions(+), 11 deletions(-) diff --git a/fs/btrfs/btrfs_inode.h b/fs/btrfs/btrfs_inode.h index d5d81f9546c3..176648f6e7b6 100644 --- a/fs/btrfs/btrfs_inode.h +++ b/fs/btrfs/btrfs_inode.h @@ -523,9 +523,11 @@ int btrfs_set_inode_index(struct btrfs_inode *dir, u64= *index); int btrfs_unlink_inode(struct btrfs_trans_handle *trans, struct btrfs_inode *dir, struct btrfs_inode *inode, const struct fscrypt_str *name); +struct btrfs_dir_index_prealloc; int btrfs_add_link(struct btrfs_trans_handle *trans, struct btrfs_inode *parent_inode, struct btrfs_inode *inode, - const struct fscrypt_str *name, bool add_backref, u64 index); + const struct fscrypt_str *name, bool add_backref, u64 index, + struct btrfs_dir_index_prealloc *prealloc); int btrfs_delete_subvolume(struct btrfs_inode *dir, struct dentry *dentry); int btrfs_truncate_block(struct btrfs_inode *inode, u64 offset, u64 start,= u64 end); =20 diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 4d9947ae08f7..9a717d21f713 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -6675,7 +6675,7 @@ int btrfs_create_new_inode(struct btrfs_trans_handle = *trans, } } else { ret =3D btrfs_add_link(trans, BTRFS_I(dir), BTRFS_I(inode), name, - false, BTRFS_I(inode)->dir_index); + false, BTRFS_I(inode)->dir_index, NULL); if (ret =3D=3D -ENOMEM) { /* * The ENOMEM came before the DIR_ITEM was inserted, @@ -6720,7 +6720,8 @@ int btrfs_create_new_inode(struct btrfs_trans_handle = *trans, */ int btrfs_add_link(struct btrfs_trans_handle *trans, struct btrfs_inode *parent_inode, struct btrfs_inode *inode, - const struct fscrypt_str *name, bool add_backref, u64 index) + const struct fscrypt_str *name, bool add_backref, u64 index, + struct btrfs_dir_index_prealloc *prealloc) { int ret =3D 0; struct btrfs_key key; @@ -6746,11 +6747,14 @@ int btrfs_add_link(struct btrfs_trans_handle *trans, } =20 /* Nothing to clean up yet */ - if (ret) + if (ret) { + if (prealloc) + btrfs_free_delayed_dir_index_prealloc(trans, prealloc); return ret; + } =20 ret =3D btrfs_insert_dir_item(trans, name, parent_inode, &key, - btrfs_inode_type(inode), index, NULL); + btrfs_inode_type(inode), index, prealloc); if (ret =3D=3D -EEXIST || ret =3D=3D -EOVERFLOW || ret =3D=3D -ENOMEM) goto fail_dir_item; else if (unlikely(ret)) { @@ -6904,7 +6908,7 @@ static int btrfs_link(struct dentry *old_dentry, stru= ct inode *dir, inode_set_ctime_current(inode); =20 ret =3D btrfs_add_link(trans, BTRFS_I(dir), BTRFS_I(inode), - &fname.disk_name, true, index); + &fname.disk_name, true, index, NULL); if (ret) goto fail; =20 @@ -8311,14 +8315,14 @@ static int btrfs_rename_exchange(struct inode *old_= dir, } =20 ret =3D btrfs_add_link(trans, BTRFS_I(new_dir), BTRFS_I(old_inode), - new_name, false, old_idx); + new_name, false, old_idx, NULL); if (unlikely(ret)) { btrfs_abort_transaction(trans, ret); goto out_fail; } =20 ret =3D btrfs_add_link(trans, BTRFS_I(old_dir), BTRFS_I(new_inode), - old_name, false, new_idx); + old_name, false, new_idx, NULL); if (unlikely(ret)) { btrfs_abort_transaction(trans, ret); goto out_fail; @@ -8391,6 +8395,7 @@ static int btrfs_rename(struct mnt_idmap *idmap, struct inode *new_inode =3D d_inode(new_dentry); struct inode *old_inode =3D d_inode(old_dentry); struct btrfs_rename_ctx rename_ctx; + struct btrfs_dir_index_prealloc prealloc =3D { }; u64 index =3D 0; int ret; int ret2; @@ -8514,6 +8519,24 @@ static int btrfs_rename(struct mnt_idmap *idmap, if (ret) goto out_fail; =20 + /* + * When not overwriting an existing entry, pre-allocate the delayed + * dir index now so that ENOMEM is returned before any btree + * modifications. For the overwrite case, too many btree changes + * have already happened by the time btrfs_add_link() is called. + */ + if (!new_inode) { + ret =3D btrfs_prealloc_delayed_dir_index( + BTRFS_I(new_dir), + new_fname.disk_name.name, + new_fname.disk_name.len, + &prealloc); + if (ret) + goto out_fail; + memcpy(prealloc.item->data + sizeof(struct btrfs_dir_item), + new_fname.disk_name.name, new_fname.disk_name.len); + } + BTRFS_I(old_inode)->dir_index =3D 0ULL; if (unlikely(old_ino =3D=3D BTRFS_FIRST_FREE_OBJECTID)) { /* force full log commit if subvolume involved. */ @@ -8609,7 +8632,9 @@ static int btrfs_rename(struct mnt_idmap *idmap, } =20 ret =3D btrfs_add_link(trans, BTRFS_I(new_dir), BTRFS_I(old_inode), - &new_fname.disk_name, false, index); + &new_fname.disk_name, false, index, + prealloc.item ? &prealloc : NULL); + prealloc.item =3D NULL; if (unlikely(ret)) { btrfs_abort_transaction(trans, ret); goto out_fail; @@ -8634,6 +8659,8 @@ static int btrfs_rename(struct mnt_idmap *idmap, } } out_fail: + if (prealloc.item) + btrfs_free_delayed_dir_index_prealloc(trans, &prealloc); if (logs_pinned) { btrfs_end_log_trans(root); btrfs_end_log_trans(dest); diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 875e4ddc68ea..86a924d7cd43 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -1700,7 +1700,7 @@ static noinline int add_inode_ref(struct walk_control= *wc) } =20 /* insert our name */ - ret =3D btrfs_add_link(trans, dir, inode, &name, false, ref_index); + ret =3D btrfs_add_link(trans, dir, inode, &name, false, ref_index, NULL= ); if (ret) { btrfs_abort_log_replay(wc, ret, "failed to add link for inode %llu in dir %llu ref_index %llu name %.*s ro= ot %llu", @@ -2048,7 +2048,7 @@ static noinline int insert_one_name(struct btrfs_tran= s_handle *trans, return PTR_ERR(dir); } =20 - ret =3D btrfs_add_link(trans, dir, inode, name, true, index); + ret =3D btrfs_add_link(trans, dir, inode, name, true, index, NULL); =20 /* FIXME, put inode into FIXUP list */ =20 --=20 2.55.0