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 (!EXT2_HAS_INCOMPAT_FEATURE(ctx
->fs
->super
,
33 EXT3_FEATURE_INCOMPAT_EXTENTS
) ||
34 (ctx
->options
& E2F_OPT_NO
) ||
35 (ino
!= EXT2_ROOT_INO
&& ino
< ctx
->fs
->super
->s_first_ino
))
38 if (ctx
->flags
& E2F_FLAG_ALLOC_OK
)
39 return e2fsck_rebuild_extents(ctx
, ino
);
41 if (!ctx
->inodes_to_rebuild
)
42 retval
= e2fsck_allocate_inode_bitmap(ctx
->fs
,
43 _("extent rebuild inode map"),
46 &ctx
->inodes_to_rebuild
);
50 ext2fs_mark_inode_bitmap2(ctx
->inodes_to_rebuild
, ino
);
54 /* Ask if an inode will have its extents rebuilt during pass 1E. */
55 int e2fsck_ino_will_be_rebuilt(e2fsck_t ctx
, ext2_ino_t ino
)
57 if (!ctx
->inodes_to_rebuild
)
59 return ext2fs_test_inode_bitmap2(ctx
->inodes_to_rebuild
, ino
);
64 struct ext2fs_extent
*extents
;
67 unsigned int ext_read
;
72 static errcode_t
load_extents(e2fsck_t ctx
, struct extent_list
*list
)
74 ext2_filsys fs
= ctx
->fs
;
75 ext2_extent_handle_t handle
;
76 struct ext2fs_extent extent
;
79 retval
= ext2fs_extent_open(fs
, list
->ino
, &handle
);
83 retval
= ext2fs_extent_get(handle
, EXT2_EXTENT_ROOT
, &extent
);
88 if (extent
.e_flags
& EXT2_EXTENT_FLAGS_SECOND_VISIT
)
91 /* Internal node; free it and we'll re-allocate it later */
92 if (!(extent
.e_flags
& EXT2_EXTENT_FLAGS_LEAF
)) {
93 #if defined(DEBUG) || defined(DEBUG_FREE)
94 printf("ino=%d free=%llu bf=%llu\n", list
->ino
,
95 extent
.e_pblk
, list
->blocks_freed
+ 1);
98 ext2fs_block_alloc_stats2(fs
, extent
.e_pblk
, -1);
103 /* Can we attach it to the previous extent? */
105 struct ext2fs_extent
*last
= list
->extents
+
107 blk64_t end
= last
->e_len
+ extent
.e_len
;
109 if (last
->e_pblk
+ last
->e_len
== extent
.e_pblk
&&
110 last
->e_lblk
+ last
->e_len
== extent
.e_lblk
&&
111 (last
->e_flags
& EXT2_EXTENT_FLAGS_UNINIT
) ==
112 (extent
.e_flags
& EXT2_EXTENT_FLAGS_UNINIT
) &&
113 end
< (1ULL << 32)) {
114 last
->e_len
+= extent
.e_len
;
116 printf("R: ino=%d len=%u\n", list
->ino
,
123 /* Do we need to expand? */
124 if (list
->count
== list
->size
) {
125 unsigned int new_size
= (list
->size
+ NUM_EXTENTS
) *
126 sizeof(struct ext2fs_extent
);
127 retval
= ext2fs_resize_mem(0, new_size
, &list
->extents
);
130 list
->size
+= NUM_EXTENTS
;
133 /* Add a new extent */
134 memcpy(list
->extents
+ list
->count
, &extent
, sizeof(extent
));
136 printf("R: ino=%d pblk=%llu lblk=%llu len=%u\n", list
->ino
,
137 extent
.e_pblk
, extent
.e_lblk
, extent
.e_len
);
141 retval
= ext2fs_extent_get(handle
, EXT2_EXTENT_NEXT
, &extent
);
142 } while (retval
== 0);
145 /* Ok if we run off the end */
146 if (retval
== EXT2_ET_EXTENT_NO_NEXT
)
148 ext2fs_extent_free(handle
);
152 static int find_blocks(ext2_filsys fs
, blk64_t
*blocknr
, e2_blkcnt_t blockcnt
,
153 blk64_t ref_blk
EXT2FS_ATTR((unused
)),
154 int ref_offset
EXT2FS_ATTR((unused
)), void *priv_data
)
156 struct extent_list
*list
= priv_data
;
160 #if defined(DEBUG) || defined(DEBUG_FREE)
161 printf("ino=%d free=%llu bf=%llu\n", list
->ino
, *blocknr
,
162 list
->blocks_freed
+ 1);
164 list
->blocks_freed
++;
165 ext2fs_block_alloc_stats2(fs
, *blocknr
, -1);
169 /* Can we attach it to the previous extent? */
171 struct ext2fs_extent
*last
= list
->extents
+
173 blk64_t end
= last
->e_len
+ 1;
175 if (last
->e_pblk
+ last
->e_len
== *blocknr
&&
176 end
< (1ULL << 32)) {
179 printf("R: ino=%d len=%u\n", list
->ino
, last
->e_len
);
185 /* Do we need to expand? */
186 if (list
->count
== list
->size
) {
187 unsigned int new_size
= (list
->size
+ NUM_EXTENTS
) *
188 sizeof(struct ext2fs_extent
);
189 list
->retval
= ext2fs_resize_mem(0, new_size
, &list
->extents
);
192 list
->size
+= NUM_EXTENTS
;
195 /* Add a new extent */
196 list
->extents
[list
->count
].e_pblk
= *blocknr
;
197 list
->extents
[list
->count
].e_lblk
= blockcnt
;
198 list
->extents
[list
->count
].e_len
= 1;
199 list
->extents
[list
->count
].e_flags
= 0;
201 printf("R: ino=%d pblk=%llu lblk=%llu len=%u\n", list
->ino
, *blocknr
,
209 static errcode_t
rebuild_extent_tree(e2fsck_t ctx
, struct extent_list
*list
,
212 struct ext2_inode inode
;
214 ext2_extent_handle_t handle
;
215 unsigned int i
, ext_written
;
216 struct ext2fs_extent
*ex
, extent
;
219 list
->blocks_freed
= 0;
222 e2fsck_read_inode(ctx
, ino
, &inode
, "rebuild_extents");
224 /* Skip deleted inodes and inline data files */
225 if (inode
.i_links_count
== 0 ||
226 inode
.i_flags
& EXT4_INLINE_DATA_FL
)
229 /* Collect lblk->pblk mappings */
230 if (inode
.i_flags
& EXT4_EXTENTS_FL
) {
231 retval
= load_extents(ctx
, list
);
237 retval
= ext2fs_block_iterate3(ctx
->fs
, ino
, BLOCK_FLAG_READ_ONLY
, 0,
242 retval
= list
->retval
;
247 /* Reset extent tree */
248 inode
.i_flags
&= ~EXT4_EXTENTS_FL
;
249 memset(inode
.i_block
, 0, sizeof(inode
.i_block
));
251 /* Make a note of freed blocks */
252 retval
= ext2fs_iblk_sub_blocks(ctx
->fs
, &inode
, list
->blocks_freed
);
256 /* Now stuff extents into the file */
257 retval
= ext2fs_extent_open2(ctx
->fs
, ino
, &inode
, &handle
);
262 for (i
= 0, ex
= list
->extents
; i
< list
->count
; i
++, ex
++) {
263 memcpy(&extent
, ex
, sizeof(struct ext2fs_extent
));
264 extent
.e_flags
&= EXT2_EXTENT_FLAGS_UNINIT
;
265 if (extent
.e_flags
& EXT2_EXTENT_FLAGS_UNINIT
) {
266 if (extent
.e_len
> EXT_UNINIT_MAX_LEN
) {
267 extent
.e_len
= EXT_UNINIT_MAX_LEN
;
268 ex
->e_pblk
+= EXT_UNINIT_MAX_LEN
;
269 ex
->e_lblk
+= EXT_UNINIT_MAX_LEN
;
270 ex
->e_len
-= EXT_UNINIT_MAX_LEN
;
275 if (extent
.e_len
> EXT_INIT_MAX_LEN
) {
276 extent
.e_len
= EXT_INIT_MAX_LEN
;
277 ex
->e_pblk
+= EXT_INIT_MAX_LEN
;
278 ex
->e_lblk
+= EXT_INIT_MAX_LEN
;
279 ex
->e_len
-= EXT_INIT_MAX_LEN
;
286 printf("W: ino=%d pblk=%llu lblk=%llu len=%u\n", ino
,
287 extent
.e_pblk
, extent
.e_lblk
, extent
.e_len
);
289 retval
= ext2fs_extent_insert(handle
, EXT2_EXTENT_INSERT_AFTER
,
293 retval
= ext2fs_extent_fix_parents(handle
);
299 #if defined(DEBUG) || defined(DEBUG_SUMMARY)
300 printf("rebuild: ino=%d extents=%d->%d\n", ino
, list
->ext_read
,
303 e2fsck_write_inode(ctx
, ino
, &inode
, "rebuild_extents");
306 ext2fs_extent_free(handle
);
311 /* Rebuild the extents immediately */
312 static errcode_t
e2fsck_rebuild_extents(e2fsck_t ctx
, ext2_ino_t ino
)
314 struct extent_list list
;
317 if (!EXT2_HAS_INCOMPAT_FEATURE(ctx
->fs
->super
,
318 EXT3_FEATURE_INCOMPAT_EXTENTS
) ||
319 (ctx
->options
& E2F_OPT_NO
) ||
320 (ino
!= EXT2_ROOT_INO
&& ino
< ctx
->fs
->super
->s_first_ino
))
323 e2fsck_read_bitmaps(ctx
);
324 memset(&list
, 0, sizeof(list
));
325 err
= ext2fs_get_mem(sizeof(struct ext2fs_extent
) * NUM_EXTENTS
,
329 list
.size
= NUM_EXTENTS
;
330 err
= rebuild_extent_tree(ctx
, &list
, ino
);
331 ext2fs_free_mem(&list
.extents
);
336 static void rebuild_extents(e2fsck_t ctx
, const char *pass_name
, int pr_header
)
338 struct problem_context pctx
;
339 #ifdef RESOURCE_TRACK
340 struct resource_track rtrack
;
342 struct extent_list list
;
347 if (!EXT2_HAS_INCOMPAT_FEATURE(ctx
->fs
->super
,
348 EXT3_FEATURE_INCOMPAT_EXTENTS
) ||
349 !ext2fs_test_valid(ctx
->fs
) ||
350 ctx
->invalid_bitmaps
) {
351 if (ctx
->inodes_to_rebuild
)
352 ext2fs_free_inode_bitmap(ctx
->inodes_to_rebuild
);
353 ctx
->inodes_to_rebuild
= NULL
;
356 if (ctx
->inodes_to_rebuild
== NULL
)
359 init_resource_track(&rtrack
, ctx
->fs
->io
);
360 clear_problem_context(&pctx
);
361 e2fsck_read_bitmaps(ctx
);
363 memset(&list
, 0, sizeof(list
));
364 retval
= ext2fs_get_mem(sizeof(struct ext2fs_extent
) * NUM_EXTENTS
,
366 list
.size
= NUM_EXTENTS
;
368 retval
= ext2fs_find_first_set_inode_bitmap2(
369 ctx
->inodes_to_rebuild
, ino
+ 1,
370 ctx
->fs
->super
->s_inodes_count
, &ino
);
375 fix_problem(ctx
, pr_header
, &pctx
);
378 pctx
.errcode
= rebuild_extent_tree(ctx
, &list
, ino
);
380 end_problem_latch(ctx
, PR_LATCH_OPTIMIZE_EXT
);
381 fix_problem(ctx
, PR_1E_OPTIMIZE_EXT_ERR
, &pctx
);
383 if (ctx
->progress
&& !ctx
->progress_fd
)
384 e2fsck_simple_progress(ctx
, "Rebuilding extents",
385 100.0 * (float) ino
/
386 (float) ctx
->fs
->super
->s_inodes_count
,
389 end_problem_latch(ctx
, PR_LATCH_OPTIMIZE_EXT
);
391 ext2fs_free_inode_bitmap(ctx
->inodes_to_rebuild
);
392 ctx
->inodes_to_rebuild
= NULL
;
393 ext2fs_free_mem(&list
.extents
);
395 print_resource_track(ctx
, pass_name
, &rtrack
, ctx
->fs
->io
);
398 /* Scan a file to see if we should rebuild its extent tree */
399 errcode_t
e2fsck_check_rebuild_extents(e2fsck_t ctx
, ext2_ino_t ino
,
400 struct ext2_inode
*inode
,
401 struct problem_context
*pctx
)
403 struct extent_tree_info eti
;
404 struct ext2_extent_info info
, top_info
;
405 struct ext2fs_extent extent
;
406 ext2_extent_handle_t ehandle
;
407 ext2_filsys fs
= ctx
->fs
;
410 /* block map file and we want extent conversion */
411 if (!(inode
->i_flags
& EXT4_EXTENTS_FL
) &&
412 !(inode
->i_flags
& EXT4_INLINE_DATA_FL
) &&
413 (ctx
->options
& E2F_OPT_CONVERT_BMAP
)) {
414 return e2fsck_rebuild_extents_later(ctx
, ino
);
417 if (!(inode
->i_flags
& EXT4_EXTENTS_FL
))
419 memset(&eti
, 0, sizeof(eti
));
422 /* Otherwise, go scan the extent tree... */
423 retval
= ext2fs_extent_open2(fs
, ino
, inode
, &ehandle
);
427 retval
= ext2fs_extent_get_info(ehandle
, &top_info
);
431 /* Check maximum extent depth */
433 pctx
->blk
= top_info
.max_depth
;
434 pctx
->blk2
= ext2fs_max_extent_depth(ehandle
);
435 if (pctx
->blk2
< pctx
->blk
&&
436 fix_problem(ctx
, PR_1_EXTENT_BAD_MAX_DEPTH
, pctx
))
437 eti
.force_rebuild
= 1;
439 /* Can we collect extent tree level stats? */
440 pctx
->blk
= MAX_EXTENT_DEPTH_COUNT
;
441 if (pctx
->blk2
> pctx
->blk
)
442 fix_problem(ctx
, PR_1E_MAX_EXTENT_TREE_DEPTH
, pctx
);
444 /* We need to fix tree depth problems, but the scan isn't a fix. */
445 if (ctx
->options
& E2F_OPT_FIXES_ONLY
)
448 retval
= ext2fs_extent_get(ehandle
, EXT2_EXTENT_ROOT
, &extent
);
453 retval
= ext2fs_extent_get_info(ehandle
, &info
);
458 * If this is the first extent in an extent block that we
459 * haven't visited, collect stats on the block.
461 if (info
.curr_entry
== 1 &&
462 !(extent
.e_flags
& EXT2_EXTENT_FLAGS_SECOND_VISIT
) &&
463 !eti
.force_rebuild
) {
464 struct extent_tree_level
*etl
;
466 etl
= eti
.ext_info
+ info
.curr_level
;
467 etl
->num_extents
+= info
.num_entries
;
468 etl
->max_extents
+= info
.max_entries
;
470 * Implementation wart: Splitting extent blocks when
471 * appending will leave the old block with one free
472 * entry. Therefore unless the node is totally full,
473 * pretend that a non-root extent block can hold one
474 * fewer entry than it actually does, so that we don't
475 * repeatedly rebuild the extent tree.
477 if (info
.curr_level
&&
478 info
.num_entries
< info
.max_entries
)
482 /* Skip to the end of a block of leaf nodes */
483 if (extent
.e_flags
& EXT2_EXTENT_FLAGS_LEAF
) {
484 retval
= ext2fs_extent_get(ehandle
,
485 EXT2_EXTENT_LAST_SIB
,
491 retval
= ext2fs_extent_get(ehandle
, EXT2_EXTENT_NEXT
, &extent
);
492 } while (retval
== 0);
494 ext2fs_extent_free(ehandle
);
495 return e2fsck_should_rebuild_extents(ctx
, pctx
, &eti
, &top_info
);
498 /* Having scanned a file's extent tree, decide if we should rebuild it */
499 errcode_t
e2fsck_should_rebuild_extents(e2fsck_t ctx
,
500 struct problem_context
*pctx
,
501 struct extent_tree_info
*eti
,
502 struct ext2_extent_info
*info
)
504 struct extent_tree_level
*ei
;
506 unsigned int extents_per_block
;
508 if (eti
->force_rebuild
)
511 extents_per_block
= (ctx
->fs
->blocksize
-
512 sizeof(struct ext3_extent_header
)) /
513 sizeof(struct ext3_extent
);
515 * If we can consolidate a level or shorten the tree, schedule the
516 * extent tree to be rebuilt.
518 for (i
= 0, ei
= eti
->ext_info
; i
< info
->max_depth
+ 1; i
++, ei
++) {
519 if (ei
->max_extents
- ei
->num_extents
> extents_per_block
) {
521 op
= PR_1E_CAN_NARROW_EXTENT_TREE
;
524 for (j
= 0; j
< i
; j
++) {
525 if (ei
->num_extents
< eti
->ext_info
[j
].max_extents
) {
527 op
= PR_1E_CAN_COLLAPSE_EXTENT_TREE
;
535 if (eti
->force_rebuild
|| fix_problem(ctx
, op
, pctx
))
536 return e2fsck_rebuild_extents_later(ctx
, eti
->ino
);
540 void e2fsck_pass1e(e2fsck_t ctx
)
542 rebuild_extents(ctx
, "Pass 1E", PR_1E_PASS_HEADER
);