Skip to content

Commit 199257a

Browse files
adam900710kdave
authored andcommitted
btrfs: defrag: don't use merged extent map for their generation check
For extent maps, if they are not compressed extents and are adjacent by logical addresses and file offsets, they can be merged into one larger extent map. Such merged extent map will have the higher generation of all the original ones. But this brings a problem for autodefrag, as it relies on accurate extent_map::generation to determine if one extent should be defragged. For merged extent maps, their higher generation can mark some older extents to be defragged while the original extent map doesn't meet the minimal generation threshold. Thus this will cause extra IO. So solve the problem, here we introduce a new flag, EXTENT_FLAG_MERGED, to indicate if the extent map is merged from one or more ems. And for autodefrag, if we find a merged extent map, and its generation meets the generation requirement, we just don't use this one, and go back to defrag_get_extent() to read extent maps from subvolume trees. This could cause more read IO, but should result less defrag data write, so in the long run it should be a win for autodefrag. Reviewed-by: Filipe Manana <fdmanana@suse.com> Signed-off-by: Qu Wenruo <wqu@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
1 parent d5633b0 commit 199257a

3 files changed

Lines changed: 24 additions & 0 deletions

File tree

fs/btrfs/extent_map.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,7 @@ static void try_merge_map(struct extent_map_tree *tree, struct extent_map *em)
261261
em->mod_len = (em->mod_len + em->mod_start) - merge->mod_start;
262262
em->mod_start = merge->mod_start;
263263
em->generation = max(em->generation, merge->generation);
264+
set_bit(EXTENT_FLAG_MERGED, &em->flags);
264265

265266
rb_erase_cached(&merge->rb_node, &tree->map);
266267
RB_CLEAR_NODE(&merge->rb_node);
@@ -278,6 +279,7 @@ static void try_merge_map(struct extent_map_tree *tree, struct extent_map *em)
278279
RB_CLEAR_NODE(&merge->rb_node);
279280
em->mod_len = (merge->mod_start + merge->mod_len) - em->mod_start;
280281
em->generation = max(em->generation, merge->generation);
282+
set_bit(EXTENT_FLAG_MERGED, &em->flags);
281283
free_extent_map(merge);
282284
}
283285
}

fs/btrfs/extent_map.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ enum {
2525
EXTENT_FLAG_FILLING,
2626
/* filesystem extent mapping type */
2727
EXTENT_FLAG_FS_MAPPING,
28+
/* This em is merged from two or more physically adjacent ems */
29+
EXTENT_FLAG_MERGED,
2830
};
2931

3032
struct extent_map {
@@ -40,6 +42,12 @@ struct extent_map {
4042
u64 ram_bytes;
4143
u64 block_start;
4244
u64 block_len;
45+
46+
/*
47+
* Generation of the extent map, for merged em it's the highest
48+
* generation of all merged ems.
49+
* For non-merged extents, it's from btrfs_file_extent_item::generation.
50+
*/
4351
u64 generation;
4452
unsigned long flags;
4553
/* Used for chunk mappings, flag EXTENT_FLAG_FS_MAPPING must be set */

fs/btrfs/ioctl.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1175,6 +1175,20 @@ static struct extent_map *defrag_lookup_extent(struct inode *inode, u64 start,
11751175
em = lookup_extent_mapping(em_tree, start, sectorsize);
11761176
read_unlock(&em_tree->lock);
11771177

1178+
/*
1179+
* We can get a merged extent, in that case, we need to re-search
1180+
* tree to get the original em for defrag.
1181+
*
1182+
* If @newer_than is 0 or em::generation < newer_than, we can trust
1183+
* this em, as either we don't care about the generation, or the
1184+
* merged extent map will be rejected anyway.
1185+
*/
1186+
if (em && test_bit(EXTENT_FLAG_MERGED, &em->flags) &&
1187+
newer_than && em->generation >= newer_than) {
1188+
free_extent_map(em);
1189+
em = NULL;
1190+
}
1191+
11781192
if (!em) {
11791193
struct extent_state *cached = NULL;
11801194
u64 end = start + sectorsize - 1;

0 commit comments

Comments
 (0)