Skip to content

Commit 3d2ac99

Browse files
adam900710kdave
authored andcommitted
btrfs: introduce new members for extent_map
Introduce two new members for extent_map: - disk_bytenr - offset Both are matching the members with the same name inside btrfs_file_extent_items. For now this patch only touches those members when: - Reading btrfs_file_extent_items from disk - Inserting new holes - Merging two extent maps With the new disk_bytenr and disk_num_bytes, doing merging would be a little more complex, as we have 3 different cases: * Both extent maps are referring to the same data extents |<----- data extent A ----->| |<- em 1 ->|<- em 2 ->| * Both extent maps are referring to different data extents |<-- data extent A -->|<-- data extent B -->| |<- em 1 ->|<- em 2 ->| * One of the extent maps is referring to a merged and larger data extent that covers both extent maps This is not really valid case other than some selftests. So this test case would be removed. A new helper merge_ondisk_extents() is introduced to handle the above valid cases. To properly assign values for those new members, a new btrfs_file_extent parameter is introduced to all the involved call sites. - For NOCOW writes the btrfs_file_extent would be exposed from can_nocow_file_extent(). - For other writes, the members can be easily calculated As most of them have 0 offset and utilizing the whole on-disk data extent. The exception is encoded write, but thankfully that interface provided offset directly and all other needed info. For now, both the old members (block_start/block_len/orig_start) are co-existing with the new members (disk_bytenr/offset), meanwhile all the critical code is still using the old members only. The cleanup will happen later after all the old and new members are properly validated. There would be some re-ordering for the assignment of the extent_map members, now we follow the new ordering: - start and len Or file_pos and num_bytes for other structures. - disk_bytenr and disk_num_bytes - offset and ram_bytes - compression So expect some seemingly unrelated line movement. Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com> Reviewed-by: Filipe Manana <fdmanana@suse.com> Signed-off-by: Qu Wenruo <wqu@suse.com> Reviewed-by: David Sterba <dsterba@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
1 parent 87a6962 commit 3d2ac99

File tree

6 files changed

+156
-11
lines changed

6 files changed

+156
-11
lines changed

fs/btrfs/defrag.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -709,6 +709,10 @@ static struct extent_map *defrag_get_extent(struct btrfs_inode *inode,
709709
em->start = start;
710710
em->orig_start = start;
711711
em->block_start = EXTENT_MAP_HOLE;
712+
em->disk_bytenr = EXTENT_MAP_HOLE;
713+
em->disk_num_bytes = 0;
714+
em->ram_bytes = 0;
715+
em->offset = 0;
712716
em->len = key.offset - start;
713717
break;
714718
}

fs/btrfs/extent_map.c

Lines changed: 75 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,61 @@ static bool mergeable_maps(const struct extent_map *prev, const struct extent_ma
229229
return next->block_start == prev->block_start;
230230
}
231231

232+
/*
233+
* Handle the on-disk data extents merge for @prev and @next.
234+
*
235+
* Only touches disk_bytenr/disk_num_bytes/offset/ram_bytes.
236+
* For now only uncompressed regular extent can be merged.
237+
*
238+
* @prev and @next will be both updated to point to the new merged range.
239+
* Thus one of them should be removed by the caller.
240+
*/
241+
static void merge_ondisk_extents(struct extent_map *prev, struct extent_map *next)
242+
{
243+
u64 new_disk_bytenr;
244+
u64 new_disk_num_bytes;
245+
u64 new_offset;
246+
247+
/* @prev and @next should not be compressed. */
248+
ASSERT(!extent_map_is_compressed(prev));
249+
ASSERT(!extent_map_is_compressed(next));
250+
251+
/*
252+
* There are two different cases where @prev and @next can be merged.
253+
*
254+
* 1) They are referring to the same data extent:
255+
*
256+
* |<----- data extent A ----->|
257+
* |<- prev ->|<- next ->|
258+
*
259+
* 2) They are referring to different data extents but still adjacent:
260+
*
261+
* |<-- data extent A -->|<-- data extent B -->|
262+
* |<- prev ->|<- next ->|
263+
*
264+
* The calculation here always merges the data extents first, then updates
265+
* @offset using the new data extents.
266+
*
267+
* For case 1), the merged data extent would be the same.
268+
* For case 2), we just merge the two data extents into one.
269+
*/
270+
new_disk_bytenr = min(prev->disk_bytenr, next->disk_bytenr);
271+
new_disk_num_bytes = max(prev->disk_bytenr + prev->disk_num_bytes,
272+
next->disk_bytenr + next->disk_num_bytes) -
273+
new_disk_bytenr;
274+
new_offset = prev->disk_bytenr + prev->offset - new_disk_bytenr;
275+
276+
prev->disk_bytenr = new_disk_bytenr;
277+
prev->disk_num_bytes = new_disk_num_bytes;
278+
prev->ram_bytes = new_disk_num_bytes;
279+
prev->offset = new_offset;
280+
281+
next->disk_bytenr = new_disk_bytenr;
282+
next->disk_num_bytes = new_disk_num_bytes;
283+
next->ram_bytes = new_disk_num_bytes;
284+
next->offset = new_offset;
285+
}
286+
232287
static void try_merge_map(struct btrfs_inode *inode, struct extent_map *em)
233288
{
234289
struct extent_map_tree *tree = &inode->extent_tree;
@@ -260,6 +315,9 @@ static void try_merge_map(struct btrfs_inode *inode, struct extent_map *em)
260315
em->block_len += merge->block_len;
261316
em->block_start = merge->block_start;
262317
em->generation = max(em->generation, merge->generation);
318+
319+
if (em->disk_bytenr < EXTENT_MAP_LAST_BYTE)
320+
merge_ondisk_extents(merge, em);
263321
em->flags |= EXTENT_FLAG_MERGED;
264322

265323
rb_erase(&merge->rb_node, &tree->root);
@@ -275,6 +333,8 @@ static void try_merge_map(struct btrfs_inode *inode, struct extent_map *em)
275333
if (rb && can_merge_extent_map(merge) && mergeable_maps(em, merge)) {
276334
em->len += merge->len;
277335
em->block_len += merge->block_len;
336+
if (em->disk_bytenr < EXTENT_MAP_LAST_BYTE)
337+
merge_ondisk_extents(em, merge);
278338
rb_erase(&merge->rb_node, &tree->root);
279339
RB_CLEAR_NODE(&merge->rb_node);
280340
em->generation = max(em->generation, merge->generation);
@@ -562,6 +622,7 @@ static noinline int merge_extent_mapping(struct btrfs_inode *inode,
562622
!extent_map_is_compressed(em)) {
563623
em->block_start += start_diff;
564624
em->block_len = em->len;
625+
em->offset += start_diff;
565626
}
566627
return add_extent_mapping(inode, em, 0);
567628
}
@@ -785,14 +846,18 @@ void btrfs_drop_extent_map_range(struct btrfs_inode *inode, u64 start, u64 end,
785846
split->block_len = em->block_len;
786847
else
787848
split->block_len = split->len;
849+
split->disk_bytenr = em->disk_bytenr;
788850
split->disk_num_bytes = max(split->block_len,
789851
em->disk_num_bytes);
852+
split->offset = em->offset;
790853
split->ram_bytes = em->ram_bytes;
791854
} else {
792855
split->orig_start = split->start;
793856
split->block_len = 0;
794857
split->block_start = em->block_start;
858+
split->disk_bytenr = em->disk_bytenr;
795859
split->disk_num_bytes = 0;
860+
split->offset = 0;
796861
split->ram_bytes = split->len;
797862
}
798863

@@ -813,13 +878,14 @@ void btrfs_drop_extent_map_range(struct btrfs_inode *inode, u64 start, u64 end,
813878
split->start = end;
814879
split->len = em_end - end;
815880
split->block_start = em->block_start;
881+
split->disk_bytenr = em->disk_bytenr;
816882
split->flags = flags;
817883
split->generation = gen;
818884

819885
if (em->block_start < EXTENT_MAP_LAST_BYTE) {
820886
split->disk_num_bytes = max(em->block_len,
821887
em->disk_num_bytes);
822-
888+
split->offset = em->offset + end - em->start;
823889
split->ram_bytes = em->ram_bytes;
824890
if (compressed) {
825891
split->block_len = em->block_len;
@@ -832,10 +898,11 @@ void btrfs_drop_extent_map_range(struct btrfs_inode *inode, u64 start, u64 end,
832898
split->orig_start = em->orig_start;
833899
}
834900
} else {
901+
split->disk_num_bytes = 0;
902+
split->offset = 0;
835903
split->ram_bytes = split->len;
836904
split->orig_start = split->start;
837905
split->block_len = 0;
838-
split->disk_num_bytes = 0;
839906
}
840907

841908
if (extent_map_in_tree(em)) {
@@ -989,10 +1056,12 @@ int split_extent_map(struct btrfs_inode *inode, u64 start, u64 len, u64 pre,
9891056
/* First, replace the em with a new extent_map starting from * em->start */
9901057
split_pre->start = em->start;
9911058
split_pre->len = pre;
1059+
split_pre->disk_bytenr = new_logical;
1060+
split_pre->disk_num_bytes = split_pre->len;
1061+
split_pre->offset = 0;
9921062
split_pre->orig_start = split_pre->start;
9931063
split_pre->block_start = new_logical;
9941064
split_pre->block_len = split_pre->len;
995-
split_pre->disk_num_bytes = split_pre->block_len;
9961065
split_pre->ram_bytes = split_pre->len;
9971066
split_pre->flags = flags;
9981067
split_pre->generation = em->generation;
@@ -1007,10 +1076,12 @@ int split_extent_map(struct btrfs_inode *inode, u64 start, u64 len, u64 pre,
10071076
/* Insert the middle extent_map. */
10081077
split_mid->start = em->start + pre;
10091078
split_mid->len = em->len - pre;
1079+
split_mid->disk_bytenr = em->block_start + pre;
1080+
split_mid->disk_num_bytes = split_mid->len;
1081+
split_mid->offset = 0;
10101082
split_mid->orig_start = split_mid->start;
10111083
split_mid->block_start = em->block_start + pre;
10121084
split_mid->block_len = split_mid->len;
1013-
split_mid->disk_num_bytes = split_mid->block_len;
10141085
split_mid->ram_bytes = split_mid->len;
10151086
split_mid->flags = flags;
10161087
split_mid->generation = em->generation;

fs/btrfs/extent_map.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,12 +70,29 @@ struct extent_map {
7070
*/
7171
u64 orig_start;
7272

73+
/*
74+
* The bytenr of the full on-disk extent.
75+
*
76+
* For regular extents it's btrfs_file_extent_item::disk_bytenr.
77+
* For holes it's EXTENT_MAP_HOLE and for inline extents it's
78+
* EXTENT_MAP_INLINE.
79+
*/
80+
u64 disk_bytenr;
81+
7382
/*
7483
* The full on-disk extent length, matching
7584
* btrfs_file_extent_item::disk_num_bytes.
7685
*/
7786
u64 disk_num_bytes;
7887

88+
/*
89+
* Offset inside the decompressed extent.
90+
*
91+
* For regular extents it's btrfs_file_extent_item::offset.
92+
* For holes and inline extents it's 0.
93+
*/
94+
u64 offset;
95+
7996
/*
8097
* The decompressed size of the whole on-disk extent, matching
8198
* btrfs_file_extent_item::ram_bytes.

fs/btrfs/file-item.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1295,12 +1295,17 @@ void btrfs_extent_item_to_extent_map(struct btrfs_inode *inode,
12951295
em->len = btrfs_file_extent_end(path) - extent_start;
12961296
em->orig_start = extent_start -
12971297
btrfs_file_extent_offset(leaf, fi);
1298-
em->disk_num_bytes = btrfs_file_extent_disk_num_bytes(leaf, fi);
12991298
bytenr = btrfs_file_extent_disk_bytenr(leaf, fi);
13001299
if (bytenr == 0) {
13011300
em->block_start = EXTENT_MAP_HOLE;
1301+
em->disk_bytenr = EXTENT_MAP_HOLE;
1302+
em->disk_num_bytes = 0;
1303+
em->offset = 0;
13021304
return;
13031305
}
1306+
em->disk_bytenr = btrfs_file_extent_disk_bytenr(leaf, fi);
1307+
em->disk_num_bytes = btrfs_file_extent_disk_num_bytes(leaf, fi);
1308+
em->offset = btrfs_file_extent_offset(leaf, fi);
13041309
if (compress_type != BTRFS_COMPRESS_NONE) {
13051310
extent_map_set_compression(em, compress_type);
13061311
em->block_start = bytenr;
@@ -1317,8 +1322,10 @@ void btrfs_extent_item_to_extent_map(struct btrfs_inode *inode,
13171322
ASSERT(extent_start == 0);
13181323

13191324
em->block_start = EXTENT_MAP_INLINE;
1325+
em->disk_bytenr = EXTENT_MAP_INLINE;
13201326
em->start = 0;
13211327
em->len = fs_info->sectorsize;
1328+
em->offset = 0;
13221329
/*
13231330
* Initialize orig_start and block_len with the same values
13241331
* as in inode.c:btrfs_get_extent().

fs/btrfs/file.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2349,6 +2349,7 @@ static int fill_holes(struct btrfs_trans_handle *trans,
23492349
hole_em->orig_start = offset;
23502350

23512351
hole_em->block_start = EXTENT_MAP_HOLE;
2352+
hole_em->disk_bytenr = EXTENT_MAP_HOLE;
23522353
hole_em->block_len = 0;
23532354
hole_em->disk_num_bytes = 0;
23542355
hole_em->generation = trans->transid;

0 commit comments

Comments
 (0)