1 /** 2 * main.c 3 * 4 * Copyright (c) 2013 Samsung Electronics Co., Ltd. 5 * http://www.samsung.com/ 6 * Copyright (c) 2015 Jaegeuk Kim <jaegeuk@kernel.org> 7 * : implement defrag.f2fs 8 * Copyright (C) 2015 Huawei Ltd. 9 * Hou Pengyang <houpengyang@huawei.com> 10 * Liu Shuoran <liushuoran@huawei.com> 11 * Jaegeuk Kim <jaegeuk@kernel.org> 12 * : add sload.f2fs 13 * Copyright (c) 2019 Google Inc. 14 * Robin Hsu <robinhsu@google.com> 15 * : add cache layer 16 * 17 * This program is free software; you can redistribute it and/or modify 18 * it under the terms of the GNU General Public License version 2 as 19 * published by the Free Software Foundation. 20 */ 21 #include "fsck.h" 22 #include <libgen.h> 23 #include <ctype.h> 24 #include <time.h> 25 #include <getopt.h> 26 #include <stdbool.h> 27 #include "quotaio.h" 28 29 struct f2fs_fsck gfsck; 30 31 #ifdef WITH_ANDROID 32 #include <sparse/sparse.h> 33 extern struct sparse_file *f2fs_sparse_file; 34 #endif 35 36 INIT_FEATURE_TABLE; 37 38 static char *absolute_path(const char *file) 39 { 40 char *ret; 41 char cwd[PATH_MAX]; 42 43 if (file[0] != '/') { 44 if (getcwd(cwd, PATH_MAX) == NULL) { 45 fprintf(stderr, "Failed to getcwd\n"); 46 exit(EXIT_FAILURE); 47 } 48 ret = malloc(strlen(cwd) + 1 + strlen(file) + 1); 49 if (ret) 50 sprintf(ret, "%s/%s", cwd, file); 51 } else 52 ret = strdup(file); 53 return ret; 54 } 55 56 void fsck_usage() 57 { 58 MSG(0, "\nUsage: fsck.f2fs [options] device\n"); 59 MSG(0, "[options]:\n"); 60 MSG(0, " -a check/fix potential corruption, reported by f2fs\n"); 61 MSG(0, " -c <num-cache-entry> set number of cache entries" 62 " (default 0)\n"); 63 MSG(0, " -m <max-hash-collision> set max cache hash collision" 64 " (default 16)\n"); 65 MSG(0, " -C encoding[:flag1,flag2] Set options for enabling" 66 " casefolding\n"); 67 MSG(0, " -d debug level [default:0]\n"); 68 MSG(0, " -f check/fix entire partition\n"); 69 MSG(0, " -g add default options\n"); 70 MSG(0, " -O feature1[feature2,feature3,...] e.g. \"encrypt\"\n"); 71 MSG(0, " -p preen mode [default:0 the same as -a [0|1]]\n"); 72 MSG(0, " -S sparse_mode\n"); 73 MSG(0, " -t show directory tree\n"); 74 MSG(0, " -q preserve quota limits\n"); 75 MSG(0, " -y fix all the time\n"); 76 MSG(0, " -V print the version number and exit\n"); 77 MSG(0, " --dry-run do not really fix corruptions\n"); 78 MSG(0, " --no-kernel-check skips detecting kernel change\n"); 79 MSG(0, " --kernel-check checks kernel change\n"); 80 MSG(0, " --debug-cache to debug cache when -c is used\n"); 81 exit(1); 82 } 83 84 void dump_usage() 85 { 86 MSG(0, "\nUsage: dump.f2fs [options] device\n"); 87 MSG(0, "[options]:\n"); 88 MSG(0, " -d debug level [default:0]\n"); 89 MSG(0, " -i inode no (hex)\n"); 90 MSG(0, " -n [NAT dump nid from #1~#2 (decimal), for all 0~-1]\n"); 91 MSG(0, " -s [SIT dump segno from #1~#2 (decimal), for all 0~-1]\n"); 92 MSG(0, " -S sparse_mode\n"); 93 MSG(0, " -a [SSA dump segno from #1~#2 (decimal), for all 0~-1]\n"); 94 MSG(0, " -b blk_addr (in 4KB)\n"); 95 MSG(0, " -V print the version number and exit\n"); 96 97 exit(1); 98 } 99 100 void defrag_usage() 101 { 102 MSG(0, "\nUsage: defrag.f2fs [options] device\n"); 103 MSG(0, "[options]:\n"); 104 MSG(0, " -d debug level [default:0]\n"); 105 MSG(0, " -s start block address [default: main_blkaddr]\n"); 106 MSG(0, " -S sparse_mode\n"); 107 MSG(0, " -l length [default:512 (2MB)]\n"); 108 MSG(0, " -t target block address [default: main_blkaddr + 2MB]\n"); 109 MSG(0, " -i set direction as shrink [default: expand]\n"); 110 MSG(0, " -V print the version number and exit\n"); 111 exit(1); 112 } 113 114 void resize_usage() 115 { 116 MSG(0, "\nUsage: resize.f2fs [options] device\n"); 117 MSG(0, "[options]:\n"); 118 MSG(0, " -d debug level [default:0]\n"); 119 MSG(0, " -i extended node bitmap, node ratio is 20%% by default\n"); 120 MSG(0, " -s safe resize (Does not resize metadata)"); 121 MSG(0, " -t target sectors [default: device size]\n"); 122 MSG(0, " -V print the version number and exit\n"); 123 exit(1); 124 } 125 126 void sload_usage() 127 { 128 MSG(0, "\nUsage: sload.f2fs [options] device\n"); 129 MSG(0, "[options]:\n"); 130 MSG(0, " -C fs_config\n"); 131 MSG(0, " -f source directory [path of the source directory]\n"); 132 MSG(0, " -p product out directory\n"); 133 MSG(0, " -s file_contexts\n"); 134 MSG(0, " -S sparse_mode\n"); 135 MSG(0, " -t mount point [prefix of target fs path, default:/]\n"); 136 MSG(0, " -T timestamp\n"); 137 MSG(0, " -d debug level [default:0]\n"); 138 MSG(0, " -V print the version number and exit\n"); 139 exit(1); 140 } 141 142 static int is_digits(char *optarg) 143 { 144 unsigned int i; 145 146 for (i = 0; i < strlen(optarg); i++) 147 if (!isdigit(optarg[i])) 148 break; 149 return i == strlen(optarg); 150 } 151 152 static void error_out(char *prog) 153 { 154 if (!strcmp("fsck.f2fs", prog)) 155 fsck_usage(); 156 else if (!strcmp("dump.f2fs", prog)) 157 dump_usage(); 158 else if (!strcmp("defrag.f2fs", prog)) 159 defrag_usage(); 160 else if (!strcmp("resize.f2fs", prog)) 161 resize_usage(); 162 else if (!strcmp("sload.f2fs", prog)) 163 sload_usage(); 164 else 165 MSG(0, "\nWrong program.\n"); 166 } 167 168 static void __add_fsck_options(void) 169 { 170 /* -a */ 171 c.auto_fix = 1; 172 } 173 174 static void add_default_options(void) 175 { 176 switch (c.defset) { 177 case CONF_ANDROID: 178 __add_fsck_options(); 179 } 180 c.quota_fix = 1; 181 } 182 183 void f2fs_parse_options(int argc, char *argv[]) 184 { 185 int option = 0; 186 char *prog = basename(argv[0]); 187 int err = NOERROR; 188 #ifdef WITH_ANDROID 189 int i; 190 191 /* Allow prog names (e.g, sload_f2fs, fsck_f2fs, etc) */ 192 for (i = 0; i < strlen(prog); i++) { 193 if (prog[i] == '_') 194 prog[i] = '.'; 195 } 196 #endif 197 if (argc < 2) { 198 MSG(0, "\tError: Device not specified\n"); 199 error_out(prog); 200 } 201 202 if (!strcmp("fsck.f2fs", prog)) { 203 const char *option_string = ":aC:c:m:d:fg:O:p:q:StyV"; 204 int opt = 0, val; 205 char *token; 206 struct option long_opt[] = { 207 {"dry-run", no_argument, 0, 1}, 208 {"no-kernel-check", no_argument, 0, 2}, 209 {"kernel-check", no_argument, 0, 3}, 210 {"debug-cache", no_argument, 0, 4}, 211 {0, 0, 0, 0} 212 }; 213 214 c.func = FSCK; 215 c.cache_config.max_hash_collision = 16; 216 c.cache_config.dbg_en = false; 217 while ((option = getopt_long(argc, argv, option_string, 218 long_opt, &opt)) != EOF) { 219 switch (option) { 220 case 1: 221 c.dry_run = 1; 222 MSG(0, "Info: Dry run\n"); 223 break; 224 case 2: 225 c.no_kernel_check = 1; 226 MSG(0, "Info: No Kernel Check\n"); 227 break; 228 case 3: 229 c.no_kernel_check = 0; 230 MSG(0, "Info: Do Kernel Check\n"); 231 break; 232 case 4: 233 c.cache_config.dbg_en = true; 234 break; 235 case 'a': 236 c.auto_fix = 1; 237 MSG(0, "Info: Fix the reported corruption.\n"); 238 break; 239 case 'c': 240 c.cache_config.num_cache_entry = atoi(optarg); 241 break; 242 case 'm': 243 c.cache_config.max_hash_collision = 244 atoi(optarg); 245 break; 246 case 'g': 247 if (!strcmp(optarg, "android")) 248 c.defset = CONF_ANDROID; 249 break; 250 case 'O': 251 if (parse_feature(feature_table, optarg)) 252 fsck_usage(); 253 break; 254 case 'p': 255 /* preen mode has different levels: 256 * 0: default level, the same as -a 257 * 1: check meta 258 * 2: same as 0, but will skip some 259 * check for old kernel 260 */ 261 if (optarg[0] == '-' || !is_digits(optarg) || 262 optind == argc) { 263 MSG(0, "Info: Use default preen mode\n"); 264 c.preen_mode = PREEN_MODE_0; 265 c.auto_fix = 1; 266 optind--; 267 break; 268 } 269 c.preen_mode = atoi(optarg); 270 if (c.preen_mode < 0) 271 c.preen_mode = PREEN_MODE_0; 272 else if (c.preen_mode >= PREEN_MODE_MAX) 273 c.preen_mode = PREEN_MODE_MAX - 1; 274 if (c.preen_mode == PREEN_MODE_0 || 275 c.preen_mode == PREEN_MODE_2) 276 c.auto_fix = 1; 277 MSG(0, "Info: Fix the reported corruption in " 278 "preen mode %d\n", c.preen_mode); 279 break; 280 case 'd': 281 if (optarg[0] == '-') { 282 err = ENEED_ARG; 283 break; 284 } else if (!is_digits(optarg)) { 285 err = EWRONG_OPT; 286 break; 287 } 288 c.dbg_lv = atoi(optarg); 289 MSG(0, "Info: Debug level = %d\n", c.dbg_lv); 290 break; 291 case 'f': 292 case 'y': 293 c.fix_on = 1; 294 c.force = 1; 295 MSG(0, "Info: Force to fix corruption\n"); 296 break; 297 case 'q': 298 c.preserve_limits = atoi(optarg); 299 MSG(0, "Info: Preserve quota limits = %d\n", 300 c.preserve_limits); 301 break; 302 case 'S': 303 c.sparse_mode = 1; 304 break; 305 case 't': 306 c.show_dentry = 1; 307 break; 308 case ':': 309 if (optopt == 'p') { 310 MSG(0, "Info: Use default preen mode\n"); 311 c.preen_mode = PREEN_MODE_0; 312 c.auto_fix = 1; 313 } else { 314 option = optopt; 315 err = ENEED_ARG; 316 break; 317 } 318 break; 319 case 'C': 320 token = strtok(optarg, ":"); 321 val = f2fs_str2encoding(token); 322 if (val < 0) { 323 MSG(0, "\tError: Unknown encoding %s\n", token); 324 fsck_usage(); 325 } 326 c.s_encoding = val; 327 token = strtok(NULL, ""); 328 val = f2fs_str2encoding_flags(&token, &c.s_encoding_flags); 329 if (val) { 330 MSG(0, "\tError: Unknown flag %s\n", token); 331 fsck_usage(); 332 } 333 c.feature |= cpu_to_le32(F2FS_FEATURE_CASEFOLD); 334 break; 335 case 'V': 336 show_version(prog); 337 exit(0); 338 case '?': 339 option = optopt; 340 default: 341 err = EUNKNOWN_OPT; 342 break; 343 } 344 if (err != NOERROR) 345 break; 346 } 347 } else if (!strcmp("dump.f2fs", prog)) { 348 const char *option_string = "d:i:n:s:Sa:b:V"; 349 static struct dump_option dump_opt = { 350 .nid = 0, /* default root ino */ 351 .start_nat = -1, 352 .end_nat = -1, 353 .start_sit = -1, 354 .end_sit = -1, 355 .start_ssa = -1, 356 .end_ssa = -1, 357 .blk_addr = -1, 358 }; 359 360 c.func = DUMP; 361 while ((option = getopt(argc, argv, option_string)) != EOF) { 362 int ret = 0; 363 364 switch (option) { 365 case 'd': 366 if (!is_digits(optarg)) { 367 err = EWRONG_OPT; 368 break; 369 } 370 c.dbg_lv = atoi(optarg); 371 MSG(0, "Info: Debug level = %d\n", 372 c.dbg_lv); 373 break; 374 case 'g': 375 if (!strcmp(optarg, "android")) { 376 c.defset = CONF_ANDROID; 377 MSG(0, "Info: Set conf for android\n"); 378 break; 379 } 380 err = EWRONG_OPT; 381 break; 382 case 'i': 383 if (strncmp(optarg, "0x", 2)) 384 ret = sscanf(optarg, "%d", 385 &dump_opt.nid); 386 else 387 ret = sscanf(optarg, "%x", 388 &dump_opt.nid); 389 break; 390 case 'n': 391 ret = sscanf(optarg, "%d~%d", 392 &dump_opt.start_nat, 393 &dump_opt.end_nat); 394 break; 395 case 's': 396 ret = sscanf(optarg, "%d~%d", 397 &dump_opt.start_sit, 398 &dump_opt.end_sit); 399 break; 400 case 'S': 401 c.sparse_mode = 1; 402 break; 403 case 'a': 404 ret = sscanf(optarg, "%d~%d", 405 &dump_opt.start_ssa, 406 &dump_opt.end_ssa); 407 break; 408 case 'b': 409 if (strncmp(optarg, "0x", 2)) 410 ret = sscanf(optarg, "%d", 411 &dump_opt.blk_addr); 412 else 413 ret = sscanf(optarg, "%x", 414 &dump_opt.blk_addr); 415 break; 416 case 'V': 417 show_version(prog); 418 exit(0); 419 default: 420 err = EUNKNOWN_OPT; 421 break; 422 } 423 ASSERT(ret >= 0); 424 if (err != NOERROR) 425 break; 426 } 427 428 c.private = &dump_opt; 429 } else if (!strcmp("defrag.f2fs", prog)) { 430 const char *option_string = "d:s:Sl:t:iV"; 431 432 c.func = DEFRAG; 433 while ((option = getopt(argc, argv, option_string)) != EOF) { 434 int ret = 0; 435 436 switch (option) { 437 case 'd': 438 if (!is_digits(optarg)) { 439 err = EWRONG_OPT; 440 break; 441 } 442 c.dbg_lv = atoi(optarg); 443 MSG(0, "Info: Debug level = %d\n", 444 c.dbg_lv); 445 break; 446 case 's': 447 if (strncmp(optarg, "0x", 2)) 448 ret = sscanf(optarg, "%"PRIu64"", 449 &c.defrag_start); 450 else 451 ret = sscanf(optarg, "%"PRIx64"", 452 &c.defrag_start); 453 break; 454 case 'S': 455 c.sparse_mode = 1; 456 break; 457 case 'l': 458 if (strncmp(optarg, "0x", 2)) 459 ret = sscanf(optarg, "%"PRIu64"", 460 &c.defrag_len); 461 else 462 ret = sscanf(optarg, "%"PRIx64"", 463 &c.defrag_len); 464 break; 465 case 't': 466 if (strncmp(optarg, "0x", 2)) 467 ret = sscanf(optarg, "%"PRIu64"", 468 &c.defrag_target); 469 else 470 ret = sscanf(optarg, "%"PRIx64"", 471 &c.defrag_target); 472 break; 473 case 'i': 474 c.defrag_shrink = 1; 475 break; 476 case 'V': 477 show_version(prog); 478 exit(0); 479 default: 480 err = EUNKNOWN_OPT; 481 break; 482 } 483 ASSERT(ret >= 0); 484 if (err != NOERROR) 485 break; 486 } 487 } else if (!strcmp("resize.f2fs", prog)) { 488 const char *option_string = "d:st:iV"; 489 490 c.func = RESIZE; 491 while ((option = getopt(argc, argv, option_string)) != EOF) { 492 int ret = 0; 493 494 switch (option) { 495 case 'd': 496 if (!is_digits(optarg)) { 497 err = EWRONG_OPT; 498 break; 499 } 500 c.dbg_lv = atoi(optarg); 501 MSG(0, "Info: Debug level = %d\n", 502 c.dbg_lv); 503 break; 504 case 's': 505 c.safe_resize = 1; 506 break; 507 case 't': 508 if (strncmp(optarg, "0x", 2)) 509 ret = sscanf(optarg, "%"PRIu64"", 510 &c.target_sectors); 511 else 512 ret = sscanf(optarg, "%"PRIx64"", 513 &c.target_sectors); 514 break; 515 case 'i': 516 c.large_nat_bitmap = 1; 517 break; 518 case 'V': 519 show_version(prog); 520 exit(0); 521 default: 522 err = EUNKNOWN_OPT; 523 break; 524 } 525 ASSERT(ret >= 0); 526 if (err != NOERROR) 527 break; 528 } 529 } else if (!strcmp("sload.f2fs", prog)) { 530 const char *option_string = "C:d:f:p:s:St:T:V"; 531 #ifdef HAVE_LIBSELINUX 532 int max_nr_opt = (int)sizeof(c.seopt_file) / 533 sizeof(c.seopt_file[0]); 534 char *token; 535 #endif 536 char *p; 537 538 c.func = SLOAD; 539 while ((option = getopt(argc, argv, option_string)) != EOF) { 540 switch (option) { 541 case 'C': 542 c.fs_config_file = absolute_path(optarg); 543 break; 544 case 'd': 545 if (!is_digits(optarg)) { 546 err = EWRONG_OPT; 547 break; 548 } 549 c.dbg_lv = atoi(optarg); 550 MSG(0, "Info: Debug level = %d\n", 551 c.dbg_lv); 552 break; 553 case 'f': 554 c.from_dir = absolute_path(optarg); 555 break; 556 case 'p': 557 c.target_out_dir = absolute_path(optarg); 558 break; 559 case 's': 560 #ifdef HAVE_LIBSELINUX 561 token = strtok(optarg, ","); 562 while (token) { 563 if (c.nr_opt == max_nr_opt) { 564 MSG(0, "\tError: Expected at most %d selinux opts\n", 565 max_nr_opt); 566 error_out(prog); 567 } 568 c.seopt_file[c.nr_opt].type = 569 SELABEL_OPT_PATH; 570 c.seopt_file[c.nr_opt].value = 571 absolute_path(token); 572 c.nr_opt++; 573 token = strtok(NULL, ","); 574 } 575 #else 576 MSG(0, "Info: Not support selinux opts\n"); 577 #endif 578 break; 579 case 'S': 580 c.sparse_mode = 1; 581 break; 582 case 't': 583 c.mount_point = (char *)optarg; 584 break; 585 case 'T': 586 c.fixed_time = strtoul(optarg, &p, 0); 587 break; 588 case 'V': 589 show_version(prog); 590 exit(0); 591 default: 592 err = EUNKNOWN_OPT; 593 break; 594 } 595 if (err != NOERROR) 596 break; 597 } 598 } 599 600 add_default_options(); 601 602 if (optind >= argc) { 603 MSG(0, "\tError: Device not specified\n"); 604 error_out(prog); 605 } 606 607 c.devices[0].path = strdup(argv[optind]); 608 if (argc > (optind + 1)) { 609 c.dbg_lv = 0; 610 err = EUNKNOWN_ARG; 611 } 612 if (err == NOERROR) 613 return; 614 615 /* print out error */ 616 switch (err) { 617 case EWRONG_OPT: 618 MSG(0, "\tError: Wrong option -%c %s\n", option, optarg); 619 break; 620 case ENEED_ARG: 621 MSG(0, "\tError: Need argument for -%c\n", option); 622 break; 623 case EUNKNOWN_OPT: 624 MSG(0, "\tError: Unknown option %c\n", option); 625 break; 626 case EUNKNOWN_ARG: 627 MSG(0, "\tError: Unknown argument %s\n", argv[optind]); 628 break; 629 } 630 error_out(prog); 631 } 632 633 static void do_fsck(struct f2fs_sb_info *sbi) 634 { 635 struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); 636 u32 flag = le32_to_cpu(ckpt->ckpt_flags); 637 u32 blk_cnt; 638 errcode_t ret; 639 640 fsck_init(sbi); 641 642 print_cp_state(flag); 643 644 fsck_chk_and_fix_write_pointers(sbi); 645 646 fsck_chk_curseg_info(sbi); 647 648 if (!c.fix_on && !c.bug_on) { 649 switch (c.preen_mode) { 650 case PREEN_MODE_1: 651 if (fsck_chk_meta(sbi)) { 652 MSG(0, "[FSCK] F2FS metadata [Fail]"); 653 MSG(0, "\tError: meta does not match, " 654 "force check all\n"); 655 } else { 656 MSG(0, "[FSCK] F2FS metadata [Ok..]"); 657 fsck_free(sbi); 658 return; 659 } 660 661 if (!c.ro) 662 c.fix_on = 1; 663 break; 664 } 665 } else if (c.preen_mode) { 666 /* 667 * we can hit this in 3 situations: 668 * 1. fsck -f, fix_on has already been set to 1 when 669 * parsing options; 670 * 2. fsck -a && CP_FSCK_FLAG is set, fix_on has already 671 * been set to 1 when checking CP_FSCK_FLAG; 672 * 3. fsck -p 1 && error is detected, then bug_on is set, 673 * we set fix_on = 1 here, so that fsck can fix errors 674 * automatically 675 */ 676 c.fix_on = 1; 677 } 678 679 fsck_chk_checkpoint(sbi); 680 681 fsck_chk_quota_node(sbi); 682 683 /* Traverse all block recursively from root inode */ 684 blk_cnt = 1; 685 686 if (c.feature & cpu_to_le32(F2FS_FEATURE_QUOTA_INO)) { 687 ret = quota_init_context(sbi); 688 if (ret) { 689 ASSERT_MSG("quota_init_context failure: %d", ret); 690 return; 691 } 692 } 693 fsck_chk_orphan_node(sbi); 694 fsck_chk_node_blk(sbi, NULL, sbi->root_ino_num, 695 F2FS_FT_DIR, TYPE_INODE, &blk_cnt, NULL); 696 fsck_chk_quota_files(sbi); 697 698 fsck_verify(sbi); 699 fsck_free(sbi); 700 } 701 702 static void do_dump(struct f2fs_sb_info *sbi) 703 { 704 struct dump_option *opt = (struct dump_option *)c.private; 705 struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); 706 u32 flag = le32_to_cpu(ckpt->ckpt_flags); 707 708 if (opt->end_nat == -1) 709 opt->end_nat = NM_I(sbi)->max_nid; 710 if (opt->end_sit == -1) 711 opt->end_sit = SM_I(sbi)->main_segments; 712 if (opt->end_ssa == -1) 713 opt->end_ssa = SM_I(sbi)->main_segments; 714 if (opt->start_nat != -1) 715 nat_dump(sbi, opt->start_nat, opt->end_nat); 716 if (opt->start_sit != -1) 717 sit_dump(sbi, opt->start_sit, opt->end_sit); 718 if (opt->start_ssa != -1) 719 ssa_dump(sbi, opt->start_ssa, opt->end_ssa); 720 if (opt->blk_addr != -1) 721 dump_info_from_blkaddr(sbi, opt->blk_addr); 722 if (opt->nid) 723 dump_node(sbi, opt->nid, 0); 724 725 print_cp_state(flag); 726 727 } 728 729 static int do_defrag(struct f2fs_sb_info *sbi) 730 { 731 struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); 732 733 if (c.defrag_start > get_sb(block_count)) 734 goto out_range; 735 if (c.defrag_start < SM_I(sbi)->main_blkaddr) 736 c.defrag_start = SM_I(sbi)->main_blkaddr; 737 738 if (c.defrag_len == 0) 739 c.defrag_len = sbi->blocks_per_seg; 740 741 if (c.defrag_start + c.defrag_len > get_sb(block_count)) 742 c.defrag_len = get_sb(block_count) - c.defrag_start; 743 744 if (c.defrag_target == 0) { 745 c.defrag_target = c.defrag_start - 1; 746 if (!c.defrag_shrink) 747 c.defrag_target += c.defrag_len + 1; 748 } 749 750 if (c.defrag_target < SM_I(sbi)->main_blkaddr || 751 c.defrag_target > get_sb(block_count)) 752 goto out_range; 753 if (c.defrag_target >= c.defrag_start && 754 c.defrag_target < c.defrag_start + c.defrag_len) 755 goto out_range; 756 757 if (c.defrag_start > c.defrag_target) 758 MSG(0, "Info: Move 0x%"PRIx64" <- [0x%"PRIx64"-0x%"PRIx64"]\n", 759 c.defrag_target, 760 c.defrag_start, 761 c.defrag_start + c.defrag_len - 1); 762 else 763 MSG(0, "Info: Move [0x%"PRIx64"-0x%"PRIx64"] -> 0x%"PRIx64"\n", 764 c.defrag_start, 765 c.defrag_start + c.defrag_len - 1, 766 c.defrag_target); 767 768 return f2fs_defragment(sbi, c.defrag_start, c.defrag_len, 769 c.defrag_target, c.defrag_shrink); 770 out_range: 771 ASSERT_MSG("Out-of-range [0x%"PRIx64" ~ 0x%"PRIx64"] to 0x%"PRIx64"", 772 c.defrag_start, 773 c.defrag_start + c.defrag_len - 1, 774 c.defrag_target); 775 return -1; 776 } 777 778 static int do_resize(struct f2fs_sb_info *sbi) 779 { 780 if (!c.target_sectors) 781 c.target_sectors = c.total_sectors; 782 783 if (c.target_sectors > c.total_sectors) { 784 ASSERT_MSG("Out-of-range Target=0x%"PRIx64" / 0x%"PRIx64"", 785 c.target_sectors, c.total_sectors); 786 return -1; 787 } 788 789 return f2fs_resize(sbi); 790 } 791 792 static int do_sload(struct f2fs_sb_info *sbi) 793 { 794 if (!c.from_dir) { 795 MSG(0, "Info: No source directory, but it's okay.\n"); 796 return 0; 797 } 798 if (!c.mount_point) 799 c.mount_point = "/"; 800 801 return f2fs_sload(sbi); 802 } 803 804 #if defined(__APPLE__) 805 static u64 get_boottime_ns() 806 { 807 #ifdef HAVE_MACH_TIME_H 808 return mach_absolute_time(); 809 #else 810 return 0; 811 #endif 812 } 813 #else 814 static u64 get_boottime_ns() 815 { 816 struct timespec t; 817 t.tv_sec = t.tv_nsec = 0; 818 clock_gettime(CLOCK_BOOTTIME, &t); 819 return (u64)t.tv_sec * 1000000000LL + t.tv_nsec; 820 } 821 #endif 822 823 int main(int argc, char **argv) 824 { 825 struct f2fs_sb_info *sbi; 826 int ret = 0; 827 u64 start = get_boottime_ns(); 828 829 f2fs_init_configuration(); 830 831 f2fs_parse_options(argc, argv); 832 833 if (c.func != DUMP && f2fs_devs_are_umounted() < 0) { 834 if (errno == EBUSY) { 835 ret = -1; 836 goto quick_err; 837 } 838 if (!c.ro || c.func == DEFRAG) { 839 MSG(0, "\tError: Not available on mounted device!\n"); 840 ret = -1; 841 goto quick_err; 842 } 843 844 /* allow ro-mounted partition */ 845 if (c.force) { 846 MSG(0, "Info: Force to check/repair FS on RO mounted device\n"); 847 } else { 848 MSG(0, "Info: Check FS only on RO mounted device\n"); 849 c.fix_on = 0; 850 c.auto_fix = 0; 851 } 852 } 853 854 /* Get device */ 855 if (f2fs_get_device_info() < 0) { 856 ret = -1; 857 goto quick_err; 858 } 859 860 fsck_again: 861 memset(&gfsck, 0, sizeof(gfsck)); 862 gfsck.sbi.fsck = &gfsck; 863 sbi = &gfsck.sbi; 864 865 ret = f2fs_do_mount(sbi); 866 if (ret != 0) { 867 if (ret == 1) { 868 MSG(0, "Info: No error was reported\n"); 869 ret = 0; 870 } 871 goto out_err; 872 } 873 874 switch (c.func) { 875 case FSCK: 876 do_fsck(sbi); 877 break; 878 #ifdef WITH_DUMP 879 case DUMP: 880 do_dump(sbi); 881 break; 882 #endif 883 #ifdef WITH_DEFRAG 884 case DEFRAG: 885 ret = do_defrag(sbi); 886 if (ret) 887 goto out_err; 888 break; 889 #endif 890 #ifdef WITH_RESIZE 891 case RESIZE: 892 if (do_resize(sbi)) 893 goto out_err; 894 break; 895 #endif 896 #ifdef WITH_SLOAD 897 case SLOAD: 898 if (do_sload(sbi)) 899 goto out_err; 900 901 ret = f2fs_sparse_initialize_meta(sbi); 902 if (ret < 0) 903 goto out_err; 904 905 f2fs_do_umount(sbi); 906 907 /* fsck to fix missing quota */ 908 c.func = FSCK; 909 c.fix_on = 1; 910 goto fsck_again; 911 #endif 912 default: 913 ERR_MSG("Wrong program name\n"); 914 ASSERT(0); 915 } 916 917 f2fs_do_umount(sbi); 918 919 if (c.func == FSCK && c.bug_on) { 920 if (!c.ro && c.fix_on == 0 && c.auto_fix == 0 && !c.dry_run) { 921 char ans[255] = {0}; 922 retry: 923 printf("Do you want to fix this partition? [Y/N] "); 924 ret = scanf("%s", ans); 925 ASSERT(ret >= 0); 926 if (!strcasecmp(ans, "y")) 927 c.fix_on = 1; 928 else if (!strcasecmp(ans, "n")) 929 c.fix_on = 0; 930 else 931 goto retry; 932 933 if (c.fix_on) 934 goto fsck_again; 935 } 936 } 937 ret = f2fs_finalize_device(); 938 if (ret < 0) 939 return ret; 940 941 printf("\nDone: %lf secs\n", (get_boottime_ns() - start) / 1000000000.0); 942 return 0; 943 944 out_err: 945 if (sbi->ckpt) 946 free(sbi->ckpt); 947 if (sbi->raw_super) 948 free(sbi->raw_super); 949 quick_err: 950 f2fs_release_sparse_resource(); 951 return ret; 952 } 953