]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
btrfs: fix silent IO error loss in encoded writes and zoned split
authorMichal Grzedzicki <mge@meta.com>
Mon, 30 Mar 2026 16:06:44 +0000 (09:06 -0700)
committerDavid Sterba <dsterba@suse.com>
Tue, 7 Apr 2026 17:43:50 +0000 (19:43 +0200)
can_finish_ordered_extent() and btrfs_finish_ordered_zoned() set
BTRFS_ORDERED_IOERR via bare set_bit(). Later,
btrfs_mark_ordered_extent_error() in btrfs_finish_one_ordered() uses
test_and_set_bit(), finds it already set, and skips
mapping_set_error(). The error is never recorded on the inode's
address_space, making it invisible to fsync. For encoded writes this
causes btrfs receive to silently produce files with zero-filled holes.

Fix: replace bare set_bit(BTRFS_ORDERED_IOERR) with
btrfs_mark_ordered_extent_error() which pairs test_and_set_bit() with
mapping_set_error(), guaranteeing the error is recorded exactly once.

Reviewed-by: Qu Wenruo <wqu@suse.com>
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Reviewed-by: Mark Harmstone <mark@harmstone.com>
Signed-off-by: Michal Grzedzicki <mge@meta.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/ordered-data.c
fs/btrfs/zoned.c

index d39f1c49d1cf8f08ea640b003b1e20820026b20d..e5a24b3ff95e46b6c5eb9c55a6c5c519a9bb0df9 100644 (file)
@@ -386,7 +386,7 @@ static bool can_finish_ordered_extent(struct btrfs_ordered_extent *ordered,
        }
 
        if (!uptodate)
-               set_bit(BTRFS_ORDERED_IOERR, &ordered->flags);
+               btrfs_mark_ordered_extent_error(ordered);
 
        if (ordered->bytes_left)
                return false;
index f7ca01a32a031499d1e8db766579105ac813d982..16dd87aa06f20c5e5bc724ecb967ddf46fb314e4 100644 (file)
@@ -2134,7 +2134,7 @@ void btrfs_finish_ordered_zoned(struct btrfs_ordered_extent *ordered)
                        continue;
                }
                if (!btrfs_zoned_split_ordered(ordered, logical, len)) {
-                       set_bit(BTRFS_ORDERED_IOERR, &ordered->flags);
+                       btrfs_mark_ordered_extent_error(ordered);
                        btrfs_err(fs_info, "failed to split ordered extent");
                        goto out;
                }