Patch "btrfs: fix extent map merging not happening for adjacent extents" has been added to the 6.11-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 extent map merging not happening for adjacent extents

to the 6.11-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-extent-map-merging-not-happening-for-adjac.patch
and it can be found in the queue-6.11 subdirectory.

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



commit 5fa935d4185f50c9e50ded8a6982ca433892847a
Author: Filipe Manana <fdmanana@xxxxxxxx>
Date:   Mon Oct 28 16:23:00 2024 +0000

    btrfs: fix extent map merging not happening for adjacent extents
    
    [ Upstream commit a0f0625390858321525c2a8d04e174a546bd19b3 ]
    
    If we have 3 or more adjacent extents in a file, that is, consecutive file
    extent items pointing to adjacent extents, within a contiguous file range
    and compatible flags, we end up not merging all the extents into a single
    extent map.
    
    For example:
    
      $ mkfs.btrfs -f /dev/sdc
      $ mount /dev/sdc /mnt/sdc
    
      $ xfs_io -f -d -c "pwrite -b 64K 0 64K" \
                     -c "pwrite -b 64K 64K 64K" \
                     -c "pwrite -b 64K 128K 64K" \
                     -c "pwrite -b 64K 192K 64K" \
                     /mnt/sdc/foo
    
    After all the ordered extents complete we unpin the extent maps and try
    to merge them, but instead of getting a single extent map we get two
    because:
    
    1) When the first ordered extent completes (file range [0, 64K)) we
       unpin its extent map and attempt to merge it with the extent map for
       the range [64K, 128K), but we can't because that extent map is still
       pinned;
    
    2) When the second ordered extent completes (file range [64K, 128K)), we
       unpin its extent map and merge it with the previous extent map, for
       file range [0, 64K), but we can't merge with the next extent map, for
       the file range [128K, 192K), because this one is still pinned.
    
       The merged extent map for the file range [0, 128K) gets the flag
       EXTENT_MAP_MERGED set;
    
    3) When the third ordered extent completes (file range [128K, 192K)), we
       unpin its extent map and attempt to merge it with the previous extent
       map, for file range [0, 128K), but we can't because that extent map
       has the flag EXTENT_MAP_MERGED set (mergeable_maps() returns false
       due to different flags) while the extent map for the range [128K, 192K)
       doesn't have that flag set.
    
       We also can't merge it with the next extent map, for file range
       [192K, 256K), because that one is still pinned.
    
       At this moment we have 3 extent maps:
    
       One for file range [0, 128K), with the flag EXTENT_MAP_MERGED set.
       One for file range [128K, 192K).
       One for file range [192K, 256K) which is still pinned;
    
    4) When the fourth and final extent completes (file range [192K, 256K)),
       we unpin its extent map and attempt to merge it with the previous
       extent map, for file range [128K, 192K), which succeeds since none
       of these extent maps have the EXTENT_MAP_MERGED flag set.
    
       So we end up with 2 extent maps:
    
       One for file range [0, 128K), with the flag EXTENT_MAP_MERGED set.
       One for file range [128K, 256K), with the flag EXTENT_MAP_MERGED set.
    
       Since after merging extent maps we don't attempt to merge again, that
       is, merge the resulting extent map with the one that is now preceding
       it (and the one following it), we end up with those two extent maps,
       when we could have had a single extent map to represent the whole file.
    
    Fix this by making mergeable_maps() ignore the EXTENT_MAP_MERGED flag.
    While this doesn't present any functional issue, it prevents the merging
    of extent maps which allows to save memory, and can make defrag not
    merging extents too (that will be addressed in the next patch).
    
    Fixes: 199257a78bb0 ("btrfs: defrag: don't use merged extent map for their generation check")
    CC: stable@xxxxxxxxxxxxxxx # 6.1+
    Reviewed-by: Qu Wenruo <wqu@xxxxxxxx>
    Signed-off-by: Filipe Manana <fdmanana@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 72ae8f64482c6..b56ec83bf9528 100644
--- a/fs/btrfs/extent_map.c
+++ b/fs/btrfs/extent_map.c
@@ -227,7 +227,12 @@ static bool mergeable_maps(const struct extent_map *prev, const struct extent_ma
 	if (extent_map_end(prev) != next->start)
 		return false;
 
-	if (prev->flags != next->flags)
+	/*
+	 * The merged flag is not an on-disk flag, it just indicates we had the
+	 * extent maps of 2 (or more) adjacent extents merged, so factor it out.
+	 */
+	if ((prev->flags & ~EXTENT_FLAG_MERGED) !=
+	    (next->flags & ~EXTENT_FLAG_MERGED))
 		return false;
 
 	if (next->disk_bytenr < EXTENT_MAP_LAST_BYTE - 1)




[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