From nobody Fri Oct 2 06:17:34 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 D63E046D54C; Tue, 4 Aug 2026 15:44:49 +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=1785858291; cv=none; b=PF/3lOUhQD20Ad9An40ssfq/dvJni+KLlPfy1AN0g36lcoqvO3QQgqTZtws7ZO0mxKQpDrZRWtEJumdPbX0kg8Jsbu6qtO894N92LSnZ16toWlN6u1j8ZRRzjlmUpaDK1RdOOKxC9q+bil+cz0mbZMMlRwWc9gpmPgJ8d/di3zQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785858291; c=relaxed/simple; bh=JJLdQjp2qSQf0aItoG8nHyAXtBvLlBsw1sE1bdwEsZc=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=S3qrrgVRw/rsrDXr9A8TYNOBDRxTmsz2P+mpXxRTFrCnXl9CZKx5M3rYPuCqql+cBkSJ3DjixLvPjZ0XeJY4BqZc0ghjgB7eColOS1OXv8RwB37lwab5/LMnWIwbUT7L5YeZzIXuZd5RSC5JVc5zyMwL983dW01oixqnetoEdCg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=BULEJteY; 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="BULEJteY" Received: by smtp.kernel.org (Postfix) with ESMTPSA id EAB8E1F00A3D; Tue, 4 Aug 2026 15:44:48 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1785858289; bh=vYcEkLUykBWNnjCNZyZnh5ss9UkSISblO9GuleIRpL8=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=BULEJteYOPpne1BaRtT5B/DYRdoEXIFoP0SM5JXHGkdcJ0ozjsAEnh19baME7JvI7 YaCsyQr2iLLNUZvkISprYt+O8XlOQxVMduAQcEBz2eG2Yu/vmlmIxiKrE8edGi8M8C W/fH5MaGnTUiF1KiSxCRo5Z28c955aGiABvMyAFI4r2m4y7EqwctxYZmFNZXCCqY0T nuW5J0j2JoR/L4OX22723cPH5fd0Q1W6e3F21SixFmXgjk2mV7/ki8QrXutVOxAJPE Nrz1gG6cctJZOsYJtwaLqnAxC7df1AWacNuhJmhEXNs1EluT1JqwnK1T+FLRTCH67g t/o9L0ApwDDrQ== From: Jeff Layton Date: Tue, 04 Aug 2026 11:44:33 -0400 Subject: [PATCH v2 1/5] btrfs: use an on-stack path in btrfs_insert_orphan_item() 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: <20260804-btrfs-enomem-v2-1-4d923170e8c1@kernel.org> References: <20260804-btrfs-enomem-v2-0-4d923170e8c1@kernel.org> In-Reply-To: <20260804-btrfs-enomem-v2-0-4d923170e8c1@kernel.org> To: Chris Mason , David Sterba Cc: Qu Wenruo , 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=1322; i=jlayton@kernel.org; h=from:subject:message-id; bh=JJLdQjp2qSQf0aItoG8nHyAXtBvLlBsw1sE1bdwEsZc=; b=owEBbQKS/ZANAwAKAQAOaEEZVoIVAcsmYgBqcgjuSXbvF9GJBqepwDzeo5mDCPTE7cQqKloL9 TUi+4wrwjSJAjMEAAEKAB0WIQRLwNeyRHGyoYTq9dMADmhBGVaCFQUCanII7gAKCRAADmhBGVaC FZl1EACnMHSigGCM3nnJ4q2/tTl/umGx4TE91WdwgD9S/VLzqZt/o8Hl7wspnFJGGMCGwudUDgn VxqpfqdNG2/qSSHQdskoH3GYtlMGUCCMszGUSElSpoGkvAnT0nocfagSfiokMyE1TQMcT2hG4Cf MejGqOkkBCYRGFOu1COyrUKN7uN3CQLMBsRY3QZlpwqbsZrkhPYNadY4V+YzWDht/DL3izvKdIo jUqyW8pCUmiSMQyDeULmZTOdlskPRhf6Yra6S1qYrsPisV8eQ5WIo09IYFWN/6QeGeC7guzkoS4 gtfohAU/ZgUldq8A+HcDu0xbUUNyQN/1b78Y9V//gDA1MYnPGdnEXSv9hf+Oc8piEjOFF1nUQVi u5EuAyGUG35191422LERyUxhgVRAlkU3zpkKlwYZRe58Ow0jTJyNlS8DqK4rG/gmneEtjq1MVbP dH3CRkfXJztwQxA0rI45yJVhSeeUWjJxPwqjN6Ceefpay+eI3ZnhSCORDeGHukBKiimemk2YEn/ yHVHTNpCsWIyKAWbfSFZZPZbkQaE43E9NCl1uOwdtJawv71SxFImtQxB/8MFJj6WHmOCYjIiqOD XKz+NmO0ne4Imemra/Hrczxdvwt64TgJ+SpI+NLYf97+IWIjuCpsqjZXWUm4EnBzcZ2uW2gaZ4g X5eLv56kIVIg50A== X-Developer-Key: i=jlayton@kernel.org; a=openpgp; fpr=4BC0D7B24471B2A184EAF5D3000E684119568215 btrfs_insert_orphan_item() allocated a btrfs_path with btrfs_alloc_path() which returns -ENOMEM on failure. It is called from btrfs_orphan_add(), so a path allocation failure there turns a recoverable error into a transaction abort. btrfs_path is only ~112 bytes, so allocate it on the stack instead. Assisted-by: LLM Suggested-by: Qu Wenruo Signed-off-by: Jeff Layton Reviewed-by: Qu Wenruo --- fs/btrfs/orphan.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/fs/btrfs/orphan.c b/fs/btrfs/orphan.c index 9f3ad124104f..72e1adec39d8 100644 --- a/fs/btrfs/orphan.c +++ b/fs/btrfs/orphan.c @@ -9,18 +9,17 @@ int btrfs_insert_orphan_item(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 offset) { - BTRFS_PATH_AUTO_FREE(path); + struct btrfs_path path =3D { 0 }; struct btrfs_key key; + int ret; =20 key.objectid =3D BTRFS_ORPHAN_OBJECTID; key.type =3D BTRFS_ORPHAN_ITEM_KEY; key.offset =3D offset; =20 - path =3D btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - return btrfs_insert_empty_item(trans, root, path, &key, 0); + ret =3D btrfs_insert_empty_item(trans, root, &path, &key, 0); + btrfs_release_path(&path); + return ret; } =20 int btrfs_del_orphan_item(struct btrfs_trans_handle *trans, --=20 2.55.0 From nobody Fri Oct 2 06:17:34 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 A1BB14446ED; Tue, 4 Aug 2026 15:44:50 +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=1785858293; cv=none; b=V01J8WLvPS7zWtGeSDz4crZd9F6cnwDflREooq4oVIpQeEyzQNf7FgBNpev3SHAi1a2mUFRu9fcS+nU7uqynf0rDYQOmz+uRImeLULB0wFgmm1trb3cHY2t6AoZiB4vs6EyRNtoEJ1+hJrpc17bh4IHLmkZp6Gyp6WV3PqjeZBU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785858293; c=relaxed/simple; bh=SesH10CprPHiL4F/9NJfV1Bwr2tG3coz+xIULq2gPBA=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Fv4CYmneSTS3o0cjis2VcUR49eI2K+Y7AN7Mt8B8iQCDDeD+Ec6k8VbCJrLMRbTU8AioTVF7HrRTqN5M4i60PU5pjRjBC9yZCjFFWfvqTnrh6F1sSgYGHPu7ujMqnVwlxgTCigSu/F7W+zHj60zkk+/WzEwEnEyclXyw6t9yqNo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Fe1nhBYM; 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="Fe1nhBYM" Received: by smtp.kernel.org (Postfix) with ESMTPSA id B09531F00A3E; Tue, 4 Aug 2026 15:44:49 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1785858290; bh=Xrv4R7OK6OePmDuDYMrX2WVaMn0ORsRTONpLfBbBmUs=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=Fe1nhBYMEqA5LBa5/n4N8W9GuoclwIalM8PdmL1IblmnKQKnXHqD42VwgV9xj3Yvs P09JEtSqrXYZrgDmGCbI1V8vmsaHneC0GA6mWTKmBV3TLow8VlG1LaOLJ/Z4Qu2oyN ERNAb+fxgGS5kXX6Xo/JBY9XoQqEJGB4GgW1yX35tuyk6mC8WI0nTqluYqcaW1A1mx E0aqpPUlpriuL5PugTsaSNBnWsdAUxfUazjQSJnLdoWMszho+WN8ytORxxp2xcI5lA AD/KF+f/qDnehQM4Lrbl4tJu4gQ5Jn9jiqOVQwVQHGDT8ndjb7npArO947C7VvIgfn v86HechtTTSpQ== From: Jeff Layton Date: Tue, 04 Aug 2026 11:44:34 -0400 Subject: [PATCH v2 2/5] 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: <20260804-btrfs-enomem-v2-2-4d923170e8c1@kernel.org> References: <20260804-btrfs-enomem-v2-0-4d923170e8c1@kernel.org> In-Reply-To: <20260804-btrfs-enomem-v2-0-4d923170e8c1@kernel.org> To: Chris Mason , David Sterba Cc: Qu Wenruo , 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=8441; i=jlayton@kernel.org; h=from:subject:message-id; bh=SesH10CprPHiL4F/9NJfV1Bwr2tG3coz+xIULq2gPBA=; b=owEBbQKS/ZANAwAKAQAOaEEZVoIVAcsmYgBqcgjvA98ApuCVPY+vI5gP4js3uCo2AMP39insN mNR0/ESACSJAjMEAAEKAB0WIQRLwNeyRHGyoYTq9dMADmhBGVaCFQUCanII7wAKCRAADmhBGVaC Fcx5D/9jaYk1xeuMk4JBq+0LkunOypeeIisfkyHRi6b1Lf4QJStxqeeM+Es96REIsK295q61GqN oGqi1Tt43OPZAe4MLifUVaO5x31Htd/8ajlycNGejWc6d3tQ7C+bMdfJhVpoB9KD7Zb1ujIU6Jp KfrDG0CaFOegnmGWKq41CTC4vfFC8in2r9NFTCg4ChW5WMpK0IQPKh27vKbIDLSj6ed/vPlNsaa wgOaHXgvI7BoSbv9WZPYG0zmf86puFn3iRKnm87umvaCRW/VEj/Qqz8SQb2Sdhu+vsrKgE1Mjd6 nk28iFJp665+ADvw0BsVjQsKVNflE0CB521DwsbNL91PVRUpRrAFz2RfjPsNmo51MCnL2jqnxl0 iedsxvPy1ok9Sz1aTjvAc8HlK1osQe1gGUi7joWVn3ylkx7p9hHAg1zYlNETKDiKlb5OW888mXp wW2cl/IWGpO0ApIau7Dz/PcxoWOUidULQGt9PhqsMZWiWBy40tvTGOiQ+Va/Krpc1wN83zQbkoO ffn2x0Dt+BwMfpcy75jxI/Tt3y1tqFdnCDvy/KuU1y8V0Hq2AwN0Sb937Ux2r60JmaHck788i1W 1v+RiiQi5egXSEBq69dKPz8yWVtsnekkL5+AXWwSp4u/cHf17TGpksQTrioj62UUp5Uvl7MSYEC ds3OjAsYsI+qsCw== 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 Reviewed-by: Qu Wenruo --- fs/btrfs/delayed-inode.c | 111 +++++++++++++++++++++++++++++++++++++------= ---- fs/btrfs/delayed-inode.h | 17 ++++++++ 2 files changed, 104 insertions(+), 24 deletions(-) diff --git a/fs/btrfs/delayed-inode.c b/fs/btrfs/delayed-inode.c index db2ffab0941a..95d2dca80444 100644 --- a/fs/btrfs/delayed-inode.c +++ b/fs/btrfs/delayed-inode.c @@ -6,6 +6,7 @@ =20 #include #include +#include #include "ctree.h" #include "fs.h" #include "messages.h" @@ -1469,35 +1470,74 @@ 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; +} +ALLOW_ERROR_INJECTION(btrfs_prealloc_delayed_dir_index, ERRNO); + +/* + * 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 +1546,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 +1564,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: %pe= ", - 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, ERR_PTR(ret)); btrfs_release_delayed_item(delayed_item); @@ -1562,10 +1604,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 Fri Oct 2 06:17:34 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 5719B468C3A; Tue, 4 Aug 2026 15:44:51 +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=1785858293; cv=none; b=ZnPcoZdEzEAMKzFZ0hBsFfZEJIeZQBwcToDb37oKT9yX230pQ0RopfM5LWnNgFMyZt/DWaDFV7xNYgENO7snWX/R5gxGKyQ1x64zEK3LVtVrCg6nRb2hKMATZESK4+CqWAxesubTqdbIaD8lKCsqXhZSZxj/ROMRZXQPIwrNcL4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785858293; c=relaxed/simple; bh=Shkh1sZbKyWa3sAJXLyv+r0Hg/03/WIqVHZgJLk/lTs=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=pz2n4JsWPDPfkPD8AYT86kijnxGxBCPLEgALoCUKvfcCb/YjRO5YABAxiM+telUOlz58AjQNLAvt+1lZvK8A0RdAXh8HhNmdnqJQWNO/202qpf3ryUO8LBZk+f2efkUK7Y6kxYTay1TyYIJrdSkSgo7mZX0ip17gtPrbtaqTNK4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=HTyWexji; 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="HTyWexji" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 771B31F00AC4; Tue, 4 Aug 2026 15:44:50 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1785858291; bh=1U+cMeYTsqCxuW8znWLZHQCalgwOpdQYETdxwXVKlXA=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=HTyWexji/I3Fa+EIB3VOkuFfuGwEzgEex38p7pZhEjN3t5Z544NyEjPVDIWgYP/1z 9khVN71Kn8q/tnPAkF+IlCsbCtckTv9moy6d85RDK+bqH+g3zHw4z1ReiizZKSmQS/ 1R1x9uYjZiNzg/zNp+dK25ZSu2QFWJaI73rmKUMUWvqn3z4deh9Psw7ZbeVy5JO3LN ckIfUh0mDm2ICEzYXlxtoi81RdFLLEvzxGQN/EiM5CTN9lRdH3zKPbuI5j0vJG5511 xX8cb/94cyxaaB8FZD4imOQwnqdtz8Lp0IveK4Tc8Kp4bqbMUNdrnh0oYsg0H39NtG q2j1eHrQlUIRw== From: Jeff Layton Date: Tue, 04 Aug 2026 11:44:35 -0400 Subject: [PATCH v2 3/5] 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: <20260804-btrfs-enomem-v2-3-4d923170e8c1@kernel.org> References: <20260804-btrfs-enomem-v2-0-4d923170e8c1@kernel.org> In-Reply-To: <20260804-btrfs-enomem-v2-0-4d923170e8c1@kernel.org> To: Chris Mason , David Sterba Cc: Qu Wenruo , 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=7421; i=jlayton@kernel.org; h=from:subject:message-id; bh=Shkh1sZbKyWa3sAJXLyv+r0Hg/03/WIqVHZgJLk/lTs=; b=owEBbQKS/ZANAwAKAQAOaEEZVoIVAcsmYgBqcgjv3dX0MXN4GbiIJ7ZbFPdh4SGG7DrBISFQn HvBbqy0hjyJAjMEAAEKAB0WIQRLwNeyRHGyoYTq9dMADmhBGVaCFQUCanII7wAKCRAADmhBGVaC FRFFD/90GNYvnzA85ZxBzG3BEsFKN4TNIkTKOWdvo3aWru1iA4ECuxb6w17sGr3Gbrz00CecPc7 YMGzURbpEyk8ORkzdwnP7imCVMCzPg2Uz/rN7r6Ef9JGkq20mSPB6Ti26DmLuqtaKCGwNU5t1yk f2M0oWJJKmVDdur37nd035S1dmGZ2+J/2iMudYd7hg4g8X9uXiXtWH45WVs9/yG45z8gwTlTXrJ IaRzjenBKGmYIVSNLXZMAklK/dWhrx2oygTqPJhkXZcXgegLCYgxs2O1YmAJ9zVGfxaOTNCrDno 48FboI4tx14ExkCCbIIbMnGzwVoitMqwb9woYV46jloHhO2onwSB62NbS6f4fgfIiLsdFWMOqzs EWCNYLwnMVVvDMfwvE9aS2LRjkh3KjalMHQv4d0KCjQj+M2rsRg8SGtwxyYxgIVW2/PkWHMp7Po jUR7dnYtMITJPeysfFfktV8jHF8X2PGcNBGzf82uVgS1GILHxQS0GaOZhP8YRcKIxzzL4abUBiN MvgV/W3j6ynuOfv7NU5P80ZpsQL3qN6rYefhVDQv280vsNF2eUj+DgoEMWKIV7PXDnaD5IOSXww ghWRDuOD/TdXemnr9xwLqEIUs24U54yrSlxYAh+TqQmA2rzA2RF2o+BsI617fg2UwO+EAuF3CZM m7q60jEMzHB5NnA== 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. 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. Remove the btrfs_insert_delayed_dir_index() wrapper, as there are no more callers. Assisted-by: LLM Suggested-by: Qu Wenruo Signed-off-by: Jeff Layton --- fs/btrfs/delayed-inode.c | 21 --------------------- fs/btrfs/delayed-inode.h | 5 ----- fs/btrfs/dir-item.c | 30 ++++++++++++++++++++++++------ fs/btrfs/dir-item.h | 5 +++-- fs/btrfs/inode.c | 2 +- fs/btrfs/transaction.c | 2 +- 6 files changed, 29 insertions(+), 36 deletions(-) diff --git a/fs/btrfs/delayed-inode.c b/fs/btrfs/delayed-inode.c index 95d2dca80444..d9de7f269874 100644 --- a/fs/btrfs/delayed-inode.c +++ b/fs/btrfs/delayed-inode.c @@ -1608,27 +1608,6 @@ int btrfs_insert_delayed_dir_index_prealloc(struct b= trfs_trans_handle *trans, 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 e310a257c9a6..878d70aee2f9 100644 --- a/fs/btrfs/delayed-inode.h +++ b/fs/btrfs/delayed-inode.h @@ -115,11 +115,6 @@ struct btrfs_delayed_item { }; =20 void btrfs_init_delayed_root(struct btrfs_delayed_root *delayed_root); -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); =20 struct btrfs_dir_index_prealloc { struct btrfs_delayed_node *node; 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 3c10a0ef0002..3a2dca093c7d 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -6924,7 +6924,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 c641099d66e2..6fdfea5d35af 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c @@ -1882,7 +1882,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 Fri Oct 2 06:17:34 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 D9B6346D2DD; Tue, 4 Aug 2026 15:44:51 +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=1785858293; cv=none; b=mnTEJfuuZpl172mA7y6IaxpNLVmIrWPE9nOpTwYk6wJSdAsxaVt0u4lavpBjYqkeJvW76qVOehBXNHpgwxFqUbs2V3bHi0IzXYQ2LFP7u98C8QgrtVY8tRxBbWCmO6y5zfhBBwMEJnjZbM7PQx6EUc252+i0tYoN4RnVKvrdchs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785858293; c=relaxed/simple; bh=zQQV/u1yIfIRCr9Itdqa5ZvznM219db8HeXfOMO7EQ0=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=XaBQvGEBTilxOIg39Odij9NLqAg/h3vsFlTG65XYoiEoww/AEyuvBKhcbMFVKwrnS+w6qzC5Y6TeXAPaUIhjkErEzV85NDVVqE9aVhqIhBoQqLSQBYiE7SBCOhNb4PQ8A3RuFMKU3Qy8ijhT0JiHS4GVV3e1KFZA+8SdPy025/Q= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=lIJkWjy7; 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="lIJkWjy7" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 3CF211F000E9; Tue, 4 Aug 2026 15:44:51 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1785858291; bh=hDwRa6sFsazKkAZEv89WhYO4cShXG6abaHduCfbLYuQ=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=lIJkWjy7uOdBmc0jeJRNVV/4H5ylStzU8o0yNhueG5qZyskj8l/b4b77g9otcIjqH EnkXuKXxXcX+QlBKSZYt5baUp5SiHC7q2ygMMzzmnFiA3vdBxKiYu+No6tBzXrkNGA cLDNFxch05x73VkhDC0uCWt36n2EkcmDKyKSkYnWr4wVAm+uJaAspiQwnaAjRPmxZu hVQ2UJPq7vf1h7FMfHkeCNWLz3Cklbpc2czdtRn/ykWfeyXBoO7La8rlq4IrAnmzsQ jypWmXCRLSc736vS2n1HVE+I1FFesR3BUr4uHp7qrkrowQ49yb6tBUFQrxBI7/0aqJ MxjXV6QE0WkrQ== From: Jeff Layton Date: Tue, 04 Aug 2026 11:44:36 -0400 Subject: [PATCH v2 4/5] 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: <20260804-btrfs-enomem-v2-4-4d923170e8c1@kernel.org> References: <20260804-btrfs-enomem-v2-0-4d923170e8c1@kernel.org> In-Reply-To: <20260804-btrfs-enomem-v2-0-4d923170e8c1@kernel.org> To: Chris Mason , David Sterba Cc: Qu Wenruo , 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=1925; i=jlayton@kernel.org; h=from:subject:message-id; bh=zQQV/u1yIfIRCr9Itdqa5ZvznM219db8HeXfOMO7EQ0=; b=owEBbQKS/ZANAwAKAQAOaEEZVoIVAcsmYgBqcgjvUNJKRTDi4okqZFBAx3neIzUwHp7np12ed 8k9Dzxn0LWJAjMEAAEKAB0WIQRLwNeyRHGyoYTq9dMADmhBGVaCFQUCanII7wAKCRAADmhBGVaC FbiHEAC6l1bknkpcKePaa/VFRzYX76QrKl25L259mTD5+ieCauGyBEYfXbEb2c5xeaTAVlhKanp daofyNPqUBHFNAiZe+S6QT2Iq9uBfLgzv/k0n6tkYMd9uoxUYAZBk+1w61e5vxpTJCGp3552GMM KPR15DqGC99K+Oczt0zjWqMrnE9pVdKze0MHFx1axRiQ58pUrD/vutvX1WS2culk47+iCvCGXu7 fRQ1xcEzxNr2qpSs8VKkpB56HvpW8E9SHKsaOn5Do5xDgp/eEDlaJytkJvRsksE5oMocYXZgZ3o 0+TzmrTu+pzckLhkWR6AlYQ4AOYTgtxO5Psa/yW3KuOpWIQLXQ2AYV+gMS6SRztGHaOo3+TACPC 8vai6CuHkdIRa1DwEeRW5tC3iixqR98/OjNX2dFhb4qPqxJkoTsBBlNkHkdazQGmlCDQnyT8GAS zYIMznUYFYGFjlyEw0pqlC9KN/XDQ+x00f23kVJUaZ4Ea/W6Qz/0QsRemeY5enij6igZILUp4NX LpBQ0ue4v+Xll98bMxZVaQcAoWLuO174dPjHVjeSR/QxkAtef5L9jA8XP9ArbsVpDvzRjevzf+X CkM8I/aqIGarLWaS15waTOfRdK8GQ0D2UVB0KrOhuNGESnvOMfNNl229rfoLQiIEeOiHW9yM2eF /PrRwHTDex0w4Mw== 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. - btrfs_add_link(): add -ENOMEM to the recoverable errors alongside -EEXIST and -EOVERFLOW. - btrfs_create_new_inode(): on -ENOMEM from btrfs_add_link(), clear nlink and orphan the newly-created inode instead of aborting. This turns a filesystem-killing abort into a graceful -ENOMEM return for create(), mkdir(), mknod(), symlink(), and link() under memory pressure. Assisted-by: LLM Signed-off-by: Jeff Layton --- fs/btrfs/inode.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 3a2dca093c7d..99e990c592f6 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -6863,7 +6863,17 @@ 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) { + clear_nlink(inode); + /* + * btrfs_orphan_add() aborts the transaction itself if it + * fails, so only override ret to -ENOMEM on success. + */ + ret =3D btrfs_orphan_add(trans, BTRFS_I(inode)); + if (!ret) + ret =3D -ENOMEM; + goto discard; + } else if (unlikely(ret)) { btrfs_abort_transaction(trans, ret); goto discard; } @@ -6925,7 +6935,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 Fri Oct 2 06:17:34 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 DD7BE46D55C; Tue, 4 Aug 2026 15:44:52 +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=1785858296; cv=none; b=us/aXEq0nmRnaCi9qs9MYyqd1yhRZaULGEES/BJ0zmGRXbp4tnxuk3vrXODzDcWA1BjglMjsF9hwCi6BrhXn0ijpYH78746LsQ8nZHAZIvHwdGB8tB2nRRe+4H023qkocYGI3nlc7MffFU4DERKgcTbW0ZOTL2DwaGgFdtx1dQ8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785858296; c=relaxed/simple; bh=tehTwQbwPDfz4Sc6CDZyu6UtOWqk+hSO5jmEuNuZDpU=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Jzc6DoLmvHAsGfXhZEe4BpCzqbXjnNdDR0AopL6uFMtbu2XGHUH5vFU36ti5IdYLOyxycSy7czUGU3PXoOjtYxio82yjHN14Q9KB+DeXM1P1YxjMWdPf/iJjci2MK4HZqi8mHZ9vPuVVne0lv7cGdcaREx0IuoLl/bGgL6tHKbA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=VCVnb8yO; 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="VCVnb8yO" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 02F851F00ACA; Tue, 4 Aug 2026 15:44:51 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1785858292; bh=PPPazqAQRZNPvNq+6vbzaaoTW9rB8N91g5P3iAp90dI=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=VCVnb8yO5A9lw7ciWixWq0GyVVjXsV7UvedlQDTQGPlyWGOjiDifvrWWmsM04vEav MrcMgWglHR0EkI4ngb3zX3+x5yJNVznie4G5hRt41gpY80anTm86Ym0Q5SWVzPbcRe 9sOweSQcOcYF79SkRzz3DO54Ao9v1vMQRNhYySXvAq8J49ASTMM9qACkUgWAYZy8vz qgELHw138ANJrqpwN1f3iSofytSNeqzN9qTjvt48/2APvReEH45MwijiCa50/DzhZG v3QODXa4johTMhLgGC3ZmbrWLZoczBQJouS962lqiPvDO3D5IrnCocmAaDCE7dgnGE UXQ+vKvmzkmjw== From: Jeff Layton Date: Tue, 04 Aug 2026 11:44:37 -0400 Subject: [PATCH v2 5/5] 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: <20260804-btrfs-enomem-v2-5-4d923170e8c1@kernel.org> References: <20260804-btrfs-enomem-v2-0-4d923170e8c1@kernel.org> In-Reply-To: <20260804-btrfs-enomem-v2-0-4d923170e8c1@kernel.org> To: Chris Mason , David Sterba Cc: Qu Wenruo , 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=7224; i=jlayton@kernel.org; h=from:subject:message-id; bh=tehTwQbwPDfz4Sc6CDZyu6UtOWqk+hSO5jmEuNuZDpU=; b=kA0DAAoBAA5oQRlWghUByyZiAGpyCO+hScPaI5RegKBepbB37CjowDQi3PJwAmJOB4sZrcshQ 4kCMwQAAQoAHRYhBEvA17JEcbKhhOr10wAOaEEZVoIVBQJqcgjvAAoJEAAOaEEZVoIVPHMP/RZ0 mQ7ru2Gh3uhcXkGIwAH4A4bYTvjUCN8ed1vb6RDkGBv/VbEwnv/sf9oV7nyao/coq9q8GptwzJj P9GgRbZEOz+eeb/oMpimG3SNSaEM5o9zlhFXdRBqvkp9NYJt44j7APgUpuB9ytE+hg9g68iylWL 3N6M62W3Hxq8qQq3xGXN7EypVO4qi8qDffd4vPkzkI2KRr5l3NVYpbsySSdgYwiw4wMfydtyYp9 24Up30Ld6+S3t3n65EoMtngIPkD/uFC3BsDSa+IP9TdV85w7MsSXWXWYTd6eu/zU0llG1iFrSGI GMgBtJkFBfi9q89PntPaYvylA9/AHjbN1qG3fmLJhGBS6uhgX0fAlZSQXqMv9jz6+UaLhs8PupQ 4wNuDwWQ7zIo2bu8/OvlfbEiHZmB6NRDYj/1w5kWRN+Il+O058QrOyMyFq1hIhvFgIm9xHUaPgU 6IMnoDcq0XMghz9keqJvcNxHi/ILYoNPmYzORqD4VXX6rgaz/gnS1f5AQ6BRh61uIngeiT4RRty /AatcqEPok9St8bkyjMtNt5gcl05eDb3EyOT3/SvTmJfmnzdSmJ0iLTPD80Fr3KGRO0EFa6ripx QLFzE5HKPHgI7Fa3yIGzx9qGVi9pwB9jAxx2adUQQ1IZJWGBzcxt99XMoDVFlb+4rJOB9gkoVmA 2gaAd 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 1082fa92c145..d4280f152027 100644 --- a/fs/btrfs/btrfs_inode.h +++ b/fs/btrfs/btrfs_inode.h @@ -525,9 +525,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 99e990c592f6..9f6a631d83a3 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -6862,7 +6862,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) { clear_nlink(inode); /* @@ -6904,7 +6904,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; @@ -6930,11 +6931,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)) { @@ -7088,7 +7092,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 @@ -8502,14 +8506,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; @@ -8582,6 +8586,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; @@ -8705,6 +8710,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. */ @@ -8800,7 +8823,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; @@ -8825,6 +8850,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 7ba7b6098aa5..a043611f82e1 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -1683,7 +1683,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", @@ -2031,7 +2031,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