2 * extents.c --- rebuild extent tree
4 * Copyright (C) 2014 Oracle.
7 * This file may be redistributed under the terms of the GNU Public
23 #define NUM_EXTENTS 341 /* about one ETB' worth of extents */
25 static errcode_t
e2fsck_rebuild_extents(e2fsck_t ctx
, ext2_ino_t ino
);
27 /* Schedule an inode to have its extent tree rebuilt during pass 1E. */
28 errcode_t
e2fsck_rebuild_extents_later(e2fsck_t ctx
, ext2_ino_t ino
)
32 if (!ext2fs_has_feature_extents(ctx
->fs
->super
) ||
33 (ctx
->options
& E2F_OPT_NO
) ||
34 (ino
!= EXT2_ROOT_INO
&& ino
< ctx
->fs
->super
->s_first_ino
))
37 if (ctx
->flags
& E2F_FLAG_ALLOC_OK
)
38 return e2fsck_rebuild_extents(ctx
, ino
);
40 if (!ctx
->inodes_to_rebuild
)
41 retval
= e2fsck_allocate_inode_bitmap(ctx
->fs
,
42 _("extent rebuild inode map"),
45 &ctx
->inodes_to_rebuild
);
49 ext2fs_mark_inode_bitmap2(ctx
->inodes_to_rebuild
, ino
);
53 /* Ask if an inode will have its extents rebuilt during pass 1E. */
54 int e2fsck_ino_will_be_rebuilt(e2fsck_t ctx
, ext2_ino_t ino
)
56 if (!ctx
->inodes_to_rebuild
)
58 return ext2fs_test_inode_bitmap2(ctx
->inodes_to_rebuild
, ino
);
61 static errcode_t
load_extents(e2fsck_t ctx
, struct extent_list
*list
)
63 ext2_filsys fs
= ctx
->fs
;
64 ext2_extent_handle_t handle
;
65 struct ext2fs_extent extent
;
68 retval
= ext2fs_extent_open(fs
, list
->ino
, &handle
);
72 retval
= ext2fs_extent_get(handle
, EXT2_EXTENT_ROOT
, &extent
);
77 if (extent
.e_flags
& EXT2_EXTENT_FLAGS_SECOND_VISIT
)
80 /* Internal node; free it and we'll re-allocate it later */
81 if (!(extent
.e_flags
& EXT2_EXTENT_FLAGS_LEAF
)) {
82 #if defined(DEBUG) || defined(DEBUG_FREE)
83 printf("ino=%d free=%llu bf=%llu\n", list
->ino
,
84 extent
.e_pblk
, list
->blocks_freed
+ 1);
87 ext2fs_block_alloc_stats2(fs
, extent
.e_pblk
, -1);
92 /* Can we attach it to the previous extent? */
94 struct ext2fs_extent
*last
= list
->extents
+
96 blk64_t end
= last
->e_len
+ extent
.e_len
;
98 if (last
->e_pblk
+ last
->e_len
== extent
.e_pblk
&&
99 last
->e_lblk
+ last
->e_len
== extent
.e_lblk
&&
100 (last
->e_flags
& EXT2_EXTENT_FLAGS_UNINIT
) ==
101 (extent
.e_flags
& EXT2_EXTENT_FLAGS_UNINIT
) &&
102 end
< (1ULL << 32)) {
103 last
->e_len
+= extent
.e_len
;
105 printf("R: ino=%d len=%u\n", list
->ino
,
112 /* Do we need to expand? */
113 if (list
->count
== list
->size
) {
114 unsigned int new_size
= (list
->size
+ NUM_EXTENTS
) *
115 sizeof(struct ext2fs_extent
);
116 retval
= ext2fs_resize_mem(0, new_size
, &list
->extents
);
119 list
->size
+= NUM_EXTENTS
;
122 /* Add a new extent */
123 memcpy(list
->extents
+ list
->count
, &extent
, sizeof(extent
));
125 printf("R: ino=%d pblk=%llu lblk=%llu len=%u\n", list
->ino
,
126 extent
.e_pblk
, extent
.e_lblk
, extent
.e_len
);
130 retval
= ext2fs_extent_get(handle
, EXT2_EXTENT_NEXT
, &extent
);
131 } while (retval
== 0);
134 /* Ok if we run off the end */
135 if (retval
== EXT2_ET_EXTENT_NO_NEXT
)
137 ext2fs_extent_free(handle
);
141 static int find_blocks(ext2_filsys fs
, blk64_t
*blocknr
, e2_blkcnt_t blockcnt
,
142 blk64_t ref_blk
EXT2FS_ATTR((unused
)),
143 int ref_offset
EXT2FS_ATTR((unused
)), void *priv_data
)
145 struct extent_list
*list
= priv_data
;
149 #if defined(DEBUG) || defined(DEBUG_FREE)
150 printf("ino=%d free=%llu bf=%llu\n", list
->ino
, *blocknr
,
151 list
->blocks_freed
+ 1);
153 list
->blocks_freed
++;
154 ext2fs_block_alloc_stats2(fs
, *blocknr
, -1);
158 /* Can we attach it to the previous extent? */
160 struct ext2fs_extent
*last
= list
->extents
+
162 blk64_t end
= last
->e_len
+ 1;
164 if (last
->e_lblk
+ last
->e_len
== (__u64
) blockcnt
&&
165 last
->e_pblk
+ last
->e_len
== *blocknr
&&
166 end
< (1ULL << 32)) {
169 printf("R: ino=%d len=%u\n", list
->ino
, last
->e_len
);
175 /* Do we need to expand? */
176 if (list
->count
== list
->size
) {
177 unsigned int new_size
= (list
->size
+ NUM_EXTENTS
) *
178 sizeof(struct ext2fs_extent
);
179 list
->retval
= ext2fs_resize_mem(0, new_size
, &list
->extents
);
182 list
->size
+= NUM_EXTENTS
;
185 /* Add a new extent */
186 list
->extents
[list
->count
].e_pblk
= *blocknr
;
187 list
->extents
[list
->count
].e_lblk
= blockcnt
;
188 list
->extents
[list
->count
].e_len
= 1;
189 list
->extents
[list
->count
].e_flags
= 0;
191 printf("R: ino=%d pblk=%llu lblk=%llu len=%u\n", list
->ino
, *blocknr
,
199 static errcode_t
rewrite_extent_replay(e2fsck_t ctx
, struct extent_list
*list
,
200 struct ext2_inode_large
*inode
)
203 ext2_extent_handle_t handle
;
204 unsigned int i
, ext_written
;
205 struct ext2fs_extent
*ex
, extent
;
206 blk64_t start_val
, delta
;
208 /* Reset extent tree */
209 inode
->i_flags
&= ~EXT4_EXTENTS_FL
;
210 memset(inode
->i_block
, 0, sizeof(inode
->i_block
));
212 /* Make a note of freed blocks */
213 quota_data_sub(ctx
->qctx
, inode
, list
->ino
,
214 list
->blocks_freed
* ctx
->fs
->blocksize
);
215 retval
= ext2fs_iblk_sub_blocks(ctx
->fs
, EXT2_INODE(inode
),
220 /* Now stuff extents into the file */
221 retval
= ext2fs_extent_open2(ctx
->fs
, list
->ino
, EXT2_INODE(inode
),
228 start_val
= ext2fs_get_stat_i_blocks(ctx
->fs
, EXT2_INODE(inode
));
230 for (i
= 0, ex
= list
->extents
; i
< list
->count
; i
++, ex
++) {
233 memcpy(&extent
, ex
, sizeof(struct ext2fs_extent
));
234 extent
.e_flags
&= EXT2_EXTENT_FLAGS_UNINIT
;
235 if (extent
.e_flags
& EXT2_EXTENT_FLAGS_UNINIT
) {
236 if (extent
.e_len
> EXT_UNINIT_MAX_LEN
) {
237 extent
.e_len
= EXT_UNINIT_MAX_LEN
;
238 ex
->e_pblk
+= EXT_UNINIT_MAX_LEN
;
239 ex
->e_lblk
+= EXT_UNINIT_MAX_LEN
;
240 ex
->e_len
-= EXT_UNINIT_MAX_LEN
;
245 if (extent
.e_len
> EXT_INIT_MAX_LEN
) {
246 extent
.e_len
= EXT_INIT_MAX_LEN
;
247 ex
->e_pblk
+= EXT_INIT_MAX_LEN
;
248 ex
->e_lblk
+= EXT_INIT_MAX_LEN
;
249 ex
->e_len
-= EXT_INIT_MAX_LEN
;
256 printf("W: ino=%d pblk=%llu lblk=%llu len=%u\n", list
->ino
,
257 extent
.e_pblk
, extent
.e_lblk
, extent
.e_len
);
259 retval
= ext2fs_extent_insert(handle
, EXT2_EXTENT_INSERT_AFTER
,
263 retval
= ext2fs_extent_fix_parents(handle
);
269 delta
= ext2fs_get_stat_i_blocks(ctx
->fs
, EXT2_INODE(inode
)) -
272 quota_data_add(ctx
->qctx
, inode
, list
->ino
, delta
<< 9);
274 #if defined(DEBUG) || defined(DEBUG_SUMMARY)
275 printf("rebuild: ino=%d extents=%d->%d\n", ino
, list
->ext_read
,
278 e2fsck_write_inode(ctx
, list
->ino
, EXT2_INODE(inode
),
282 ext2fs_extent_free(handle
);
286 errcode_t
e2fsck_rewrite_extent_tree(e2fsck_t ctx
, struct extent_list
*list
)
288 struct ext2_inode_large inode
;
292 memset(&inode
, 0, sizeof(inode
));
293 err
= ext2fs_read_inode_full(ctx
->fs
, list
->ino
, EXT2_INODE(&inode
),
298 /* Skip deleted inodes and inline data files */
299 if (inode
.i_flags
& EXT4_INLINE_DATA_FL
)
302 err
= rewrite_extent_replay(ctx
, list
, &inode
);
306 err
= ext2fs_count_blocks(ctx
->fs
, list
->ino
, EXT2_INODE(&inode
),
310 err
= ext2fs_iblk_set(ctx
->fs
, EXT2_INODE(&inode
), blk_count
);
313 return ext2fs_write_inode_full(ctx
->fs
, list
->ino
, EXT2_INODE(&inode
),
317 errcode_t
e2fsck_read_extents(e2fsck_t ctx
, struct extent_list
*extents
)
319 struct ext2_inode_large inode
;
322 extents
->extents
= NULL
;
324 extents
->blocks_freed
= 0;
325 extents
->ext_read
= 0;
326 extents
->size
= NUM_EXTENTS
;
327 retval
= ext2fs_get_array(NUM_EXTENTS
, sizeof(struct ext2fs_extent
),
332 retval
= ext2fs_read_inode(ctx
->fs
, extents
->ino
, EXT2_INODE(&inode
));
336 retval
= load_extents(ctx
, extents
);
340 ext2fs_free_mem(&extents
->extents
);
346 static errcode_t
rebuild_extent_tree(e2fsck_t ctx
, struct extent_list
*list
,
349 struct ext2_inode_large inode
;
353 list
->blocks_freed
= 0;
356 e2fsck_read_inode_full(ctx
, ino
, EXT2_INODE(&inode
), sizeof(inode
),
359 /* Skip deleted inodes and inline data files */
360 if (inode
.i_links_count
== 0 ||
361 inode
.i_flags
& EXT4_INLINE_DATA_FL
)
364 /* Collect lblk->pblk mappings */
365 if (inode
.i_flags
& EXT4_EXTENTS_FL
) {
366 retval
= load_extents(ctx
, list
);
369 return rewrite_extent_replay(ctx
, list
, &inode
);
372 retval
= ext2fs_block_iterate3(ctx
->fs
, ino
, BLOCK_FLAG_READ_ONLY
, 0,
375 return retval
|| list
->retval
||
376 rewrite_extent_replay(ctx
, list
, &inode
);
379 /* Rebuild the extents immediately */
380 static errcode_t
e2fsck_rebuild_extents(e2fsck_t ctx
, ext2_ino_t ino
)
382 struct extent_list list
= { 0 };
385 if (!ext2fs_has_feature_extents(ctx
->fs
->super
) ||
386 (ctx
->options
& E2F_OPT_NO
) ||
387 (ino
!= EXT2_ROOT_INO
&& ino
< ctx
->fs
->super
->s_first_ino
))
390 e2fsck_read_bitmaps(ctx
);
391 err
= ext2fs_get_array(NUM_EXTENTS
, sizeof(struct ext2fs_extent
),
395 list
.size
= NUM_EXTENTS
;
396 err
= rebuild_extent_tree(ctx
, &list
, ino
);
397 ext2fs_free_mem(&list
.extents
);
402 static void rebuild_extents(e2fsck_t ctx
, const char *pass_name
, int pr_header
)
404 struct problem_context pctx
;
405 #ifdef RESOURCE_TRACK
406 struct resource_track rtrack
;
408 struct extent_list list
= { 0 };
413 if (!ext2fs_has_feature_extents(ctx
->fs
->super
) ||
414 !ext2fs_test_valid(ctx
->fs
) ||
415 ctx
->invalid_bitmaps
) {
416 if (ctx
->inodes_to_rebuild
)
417 ext2fs_free_inode_bitmap(ctx
->inodes_to_rebuild
);
418 ctx
->inodes_to_rebuild
= NULL
;
421 if (ctx
->inodes_to_rebuild
== NULL
)
424 init_resource_track(&rtrack
, ctx
->fs
->io
);
425 clear_problem_context(&pctx
);
426 e2fsck_read_bitmaps(ctx
);
428 list
.size
= NUM_EXTENTS
;
429 retval
= ext2fs_get_array(sizeof(struct ext2fs_extent
),
430 list
.size
, &list
.extents
);
434 retval
= ext2fs_find_first_set_inode_bitmap2(
435 ctx
->inodes_to_rebuild
, ino
+ 1,
436 ctx
->fs
->super
->s_inodes_count
, &ino
);
441 fix_problem(ctx
, pr_header
, &pctx
);
444 pctx
.errcode
= rebuild_extent_tree(ctx
, &list
, ino
);
446 end_problem_latch(ctx
, PR_LATCH_OPTIMIZE_EXT
);
447 fix_problem(ctx
, PR_1E_OPTIMIZE_EXT_ERR
, &pctx
);
449 if (ctx
->progress
&& !ctx
->progress_fd
)
450 e2fsck_simple_progress(ctx
, "Rebuilding extents",
451 100.0 * (float) ino
/
452 (float) ctx
->fs
->super
->s_inodes_count
,
455 end_problem_latch(ctx
, PR_LATCH_OPTIMIZE_EXT
);
457 ext2fs_free_inode_bitmap(ctx
->inodes_to_rebuild
);
458 ctx
->inodes_to_rebuild
= NULL
;
459 ext2fs_free_mem(&list
.extents
);
461 print_resource_track(ctx
, pass_name
, &rtrack
, ctx
->fs
->io
);
464 /* Scan a file to see if we should rebuild its extent tree */
465 errcode_t
e2fsck_check_rebuild_extents(e2fsck_t ctx
, ext2_ino_t ino
,
466 struct ext2_inode
*inode
,
467 struct problem_context
*pctx
)
469 struct extent_tree_info eti
;
470 struct ext2_extent_info info
, top_info
;
471 struct ext2fs_extent extent
;
472 ext2_extent_handle_t ehandle
;
473 ext2_filsys fs
= ctx
->fs
;
476 /* block map file and we want extent conversion */
477 if (!(inode
->i_flags
& EXT4_EXTENTS_FL
) &&
478 !(inode
->i_flags
& EXT4_INLINE_DATA_FL
) &&
479 (ctx
->options
& E2F_OPT_CONVERT_BMAP
)) {
480 return e2fsck_rebuild_extents_later(ctx
, ino
);
483 if (!(inode
->i_flags
& EXT4_EXTENTS_FL
))
485 memset(&eti
, 0, sizeof(eti
));
488 /* Otherwise, go scan the extent tree... */
489 retval
= ext2fs_extent_open2(fs
, ino
, inode
, &ehandle
);
493 retval
= ext2fs_extent_get_info(ehandle
, &top_info
);
497 /* Check maximum extent depth */
499 pctx
->blk
= top_info
.max_depth
;
500 pctx
->blk2
= ext2fs_max_extent_depth(ehandle
);
501 if (pctx
->blk2
< pctx
->blk
&&
502 fix_problem(ctx
, PR_1_EXTENT_BAD_MAX_DEPTH
, pctx
))
503 eti
.force_rebuild
= 1;
505 /* Can we collect extent tree level stats? */
506 pctx
->blk
= MAX_EXTENT_DEPTH_COUNT
;
507 if (pctx
->blk2
> pctx
->blk
)
508 fix_problem(ctx
, PR_1E_MAX_EXTENT_TREE_DEPTH
, pctx
);
510 /* We need to fix tree depth problems, but the scan isn't a fix. */
511 if (ctx
->options
& E2F_OPT_FIXES_ONLY
)
514 retval
= ext2fs_extent_get(ehandle
, EXT2_EXTENT_ROOT
, &extent
);
519 retval
= ext2fs_extent_get_info(ehandle
, &info
);
524 * If this is the first extent in an extent block that we
525 * haven't visited, collect stats on the block.
527 if (info
.curr_entry
== 1 &&
528 !(extent
.e_flags
& EXT2_EXTENT_FLAGS_SECOND_VISIT
) &&
529 !eti
.force_rebuild
&&
530 info
.curr_level
< MAX_EXTENT_DEPTH_COUNT
) {
531 struct extent_tree_level
*etl
;
533 etl
= eti
.ext_info
+ info
.curr_level
;
534 etl
->num_extents
+= info
.num_entries
;
535 etl
->max_extents
+= info
.max_entries
;
537 * Implementation wart: Splitting extent blocks when
538 * appending will leave the old block with one free
539 * entry. Therefore unless the node is totally full,
540 * pretend that a non-root extent block can hold one
541 * fewer entry than it actually does, so that we don't
542 * repeatedly rebuild the extent tree.
544 if (info
.curr_level
&&
545 info
.num_entries
< info
.max_entries
)
549 /* Skip to the end of a block of leaf nodes */
550 if (extent
.e_flags
& EXT2_EXTENT_FLAGS_LEAF
) {
551 retval
= ext2fs_extent_get(ehandle
,
552 EXT2_EXTENT_LAST_SIB
,
558 retval
= ext2fs_extent_get(ehandle
, EXT2_EXTENT_NEXT
, &extent
);
559 } while (retval
== 0);
561 ext2fs_extent_free(ehandle
);
562 return e2fsck_should_rebuild_extents(ctx
, pctx
, &eti
, &top_info
);
565 /* Having scanned a file's extent tree, decide if we should rebuild it */
566 errcode_t
e2fsck_should_rebuild_extents(e2fsck_t ctx
,
567 struct problem_context
*pctx
,
568 struct extent_tree_info
*eti
,
569 struct ext2_extent_info
*info
)
571 struct extent_tree_level
*ei
;
573 unsigned int extents_per_block
;
575 if (eti
->force_rebuild
)
578 if (ctx
->options
& E2F_OPT_NOOPT_EXTENTS
)
581 extents_per_block
= (ctx
->fs
->blocksize
-
582 sizeof(struct ext3_extent_header
)) /
583 sizeof(struct ext3_extent
);
585 /* If the extent tree is too deep, then rebuild it. */
586 if (info
->max_depth
> MAX_EXTENT_DEPTH_COUNT
) {
587 pctx
->blk
= info
->max_depth
;
588 op
= PR_1E_CAN_COLLAPSE_EXTENT_TREE
;
592 * If we can consolidate a level or shorten the tree, schedule the
593 * extent tree to be rebuilt.
595 for (i
= 0, ei
= eti
->ext_info
; i
< info
->max_depth
+ 1; i
++, ei
++) {
596 if (ei
->max_extents
- ei
->num_extents
> extents_per_block
) {
598 op
= PR_1E_CAN_NARROW_EXTENT_TREE
;
601 for (j
= 0; j
< i
; j
++) {
602 if (ei
->num_extents
< eti
->ext_info
[j
].max_extents
) {
604 op
= PR_1E_CAN_COLLAPSE_EXTENT_TREE
;
612 if (eti
->force_rebuild
|| fix_problem(ctx
, op
, pctx
))
613 return e2fsck_rebuild_extents_later(ctx
, eti
->ino
);
617 void e2fsck_pass1e(e2fsck_t ctx
)
619 rebuild_extents(ctx
, "Pass 1E", PR_1E_PASS_HEADER
);