btrfs: fix unnecessary transaction commit fallback from btrfs_log_all_parents()

When btrfs_log_all_parents() returns without doing any work (because all
parent directories were already logged), it returns 1, which is propagated
up the fsync call chain up to btrfs_log_dentry_safe(), and that causes
btrfs_sync_file() to trigger am unnecessary transaction commit.

This all happens because the call to btrfs_search_slot() in
btrfs_log_all_parents() always returns 1, as there can not be any inode
ref keys with an offset 0 (an invalid inode number), so if the while loop
below it does not do any work because all parent directories were already
logged, the 'ret' variable remains with a value of 1, which is then
returned up the call chain to btrfs_sync_file().

Fix this by setting 'ret' to 0 after the call to btrfs_search_slot().

Fixes: 0f24ea456a ("btrfs: tracepoints: add trace event for btrfs_log_all_parents()")
Reviewed-by: Boris Burkov <boris@bur.io>
Reviewed-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
Filipe Manana 2026-09-03 13:15:46 +01:00 committed by David Sterba
parent 776924b2d9
commit 36f9aafa46

View File

@ -7286,6 +7286,22 @@ static int btrfs_log_all_parents(struct btrfs_trans_handle *trans,
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
if (ret < 0)
goto out;
/*
* There can't be an inode ref key with offset 0 because inode numbers
* start at BTRFS_FIRST_FREE_OBJECTID.
*/
if (WARN_ON_ONCE(ret == 0)) {
btrfs_err(trans->fs_info,
"found inode ref key with offset 0 for root %llu inode %llu",
btrfs_root_id(root), ino);
ret = BTRFS_LOG_FORCE_COMMIT;
goto out;
}
/*
* Set to 0 so that in case we don't do any work below, we won't return
* 1 and trigger an unnecessary transaction commit.
*/
ret = 0;
while (true) {
struct extent_buffer *leaf = path->nodes[0];