Commit 3cd181cc authored by Michal Grzedzicki's avatar Michal Grzedzicki Committed by David Sterba
Browse files

btrfs: fix silent IO error loss in encoded writes and zoned split



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: default avatarQu Wenruo <wqu@suse.com>
Reviewed-by: default avatarJohannes Thumshirn <johannes.thumshirn@wdc.com>
Reviewed-by: default avatarMark Harmstone <mark@harmstone.com>
Signed-off-by: default avatarMichal Grzedzicki <mge@meta.com>
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
parent e0dfaebb
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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;
+1 −1
Original line number Diff line number Diff line
@@ -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;
		}