* [PATCH 1/2] btrfs: fix the possible bioc_list memory leak during error
2026-08-17 5:13 [PATCH 0/2] btrfs: rst: minor error handling fixes Qu Wenruo
@ 2026-08-17 5:13 ` Qu Wenruo
2026-08-17 5:13 ` [PATCH 2/2] btrfs: return proper negative error code for update_raid_extent_item() Qu Wenruo
1 sibling, 0 replies; 3+ messages in thread
From: Qu Wenruo @ 2026-08-17 5:13 UTC (permalink / raw)
To: linux-btrfs
There are two possible ways to leak bioc memory on
btrfs_ordered_extent::bioc_list:
- An error occurred for btrfs_insert_one_raid_extent()
Then the function btrfs_insert_raid_extent() immediately return
without freeing any bioc in the bioc_list.
- An ordered extent hit an IO error
In that case the ordered extent will have BTRFS_ORDERED_IOERR set, and
skip the call on btrfs_insert_raid_extent() completely.
Fix the problem by:
- Introduce a new helper, btrfs_cleanup_ordered_bioc_list()
Which will remove all bioc from the bioc_list, and release the bioc.
- Call the above helper for btrfs_insert_raid_extent()
So that the cleanup helper is always called no matter what.
- Call the above helper for btrfs_finish_one_ordered()
This is called just before the final release on the ordered extent.
This is reported by Sashiko when reviewing another patch.
Link: https://sashiko.dev/#/patchset/20260817021512.3010812-1-shuangpeng.kernel%40gmail.com
Fixes: 02c372e1f016 ("btrfs: add support for inserting raid stripe extents")
Signed-off-by: Qu Wenruo <wqu@suse.com>
---
fs/btrfs/inode.c | 3 +++
fs/btrfs/raid-stripe-tree.c | 18 ++++++++++++------
fs/btrfs/raid-stripe-tree.h | 1 +
3 files changed, 16 insertions(+), 6 deletions(-)
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 8a9b52848fbc..b896358678ab 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -3436,6 +3436,9 @@ int btrfs_finish_one_ordered(struct btrfs_ordered_extent *ordered_extent)
*/
btrfs_remove_ordered_extent(ordered_extent);
+ /* Cleanup any remaining biocs attached to the OE. */
+ btrfs_cleanup_ordered_bioc_list(ordered_extent);
+
/* once for us */
btrfs_put_ordered_extent(ordered_extent);
/* once for the tree */
diff --git a/fs/btrfs/raid-stripe-tree.c b/fs/btrfs/raid-stripe-tree.c
index 89e259a47d8d..6291775dbe0e 100644
--- a/fs/btrfs/raid-stripe-tree.c
+++ b/fs/btrfs/raid-stripe-tree.c
@@ -373,7 +373,7 @@ int btrfs_insert_raid_extent(struct btrfs_trans_handle *trans,
struct btrfs_ordered_extent *ordered_extent)
{
struct btrfs_io_context *bioc;
- int ret;
+ int ret = 0;
if (!btrfs_fs_incompat(trans->fs_info, RAID_STRIPE_TREE))
return 0;
@@ -381,17 +381,23 @@ int btrfs_insert_raid_extent(struct btrfs_trans_handle *trans,
list_for_each_entry(bioc, &ordered_extent->bioc_list, rst_ordered_entry) {
ret = btrfs_insert_one_raid_extent(trans, bioc);
if (ret)
- return ret;
+ break;
}
- while (!list_empty(&ordered_extent->bioc_list)) {
- bioc = list_first_entry(&ordered_extent->bioc_list,
+ btrfs_cleanup_ordered_bioc_list(ordered_extent);
+ return ret;
+}
+
+void btrfs_cleanup_ordered_bioc_list(struct btrfs_ordered_extent *ordered)
+{
+ while (!list_empty(&ordered->bioc_list)) {
+ struct btrfs_io_context *bioc;
+
+ bioc = list_first_entry(&ordered->bioc_list,
typeof(*bioc), rst_ordered_entry);
list_del(&bioc->rst_ordered_entry);
btrfs_put_bioc(bioc);
}
-
- return 0;
}
int btrfs_get_raid_extent_offset(struct btrfs_fs_info *fs_info,
diff --git a/fs/btrfs/raid-stripe-tree.h b/fs/btrfs/raid-stripe-tree.h
index 69942ad43140..eb02cf48511b 100644
--- a/fs/btrfs/raid-stripe-tree.h
+++ b/fs/btrfs/raid-stripe-tree.h
@@ -28,6 +28,7 @@ int btrfs_get_raid_extent_offset(struct btrfs_fs_info *fs_info,
u32 stripe_index, struct btrfs_io_stripe *stripe);
int btrfs_insert_raid_extent(struct btrfs_trans_handle *trans,
struct btrfs_ordered_extent *ordered_extent);
+void btrfs_cleanup_ordered_bioc_list(struct btrfs_ordered_extent *ordered);
#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
int btrfs_insert_one_raid_extent(struct btrfs_trans_handle *trans,
--
2.54.0
^ permalink raw reply related [flat|nested] 3+ messages in thread* [PATCH 2/2] btrfs: return proper negative error code for update_raid_extent_item()
2026-08-17 5:13 [PATCH 0/2] btrfs: rst: minor error handling fixes Qu Wenruo
2026-08-17 5:13 ` [PATCH 1/2] btrfs: fix the possible bioc_list memory leak during error Qu Wenruo
@ 2026-08-17 5:13 ` Qu Wenruo
1 sibling, 0 replies; 3+ messages in thread
From: Qu Wenruo @ 2026-08-17 5:13 UTC (permalink / raw)
To: linux-btrfs
The function btrfs_abort_transaction() only accepts negative error code,
and have the macro VERIFY_NEGATIVE_ERROR() to verify that error code.
But inside update_raid_extent_item(), if there is such key found, we
return 1, breaking the negative error code scheme.
Furthermore if we hit some real error during the tree search, e.g. -EIO,
then the error code is always over-written to -EINVAL.
Fix both problems by following other call sites by overwriting @ret to
-ENOENT if the btrfs_search_slot() failed to locate the key.
This is very unlikely to hit, as we only enter update_raid_extent_item()
if there is a conflicting key already in the raid stripe tree.
This is again reported by Sashiko when reviewing another patch.
Link: https://sashiko.dev/#/patchset/20260817021512.3010812-1-shuangpeng.kernel%40gmail.com
Fixes: 8c4cba2adbb0 ("btrfs: update stripe extents for existing logical addresses")
Signed-off-by: Qu Wenruo <wqu@suse.com>
---
fs/btrfs/raid-stripe-tree.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/fs/btrfs/raid-stripe-tree.c b/fs/btrfs/raid-stripe-tree.c
index 6291775dbe0e..d9e660447205 100644
--- a/fs/btrfs/raid-stripe-tree.c
+++ b/fs/btrfs/raid-stripe-tree.c
@@ -310,8 +310,10 @@ static int update_raid_extent_item(struct btrfs_trans_handle *trans,
ret = btrfs_search_slot(trans, trans->fs_info->stripe_root, key, path,
0, 1);
- if (ret)
- return (ret == 1 ? ret : -EINVAL);
+ if (ret > 0)
+ ret = -ENOENT;
+ if (ret < 0)
+ return ret;
leaf = path->nodes[0];
slot = path->slots[0];
--
2.54.0
^ permalink raw reply related [flat|nested] 3+ messages in thread