1 /* 2 * extents.c --- rebuild extent tree 3 * 4 * Copyright (C) 2014 Oracle. 5 * 6 * %Begin-Header% 7 * This file may be redistributed under the terms of the GNU Public 8 * License, version 2. 9 * %End-Header% 10 */ 11 12 #include "config.h" 13 #include <string.h> 14 #include <ctype.h> 15 #include <errno.h> 16 #include "e2fsck.h" 17 #include "problem.h" 18 19 #undef DEBUG 20 #undef DEBUG_SUMMARY 21 #undef DEBUG_FREE 22 23 #define NUM_EXTENTS 341 /* about one ETB' worth of extents */ 24 25 static errcode_t e2fsck_rebuild_extents(e2fsck_t ctx, ext2_ino_t ino); 26 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) 29 { 30 errcode_t retval = 0; 31 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)) 35 return 0; 36 37 if (ctx->flags & E2F_FLAG_ALLOC_OK) 38 return e2fsck_rebuild_extents(ctx, ino); 39 40 if (!ctx->inodes_to_rebuild) 41 retval = e2fsck_allocate_inode_bitmap(ctx->fs, 42 _("extent rebuild inode map"), 43 EXT2FS_BMAP64_RBTREE, 44 "inodes_to_rebuild", 45 &ctx->inodes_to_rebuild); 46 if (retval) 47 return retval; 48 49 ext2fs_mark_inode_bitmap2(ctx->inodes_to_rebuild, ino); 50 return 0; 51 } 52 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) 55 { 56 if (!ctx->inodes_to_rebuild) 57 return 0; 58 return ext2fs_test_inode_bitmap2(ctx->inodes_to_rebuild, ino); 59 } 60 61 struct extent_list { 62 blk64_t blocks_freed; 63 struct ext2fs_extent *extents; 64 unsigned int count; 65 unsigned int size; 66 unsigned int ext_read; 67 errcode_t retval; 68 ext2_ino_t ino; 69 }; 70 71 static errcode_t load_extents(e2fsck_t ctx, struct extent_list *list) 72 { 73 ext2_filsys fs = ctx->fs; 74 ext2_extent_handle_t handle; 75 struct ext2fs_extent extent; 76 errcode_t retval; 77 78 retval = ext2fs_extent_open(fs, list->ino, &handle); 79 if (retval) 80 return retval; 81 82 retval = ext2fs_extent_get(handle, EXT2_EXTENT_ROOT, &extent); 83 if (retval) 84 goto out; 85 86 do { 87 if (extent.e_flags & EXT2_EXTENT_FLAGS_SECOND_VISIT) 88 goto next; 89 90 /* Internal node; free it and we'll re-allocate it later */ 91 if (!(extent.e_flags & EXT2_EXTENT_FLAGS_LEAF)) { 92 #if defined(DEBUG) || defined(DEBUG_FREE) 93 printf("ino=%d free=%llu bf=%llu\n", list->ino, 94 extent.e_pblk, list->blocks_freed + 1); 95 #endif 96 list->blocks_freed++; 97 ext2fs_block_alloc_stats2(fs, extent.e_pblk, -1); 98 goto next; 99 } 100 101 list->ext_read++; 102 /* Can we attach it to the previous extent? */ 103 if (list->count) { 104 struct ext2fs_extent *last = list->extents + 105 list->count - 1; 106 blk64_t end = last->e_len + extent.e_len; 107 108 if (last->e_pblk + last->e_len == extent.e_pblk && 109 last->e_lblk + last->e_len == extent.e_lblk && 110 (last->e_flags & EXT2_EXTENT_FLAGS_UNINIT) == 111 (extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT) && 112 end < (1ULL << 32)) { 113 last->e_len += extent.e_len; 114 #ifdef DEBUG 115 printf("R: ino=%d len=%u\n", list->ino, 116 last->e_len); 117 #endif 118 goto next; 119 } 120 } 121 122 /* Do we need to expand? */ 123 if (list->count == list->size) { 124 unsigned int new_size = (list->size + NUM_EXTENTS) * 125 sizeof(struct ext2fs_extent); 126 retval = ext2fs_resize_mem(0, new_size, &list->extents); 127 if (retval) 128 goto out; 129 list->size += NUM_EXTENTS; 130 } 131 132 /* Add a new extent */ 133 memcpy(list->extents + list->count, &extent, sizeof(extent)); 134 #ifdef DEBUG 135 printf("R: ino=%d pblk=%llu lblk=%llu len=%u\n", list->ino, 136 extent.e_pblk, extent.e_lblk, extent.e_len); 137 #endif 138 list->count++; 139 next: 140 retval = ext2fs_extent_get(handle, EXT2_EXTENT_NEXT, &extent); 141 } while (retval == 0); 142 143 out: 144 /* Ok if we run off the end */ 145 if (retval == EXT2_ET_EXTENT_NO_NEXT) 146 retval = 0; 147 ext2fs_extent_free(handle); 148 return retval; 149 } 150 151 static int find_blocks(ext2_filsys fs, blk64_t *blocknr, e2_blkcnt_t blockcnt, 152 blk64_t ref_blk EXT2FS_ATTR((unused)), 153 int ref_offset EXT2FS_ATTR((unused)), void *priv_data) 154 { 155 struct extent_list *list = priv_data; 156 157 /* Internal node? */ 158 if (blockcnt < 0) { 159 #if defined(DEBUG) || defined(DEBUG_FREE) 160 printf("ino=%d free=%llu bf=%llu\n", list->ino, *blocknr, 161 list->blocks_freed + 1); 162 #endif 163 list->blocks_freed++; 164 ext2fs_block_alloc_stats2(fs, *blocknr, -1); 165 return 0; 166 } 167 168 /* Can we attach it to the previous extent? */ 169 if (list->count) { 170 struct ext2fs_extent *last = list->extents + 171 list->count - 1; 172 blk64_t end = last->e_len + 1; 173 174 if (last->e_pblk + last->e_len == *blocknr && 175 end < (1ULL << 32)) { 176 last->e_len++; 177 #ifdef DEBUG 178 printf("R: ino=%d len=%u\n", list->ino, last->e_len); 179 #endif 180 return 0; 181 } 182 } 183 184 /* Do we need to expand? */ 185 if (list->count == list->size) { 186 unsigned int new_size = (list->size + NUM_EXTENTS) * 187 sizeof(struct ext2fs_extent); 188 list->retval = ext2fs_resize_mem(0, new_size, &list->extents); 189 if (list->retval) 190 return BLOCK_ABORT; 191 list->size += NUM_EXTENTS; 192 } 193 194 /* Add a new extent */ 195 list->extents[list->count].e_pblk = *blocknr; 196 list->extents[list->count].e_lblk = blockcnt; 197 list->extents[list->count].e_len = 1; 198 list->extents[list->count].e_flags = 0; 199 #ifdef DEBUG 200 printf("R: ino=%d pblk=%llu lblk=%llu len=%u\n", list->ino, *blocknr, 201 blockcnt, 1); 202 #endif 203 list->count++; 204 205 return 0; 206 } 207 208 static errcode_t rebuild_extent_tree(e2fsck_t ctx, struct extent_list *list, 209 ext2_ino_t ino) 210 { 211 struct ext2_inode_large inode; 212 errcode_t retval; 213 ext2_extent_handle_t handle; 214 unsigned int i, ext_written; 215 struct ext2fs_extent *ex, extent; 216 blk64_t start_val, delta; 217 218 list->count = 0; 219 list->blocks_freed = 0; 220 list->ino = ino; 221 list->ext_read = 0; 222 e2fsck_read_inode_full(ctx, ino, EXT2_INODE(&inode), sizeof(inode), 223 "rebuild_extents"); 224 225 /* Skip deleted inodes and inline data files */ 226 if (inode.i_links_count == 0 || 227 inode.i_flags & EXT4_INLINE_DATA_FL) 228 return 0; 229 230 /* Collect lblk->pblk mappings */ 231 if (inode.i_flags & EXT4_EXTENTS_FL) { 232 retval = load_extents(ctx, list); 233 if (retval) 234 goto err; 235 goto extents_loaded; 236 } 237 238 retval = ext2fs_block_iterate3(ctx->fs, ino, BLOCK_FLAG_READ_ONLY, 0, 239 find_blocks, list); 240 if (retval) 241 goto err; 242 if (list->retval) { 243 retval = list->retval; 244 goto err; 245 } 246 247 extents_loaded: 248 /* Reset extent tree */ 249 inode.i_flags &= ~EXT4_EXTENTS_FL; 250 memset(inode.i_block, 0, sizeof(inode.i_block)); 251 252 /* Make a note of freed blocks */ 253 quota_data_sub(ctx->qctx, &inode, ino, 254 list->blocks_freed * ctx->fs->blocksize); 255 retval = ext2fs_iblk_sub_blocks(ctx->fs, EXT2_INODE(&inode), 256 list->blocks_freed); 257 if (retval) 258 goto err; 259 260 /* Now stuff extents into the file */ 261 retval = ext2fs_extent_open2(ctx->fs, ino, EXT2_INODE(&inode), &handle); 262 if (retval) 263 goto err; 264 265 ext_written = 0; 266 start_val = ext2fs_inode_i_blocks(ctx->fs, EXT2_INODE(&inode)); 267 for (i = 0, ex = list->extents; i < list->count; i++, ex++) { 268 memcpy(&extent, ex, sizeof(struct ext2fs_extent)); 269 extent.e_flags &= EXT2_EXTENT_FLAGS_UNINIT; 270 if (extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT) { 271 if (extent.e_len > EXT_UNINIT_MAX_LEN) { 272 extent.e_len = EXT_UNINIT_MAX_LEN; 273 ex->e_pblk += EXT_UNINIT_MAX_LEN; 274 ex->e_lblk += EXT_UNINIT_MAX_LEN; 275 ex->e_len -= EXT_UNINIT_MAX_LEN; 276 ex--; 277 i--; 278 } 279 } else { 280 if (extent.e_len > EXT_INIT_MAX_LEN) { 281 extent.e_len = EXT_INIT_MAX_LEN; 282 ex->e_pblk += EXT_INIT_MAX_LEN; 283 ex->e_lblk += EXT_INIT_MAX_LEN; 284 ex->e_len -= EXT_INIT_MAX_LEN; 285 ex--; 286 i--; 287 } 288 } 289 290 #ifdef DEBUG 291 printf("W: ino=%d pblk=%llu lblk=%llu len=%u\n", ino, 292 extent.e_pblk, extent.e_lblk, extent.e_len); 293 #endif 294 retval = ext2fs_extent_insert(handle, EXT2_EXTENT_INSERT_AFTER, 295 &extent); 296 if (retval) 297 goto err2; 298 retval = ext2fs_extent_fix_parents(handle); 299 if (retval) 300 goto err2; 301 ext_written++; 302 } 303 304 delta = ext2fs_inode_i_blocks(ctx->fs, EXT2_INODE(&inode)) - start_val; 305 if (delta) { 306 if (!ext2fs_has_feature_huge_file(ctx->fs->super) || 307 !(inode.i_flags & EXT4_HUGE_FILE_FL)) 308 delta <<= 9; 309 else 310 delta *= ctx->fs->blocksize; 311 quota_data_add(ctx->qctx, &inode, ino, delta); 312 } 313 314 #if defined(DEBUG) || defined(DEBUG_SUMMARY) 315 printf("rebuild: ino=%d extents=%d->%d\n", ino, list->ext_read, 316 ext_written); 317 #endif 318 e2fsck_write_inode(ctx, ino, EXT2_INODE(&inode), "rebuild_extents"); 319 320 err2: 321 ext2fs_extent_free(handle); 322 err: 323 return retval; 324 } 325 326 /* Rebuild the extents immediately */ 327 static errcode_t e2fsck_rebuild_extents(e2fsck_t ctx, ext2_ino_t ino) 328 { 329 struct extent_list list; 330 errcode_t err; 331 332 if (!ext2fs_has_feature_extents(ctx->fs->super) || 333 (ctx->options & E2F_OPT_NO) || 334 (ino != EXT2_ROOT_INO && ino < ctx->fs->super->s_first_ino)) 335 return 0; 336 337 e2fsck_read_bitmaps(ctx); 338 memset(&list, 0, sizeof(list)); 339 err = ext2fs_get_mem(sizeof(struct ext2fs_extent) * NUM_EXTENTS, 340 &list.extents); 341 if (err) 342 return err; 343 list.size = NUM_EXTENTS; 344 err = rebuild_extent_tree(ctx, &list, ino); 345 ext2fs_free_mem(&list.extents); 346 347 return err; 348 } 349 350 static void rebuild_extents(e2fsck_t ctx, const char *pass_name, int pr_header) 351 { 352 struct problem_context pctx; 353 #ifdef RESOURCE_TRACK 354 struct resource_track rtrack; 355 #endif 356 struct extent_list list; 357 int first = 1; 358 ext2_ino_t ino = 0; 359 errcode_t retval; 360 361 if (!ext2fs_has_feature_extents(ctx->fs->super) || 362 !ext2fs_test_valid(ctx->fs) || 363 ctx->invalid_bitmaps) { 364 if (ctx->inodes_to_rebuild) 365 ext2fs_free_inode_bitmap(ctx->inodes_to_rebuild); 366 ctx->inodes_to_rebuild = NULL; 367 } 368 369 if (ctx->inodes_to_rebuild == NULL) 370 return; 371 372 init_resource_track(&rtrack, ctx->fs->io); 373 clear_problem_context(&pctx); 374 e2fsck_read_bitmaps(ctx); 375 376 memset(&list, 0, sizeof(list)); 377 retval = ext2fs_get_mem(sizeof(struct ext2fs_extent) * NUM_EXTENTS, 378 &list.extents); 379 list.size = NUM_EXTENTS; 380 while (1) { 381 retval = ext2fs_find_first_set_inode_bitmap2( 382 ctx->inodes_to_rebuild, ino + 1, 383 ctx->fs->super->s_inodes_count, &ino); 384 if (retval) 385 break; 386 pctx.ino = ino; 387 if (first) { 388 fix_problem(ctx, pr_header, &pctx); 389 first = 0; 390 } 391 pctx.errcode = rebuild_extent_tree(ctx, &list, ino); 392 if (pctx.errcode) { 393 end_problem_latch(ctx, PR_LATCH_OPTIMIZE_EXT); 394 fix_problem(ctx, PR_1E_OPTIMIZE_EXT_ERR, &pctx); 395 } 396 if (ctx->progress && !ctx->progress_fd) 397 e2fsck_simple_progress(ctx, "Rebuilding extents", 398 100.0 * (float) ino / 399 (float) ctx->fs->super->s_inodes_count, 400 ino); 401 } 402 end_problem_latch(ctx, PR_LATCH_OPTIMIZE_EXT); 403 404 ext2fs_free_inode_bitmap(ctx->inodes_to_rebuild); 405 ctx->inodes_to_rebuild = NULL; 406 ext2fs_free_mem(&list.extents); 407 408 print_resource_track(ctx, pass_name, &rtrack, ctx->fs->io); 409 } 410 411 /* Scan a file to see if we should rebuild its extent tree */ 412 errcode_t e2fsck_check_rebuild_extents(e2fsck_t ctx, ext2_ino_t ino, 413 struct ext2_inode *inode, 414 struct problem_context *pctx) 415 { 416 struct extent_tree_info eti; 417 struct ext2_extent_info info, top_info; 418 struct ext2fs_extent extent; 419 ext2_extent_handle_t ehandle; 420 ext2_filsys fs = ctx->fs; 421 errcode_t retval; 422 423 /* block map file and we want extent conversion */ 424 if (!(inode->i_flags & EXT4_EXTENTS_FL) && 425 !(inode->i_flags & EXT4_INLINE_DATA_FL) && 426 (ctx->options & E2F_OPT_CONVERT_BMAP)) { 427 return e2fsck_rebuild_extents_later(ctx, ino); 428 } 429 430 if (!(inode->i_flags & EXT4_EXTENTS_FL)) 431 return 0; 432 memset(&eti, 0, sizeof(eti)); 433 eti.ino = ino; 434 435 /* Otherwise, go scan the extent tree... */ 436 retval = ext2fs_extent_open2(fs, ino, inode, &ehandle); 437 if (retval) 438 return 0; 439 440 retval = ext2fs_extent_get_info(ehandle, &top_info); 441 if (retval) 442 goto out; 443 444 /* Check maximum extent depth */ 445 pctx->ino = ino; 446 pctx->blk = top_info.max_depth; 447 pctx->blk2 = ext2fs_max_extent_depth(ehandle); 448 if (pctx->blk2 < pctx->blk && 449 fix_problem(ctx, PR_1_EXTENT_BAD_MAX_DEPTH, pctx)) 450 eti.force_rebuild = 1; 451 452 /* Can we collect extent tree level stats? */ 453 pctx->blk = MAX_EXTENT_DEPTH_COUNT; 454 if (pctx->blk2 > pctx->blk) 455 fix_problem(ctx, PR_1E_MAX_EXTENT_TREE_DEPTH, pctx); 456 457 /* We need to fix tree depth problems, but the scan isn't a fix. */ 458 if (ctx->options & E2F_OPT_FIXES_ONLY) 459 goto out; 460 461 retval = ext2fs_extent_get(ehandle, EXT2_EXTENT_ROOT, &extent); 462 if (retval) 463 goto out; 464 465 do { 466 retval = ext2fs_extent_get_info(ehandle, &info); 467 if (retval) 468 break; 469 470 /* 471 * If this is the first extent in an extent block that we 472 * haven't visited, collect stats on the block. 473 */ 474 if (info.curr_entry == 1 && 475 !(extent.e_flags & EXT2_EXTENT_FLAGS_SECOND_VISIT) && 476 !eti.force_rebuild) { 477 struct extent_tree_level *etl; 478 479 etl = eti.ext_info + info.curr_level; 480 etl->num_extents += info.num_entries; 481 etl->max_extents += info.max_entries; 482 /* 483 * Implementation wart: Splitting extent blocks when 484 * appending will leave the old block with one free 485 * entry. Therefore unless the node is totally full, 486 * pretend that a non-root extent block can hold one 487 * fewer entry than it actually does, so that we don't 488 * repeatedly rebuild the extent tree. 489 */ 490 if (info.curr_level && 491 info.num_entries < info.max_entries) 492 etl->max_extents--; 493 } 494 495 /* Skip to the end of a block of leaf nodes */ 496 if (extent.e_flags & EXT2_EXTENT_FLAGS_LEAF) { 497 retval = ext2fs_extent_get(ehandle, 498 EXT2_EXTENT_LAST_SIB, 499 &extent); 500 if (retval) 501 break; 502 } 503 504 retval = ext2fs_extent_get(ehandle, EXT2_EXTENT_NEXT, &extent); 505 } while (retval == 0); 506 out: 507 ext2fs_extent_free(ehandle); 508 return e2fsck_should_rebuild_extents(ctx, pctx, &eti, &top_info); 509 } 510 511 /* Having scanned a file's extent tree, decide if we should rebuild it */ 512 errcode_t e2fsck_should_rebuild_extents(e2fsck_t ctx, 513 struct problem_context *pctx, 514 struct extent_tree_info *eti, 515 struct ext2_extent_info *info) 516 { 517 struct extent_tree_level *ei; 518 int i, j, op; 519 unsigned int extents_per_block; 520 521 if (eti->force_rebuild) 522 goto rebuild; 523 524 extents_per_block = (ctx->fs->blocksize - 525 sizeof(struct ext3_extent_header)) / 526 sizeof(struct ext3_extent); 527 /* 528 * If we can consolidate a level or shorten the tree, schedule the 529 * extent tree to be rebuilt. 530 */ 531 for (i = 0, ei = eti->ext_info; i < info->max_depth + 1; i++, ei++) { 532 if (ei->max_extents - ei->num_extents > extents_per_block) { 533 pctx->blk = i; 534 op = PR_1E_CAN_NARROW_EXTENT_TREE; 535 goto rebuild; 536 } 537 for (j = 0; j < i; j++) { 538 if (ei->num_extents < eti->ext_info[j].max_extents) { 539 pctx->blk = i; 540 op = PR_1E_CAN_COLLAPSE_EXTENT_TREE; 541 goto rebuild; 542 } 543 } 544 } 545 return 0; 546 547 rebuild: 548 if (eti->force_rebuild || fix_problem(ctx, op, pctx)) 549 return e2fsck_rebuild_extents_later(ctx, eti->ino); 550 return 0; 551 } 552 553 void e2fsck_pass1e(e2fsck_t ctx) 554 { 555 rebuild_extents(ctx, "Pass 1E", PR_1E_PASS_HEADER); 556 } 557