Patch "btrfs: fix wrong block_start calculation for btrfs_drop_extent_map_range()" has been added to the 6.1-stable tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is a note to let you know that I've just added the patch titled

    btrfs: fix wrong block_start calculation for btrfs_drop_extent_map_range()

to the 6.1-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     btrfs-fix-wrong-block_start-calculation-for-btrfs_dr.patch
and it can be found in the queue-6.1 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@xxxxxxxxxxxxxxx> know about it.



commit 8f394f9f4fc10a17e405d4998dae170b3d07cd6b
Author: Qu Wenruo <wqu@xxxxxxxx>
Date:   Tue Apr 9 20:32:34 2024 +0930

    btrfs: fix wrong block_start calculation for btrfs_drop_extent_map_range()
    
    [ Upstream commit fe1c6c7acce10baf9521d6dccc17268d91ee2305 ]
    
    [BUG]
    During my extent_map cleanup/refactor, with extra sanity checks,
    extent-map-tests::test_case_7() would not pass the checks.
    
    The problem is, after btrfs_drop_extent_map_range(), the resulted
    extent_map has a @block_start way too large.
    Meanwhile my btrfs_file_extent_item based members are returning a
    correct @disk_bytenr/@offset combination.
    
    The extent map layout looks like this:
    
         0        16K    32K       48K
         | PINNED |      | Regular |
    
    The regular em at [32K, 48K) also has 32K @block_start.
    
    Then drop range [0, 36K), which should shrink the regular one to be
    [36K, 48K).
    However the @block_start is incorrect, we expect 32K + 4K, but got 52K.
    
    [CAUSE]
    Inside btrfs_drop_extent_map_range() function, if we hit an extent_map
    that covers the target range but is still beyond it, we need to split
    that extent map into half:
    
            |<-- drop range -->|
                     |<----- existing extent_map --->|
    
    And if the extent map is not compressed, we need to forward
    extent_map::block_start by the difference between the end of drop range
    and the extent map start.
    
    However in that particular case, the difference is calculated using
    (start + len - em->start).
    
    The problem is @start can be modified if the drop range covers any
    pinned extent.
    
    This leads to wrong calculation, and would be caught by my later
    extent_map sanity checks, which checks the em::block_start against
    btrfs_file_extent_item::disk_bytenr + btrfs_file_extent_item::offset.
    
    This is a regression caused by commit c962098ca4af ("btrfs: fix
    incorrect splitting in btrfs_drop_extent_map_range"), which removed the
    @len update for pinned extents.
    
    [FIX]
    Fix it by avoiding using @start completely, and use @end - em->start
    instead, which @end is exclusive bytenr number.
    
    And update the test case to verify the @block_start to prevent such
    problem from happening.
    
    Thankfully this is not going to lead to any data corruption, as IO path
    does not utilize btrfs_drop_extent_map_range() with @skip_pinned set.
    
    So this fix is only here for the sake of consistency/correctness.
    
    CC: stable@xxxxxxxxxxxxxxx # 6.5+
    Fixes: c962098ca4af ("btrfs: fix incorrect splitting in btrfs_drop_extent_map_range")
    Reviewed-by: Filipe Manana <fdmanana@xxxxxxxx>
    Signed-off-by: Qu Wenruo <wqu@xxxxxxxx>
    Signed-off-by: David Sterba <dsterba@xxxxxxxx>
    Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>

diff --git a/fs/btrfs/extent_map.c b/fs/btrfs/extent_map.c
index 56d7580fdc3c4..3518e638374ea 100644
--- a/fs/btrfs/extent_map.c
+++ b/fs/btrfs/extent_map.c
@@ -867,7 +867,7 @@ void btrfs_drop_extent_map_range(struct btrfs_inode *inode, u64 start, u64 end,
 					split->block_len = em->block_len;
 					split->orig_start = em->orig_start;
 				} else {
-					const u64 diff = start + len - em->start;
+					const u64 diff = end - em->start;
 
 					split->block_len = split->len;
 					split->block_start += diff;




[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux