pass1b.c revision 0c80c44bd08c60f3cd0ad87f12a71a75cac3bcaa
1/* 2 * pass1b.c --- Pass #1b of e2fsck 3 * 4 * This file contains pass1B, pass1C, and pass1D of e2fsck. They are 5 * only invoked if pass 1 discovered blocks which are in use by more 6 * than one inode. 7 * 8 * Pass1B scans the data blocks of all the inodes again, generating a 9 * complete list of duplicate blocks and which inodes have claimed 10 * them. 11 * 12 * Pass1C does a tree-traversal of the filesystem, to determine the 13 * parent directories of these inodes. This step is necessary so that 14 * e2fsck can print out the pathnames of affected inodes. 15 * 16 * Pass1D is a reconciliation pass. For each inode with duplicate 17 * blocks, the user is prompted if s/he would like to clone the file 18 * (so that the file gets a fresh copy of the duplicated blocks) or 19 * simply to delete the file. 20 * 21 * Copyright (C) 1993, 1994, 1995, 1996, 1997 Theodore Ts'o. 22 * 23 * %Begin-Header% 24 * This file may be redistributed under the terms of the GNU Public 25 * License. 26 * %End-Header% 27 * 28 */ 29 30#include "config.h" 31#include <time.h> 32#ifdef HAVE_ERRNO_H 33#include <errno.h> 34#endif 35 36#ifdef HAVE_INTTYPES_H 37#include <inttypes.h> 38#endif 39 40#ifndef HAVE_INTPTR_T 41typedef long intptr_t; 42#endif 43 44/* Needed for architectures where sizeof(int) != sizeof(void *) */ 45#define INT_TO_VOIDPTR(val) ((void *)(intptr_t)(val)) 46#define VOIDPTR_TO_INT(ptr) ((int)(intptr_t)(ptr)) 47 48#include <et/com_err.h> 49#include "e2fsck.h" 50 51#include "problem.h" 52#include "dict.h" 53 54/* Define an extension to the ext2 library's block count information */ 55#define BLOCK_COUNT_EXTATTR (-5) 56 57struct cluster_el { 58 blk64_t cluster; 59 struct cluster_el *next; 60}; 61 62struct inode_el { 63 ext2_ino_t inode; 64 struct inode_el *next; 65}; 66 67struct dup_cluster { 68 int num_bad; 69 struct inode_el *inode_list; 70}; 71 72/* 73 * This structure stores information about a particular inode which 74 * is sharing blocks with other inodes. This information is collected 75 * to display to the user, so that the user knows what files he or she 76 * is dealing with, when trying to decide how to resolve the conflict 77 * of multiply-claimed blocks. 78 */ 79struct dup_inode { 80 ext2_ino_t dir; 81 int num_dupblocks; 82 struct ext2_inode inode; 83 struct cluster_el *cluster_list; 84}; 85 86static int process_pass1b_block(ext2_filsys fs, blk64_t *blocknr, 87 e2_blkcnt_t blockcnt, blk64_t ref_blk, 88 int ref_offset, void *priv_data); 89static void delete_file(e2fsck_t ctx, ext2_ino_t ino, 90 struct dup_inode *dp, char *block_buf); 91static int clone_file(e2fsck_t ctx, ext2_ino_t ino, 92 struct dup_inode *dp, char* block_buf); 93static int check_if_fs_block(e2fsck_t ctx, blk64_t test_block); 94static int check_if_fs_cluster(e2fsck_t ctx, blk64_t cluster); 95 96static void pass1b(e2fsck_t ctx, char *block_buf); 97static void pass1c(e2fsck_t ctx, char *block_buf); 98static void pass1d(e2fsck_t ctx, char *block_buf); 99 100static int dup_inode_count = 0; 101static int dup_inode_founddir = 0; 102 103static dict_t clstr_dict, ino_dict; 104 105static ext2fs_inode_bitmap inode_dup_map; 106 107static int dict_int_cmp(const void *a, const void *b) 108{ 109 intptr_t ia, ib; 110 111 ia = (intptr_t)a; 112 ib = (intptr_t)b; 113 114 return (ia-ib); 115} 116 117/* 118 * Add a duplicate block record 119 */ 120static void add_dupe(e2fsck_t ctx, ext2_ino_t ino, blk64_t cluster, 121 struct ext2_inode *inode) 122{ 123 dnode_t *n; 124 struct dup_cluster *db; 125 struct dup_inode *di; 126 struct cluster_el *cluster_el; 127 struct inode_el *ino_el; 128 129 n = dict_lookup(&clstr_dict, INT_TO_VOIDPTR(cluster)); 130 if (n) 131 db = (struct dup_cluster *) dnode_get(n); 132 else { 133 db = (struct dup_cluster *) e2fsck_allocate_memory(ctx, 134 sizeof(struct dup_cluster), "duplicate cluster header"); 135 db->num_bad = 0; 136 db->inode_list = 0; 137 dict_alloc_insert(&clstr_dict, INT_TO_VOIDPTR(cluster), db); 138 } 139 ino_el = (struct inode_el *) e2fsck_allocate_memory(ctx, 140 sizeof(struct inode_el), "inode element"); 141 ino_el->inode = ino; 142 ino_el->next = db->inode_list; 143 db->inode_list = ino_el; 144 db->num_bad++; 145 146 n = dict_lookup(&ino_dict, INT_TO_VOIDPTR(ino)); 147 if (n) 148 di = (struct dup_inode *) dnode_get(n); 149 else { 150 di = (struct dup_inode *) e2fsck_allocate_memory(ctx, 151 sizeof(struct dup_inode), "duplicate inode header"); 152 if (ino == EXT2_ROOT_INO) { 153 di->dir = EXT2_ROOT_INO; 154 dup_inode_founddir++; 155 } else 156 di->dir = 0; 157 158 di->num_dupblocks = 0; 159 di->cluster_list = 0; 160 di->inode = *inode; 161 dict_alloc_insert(&ino_dict, INT_TO_VOIDPTR(ino), di); 162 } 163 cluster_el = (struct cluster_el *) e2fsck_allocate_memory(ctx, 164 sizeof(struct cluster_el), "cluster element"); 165 cluster_el->cluster = cluster; 166 cluster_el->next = di->cluster_list; 167 di->cluster_list = cluster_el; 168 di->num_dupblocks++; 169} 170 171/* 172 * Free a duplicate inode record 173 */ 174static void inode_dnode_free(dnode_t *node, 175 void *context EXT2FS_ATTR((unused))) 176{ 177 struct dup_inode *di; 178 struct cluster_el *p, *next; 179 180 di = (struct dup_inode *) dnode_get(node); 181 for (p = di->cluster_list; p; p = next) { 182 next = p->next; 183 free(p); 184 } 185 free(di); 186 free(node); 187} 188 189/* 190 * Free a duplicate cluster record 191 */ 192static void cluster_dnode_free(dnode_t *node, 193 void *context EXT2FS_ATTR((unused))) 194{ 195 struct dup_cluster *dc; 196 struct inode_el *p, *next; 197 198 dc = (struct dup_cluster *) dnode_get(node); 199 for (p = dc->inode_list; p; p = next) { 200 next = p->next; 201 free(p); 202 } 203 free(dc); 204 free(node); 205} 206 207 208/* 209 * Main procedure for handling duplicate blocks 210 */ 211void e2fsck_pass1_dupblocks(e2fsck_t ctx, char *block_buf) 212{ 213 ext2_filsys fs = ctx->fs; 214 struct problem_context pctx; 215#ifdef RESOURCE_TRACK 216 struct resource_track rtrack; 217#endif 218 219 clear_problem_context(&pctx); 220 221 pctx.errcode = ext2fs_allocate_inode_bitmap(fs, 222 _("multiply claimed inode map"), &inode_dup_map); 223 if (pctx.errcode) { 224 fix_problem(ctx, PR_1B_ALLOCATE_IBITMAP_ERROR, &pctx); 225 ctx->flags |= E2F_FLAG_ABORT; 226 return; 227 } 228 229 dict_init(&ino_dict, DICTCOUNT_T_MAX, dict_int_cmp); 230 dict_init(&clstr_dict, DICTCOUNT_T_MAX, dict_int_cmp); 231 dict_set_allocator(&ino_dict, NULL, inode_dnode_free, NULL); 232 dict_set_allocator(&clstr_dict, NULL, cluster_dnode_free, NULL); 233 234 init_resource_track(&rtrack, ctx->fs->io); 235 pass1b(ctx, block_buf); 236 print_resource_track(ctx, "Pass 1b", &rtrack, ctx->fs->io); 237 238 init_resource_track(&rtrack, ctx->fs->io); 239 pass1c(ctx, block_buf); 240 print_resource_track(ctx, "Pass 1c", &rtrack, ctx->fs->io); 241 242 init_resource_track(&rtrack, ctx->fs->io); 243 pass1d(ctx, block_buf); 244 print_resource_track(ctx, "Pass 1d", &rtrack, ctx->fs->io); 245 246 /* 247 * Time to free all of the accumulated data structures that we 248 * don't need anymore. 249 */ 250 dict_free_nodes(&ino_dict); 251 dict_free_nodes(&clstr_dict); 252 ext2fs_free_inode_bitmap(inode_dup_map); 253} 254 255/* 256 * Scan the inodes looking for inodes that contain duplicate blocks. 257 */ 258struct process_block_struct { 259 e2fsck_t ctx; 260 ext2_ino_t ino; 261 int dup_blocks; 262 struct ext2_inode *inode; 263 struct problem_context *pctx; 264}; 265 266static void pass1b(e2fsck_t ctx, char *block_buf) 267{ 268 ext2_filsys fs = ctx->fs; 269 ext2_ino_t ino; 270 struct ext2_inode inode; 271 ext2_inode_scan scan; 272 struct process_block_struct pb; 273 struct problem_context pctx; 274 275 clear_problem_context(&pctx); 276 277 if (!(ctx->options & E2F_OPT_PREEN)) 278 fix_problem(ctx, PR_1B_PASS_HEADER, &pctx); 279 pctx.errcode = ext2fs_open_inode_scan(fs, ctx->inode_buffer_blocks, 280 &scan); 281 if (pctx.errcode) { 282 fix_problem(ctx, PR_1B_ISCAN_ERROR, &pctx); 283 ctx->flags |= E2F_FLAG_ABORT; 284 return; 285 } 286 ctx->stashed_inode = &inode; 287 pb.ctx = ctx; 288 pb.pctx = &pctx; 289 pctx.str = "pass1b"; 290 while (1) { 291 if (ino % (fs->super->s_inodes_per_group * 4) == 1) { 292 if (e2fsck_mmp_update(fs)) 293 fatal_error(ctx, 0); 294 } 295 pctx.errcode = ext2fs_get_next_inode(scan, &ino, &inode); 296 if (pctx.errcode == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE) 297 continue; 298 if (pctx.errcode) { 299 fix_problem(ctx, PR_1B_ISCAN_ERROR, &pctx); 300 ctx->flags |= E2F_FLAG_ABORT; 301 return; 302 } 303 if (!ino) 304 break; 305 pctx.ino = ctx->stashed_ino = ino; 306 if ((ino != EXT2_BAD_INO) && 307 !ext2fs_test_inode_bitmap2(ctx->inode_used_map, ino)) 308 continue; 309 310 pb.ino = ino; 311 pb.dup_blocks = 0; 312 pb.inode = &inode; 313 314 if (ext2fs_inode_has_valid_blocks2(fs, &inode) || 315 (ino == EXT2_BAD_INO)) 316 pctx.errcode = ext2fs_block_iterate3(fs, ino, 317 BLOCK_FLAG_READ_ONLY, block_buf, 318 process_pass1b_block, &pb); 319 /* If the feature is not set, attrs will be cleared later anyway */ 320 if ((fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR) && 321 ext2fs_file_acl_block(fs, &inode)) { 322 blk64_t blk = ext2fs_file_acl_block(fs, &inode); 323 process_pass1b_block(fs, &blk, 324 BLOCK_COUNT_EXTATTR, 0, 0, &pb); 325 ext2fs_file_acl_block_set(fs, &inode, blk); 326 } 327 if (pb.dup_blocks) { 328 end_problem_latch(ctx, PR_LATCH_DBLOCK); 329 if (ino >= EXT2_FIRST_INODE(fs->super) || 330 ino == EXT2_ROOT_INO) 331 dup_inode_count++; 332 } 333 if (pctx.errcode) 334 fix_problem(ctx, PR_1B_BLOCK_ITERATE, &pctx); 335 } 336 ext2fs_close_inode_scan(scan); 337 e2fsck_use_inode_shortcuts(ctx, 0); 338} 339 340static int process_pass1b_block(ext2_filsys fs EXT2FS_ATTR((unused)), 341 blk64_t *block_nr, 342 e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)), 343 blk64_t ref_blk EXT2FS_ATTR((unused)), 344 int ref_offset EXT2FS_ATTR((unused)), 345 void *priv_data) 346{ 347 struct process_block_struct *p; 348 e2fsck_t ctx; 349 350 if (HOLE_BLKADDR(*block_nr)) 351 return 0; 352 p = (struct process_block_struct *) priv_data; 353 ctx = p->ctx; 354 355 if (!ext2fs_test_block_bitmap2(ctx->block_dup_map, *block_nr)) 356 return 0; 357 358 /* OK, this is a duplicate block */ 359 if (p->ino != EXT2_BAD_INO) { 360 p->pctx->blk = *block_nr; 361 fix_problem(ctx, PR_1B_DUP_BLOCK, p->pctx); 362 } 363 p->dup_blocks++; 364 ext2fs_mark_inode_bitmap2(inode_dup_map, p->ino); 365 366 add_dupe(ctx, p->ino, EXT2FS_B2C(fs, *block_nr), p->inode); 367 368 return 0; 369} 370 371/* 372 * Pass 1c: Scan directories for inodes with duplicate blocks. This 373 * is used so that we can print pathnames when prompting the user for 374 * what to do. 375 */ 376struct search_dir_struct { 377 int count; 378 ext2_ino_t first_inode; 379 ext2_ino_t max_inode; 380}; 381 382static int search_dirent_proc(ext2_ino_t dir, int entry, 383 struct ext2_dir_entry *dirent, 384 int offset EXT2FS_ATTR((unused)), 385 int blocksize EXT2FS_ATTR((unused)), 386 char *buf EXT2FS_ATTR((unused)), 387 void *priv_data) 388{ 389 struct search_dir_struct *sd; 390 struct dup_inode *p; 391 dnode_t *n; 392 393 sd = (struct search_dir_struct *) priv_data; 394 395 if (dirent->inode > sd->max_inode) 396 /* Should abort this inode, but not everything */ 397 return 0; 398 399 if ((dirent->inode < sd->first_inode) || (entry < DIRENT_OTHER_FILE) || 400 !ext2fs_test_inode_bitmap2(inode_dup_map, dirent->inode)) 401 return 0; 402 403 n = dict_lookup(&ino_dict, INT_TO_VOIDPTR(dirent->inode)); 404 if (!n) 405 return 0; 406 p = (struct dup_inode *) dnode_get(n); 407 if (!p->dir) { 408 p->dir = dir; 409 sd->count--; 410 } 411 412 return(sd->count ? 0 : DIRENT_ABORT); 413} 414 415 416static void pass1c(e2fsck_t ctx, char *block_buf) 417{ 418 ext2_filsys fs = ctx->fs; 419 struct search_dir_struct sd; 420 struct problem_context pctx; 421 422 clear_problem_context(&pctx); 423 424 if (!(ctx->options & E2F_OPT_PREEN)) 425 fix_problem(ctx, PR_1C_PASS_HEADER, &pctx); 426 427 /* 428 * Search through all directories to translate inodes to names 429 * (by searching for the containing directory for that inode.) 430 */ 431 sd.count = dup_inode_count - dup_inode_founddir; 432 sd.first_inode = EXT2_FIRST_INODE(fs->super); 433 sd.max_inode = fs->super->s_inodes_count; 434 ext2fs_dblist_dir_iterate(fs->dblist, 0, block_buf, 435 search_dirent_proc, &sd); 436} 437 438static void pass1d(e2fsck_t ctx, char *block_buf) 439{ 440 ext2_filsys fs = ctx->fs; 441 struct dup_inode *p, *t; 442 struct dup_cluster *q; 443 ext2_ino_t *shared, ino; 444 int shared_len; 445 int i; 446 int file_ok; 447 int meta_data = 0; 448 struct problem_context pctx; 449 dnode_t *n, *m; 450 struct cluster_el *s; 451 struct inode_el *r; 452 453 clear_problem_context(&pctx); 454 455 if (!(ctx->options & E2F_OPT_PREEN)) 456 fix_problem(ctx, PR_1D_PASS_HEADER, &pctx); 457 e2fsck_read_bitmaps(ctx); 458 459 pctx.num = dup_inode_count; /* dict_count(&ino_dict); */ 460 fix_problem(ctx, PR_1D_NUM_DUP_INODES, &pctx); 461 shared = (ext2_ino_t *) e2fsck_allocate_memory(ctx, 462 sizeof(ext2_ino_t) * dict_count(&ino_dict), 463 "Shared inode list"); 464 for (n = dict_first(&ino_dict); n; n = dict_next(&ino_dict, n)) { 465 p = (struct dup_inode *) dnode_get(n); 466 shared_len = 0; 467 file_ok = 1; 468 ino = (ext2_ino_t)VOIDPTR_TO_INT(dnode_getkey(n)); 469 if (ino == EXT2_BAD_INO || ino == EXT2_RESIZE_INO) 470 continue; 471 472 /* 473 * Find all of the inodes which share blocks with this 474 * one. First we find all of the duplicate blocks 475 * belonging to this inode, and then search each block 476 * get the list of inodes, and merge them together. 477 */ 478 for (s = p->cluster_list; s; s = s->next) { 479 m = dict_lookup(&clstr_dict, 480 INT_TO_VOIDPTR(s->cluster)); 481 if (!m) 482 continue; /* Should never happen... */ 483 q = (struct dup_cluster *) dnode_get(m); 484 if (q->num_bad > 1) 485 file_ok = 0; 486 if (check_if_fs_cluster(ctx, s->cluster)) { 487 file_ok = 0; 488 meta_data = 1; 489 } 490 491 /* 492 * Add all inodes used by this block to the 493 * shared[] --- which is a unique list, so 494 * if an inode is already in shared[], don't 495 * add it again. 496 */ 497 for (r = q->inode_list; r; r = r->next) { 498 if (r->inode == ino) 499 continue; 500 for (i = 0; i < shared_len; i++) 501 if (shared[i] == r->inode) 502 break; 503 if (i == shared_len) { 504 shared[shared_len++] = r->inode; 505 } 506 } 507 } 508 509 /* 510 * Report the inode that we are working on 511 */ 512 pctx.inode = &p->inode; 513 pctx.ino = ino; 514 pctx.dir = p->dir; 515 pctx.blkcount = p->num_dupblocks; 516 pctx.num = meta_data ? shared_len+1 : shared_len; 517 fix_problem(ctx, PR_1D_DUP_FILE, &pctx); 518 pctx.blkcount = 0; 519 pctx.num = 0; 520 521 if (meta_data) 522 fix_problem(ctx, PR_1D_SHARE_METADATA, &pctx); 523 524 for (i = 0; i < shared_len; i++) { 525 m = dict_lookup(&ino_dict, INT_TO_VOIDPTR(shared[i])); 526 if (!m) 527 continue; /* should never happen */ 528 t = (struct dup_inode *) dnode_get(m); 529 /* 530 * Report the inode that we are sharing with 531 */ 532 pctx.inode = &t->inode; 533 pctx.ino = shared[i]; 534 pctx.dir = t->dir; 535 fix_problem(ctx, PR_1D_DUP_FILE_LIST, &pctx); 536 } 537 if (file_ok) { 538 fix_problem(ctx, PR_1D_DUP_BLOCKS_DEALT, &pctx); 539 continue; 540 } 541 if (fix_problem(ctx, PR_1D_CLONE_QUESTION, &pctx)) { 542 pctx.errcode = clone_file(ctx, ino, p, block_buf); 543 if (pctx.errcode) 544 fix_problem(ctx, PR_1D_CLONE_ERROR, &pctx); 545 else 546 continue; 547 } 548 if (fix_problem(ctx, PR_1D_DELETE_QUESTION, &pctx)) 549 delete_file(ctx, ino, p, block_buf); 550 else 551 ext2fs_unmark_valid(fs); 552 } 553 ext2fs_free_mem(&shared); 554} 555 556/* 557 * Drop the refcount on the dup_block structure, and clear the entry 558 * in the block_dup_map if appropriate. 559 */ 560static void decrement_badcount(e2fsck_t ctx, blk64_t block, 561 struct dup_cluster *p) 562{ 563 p->num_bad--; 564 if (p->num_bad <= 0 || 565 (p->num_bad == 1 && !check_if_fs_block(ctx, block))) { 566 if (check_if_fs_cluster(ctx, EXT2FS_B2C(ctx->fs, block))) 567 return; 568 ext2fs_unmark_block_bitmap2(ctx->block_dup_map, block); 569 } 570} 571 572static int delete_file_block(ext2_filsys fs, 573 blk64_t *block_nr, 574 e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)), 575 blk64_t ref_block EXT2FS_ATTR((unused)), 576 int ref_offset EXT2FS_ATTR((unused)), 577 void *priv_data) 578{ 579 struct process_block_struct *pb; 580 struct dup_cluster *p; 581 dnode_t *n; 582 e2fsck_t ctx; 583 blk64_t c; 584 585 pb = (struct process_block_struct *) priv_data; 586 ctx = pb->ctx; 587 588 if (HOLE_BLKADDR(*block_nr)) 589 return 0; 590 591 c = EXT2FS_B2C(fs, *block_nr); 592 if (ext2fs_test_block_bitmap2(ctx->block_dup_map, *block_nr)) { 593 n = dict_lookup(&clstr_dict, INT_TO_VOIDPTR(c)); 594 if (n) { 595 p = (struct dup_cluster *) dnode_get(n); 596 decrement_badcount(ctx, *block_nr, p); 597 } else 598 com_err("delete_file_block", 0, 599 _("internal error: can't find dup_blk for %llu\n"), 600 *block_nr); 601 } else { 602 ext2fs_unmark_block_bitmap2(ctx->block_found_map, *block_nr); 603 ext2fs_block_alloc_stats2(fs, *block_nr, -1); 604 pb->dup_blocks++; 605 } 606 607 return 0; 608} 609 610static void delete_file(e2fsck_t ctx, ext2_ino_t ino, 611 struct dup_inode *dp, char* block_buf) 612{ 613 ext2_filsys fs = ctx->fs; 614 struct process_block_struct pb; 615 struct ext2_inode inode; 616 struct problem_context pctx; 617 unsigned int count; 618 619 clear_problem_context(&pctx); 620 pctx.ino = pb.ino = ino; 621 pb.dup_blocks = 0; 622 pb.ctx = ctx; 623 pctx.str = "delete_file"; 624 625 e2fsck_read_inode(ctx, ino, &inode, "delete_file"); 626 if (ext2fs_inode_has_valid_blocks2(fs, &inode)) 627 pctx.errcode = ext2fs_block_iterate3(fs, ino, BLOCK_FLAG_READ_ONLY, 628 block_buf, delete_file_block, &pb); 629 if (pctx.errcode) 630 fix_problem(ctx, PR_1B_BLOCK_ITERATE, &pctx); 631 if (ctx->inode_bad_map) 632 ext2fs_unmark_inode_bitmap2(ctx->inode_bad_map, ino); 633 ext2fs_inode_alloc_stats2(fs, ino, -1, LINUX_S_ISDIR(inode.i_mode)); 634 quota_data_sub(ctx->qctx, &inode, ino, pb.dup_blocks * fs->blocksize); 635 quota_data_inodes(ctx->qctx, &inode, ino, -1); 636 637 /* Inode may have changed by block_iterate, so reread it */ 638 e2fsck_read_inode(ctx, ino, &inode, "delete_file"); 639 e2fsck_clear_inode(ctx, ino, &inode, 0, "delete_file"); 640 if (ext2fs_file_acl_block(fs, &inode) && 641 (fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR)) { 642 count = 1; 643 pctx.errcode = ext2fs_adjust_ea_refcount2(fs, 644 ext2fs_file_acl_block(fs, &inode), 645 block_buf, -1, &count); 646 if (pctx.errcode == EXT2_ET_BAD_EA_BLOCK_NUM) { 647 pctx.errcode = 0; 648 count = 1; 649 } 650 if (pctx.errcode) { 651 pctx.blk = ext2fs_file_acl_block(fs, &inode); 652 fix_problem(ctx, PR_1B_ADJ_EA_REFCOUNT, &pctx); 653 } 654 /* 655 * If the count is zero, then arrange to have the 656 * block deleted. If the block is in the block_dup_map, 657 * also call delete_file_block since it will take care 658 * of keeping the accounting straight. 659 */ 660 if ((count == 0) || 661 ext2fs_test_block_bitmap2(ctx->block_dup_map, 662 ext2fs_file_acl_block(fs, &inode))) { 663 blk64_t blk = ext2fs_file_acl_block(fs, &inode); 664 delete_file_block(fs, &blk, 665 BLOCK_COUNT_EXTATTR, 0, 0, &pb); 666 ext2fs_file_acl_block_set(fs, &inode, blk); 667 quota_data_sub(ctx->qctx, &inode, ino, fs->blocksize); 668 } 669 } 670} 671 672struct clone_struct { 673 errcode_t errcode; 674 blk64_t dup_cluster; 675 blk64_t alloc_block; 676 ext2_ino_t dir; 677 char *buf; 678 e2fsck_t ctx; 679}; 680 681static int clone_file_block(ext2_filsys fs, 682 blk64_t *block_nr, 683 e2_blkcnt_t blockcnt, 684 blk64_t ref_block EXT2FS_ATTR((unused)), 685 int ref_offset EXT2FS_ATTR((unused)), 686 void *priv_data) 687{ 688 struct dup_cluster *p; 689 blk64_t new_block; 690 errcode_t retval; 691 struct clone_struct *cs = (struct clone_struct *) priv_data; 692 dnode_t *n; 693 e2fsck_t ctx; 694 blk64_t c; 695 int is_meta = 0; 696 697 ctx = cs->ctx; 698 699 if (HOLE_BLKADDR(*block_nr)) 700 return 0; 701 702 c = EXT2FS_B2C(fs, blockcnt); 703 if (check_if_fs_cluster(ctx, EXT2FS_B2C(fs, *block_nr))) 704 is_meta = 1; 705 706 if (((blockcnt > 0) && c == cs->dup_cluster) || 707 ext2fs_test_block_bitmap2(ctx->block_dup_map, *block_nr)) { 708 n = dict_lookup(&clstr_dict, 709 INT_TO_VOIDPTR(EXT2FS_B2C(fs, *block_nr))); 710 if (!n) { 711 com_err("clone_file_block", 0, 712 _("internal error: can't find dup_blk for %llu\n"), 713 *block_nr); 714 return 0; 715 } 716 717 p = (struct dup_cluster *) dnode_get(n); 718 if (!is_meta) 719 decrement_badcount(ctx, *block_nr, p); 720 721 if (p->num_bad == 0 && !is_meta) { 722 /* 723 * Normally num_bad never gets to zero; but in 724 * the case of bigalloc file systems, we don't 725 * how many blocks might be in use by a 726 * particular inode. So we may end up 727 * relocating the cluster even though this 728 * inode is the last user of the cluster. In 729 * that case, since we've already moved some 730 * of the blocks of that cluster, we'll 731 * complete the relocation and free the 732 * original cluster here. 733 */ 734 ext2fs_unmark_block_bitmap2(ctx->block_found_map, 735 *block_nr); 736 ext2fs_block_alloc_stats2(fs, *block_nr, -1); 737 } 738 739 if ((blockcnt > 0) && c == cs->dup_cluster) { 740 new_block = cs->alloc_block; 741 goto got_block; 742 } 743 cs->dup_cluster = c; 744 745 retval = ext2fs_new_block2(fs, 0, ctx->block_found_map, 746 &new_block); 747 if (retval) { 748 cs->errcode = retval; 749 return BLOCK_ABORT; 750 } 751 cs->alloc_block = new_block; 752 753 got_block: 754 new_block &= ~EXT2FS_CLUSTER_MASK(fs); 755 new_block += EXT2FS_CLUSTER_MASK(fs) & blockcnt; 756 if (cs->dir && (blockcnt >= 0)) { 757 retval = ext2fs_set_dir_block2(fs->dblist, 758 cs->dir, new_block, blockcnt); 759 if (retval) { 760 cs->errcode = retval; 761 return BLOCK_ABORT; 762 } 763 } 764#if 0 765 printf("Cloning block #%lld from %llu to %llu\n", 766 blockcnt, *block_nr, new_block); 767#endif 768 retval = io_channel_read_blk64(fs->io, *block_nr, 1, cs->buf); 769 if (retval) { 770 cs->errcode = retval; 771 return BLOCK_ABORT; 772 } 773 retval = io_channel_write_blk64(fs->io, new_block, 1, cs->buf); 774 if (retval) { 775 cs->errcode = retval; 776 return BLOCK_ABORT; 777 } 778 *block_nr = new_block; 779 ext2fs_mark_block_bitmap2(ctx->block_found_map, new_block); 780 ext2fs_mark_block_bitmap2(fs->block_map, new_block); 781 return BLOCK_CHANGED; 782 } 783 return 0; 784} 785 786static int clone_file(e2fsck_t ctx, ext2_ino_t ino, 787 struct dup_inode *dp, char* block_buf) 788{ 789 ext2_filsys fs = ctx->fs; 790 errcode_t retval; 791 struct clone_struct cs; 792 struct problem_context pctx; 793 blk64_t blk, new_blk; 794 dnode_t *n; 795 struct inode_el *ino_el; 796 struct dup_cluster *dc; 797 struct dup_inode *di; 798 799 clear_problem_context(&pctx); 800 cs.errcode = 0; 801 cs.dir = 0; 802 cs.dup_cluster = 0; 803 cs.alloc_block = 0; 804 cs.ctx = ctx; 805 retval = ext2fs_get_mem(fs->blocksize, &cs.buf); 806 if (retval) 807 return retval; 808 809 if (ext2fs_test_inode_bitmap2(ctx->inode_dir_map, ino)) 810 cs.dir = ino; 811 812 pctx.ino = ino; 813 pctx.str = "clone_file"; 814 if (ext2fs_inode_has_valid_blocks2(fs, &dp->inode)) 815 pctx.errcode = ext2fs_block_iterate3(fs, ino, 0, block_buf, 816 clone_file_block, &cs); 817 ext2fs_mark_bb_dirty(fs); 818 if (pctx.errcode) { 819 fix_problem(ctx, PR_1B_BLOCK_ITERATE, &pctx); 820 retval = pctx.errcode; 821 goto errout; 822 } 823 if (cs.errcode) { 824 com_err("clone_file", cs.errcode, 825 _("returned from clone_file_block")); 826 retval = cs.errcode; 827 goto errout; 828 } 829 /* The inode may have changed on disk, so we have to re-read it */ 830 e2fsck_read_inode(ctx, ino, &dp->inode, "clone file EA"); 831 blk = ext2fs_file_acl_block(fs, &dp->inode); 832 new_blk = blk; 833 if (blk && (clone_file_block(fs, &new_blk, 834 BLOCK_COUNT_EXTATTR, 0, 0, &cs) == 835 BLOCK_CHANGED)) { 836 ext2fs_file_acl_block_set(fs, &dp->inode, new_blk); 837 e2fsck_write_inode(ctx, ino, &dp->inode, "clone file EA"); 838 /* 839 * If we cloned the EA block, find all other inodes 840 * which refered to that EA block, and modify 841 * them to point to the new EA block. 842 */ 843 n = dict_lookup(&clstr_dict, 844 INT_TO_VOIDPTR(EXT2FS_B2C(fs, blk))); 845 if (!n) { 846 com_err("clone_file", 0, 847 _("internal error: couldn't lookup EA " 848 "block record for %llu"), blk); 849 retval = 0; /* OK to stumble on... */ 850 goto errout; 851 } 852 dc = (struct dup_cluster *) dnode_get(n); 853 for (ino_el = dc->inode_list; ino_el; ino_el = ino_el->next) { 854 if (ino_el->inode == ino) 855 continue; 856 n = dict_lookup(&ino_dict, INT_TO_VOIDPTR(ino_el->inode)); 857 if (!n) { 858 com_err("clone_file", 0, 859 _("internal error: couldn't lookup EA " 860 "inode record for %u"), 861 ino_el->inode); 862 retval = 0; /* OK to stumble on... */ 863 goto errout; 864 } 865 di = (struct dup_inode *) dnode_get(n); 866 if (ext2fs_file_acl_block(fs, &di->inode) == blk) { 867 ext2fs_file_acl_block_set(fs, &di->inode, 868 ext2fs_file_acl_block(fs, &dp->inode)); 869 e2fsck_write_inode(ctx, ino_el->inode, 870 &di->inode, "clone file EA"); 871 decrement_badcount(ctx, blk, dc); 872 } 873 } 874 } 875 retval = 0; 876errout: 877 ext2fs_free_mem(&cs.buf); 878 return retval; 879} 880 881/* 882 * This routine returns 1 if a block overlaps with one of the superblocks, 883 * group descriptors, inode bitmaps, or block bitmaps. 884 */ 885static int check_if_fs_block(e2fsck_t ctx, blk64_t test_block) 886{ 887 ext2_filsys fs = ctx->fs; 888 blk64_t first_block; 889 dgrp_t i; 890 891 first_block = fs->super->s_first_data_block; 892 for (i = 0; i < fs->group_desc_count; i++) { 893 894 /* Check superblocks/block group descriptors */ 895 if (ext2fs_bg_has_super(fs, i)) { 896 if (test_block >= first_block && 897 (test_block <= first_block + fs->desc_blocks)) 898 return 1; 899 } 900 901 /* Check the inode table */ 902 if ((ext2fs_inode_table_loc(fs, i)) && 903 (test_block >= ext2fs_inode_table_loc(fs, i)) && 904 (test_block < (ext2fs_inode_table_loc(fs, i) + 905 fs->inode_blocks_per_group))) 906 return 1; 907 908 /* Check the bitmap blocks */ 909 if ((test_block == ext2fs_block_bitmap_loc(fs, i)) || 910 (test_block == ext2fs_inode_bitmap_loc(fs, i))) 911 return 1; 912 913 first_block += fs->super->s_blocks_per_group; 914 } 915 return 0; 916} 917 918/* 919 * This routine returns 1 if a cluster overlaps with one of the superblocks, 920 * group descriptors, inode bitmaps, or block bitmaps. 921 */ 922static int check_if_fs_cluster(e2fsck_t ctx, blk64_t cluster) 923{ 924 ext2_filsys fs = ctx->fs; 925 blk64_t first_block; 926 dgrp_t i; 927 928 first_block = fs->super->s_first_data_block; 929 for (i = 0; i < fs->group_desc_count; i++) { 930 931 /* Check superblocks/block group descriptors */ 932 if (ext2fs_bg_has_super(fs, i)) { 933 if (cluster >= EXT2FS_B2C(fs, first_block) && 934 (cluster <= EXT2FS_B2C(fs, first_block + 935 fs->desc_blocks))) 936 return 1; 937 } 938 939 /* Check the inode table */ 940 if ((ext2fs_inode_table_loc(fs, i)) && 941 (cluster >= EXT2FS_B2C(fs, 942 ext2fs_inode_table_loc(fs, i))) && 943 (cluster <= EXT2FS_B2C(fs, 944 ext2fs_inode_table_loc(fs, i) + 945 fs->inode_blocks_per_group - 1))) 946 return 1; 947 948 /* Check the bitmap blocks */ 949 if ((cluster == EXT2FS_B2C(fs, 950 ext2fs_block_bitmap_loc(fs, i))) || 951 (cluster == EXT2FS_B2C(fs, 952 ext2fs_inode_bitmap_loc(fs, i)))) 953 return 1; 954 955 first_block += fs->super->s_blocks_per_group; 956 } 957 return 0; 958} 959