Patch "btrfs: fix defrag not merging contiguous extents due to merged extent maps" 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 defrag not merging contiguous extents due to merged extent maps

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-defrag-not-merging-contiguous-extents-due-.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 60e96501621d271121d40e3002f5fe2317f42273
Author: Filipe Manana <fdmanana@xxxxxxxx>
Date:   Tue Oct 29 15:18:45 2024 +0000

    btrfs: fix defrag not merging contiguous extents due to merged extent maps
    
    [ Upstream commit 77b0d113eec49a7390ff1a08ca1923e89f5f86c6 ]
    
    When running defrag (manual defrag) against a file that has extents that
    are contiguous and we already have the respective extent maps loaded and
    merged, we end up not defragging the range covered by those contiguous
    extents. This happens when we have an extent map that was the result of
    merging multiple extent maps for contiguous extents and the length of the
    merged extent map is greater than or equals to the defrag threshold
    length.
    
    The script below reproduces this scenario:
    
       $ cat test.sh
       #!/bin/bash
    
       DEV=/dev/sdi
       MNT=/mnt/sdi
    
       mkfs.btrfs -f $DEV
       mount $DEV $MNT
    
       # Create a 256K file with 4 extents of 64K each.
       xfs_io -f -c "falloc 0 64K" \
                 -c "pwrite 0 64K" \
                 -c "falloc 64K 64K" \
                 -c "pwrite 64K 64K" \
                 -c "falloc 128K 64K" \
                 -c "pwrite 128K 64K" \
                 -c "falloc 192K 64K" \
                 -c "pwrite 192K 64K" \
                 $MNT/foo
    
       umount $MNT
       echo -n "Initial number of file extent items: "
       btrfs inspect-internal dump-tree -t 5 $DEV | grep EXTENT_DATA | wc -l
    
       mount $DEV $MNT
       # Read the whole file in order to load and merge extent maps.
       cat $MNT/foo > /dev/null
    
       btrfs filesystem defragment -t 128K $MNT/foo
       umount $MNT
       echo -n "Number of file extent items after defrag with 128K threshold: "
       btrfs inspect-internal dump-tree -t 5 $DEV | grep EXTENT_DATA | wc -l
    
       mount $DEV $MNT
       # Read the whole file in order to load and merge extent maps.
       cat $MNT/foo > /dev/null
    
       btrfs filesystem defragment -t 256K $MNT/foo
       umount $MNT
       echo -n "Number of file extent items after defrag with 256K threshold: "
       btrfs inspect-internal dump-tree -t 5 $DEV | grep EXTENT_DATA | wc -l
    
    Running it:
    
       $ ./test.sh
       Initial number of file extent items: 4
       Number of file extent items after defrag with 128K threshold: 4
       Number of file extent items after defrag with 256K threshold: 4
    
    The 4 extents don't get merged because we have an extent map with a size
    of 256K that is the result of merging the individual extent maps for each
    of the four 64K extents and at defrag_lookup_extent() we have a value of
    zero for the generation threshold ('newer_than' argument) since this is a
    manual defrag. As a consequence we don't call defrag_get_extent() to get
    an extent map representing a single file extent item in the inode's
    subvolume tree, so we end up using the merged extent map at
    defrag_collect_targets() and decide not to defrag.
    
    Fix this by updating defrag_lookup_extent() to always discard extent maps
    that were merged and call defrag_get_extent() regardless of the minimum
    generation threshold ('newer_than' argument).
    
    A test case for fstests will be sent along soon.
    
    CC: stable@xxxxxxxxxxxxxxx # 6.1+
    Fixes: 199257a78bb0 ("btrfs: defrag: don't use merged extent map for their generation check")
    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/defrag.c b/fs/btrfs/defrag.c
index f6dbda37a3615..990ef97accec4 100644
--- a/fs/btrfs/defrag.c
+++ b/fs/btrfs/defrag.c
@@ -772,12 +772,12 @@ static struct extent_map *defrag_lookup_extent(struct inode *inode, u64 start,
 	 * We can get a merged extent, in that case, we need to re-search
 	 * tree to get the original em for defrag.
 	 *
-	 * If @newer_than is 0 or em::generation < newer_than, we can trust
-	 * this em, as either we don't care about the generation, or the
-	 * merged extent map will be rejected anyway.
+	 * This is because even if we have adjacent extents that are contiguous
+	 * and compatible (same type and flags), we still want to defrag them
+	 * so that we use less metadata (extent items in the extent tree and
+	 * file extent items in the inode's subvolume tree).
 	 */
-	if (em && (em->flags & EXTENT_FLAG_MERGED) &&
-	    newer_than && em->generation >= newer_than) {
+	if (em && (em->flags & EXTENT_FLAG_MERGED)) {
 		free_extent_map(em);
 		em = NULL;
 	}




[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