* [PATCH 0/5] btrfs-progs: btrfs path leak fix, part 1
@ 2026-10-29 9:46 Qu Wenruo
2026-10-29 9:46 ` [PATCH 1/5] btrfs-progs: introduce compiler_attributes.h Qu Wenruo
` (4 more replies)
0 siblings, 5 replies; 6+ messages in thread
From: Qu Wenruo @ 2026-10-29 9:46 UTC (permalink / raw)
To: linux-btrfs
To avoid future LLM script kiddos, we need to fix path leaks.
This is part 1, focusing on leaks on btrfs_alloc_path().
The most important part is the second patch, which introduces
BTRFS_PATH_AUTO_(FREE|RELEASE), so that we can finally get the same
capability.
Unfortunately this will require the compiler support for the __cleanup__
attribute. If not supported, configure will reject the build.
Then several fixes using BTRFS_PATH_AUTO_FREE().
The last one has several other small fixes batched together, as they are
all inside the same btrfs-corrupt-block.
Part 2 will focus on the on-stack paths, which can still leak the ebs,
and are the most common sites in btrfs-progs.
Qu Wenruo (5):
btrfs-progs: introduce compiler_attributes.h
btrfs-progs: utilize __cleanup__ attribute for btrfs_path
btrfs-progs: sync btrfs_translate_remap() to fix a path leak
btrfs-progs: fix a path leak in alloc_reserved_tree_block()
btrfs-progs: fix several memory bugs in btrfs-corrupt-block
btrfs-corrupt-block.c | 34 ++++++++-----
configure.ac | 15 ++++++
include/compiler_attributes.h | 39 +++++++++++++++
include/kerncompat.h | 7 +--
kernel-lib/overflow.h | 8 +---
kernel-shared/cleanup.h | 89 +++++++++++++++++++++++++++++++++++
kernel-shared/ctree.h | 10 ++++
kernel-shared/extent-tree.c | 4 +-
kernel-shared/volumes.c | 55 +++++-----------------
9 files changed, 193 insertions(+), 68 deletions(-)
create mode 100644 include/compiler_attributes.h
create mode 100644 kernel-shared/cleanup.h
--
2.56.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 1/5] btrfs-progs: introduce compiler_attributes.h
2026-10-29 9:46 [PATCH 0/5] btrfs-progs: btrfs path leak fix, part 1 Qu Wenruo
@ 2026-10-29 9:46 ` Qu Wenruo
2026-10-29 9:46 ` [PATCH 2/5] btrfs-progs: utilize __cleanup__ attribute for btrfs_path Qu Wenruo
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Qu Wenruo @ 2026-10-29 9:46 UTC (permalink / raw)
To: linux-btrfs
Cross-port a minimal include/compiler_attributes.h from the kernel's
include/linux/compiler_attributes.h, and move the existing attribute
definitions there:
- __must_check
Previously defined in kernel-lib/overflow.h, which is not a proper
place for a generic attribute. Anyone wanting __must_check would have
to include overflow.h just for it.
- __printf
- __maybe_unused
Previously defined in include/kerncompat.h.
The new header has no other includes so it can be pulled in by any
header that only needs a compiler attribute. kerncompat.h includes it,
so existing users are not affected.
Assisted-By: LLM (Split the compiler_attributes.h from the next commit)
Signed-off-by: Qu Wenruo <wqu@suse.com>
---
include/compiler_attributes.h | 33 +++++++++++++++++++++++++++++++++
include/kerncompat.h | 7 +------
kernel-lib/overflow.h | 8 +-------
3 files changed, 35 insertions(+), 13 deletions(-)
create mode 100644 include/compiler_attributes.h
diff --git a/include/compiler_attributes.h b/include/compiler_attributes.h
new file mode 100644
index 000000000000..e9ac1ac64cd8
--- /dev/null
+++ b/include/compiler_attributes.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _COMPILER_ATTRIBUTES_H
+#define _COMPILER_ATTRIBUTES_H
+
+/*
+ * Copied from linux.git/include/linux/compiler_attributes.h, only contains the
+ * attributes btrfs-progs needs.
+ *
+ * This header must stay free of any other includes, so it can be pulled in by
+ * any header which only needs a compiler attribute.
+ */
+
+/*
+ * gcc: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-format-function-attribute
+ * clang: https://clang.llvm.org/docs/AttributeReference.html#format
+ */
+#define __printf(a, b) __attribute__((__format__(printf, a, b)))
+
+/*
+ * gcc: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-warn_005funused_005fresult-function-attribute
+ * clang: https://clang.llvm.org/docs/AttributeReference.html#nodiscard-warn-unused-result
+ */
+#define __must_check __attribute__((__warn_unused_result__))
+
+/*
+ * gcc: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-unused-function-attribute
+ * clang: https://clang.llvm.org/docs/AttributeReference.html#maybe-unused-unused
+ */
+#ifndef __maybe_unused
+#define __maybe_unused __attribute__((__unused__))
+#endif
+
+#endif
diff --git a/include/kerncompat.h b/include/kerncompat.h
index 0239b0ac807a..b8e9a6c9c04b 100644
--- a/include/kerncompat.h
+++ b/include/kerncompat.h
@@ -38,6 +38,7 @@
#include <stdbool.h>
#include <stdarg.h>
#include <features.h>
+#include "compiler_attributes.h"
#ifndef static_assert
#define static_assert(expr, str) _Static_assert(expr, str)
@@ -58,10 +59,6 @@
#endif
-#ifndef __maybe_unused
-#define __maybe_unused __attribute__((__unused__))
-#endif
-
#ifndef BTRFS_DISABLE_BACKTRACE
#include <execinfo.h>
#endif
@@ -776,8 +773,6 @@ struct lock_class_key {
#define __user
#define __pure
-#define __printf(a, b) __attribute__((__format__(printf, a, b)))
-
static inline bool sb_rdonly(struct super_block *sb)
{
return false;
diff --git a/kernel-lib/overflow.h b/kernel-lib/overflow.h
index b2a376ee13c4..d942b11924cc 100644
--- a/kernel-lib/overflow.h
+++ b/kernel-lib/overflow.h
@@ -5,6 +5,7 @@
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
+#include "compiler_attributes.h"
/*
* We need to compute the minimum and maximum values representable in a given
@@ -42,13 +43,6 @@
#define is_non_negative(a) ((a) > 0 || (a) == 0)
#define is_negative(a) (!(is_non_negative(a)))
-/* Copied from linux.git/include/compiler_attributes.h */
-/*
- * gcc: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-warn_005funused_005fresult-function-attribute
- * clang: https://clang.llvm.org/docs/AttributeReference.html#nodiscard-warn-unused-result
- */
-#define __must_check __attribute__((__warn_unused_result__))
-
/*
* Allows for effectively applying __must_check to a macro so we can have
* both the type-agnostic benefits of the macros while also being able to
--
2.56.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 2/5] btrfs-progs: utilize __cleanup__ attribute for btrfs_path
2026-10-29 9:46 [PATCH 0/5] btrfs-progs: btrfs path leak fix, part 1 Qu Wenruo
2026-10-29 9:46 ` [PATCH 1/5] btrfs-progs: introduce compiler_attributes.h Qu Wenruo
@ 2026-10-29 9:46 ` Qu Wenruo
2026-10-29 9:46 ` [PATCH 3/5] btrfs-progs: sync btrfs_translate_remap() to fix a path leak Qu Wenruo
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Qu Wenruo @ 2026-10-29 9:46 UTC (permalink / raw)
To: linux-btrfs
The new header at kernel-shared/cleanup.h is cross-ported from the
kernel's linux/cleanup.h.
Since we rely on the newer __cleanup__ attribute, also update the
configure tool to detect the compiler support.
If no support, error out.
As we will rely on the __cleanup__ attribute to do auto cleanup. Ignoring
such attribute will easily screw up future resource management.
With the new __free() macros, define BTRFS_PATH_AUTO_FREE() and
BTRFS_PATH_AUTO_RELEASE(), so we can sync the code between progs and
kernel.
Assisted-by: LLM (updating configure.ac to error out if no such support)
Signed-off-by: Qu Wenruo <wqu@suse.com>
---
configure.ac | 15 ++++++
include/compiler_attributes.h | 6 +++
kernel-shared/cleanup.h | 89 +++++++++++++++++++++++++++++++++++
kernel-shared/ctree.h | 10 ++++
4 files changed, 120 insertions(+)
create mode 100644 kernel-shared/cleanup.h
diff --git a/configure.ac b/configure.ac
index b12ca46814bf..07cd92df5947 100644
--- a/configure.ac
+++ b/configure.ac
@@ -67,6 +67,21 @@ AS_IF([test "x$target_cpu" = 'xx86_64'], [
AX_CHECK_COMPILE_FLAG([-std=gnu11], [],
[AC_MSG_ERROR([std=gnu11 compiler required])])
+dnl The __cleanup__ variable attribute is required by kernel-shared/cleanup.h
+AC_MSG_CHECKING([whether the compiler supports __attribute__((__cleanup__))])
+save_ac_c_werror_flag=$ac_c_werror_flag
+ac_c_werror_flag=yes
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+static void free_int(int *p) { *p = 0; }
+]], [[
+ int x __attribute__((__cleanup__(free_int))) = 1;
+ (void)x;
+]])],
+ [AC_MSG_RESULT([yes])],
+ [AC_MSG_RESULT([no])
+ AC_MSG_ERROR([compiler with __attribute__((__cleanup__)) support required])])
+ac_c_werror_flag=$save_ac_c_werror_flag
+
AC_SYS_LARGEFILE
AC_PROG_INSTALL
diff --git a/include/compiler_attributes.h b/include/compiler_attributes.h
index e9ac1ac64cd8..41edbab9c55a 100644
--- a/include/compiler_attributes.h
+++ b/include/compiler_attributes.h
@@ -10,6 +10,12 @@
* any header which only needs a compiler attribute.
*/
+/*
+ * gcc: https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attributes.html#index-cleanup-variable-attribute
+ * clang: https://clang.llvm.org/docs/AttributeReference.html#cleanup
+ */
+#define __cleanup(func) __attribute__((__cleanup__(func)))
+
/*
* gcc: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-format-function-attribute
* clang: https://clang.llvm.org/docs/AttributeReference.html#format
diff --git a/kernel-shared/cleanup.h b/kernel-shared/cleanup.h
new file mode 100644
index 000000000000..c8f12e2e343a
--- /dev/null
+++ b/kernel-shared/cleanup.h
@@ -0,0 +1,89 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/*
+ * Cross-ported from kernel's include/linux/cleanup.h, along with needed
+ * compiler attributes from include/linux/compiler_attributes.h
+ */
+#ifndef _LINUX_CLEANUP_H
+#define _LINUX_CLEANUP_H
+
+#include "kerncompat.h"
+#include "compiler_attributes.h"
+
+/*
+ * DEFINE_FREE(name, type, free):
+ * simple helper macro that defines the required wrapper for a __free()
+ * based cleanup function. @free is an expression using '_T' to access the
+ * variable. @free should typically include a NULL test before calling a
+ * function, see the example below.
+ *
+ * __free(name):
+ * variable attribute to add a scoped based cleanup to the variable.
+ *
+ * no_free_ptr(var):
+ * like a non-atomic xchg(var, NULL), such that the cleanup function will
+ * be inhibited -- provided it sanely deals with a NULL value.
+ *
+ * NOTE: this has __must_check semantics so that it is harder to accidentally
+ * leak the resource.
+ *
+ * return_ptr(p):
+ * returns p while inhibiting the __free().
+ *
+ * Ex.
+ *
+ * DEFINE_FREE(kfree, void *, if (_T) kfree(_T))
+ *
+ * void *alloc_obj(...)
+ * {
+ * struct obj *p __free(kfree) = kmalloc(...);
+ * if (!p)
+ * return NULL;
+ *
+ * if (!init_obj(p))
+ * return NULL;
+ *
+ * return_ptr(p);
+ * }
+ *
+ * NOTE: the DEFINE_FREE()'s @free expression includes a NULL test even though
+ * kfree() is fine to be called with a NULL value. This is on purpose. This way
+ * the compiler sees the end of our alloc_obj() function as:
+ *
+ * tmp = p;
+ * p = NULL;
+ * if (p)
+ * kfree(p);
+ * return tmp;
+ *
+ * And through the magic of value-propagation and dead-code-elimination, it
+ * eliminates the actual cleanup call and compiles into:
+ *
+ * return p;
+ *
+ * Without the NULL test it turns into a mess and the compiler can't help us.
+ */
+
+#define DEFINE_FREE(_name, _type, _free) \
+ static __always_inline void __free_##_name(void *p) { _type _T = *(_type *)p; _free; }
+
+#define __free(_name) __cleanup(__free_##_name)
+
+#define __get_and_null(p, nullvalue) \
+ ({ \
+ auto __ptr = &(p); \
+ auto __val = *__ptr; \
+ *__ptr = nullvalue; \
+ __val; \
+ })
+
+static __always_inline __must_check
+const volatile void * __must_check_fn(const volatile void *val)
+{ return val; }
+
+#define no_free_ptr(p) \
+ ((typeof(p)) __must_check_fn((__force const volatile void *)__get_and_null(p, NULL)))
+
+#define return_ptr(p) return no_free_ptr(p)
+
+#endif
diff --git a/kernel-shared/ctree.h b/kernel-shared/ctree.h
index 93fd7f18049e..3a5f456df315 100644
--- a/kernel-shared/ctree.h
+++ b/kernel-shared/ctree.h
@@ -30,6 +30,7 @@
#include "kernel-shared/accessors.h"
#include "kernel-shared/extent-io-tree.h"
#include "kernel-shared/locking.h"
+#include "kernel-shared/cleanup.h"
#include "crypto/crc32c.h"
#include "common/extent-cache.h"
@@ -1024,6 +1025,15 @@ void btrfs_release_path(struct btrfs_path *p);
void add_root_to_dirty_list(struct btrfs_root *root);
struct btrfs_path *btrfs_alloc_path(void);
void btrfs_free_path(struct btrfs_path *p);
+DEFINE_FREE(btrfs_free_path, struct btrfs_path *, btrfs_free_path(_T))
+DEFINE_FREE(btrfs_release_path, struct btrfs_path, btrfs_release_path(&_T))
+
+#define BTRFS_PATH_AUTO_FREE(path_name) \
+ struct btrfs_path *path_name __free(btrfs_free_path) = NULL
+
+#define BTRFS_PATH_AUTO_RELEASE(path_name) \
+ struct btrfs_path path_name __free(btrfs_release_path) = { 0 }
+
int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root,
struct btrfs_path *path, int slot, int nr);
--
2.56.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 3/5] btrfs-progs: sync btrfs_translate_remap() to fix a path leak
2026-10-29 9:46 [PATCH 0/5] btrfs-progs: btrfs path leak fix, part 1 Qu Wenruo
2026-10-29 9:46 ` [PATCH 1/5] btrfs-progs: introduce compiler_attributes.h Qu Wenruo
2026-10-29 9:46 ` [PATCH 2/5] btrfs-progs: utilize __cleanup__ attribute for btrfs_path Qu Wenruo
@ 2026-10-29 9:46 ` Qu Wenruo
2026-10-29 9:46 ` [PATCH 4/5] btrfs-progs: fix a path leak in alloc_reserved_tree_block() Qu Wenruo
2026-10-29 9:46 ` [PATCH 5/5] btrfs-progs: fix several memory bugs in btrfs-corrupt-block Qu Wenruo
4 siblings, 0 replies; 6+ messages in thread
From: Qu Wenruo @ 2026-10-29 9:46 UTC (permalink / raw)
To: linux-btrfs
In the current implementation, if btrfs_next_leaf() returned 1, the
function returned without freeing the path.
Fix it by syncing the code from kernel, which do a key search using
(*logical, -1, -1), then moving to the previous slot, which should be
safer than the current one.
Signed-off-by: Qu Wenruo <wqu@suse.com>
---
kernel-shared/volumes.c | 55 ++++++++++-------------------------------
1 file changed, 13 insertions(+), 42 deletions(-)
diff --git a/kernel-shared/volumes.c b/kernel-shared/volumes.c
index e2b6708ad872..fedcaa5f9216 100644
--- a/kernel-shared/volumes.c
+++ b/kernel-shared/volumes.c
@@ -2098,75 +2098,46 @@ static int btrfs_translate_remap(struct btrfs_fs_info *fs_info, u64 *logical, u6
struct btrfs_key key, found_key;
struct extent_buffer *leaf;
struct btrfs_remap_item *remap;
- struct btrfs_path *path;
+ BTRFS_PATH_AUTO_FREE(path);
path = btrfs_alloc_path();
if (!path)
return -ENOMEM;
key.objectid = *logical;
- key.type = BTRFS_IDENTITY_REMAP_KEY;
- key.offset = 0;
+ key.type = (u8)-1;
+ key.offset = (u64)-1;
ret = btrfs_search_slot(NULL, fs_info->remap_root, &key, path, 0, 0);
- if (ret < 0) {
- btrfs_free_path(path);
+ if (ret < 0)
return ret;
- }
leaf = path->nodes[0];
+ if (path->slots[0] == 0)
+ return -ENOENT;
- if (path->slots[0] >= btrfs_header_nritems(leaf)) {
- ret = btrfs_next_leaf(fs_info->remap_root, path);
- if (ret < 0) {
- btrfs_free_path(path);
- return ret;
- }
-
- leaf = path->nodes[0];
- }
+ path->slots[0]--;
btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
- if (found_key.objectid > *logical) {
- if (path->slots[0] == 0) {
- ret = btrfs_prev_leaf(fs_info->remap_root, path);
- if (ret) {
- if (ret == 1)
- ret = -ENOENT;
- return ret;
- }
-
- leaf = path->nodes[0];
- } else {
- path->slots[0]--;
- }
-
- btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
- }
-
- if (found_key.type != BTRFS_REMAP_KEY && found_key.type != BTRFS_IDENTITY_REMAP_KEY) {
- btrfs_free_path(path);
+ if (found_key.type != BTRFS_REMAP_KEY &&
+ found_key.type != BTRFS_IDENTITY_REMAP_KEY) {
return -ENOENT;
}
- if (found_key.objectid > *logical || found_key.objectid + found_key.offset <= *logical) {
- btrfs_free_path(path);
+ if (found_key.objectid > *logical ||
+ found_key.objectid + found_key.offset <= *logical) {
return -ENOENT;
}
if (*logical + *length > found_key.objectid + found_key.offset)
*length = found_key.objectid + found_key.offset - *logical;
- if (found_key.type == BTRFS_IDENTITY_REMAP_KEY) {
- btrfs_free_path(path);
+ if (found_key.type == BTRFS_IDENTITY_REMAP_KEY)
return 0;
- }
remap = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_remap_item);
- *logical = *logical - found_key.objectid + btrfs_remap_address(leaf, remap);
-
- btrfs_free_path(path);
+ *logical += btrfs_remap_address(leaf, remap) - found_key.objectid;
return 0;
}
--
2.56.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 4/5] btrfs-progs: fix a path leak in alloc_reserved_tree_block()
2026-10-29 9:46 [PATCH 0/5] btrfs-progs: btrfs path leak fix, part 1 Qu Wenruo
` (2 preceding siblings ...)
2026-10-29 9:46 ` [PATCH 3/5] btrfs-progs: sync btrfs_translate_remap() to fix a path leak Qu Wenruo
@ 2026-10-29 9:46 ` Qu Wenruo
2026-10-29 9:46 ` [PATCH 5/5] btrfs-progs: fix several memory bugs in btrfs-corrupt-block Qu Wenruo
4 siblings, 0 replies; 6+ messages in thread
From: Qu Wenruo @ 2026-10-29 9:46 UTC (permalink / raw)
To: linux-btrfs
If btrfs_insert_empty_item() failed with -EEXIST, the path is not
released by btrfs_insert_empty_item().
But the function returns without freeing @path, causing a leak.
This function has lagged behind kernel quite some, so here I just fix
the path leak by utilizing BTRFS_PATH_AUTO_FREE() inside the if ()
branch.
Signed-off-by: Qu Wenruo <wqu@suse.com>
---
kernel-shared/extent-tree.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/kernel-shared/extent-tree.c b/kernel-shared/extent-tree.c
index 64479e6e43f1..bac44654eab8 100644
--- a/kernel-shared/extent-tree.c
+++ b/kernel-shared/extent-tree.c
@@ -2403,7 +2403,6 @@ static int alloc_reserved_tree_block(struct btrfs_trans_handle *trans,
struct btrfs_extent_inline_ref *iref;
struct btrfs_space_info *sinfo;
struct extent_buffer *leaf;
- struct btrfs_path *path;
struct btrfs_key ins;
u32 size = sizeof(*extent_item) + sizeof(*iref);
u64 start, end;
@@ -2415,6 +2414,8 @@ static int alloc_reserved_tree_block(struct btrfs_trans_handle *trans,
ins.objectid = node->bytenr;
if (ref->root != BTRFS_REMAP_TREE_OBJECTID) {
+ BTRFS_PATH_AUTO_FREE(path);
+
if (skinny_metadata) {
ins.type = BTRFS_METADATA_ITEM_KEY;
ins.offset = ref->level;
@@ -2462,7 +2463,6 @@ static int alloc_reserved_tree_block(struct btrfs_trans_handle *trans,
btrfs_set_extent_inline_ref_offset(leaf, iref, ref->root);
btrfs_mark_buffer_dirty(leaf);
- btrfs_free_path(path);
}
ret = remove_from_free_space_tree(trans, ins.objectid, fs_info->nodesize);
--
2.56.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 5/5] btrfs-progs: fix several memory bugs in btrfs-corrupt-block
2026-10-29 9:46 [PATCH 0/5] btrfs-progs: btrfs path leak fix, part 1 Qu Wenruo
` (3 preceding siblings ...)
2026-10-29 9:46 ` [PATCH 4/5] btrfs-progs: fix a path leak in alloc_reserved_tree_block() Qu Wenruo
@ 2026-10-29 9:46 ` Qu Wenruo
4 siblings, 0 replies; 6+ messages in thread
From: Qu Wenruo @ 2026-10-29 9:46 UTC (permalink / raw)
To: linux-btrfs
These involves several call sites:
- BTRFS_METADATA_BLOCK_GENERATION branch of corrupt_metadata_block()
- BTRFS_METADATA_BLOCK_SHIFT_ITEMS branch of corrupt_metadata_block()
- if (chunk_rec) branch of main()
The bugs are:
- Use-after-free if write_data_to_disk() failed in
BTRFS_METADATA_BLOCK_GENERATION branch
Fix it by saving @eb->start and use that saved value for error
message.
- Path leak in the successful path
Fix it by using BTRFS_PATH_AUTO_FREE() and remove all existing
btrfs_free_path().
- Path held after btrfs_commit_transaction()
This is minor, but still release the path before
btrfs_commit_transaction() to follow the kernel behavior.
- Missing error message and code if btrfs_commit_transaction failed
Just add the missing error message and save the error code from it.
- Wrong value in the error message if btrfs_read_fs_root() failed
Fix it by printing root_key.objectid.
- Missing error code if early failures happened in chunk_rec branch
Fix it by setting @ret to -ENOMEM or -ENOENT respectively.
Behavior changes:
- Abort the transaction if corrupt_item_nocow() failed in chunk_rec
branch
Previously we would still commit the transaction after a failed
corrupt_item_nocow(), which is meaningless for a failed operation.
Now we abort the transaction and exit through out_close, without
committing.
Cleanup:
- Remove the dead "eb = path->nodes[level]" assignment in SHIFT_ITEMS
branch
@eb is not used after that, and it was already freed earlier.
Assisted-by: LLM (generate the commit message with human modification)
Signed-off-by: Qu Wenruo <wqu@suse.com>
---
btrfs-corrupt-block.c | 34 +++++++++++++++++++++++-----------
1 file changed, 23 insertions(+), 11 deletions(-)
diff --git a/btrfs-corrupt-block.c b/btrfs-corrupt-block.c
index 94815221a32d..0fc2c42e7ffa 100644
--- a/btrfs-corrupt-block.c
+++ b/btrfs-corrupt-block.c
@@ -910,6 +910,7 @@ static int corrupt_metadata_block(struct btrfs_fs_info *fs_info, u64 block,
{
u64 orig = btrfs_header_generation(eb);
u64 bogus = generate_u64(orig);
+ const u64 start = eb->start;
btrfs_set_header_generation(eb, bogus);
csum_tree_block_size(eb, fs_info->csum_size, 0,
@@ -919,7 +920,7 @@ static int corrupt_metadata_block(struct btrfs_fs_info *fs_info, u64 block,
if (ret < 0) {
errno = -ret;
error("failed to write extent buffer at %llu: %m",
- eb->start);
+ start);
return ret;
}
break;
@@ -928,7 +929,7 @@ static int corrupt_metadata_block(struct btrfs_fs_info *fs_info, u64 block,
{
struct btrfs_trans_handle *trans;
struct btrfs_root *root;
- struct btrfs_path *path;
+ BTRFS_PATH_AUTO_FREE(path);
struct btrfs_key key, root_key;
u64 root_objectid;
u8 level;
@@ -947,7 +948,7 @@ static int corrupt_metadata_block(struct btrfs_fs_info *fs_info, u64 block,
root = btrfs_read_fs_root(fs_info, &root_key);
if (IS_ERR(root)) {
- error("couldn't find owner root %llu", key.objectid);
+ error("couldn't find owner root %llu", root_key.objectid);
return PTR_ERR(root);
}
@@ -957,7 +958,6 @@ static int corrupt_metadata_block(struct btrfs_fs_info *fs_info, u64 block,
trans = btrfs_start_transaction(root, 1);
if (IS_ERR(trans)) {
- btrfs_free_path(path);
ret = PTR_ERR(trans);
errno = -ret;
error_msg(ERROR_MSG_START_TRANS, "%m");
@@ -968,14 +968,17 @@ static int corrupt_metadata_block(struct btrfs_fs_info *fs_info, u64 block,
ret = btrfs_search_slot(trans, root, &key, path, 0, 1);
if (ret < 0) {
error("error searching to node %d", ret);
- btrfs_free_path(path);
btrfs_abort_transaction(trans, ret);
return ret;
}
- eb = path->nodes[level];
shift_items(root, path->nodes[level]);
btrfs_mark_buffer_dirty(path->nodes[level]);
- btrfs_commit_transaction(trans, root);
+ btrfs_release_path(path);
+ ret = btrfs_commit_transaction(trans, root);
+ if (ret < 0) {
+ errno = -ret;
+ error_msg(ERROR_MSG_COMMIT_TRANS, "%m");
+ }
break;
}
default:
@@ -1502,7 +1505,7 @@ int main(int argc, char **argv)
}
if (chunk_rec) {
struct btrfs_trans_handle *trans;
- struct btrfs_path *path;
+ BTRFS_PATH_AUTO_FREE(path);
int del;
if (logical == (u64)-1)
@@ -1511,21 +1514,30 @@ int main(int argc, char **argv)
path = btrfs_alloc_path();
if (!path) {
error_mem(NULL);
+ ret = -ENOMEM;
goto out_close;
}
if (find_chunk_offset(root->fs_info->chunk_root, path,
logical) != 0) {
- btrfs_free_path(path);
+ ret = -ENOENT;
goto out_close;
}
trans = btrfs_start_transaction(root, 1);
BUG_ON(IS_ERR(trans));
ret = corrupt_item_nocow(trans, root->fs_info->chunk_root,
path, del);
- if (ret < 0)
+ btrfs_release_path(path);
+ if (ret < 0) {
error("failed to corrupt chunk record");
- btrfs_commit_transaction(trans, root);
+ btrfs_abort_transaction(trans, ret);
+ goto out_close;
+ }
+ ret = btrfs_commit_transaction(trans, root);
+ if (ret < 0) {
+ errno = -ret;
+ error_msg(ERROR_MSG_COMMIT_TRANS, "%m");
+ }
goto out_close;
}
if (chunk_tree) {
--
2.56.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-10-29 9:46 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-29 9:46 [PATCH 0/5] btrfs-progs: btrfs path leak fix, part 1 Qu Wenruo
2026-10-29 9:46 ` [PATCH 1/5] btrfs-progs: introduce compiler_attributes.h Qu Wenruo
2026-10-29 9:46 ` [PATCH 2/5] btrfs-progs: utilize __cleanup__ attribute for btrfs_path Qu Wenruo
2026-10-29 9:46 ` [PATCH 3/5] btrfs-progs: sync btrfs_translate_remap() to fix a path leak Qu Wenruo
2026-10-29 9:46 ` [PATCH 4/5] btrfs-progs: fix a path leak in alloc_reserved_tree_block() Qu Wenruo
2026-10-29 9:46 ` [PATCH 5/5] btrfs-progs: fix several memory bugs in btrfs-corrupt-block Qu Wenruo
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.