X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;f=e2fsck%2Funix.c;h=853eb29644ad6c9622d4c95805f344770e82b88b;hb=b84eee32d54b20679b27cdff231cd72619e4cc44;hp=e54e2cea8208a84bd427b4a323fd39350174b925;hpb=c2db4cb7a2a4b094a4a4a06dd22fc744d10d490b;p=tools%2Fe2fsprogs.git diff --git a/e2fsck/unix.c b/e2fsck/unix.c index e54e2ce..853eb29 100644 --- a/e2fsck/unix.c +++ b/e2fsck/unix.c @@ -50,9 +50,12 @@ extern int optind; #include "e2p/e2p.h" #include "et/com_err.h" #include "e2p/e2p.h" +#include "uuid/uuid.h" #include "support/plausible.h" +#include "support/devname.h" #include "e2fsck.h" #include "problem.h" +#include "jfs_user.h" #include "../version.h" /* Command line options */ @@ -66,18 +69,17 @@ static char *bad_blocks_file; e2fsck_t e2fsck_global_ctx; /* Try your very best not to use this! */ -#ifdef CONFIG_JBD_DEBUG /* Enabled by configure --enable-jfs-debug */ +#ifdef CONFIG_JBD_DEBUG /* Enabled by configure --enable-jbd-debug */ int journal_enable_debug = -1; #endif static void usage(e2fsck_t ctx) { fprintf(stderr, - _("Usage: %s [-panyrcdfvtDFV] [-b superblock] [-B blocksize]\n" - "\t\t[-I inode_buffer_blocks] [-P process_inode_size]\n" + _("Usage: %s [-panyrcdfktvDFV] [-b superblock] [-B blocksize]\n" "\t\t[-l|-L bad_blocks_file] [-C fd] [-j external_journal]\n" "\t\t[-E extended-options] [-z undo_file] device\n"), - ctx->program_name); + ctx->program_name ? ctx->program_name : "e2fsck"); fprintf(stderr, "%s", _("\nEmergency help:\n" " -p Automatic repair (no questions)\n" @@ -106,7 +108,7 @@ static void show_stats(e2fsck_t ctx) unsigned int dir_links; unsigned int num_files, num_links; __u32 *mask, m; - int frag_percent_file, frag_percent_dir, frag_percent_total; + int frag_percent_file = 0, frag_percent_dir = 0, frag_percent_total = 0; int i, j, printed = 0; dir_links = 2 * ctx->fs_directory_count - 1; @@ -119,23 +121,26 @@ static void show_stats(e2fsck_t ctx) blocks_used = (ext2fs_blocks_count(fs->super) - ext2fs_free_blocks_count(fs->super)); - frag_percent_file = (10000 * ctx->fs_fragmented) / inodes_used; - frag_percent_file = (frag_percent_file + 5) / 10; + if (inodes_used > 0) { + frag_percent_file = (10000 * ctx->fs_fragmented) / inodes_used; + frag_percent_file = (frag_percent_file + 5) / 10; - frag_percent_dir = (10000 * ctx->fs_fragmented_dir) / inodes_used; - frag_percent_dir = (frag_percent_dir + 5) / 10; + frag_percent_dir = (10000 * ctx->fs_fragmented_dir) / inodes_used; + frag_percent_dir = (frag_percent_dir + 5) / 10; - frag_percent_total = ((10000 * (ctx->fs_fragmented + - ctx->fs_fragmented_dir)) - / inodes_used); - frag_percent_total = (frag_percent_total + 5) / 10; + frag_percent_total = ((10000 * (ctx->fs_fragmented + + ctx->fs_fragmented_dir)) + / inodes_used); + frag_percent_total = (frag_percent_total + 5) / 10; + } if (!verbose) { log_out(ctx, _("%s: %u/%u files (%0d.%d%% non-contiguous), " "%llu/%llu blocks\n"), ctx->device_name, inodes_used, inodes, frag_percent_total / 10, frag_percent_total % 10, - blocks_used, blocks); + (unsigned long long) blocks_used, + (unsigned long long) blocks); return; } profile_get_boolean(ctx->profile, "options", "report_features", 0, 0, @@ -191,7 +196,8 @@ static void show_stats(e2fsck_t ctx) log_out(ctx, P_("%12llu block used (%2.2f%%, out of %llu)\n", "%12llu blocks used (%2.2f%%, out of %llu)\n", blocks_used), - blocks_used, 100.0 * blocks_used / blocks, blocks); + (unsigned long long) blocks_used, 100.0 * blocks_used / blocks, + (unsigned long long) blocks); log_out(ctx, P_("%12u bad block\n", "%12u bad blocks\n", ctx->fs_badblocks_count), ctx->fs_badblocks_count); log_out(ctx, P_("%12u large file\n", "%12u large files\n", @@ -285,7 +291,7 @@ static int is_on_batt(void) { FILE *f; DIR *d; - char tmp[80], tmp2[80], fname[80]; + char tmp[80], tmp2[80], fname[NAME_MAX+30]; unsigned int acflag; struct dirent* de; @@ -299,7 +305,7 @@ static int is_on_batt(void) } f = fopen("/proc/apm", "r"); if (f) { - if (fscanf(f, "%s %s %s %x", tmp, tmp, tmp, &acflag) != 4) + if (fscanf(f, "%79s %79s %79s %x", tmp, tmp, tmp, &acflag) != 4) acflag = 1; fclose(f); return (acflag != 1); @@ -309,12 +315,13 @@ static int is_on_batt(void) while ((de=readdir(d)) != NULL) { if (!strncmp(".", de->d_name, 1)) continue; - snprintf(fname, 80, "/proc/acpi/ac_adapter/%s/state", + snprintf(fname, sizeof(fname), + "/proc/acpi/ac_adapter/%s/state", de->d_name); f = fopen(fname, "r"); if (!f) continue; - if (fscanf(f, "%s %s", tmp2, tmp) != 2) + if (fscanf(f, "%79s %79s", tmp2, tmp) != 2) tmp[0] = 0; fclose(f); if (strncmp(tmp, "off-line", 8) == 0) { @@ -394,7 +401,12 @@ static void check_if_skip(e2fsck_t ctx) if (batt && ((ctx->now - fs->super->s_lastcheck) < fs->super->s_checkinterval*2)) reason = 0; + } else if (broken_system_clock && fs->super->s_checkinterval) { + log_out(ctx, "%s: ", ctx->device_name); + log_out(ctx, "%s", + _("ignoring check interval, broken_system_clock set\n")); } + if (reason) { log_out(ctx, "%s", ctx->device_name); log_out(ctx, reason, reason_arg); @@ -435,9 +447,9 @@ static void check_if_skip(e2fsck_t ctx) ctx->device_name, fs->super->s_inodes_count - fs->super->s_free_inodes_count, fs->super->s_inodes_count, - ext2fs_blocks_count(fs->super) - + (unsigned long long) ext2fs_blocks_count(fs->super) - ext2fs_free_blocks_count(fs->super), - ext2fs_blocks_count(fs->super)); + (unsigned long long) ext2fs_blocks_count(fs->super)); next_check = 100000; if (fs->super->s_max_mnt_count > 0) { next_check = fs->super->s_max_mnt_count - fs->super->s_mnt_count; @@ -609,9 +621,10 @@ static void reserve_stdio_fds(void) fprintf(stderr, _("ERROR: Couldn't open " "/dev/null (%s)\n"), strerror(errno)); - break; + return; } } + (void) close(fd); } #ifdef HAVE_SIGNAL_H @@ -709,18 +722,48 @@ static void parse_extended_opts(e2fsck_t ctx, const char *opts) } else if (strcmp(token, "nodiscard") == 0) { ctx->options &= ~E2F_OPT_DISCARD; continue; + } else if (strcmp(token, "optimize_extents") == 0) { + ctx->options &= ~E2F_OPT_NOOPT_EXTENTS; + continue; + } else if (strcmp(token, "no_optimize_extents") == 0) { + ctx->options |= E2F_OPT_NOOPT_EXTENTS; + continue; + } else if (strcmp(token, "inode_count_fullmap") == 0) { + ctx->options |= E2F_OPT_ICOUNT_FULLMAP; + continue; + } else if (strcmp(token, "no_inode_count_fullmap") == 0) { + ctx->options &= ~E2F_OPT_ICOUNT_FULLMAP; + continue; } else if (strcmp(token, "log_filename") == 0) { if (!arg) extended_usage++; else ctx->log_fn = string_copy(ctx, arg, 0); continue; + } else if (strcmp(token, "problem_log") == 0) { + if (!arg) + extended_usage++; + else + ctx->problem_log_fn = string_copy(ctx, arg, 0); + continue; } else if (strcmp(token, "bmap2extent") == 0) { ctx->options |= E2F_OPT_CONVERT_BMAP; continue; } else if (strcmp(token, "fixes_only") == 0) { ctx->options |= E2F_OPT_FIXES_ONLY; continue; + } else if (strcmp(token, "unshare_blocks") == 0) { + ctx->options |= E2F_OPT_UNSHARE_BLOCKS; + ctx->options |= E2F_OPT_FORCE; + continue; + } else if (strcmp(token, "check_encoding") == 0) { + ctx->options |= E2F_OPT_CHECK_ENCODING; + continue; +#ifdef CONFIG_DEVELOPER_FEATURES + } else if (strcmp(token, "clear_all_uninit_bits") == 0) { + ctx->options |= E2F_OPT_CLEAR_UNINIT; + continue; +#endif } else { fprintf(stderr, _("Unknown extended option: %s\n"), token); @@ -730,17 +773,24 @@ static void parse_extended_opts(e2fsck_t ctx, const char *opts) free(buf); if (extended_usage) { - fputs(("\nExtended options are separated by commas, " + fputs(_("\nExtended options are separated by commas, " "and may take an argument which\n" "is set off by an equals ('=') sign. " - "Valid extended options are:\n"), stderr); - fputs(("\tea_ver=\n"), stderr); - fputs(("\tfragcheck\n"), stderr); - fputs(("\tjournal_only\n"), stderr); - fputs(("\tdiscard\n"), stderr); - fputs(("\tnodiscard\n"), stderr); - fputs(("\treadahead_kb=\n"), stderr); - fputs(("\tbmap2extent\n"), stderr); + "Valid extended options are:\n\n"), stderr); + fputs(_("\tea_ver=\n"), stderr); + fputs("\tfragcheck\n", stderr); + fputs("\tjournal_only\n", stderr); + fputs("\tdiscard\n", stderr); + fputs("\tnodiscard\n", stderr); + fputs("\toptimize_extents\n", stderr); + fputs("\tno_optimize_extents\n", stderr); + fputs("\tinode_count_fullmap\n", stderr); + fputs("\tno_inode_count_fullmap\n", stderr); + fputs(_("\treadahead_kb=\n"), stderr); + fputs("\tbmap2extent\n", stderr); + fputs("\tunshare_blocks\n", stderr); + fputs("\tfixes_only\n", stderr); + fputs("\tcheck_encoding\n", stderr); fputc('\n', stderr); exit(1); } @@ -774,7 +824,7 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx) #ifdef CONFIG_JBD_DEBUG char *jbd_debug; #endif - unsigned long long phys_mem_kb; + unsigned long long phys_mem_kb, blk; retval = e2fsck_allocate_context(&ctx); if (retval) @@ -800,7 +850,7 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx) if (argc && *argv) ctx->program_name = *argv; else - ctx->program_name = "e2fsck"; + usage(NULL); phys_mem_kb = get_memory_size() / 1024; ctx->readahead_kb = ~0ULL; @@ -875,7 +925,8 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx) /* What we do by default, anyway! */ break; case 'b': - res = sscanf(optarg, "%llu", &ctx->use_superblock); + res = sscanf(optarg, "%llu", &blk); + ctx->use_superblock = blk; if (res != 1) goto sscanf_err; ctx->flags |= E2F_FLAG_SB_SPECIFIED; @@ -889,8 +940,8 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx) goto sscanf_err; break; case 'j': - ctx->journal_name = blkid_get_devname(ctx->blkid, - optarg, NULL); + ctx->journal_name = get_devname(ctx->blkid, + optarg, NULL); if (!ctx->journal_name) { com_err(ctx->program_name, 0, _("Unable to resolve '%s'"), @@ -905,6 +956,7 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx) break; case 'L': replace_bad_blocks++; + /* fall through */ case 'l': if (bad_blocks_file) free(bad_blocks_file); @@ -968,7 +1020,7 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx) ctx->io_options = strchr(argv[optind], '?'); if (ctx->io_options) *ctx->io_options++ = 0; - ctx->filesystem_name = blkid_get_devname(ctx->blkid, argv[optind], 0); + ctx->filesystem_name = get_devname(ctx->blkid, argv[optind], 0); if (!ctx->filesystem_name) { com_err(ctx->program_name, 0, _("Unable to resolve '%s'"), argv[optind]); @@ -1007,6 +1059,16 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx) if (c) verbose = 1; + profile_get_boolean(ctx->profile, "options", "no_optimize_extents", + 0, 0, &c); + if (c) + ctx->options |= E2F_OPT_NOOPT_EXTENTS; + + profile_get_boolean(ctx->profile, "options", "inode_count_fullmap", + 0, 0, &c); + if (c) + ctx->options |= E2F_OPT_ICOUNT_FULLMAP; + if (ctx->readahead_kb == ~0ULL) { profile_get_integer(ctx->profile, "options", "readahead_mem_pct", 0, -1, &c); @@ -1110,25 +1172,32 @@ static errcode_t try_open_fs(e2fsck_t ctx, int flags, io_manager io_ptr, errcode_t retval; *ret_fs = NULL; - if (ctx->superblock && ctx->blocksize) { - retval = ext2fs_open2(ctx->filesystem_name, ctx->io_options, - flags, ctx->superblock, ctx->blocksize, - io_ptr, ret_fs); - } else if (ctx->superblock) { - int blocksize; - for (blocksize = EXT2_MIN_BLOCK_SIZE; - blocksize <= EXT2_MAX_BLOCK_SIZE; blocksize *= 2) { - if (*ret_fs) { - ext2fs_free(*ret_fs); - *ret_fs = NULL; + + if (ctx->superblock) { + unsigned long blocksize = ctx->blocksize; + + if (!blocksize) { + for (blocksize = EXT2_MIN_BLOCK_SIZE; + blocksize <= EXT2_MAX_BLOCK_SIZE; blocksize *= 2) { + + retval = ext2fs_open2(ctx->filesystem_name, + ctx->io_options, flags, + ctx->superblock, blocksize, + unix_io_manager, ret_fs); + if (*ret_fs) { + ext2fs_free(*ret_fs); + *ret_fs = NULL; + } + if (!retval) + break; } - retval = ext2fs_open2(ctx->filesystem_name, - ctx->io_options, flags, - ctx->superblock, blocksize, - io_ptr, ret_fs); - if (!retval) - break; + if (retval) + return retval; } + + retval = ext2fs_open2(ctx->filesystem_name, ctx->io_options, + flags, ctx->superblock, blocksize, + io_ptr, ret_fs); } else retval = ext2fs_open2(ctx->filesystem_name, ctx->io_options, flags, 0, 0, io_ptr, ret_fs); @@ -1188,7 +1257,7 @@ static errcode_t e2fsck_check_mmp(ext2_filsys fs, e2fsck_t ctx) if (retval) goto check_error; - /* Print warning if e2fck will wait for more than 20 secs. */ + /* Print warning if e2fsck will wait for more than 20 secs. */ if (verbose || wait_time > EXT4_MMP_MIN_CHECK_INTERVAL * 4) { log_out(ctx, _("MMP interval is %u seconds and total wait " "time is %u seconds. Please wait...\n"), @@ -1216,7 +1285,8 @@ check_error: dump_mmp_msg(fs->mmp_buf, _("If you are sure the filesystem is not " "in use on any node, run:\n" - "'tune2fs -f -E clear_mmp {device}'\n")); + "'tune2fs -f -E clear_mmp %s'\n"), + ctx->device_name); } else if (retval == EXT2_ET_MMP_MAGIC_INVALID) { if (fix_problem(ctx, PR_0_MMP_INVALID_MAGIC, &pctx)) { ext2fs_mmp_clear(fs); @@ -1330,7 +1400,7 @@ int main (int argc, char *argv[]) const char *lib_ver_date; int my_ver, lib_ver; e2fsck_t ctx; - blk64_t orig_superblock; + blk64_t orig_superblock = ~(blk64_t)0; struct problem_context pctx; int flags, run_result, was_changed; int journal_size; @@ -1338,8 +1408,8 @@ int main (int argc, char *argv[]) int old_bitmaps; __u32 features[3]; char *cp; - unsigned int qtype_bits = 0; enum quota_type qtype; + struct ext2fs_journal_params jparams; clear_problem_context(&pctx); sigcatcher_setup(); @@ -1375,6 +1445,7 @@ int main (int argc, char *argv[]) set_up_logging(ctx); if (ctx->logf) { int i; + fputs("E2fsck run: ", ctx->logf); for (i = 0; i < argc; i++) { if (i) @@ -1383,6 +1454,19 @@ int main (int argc, char *argv[]) } fputc('\n', ctx->logf); } + if (ctx->problem_logf) { + int i; + + fputs("\n", + ctx->problem_logf); + fprintf(ctx->problem_logf, "\n", + (unsigned long) ctx->now); + fprintf(ctx->problem_logf, "problem_logf, " arg%d=\"%s\"", i, argv[i]); + fputs("/>\n", ctx->problem_logf); + } init_resource_track(&ctx->global_rtrack, NULL); if (!(ctx->options & E2F_OPT_PREEN) || show_version_only) @@ -1406,7 +1490,7 @@ int main (int argc, char *argv[]) } ctx->superblock = ctx->use_superblock; - flags = EXT2_FLAG_SKIP_MMP; + flags = EXT2_FLAG_SKIP_MMP | EXT2_FLAG_THREADS; restart: #ifdef CONFIG_TESTIO_DEBUG if (getenv("TEST_IO_FLAGS") || getenv("TEST_IO_BLOCK")) { @@ -1538,6 +1622,28 @@ failure: "check of the device.\n")); #endif else { + /* + * Let's try once more will less consistency checking + * so that we are able to recover from more errors + * (e.g. some tool messing up some value in the sb). + */ + if (((retval == EXT2_ET_CORRUPT_SUPERBLOCK) || + (retval == EXT2_ET_BAD_DESC_SIZE)) && + !(flags & EXT2_FLAG_IGNORE_SB_ERRORS)) { + if (fs) + ext2fs_close_free(&fs); + log_out(ctx, _("%s: Trying to load superblock " + "despite errors...\n"), + ctx->program_name); + flags |= EXT2_FLAG_IGNORE_SB_ERRORS; + /* + * If we tried backup sb, revert to the + * original one now. + */ + if (orig_superblock != ~(blk64_t)0) + ctx->superblock = orig_superblock; + goto restart; + } fix_problem(ctx, PR_0_SB_CORRUPT, &pctx); if (retval == EXT2_ET_BAD_MAGIC) check_plausibility(ctx->filesystem_name, @@ -1608,17 +1714,33 @@ failure: * Set the device name, which is used whenever we print error * or informational messages to the user. */ - if (ctx->device_name == 0 && - (sb->s_volume_name[0] != 0)) { - ctx->device_name = string_copy(ctx, sb->s_volume_name, + if (ctx->device_name == 0 && sb->s_volume_name[0]) + ctx->device_name = string_copy(ctx, (char *) sb->s_volume_name, sizeof(sb->s_volume_name)); - } + if (ctx->device_name == 0) ctx->device_name = string_copy(ctx, ctx->filesystem_name, 0); for (cp = ctx->device_name; *cp; cp++) if (isspace(*cp) || *cp == ':') *cp = '_'; + if (ctx->problem_logf) { + + fprintf(ctx->problem_logf, "filesystem_name); + if (!uuid_is_null(sb->s_uuid)) { + char buf[48]; + + uuid_unparse(sb->s_uuid, buf); + fprintf(ctx->problem_logf, " uuid=\"%s\"", buf); + } + if (sb->s_volume_name[0]) + fprintf(ctx->problem_logf, " label=\"%.*s\"", + EXT2_LEN_STR(sb->s_volume_name)); + + fputs("/>\n", ctx->problem_logf); + } + ehandler_init(fs->io); if (ext2fs_has_feature_mmp(fs->super) && @@ -1645,9 +1767,10 @@ failure: retval = e2fsck_check_ext3_journal(ctx); if (retval) { com_err(ctx->program_name, retval, - _("while checking ext3 journal for %s"), + _("while checking journal for %s"), ctx->device_name); - fatal_error(ctx, 0); + fatal_error(ctx, + _("Cannot proceed with file system check")); } } @@ -1675,11 +1798,17 @@ failure: fatal_error(ctx, 0); } retval = e2fsck_run_ext3_journal(ctx); - if (retval) { + if (retval == EFSBADCRC) { + log_out(ctx, _("Journal checksum error " + "found in %s\n"), + ctx->device_name); + } else if (retval == EFSCORRUPTED) { + log_out(ctx, _("Journal corrupted in %s\n"), + ctx->device_name); + } else if (retval) { com_err(ctx->program_name, retval, - _("while recovering ext3 journal of %s"), + _("while recovering journal of %s"), ctx->device_name); - fatal_error(ctx, 0); } ext2fs_close_free(&ctx->fs); ctx->flags |= E2F_FLAG_RESTARTED; @@ -1714,6 +1843,12 @@ print_unsupp_features: goto get_newer; } + if (ext2fs_has_feature_casefold(sb) && !fs->encoding) { + log_err(ctx, _("%s has unsupported encoding: %0x\n"), + ctx->filesystem_name, sb->s_encoding); + goto get_newer; + } + /* * If the user specified a specific superblock, presumably the * master superblock has been trashed. So we mark the @@ -1769,9 +1904,15 @@ print_unsupp_features: /* * Save the journal size in megabytes. * Try and use the journal size from the backup else let e2fsck - * find the default journal size. + * find the default journal size. If fast commit feature is enabled, + * it is not clear how many of the journal blocks were fast commit + * blocks. So, ignore the size of journal found in backup. + * + * TODO: Add a new backup type that captures fast commit info as + * well. */ - if (sb->s_jnl_backup_type == EXT3_JNL_BACKUP_BLOCKS) + if (sb->s_jnl_backup_type == EXT3_JNL_BACKUP_BLOCKS && + !ext2fs_has_feature_fast_commit(sb)) journal_size = (sb->s_jnl_blocks[15] << (32 - 20)) | (sb->s_jnl_blocks[16] >> 20); else @@ -1779,12 +1920,12 @@ print_unsupp_features: if (ext2fs_has_feature_quota(sb)) { /* Quotas were enabled. Do quota accounting during fsck. */ - for (qtype = 0; qtype < MAXQUOTAS; qtype++) { - if (*quota_sb_inump(sb, qtype) != 0) - qtype_bits |= 1 << qtype; + clear_problem_context(&pctx); + pctx.errcode = quota_init_context(&ctx->qctx, ctx->fs, 0); + if (pctx.errcode) { + fix_problem(ctx, PR_0_QUOTA_INIT_CTX, &pctx); + fatal_error(ctx, 0); } - - quota_init_context(&ctx->qctx, ctx->fs, qtype_bits); } run_result = e2fsck_run(ctx); @@ -1793,20 +1934,16 @@ print_unsupp_features: if (!ctx->invalid_bitmaps && (ctx->flags & E2F_FLAG_JOURNAL_INODE)) { if (fix_problem(ctx, PR_6_RECREATE_JOURNAL, &pctx)) { - if (journal_size < 1024) - journal_size = ext2fs_default_journal_size(ext2fs_blocks_count(fs->super)); - if (journal_size < 0) { - ext2fs_clear_feature_journal(fs->super); - fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY; - log_out(ctx, "%s: Couldn't determine " - "journal size\n", ctx->program_name); - goto no_journal; + if (journal_size < 1024) { + ext2fs_get_journal_params(&jparams, fs); + } else { + jparams.num_journal_blocks = journal_size; + jparams.num_fc_blocks = 0; } log_out(ctx, _("Creating journal (%d blocks): "), - journal_size); + jparams.num_journal_blocks); fflush(stdout); - retval = ext2fs_add_journal_inode(fs, - journal_size, 0); + retval = ext2fs_add_journal_inode3(fs, &jparams, ~0ULL, 0); if (retval) { log_out(ctx, "%s: while trying to create " "journal\n", error_message(retval)); @@ -1829,15 +1966,20 @@ no_journal: int needs_writeout; for (qtype = 0; qtype < MAXQUOTAS; qtype++) { - if (((1 << qtype) & qtype_bits) == 0) + if (*quota_sb_inump(sb, qtype) == 0) continue; needs_writeout = 0; pctx.num = qtype; retval = quota_compare_and_update(ctx->qctx, qtype, &needs_writeout); if ((retval || needs_writeout) && - fix_problem(ctx, PR_6_UPDATE_QUOTAS, &pctx)) - quota_write_inode(ctx->qctx, 1 << qtype); + fix_problem(ctx, PR_6_UPDATE_QUOTAS, &pctx)) { + pctx.errcode = quota_write_inode(ctx->qctx, + 1 << qtype); + if (pctx.errcode) + (void) fix_problem(ctx, + PR_6_WRITE_QUOTAS, &pctx); + } } quota_release_context(&ctx->qctx); } @@ -1879,28 +2021,52 @@ no_journal: ext2fs_mark_super_dirty(fs); } - e2fsck_write_bitmaps(ctx); - if (fs->flags & EXT2_FLAG_DIRTY) { - pctx.errcode = ext2fs_flush(ctx->fs); + if (ext2fs_has_feature_shared_blocks(ctx->fs->super) && + (ctx->options & E2F_OPT_UNSHARE_BLOCKS) && + (ctx->options & E2F_OPT_NO)) + /* Don't try to write or flush I/O, we just wanted to know whether or + * not there were enough free blocks to undo deduplication. + */ + goto skip_write; + + if (!(ctx->options & E2F_OPT_READONLY)) { + e2fsck_write_bitmaps(ctx); + if (fs->flags & EXT2_FLAG_DIRTY) { + pctx.errcode = ext2fs_flush(ctx->fs); + if (pctx.errcode) + fix_problem(ctx, PR_6_FLUSH_FILESYSTEM, &pctx); + } + pctx.errcode = io_channel_flush(ctx->fs->io); if (pctx.errcode) - fix_problem(ctx, PR_6_FLUSH_FILESYSTEM, &pctx); + fix_problem(ctx, PR_6_IO_FLUSH, &pctx); } - pctx.errcode = io_channel_flush(ctx->fs->io); - if (pctx.errcode) - fix_problem(ctx, PR_6_IO_FLUSH, &pctx); if (was_changed) { - exit_value |= FSCK_NONDESTRUCT; - if (!(ctx->options & E2F_OPT_PREEN)) - log_out(ctx, _("\n%s: ***** FILE SYSTEM WAS " - "MODIFIED *****\n"), + int fs_fixed = (ctx->flags & E2F_FLAG_PROBLEMS_FIXED); + + if (fs_fixed) + exit_value |= FSCK_NONDESTRUCT; + if (!(ctx->options & E2F_OPT_PREEN)) { +#if 0 /* Do this later; it breaks too many tests' golden outputs */ + log_out(ctx, fs_fixed ? + _("\n%s: ***** FILE SYSTEM ERRORS " + "CORRECTED *****\n") : + _("%s: File system was modified.\n"), + ctx->device_name); +#else + log_out(ctx, + _("\n%s: ***** FILE SYSTEM WAS MODIFIED *****\n"), ctx->device_name); +#endif + } if (ctx->mount_flags & EXT2_MF_ISROOT) { log_out(ctx, _("%s: ***** REBOOT SYSTEM *****\n"), ctx->device_name); exit_value |= FSCK_REBOOT; } } + +skip_write: if (!ext2fs_test_valid(fs) || ((exit_value & FSCK_CANCELED) && (sb->s_state & EXT2_ERROR_FS))) { @@ -1928,6 +2094,8 @@ no_journal: ext2fs_close_free(&ctx->fs); free(ctx->journal_name); + if (ctx->logf) + fprintf(ctx->logf, "Exit status: %d\n", exit_value); e2fsck_free_context(ctx); remove_error_table(&et_ext2_error_table); remove_error_table(&et_prof_error_table);