Whamcloud - gitweb
e2fsck: add support for dirdata feature
[tools/e2fsprogs.git] / e2fsck / unix.c
index 42eef75..4cda592 100644 (file)
@@ -50,6 +50,7 @@ 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 "e2fsck.h"
 #include "problem.h"
@@ -74,13 +75,16 @@ int journal_enable_debug = -1;
 static void usage(e2fsck_t ctx)
 {
        fprintf(stderr,
-               _("Usage: %s [-panyrcdfktvDFV] [-b superblock] [-B blocksize]\n"
+               _("Usage: %s [-pamnyrcdfktvDFV] [-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);
 
        fprintf(stderr, "%s", _("\nEmergency help:\n"
                " -p                   Automatic repair (no questions)\n"
+#ifdef HAVE_PTHREAD
+               " -m                   multiple threads to speedup fsck\n"
+#endif
                " -n                   Make no changes to the filesystem\n"
                " -y                   Assume \"yes\" to all questions\n"
                " -c                   Check for bad blocks and add them to the badblock list\n"
@@ -137,7 +141,8 @@ static void show_stats(e2fsck_t     ctx)
                               "%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,
@@ -193,7 +198,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",
@@ -443,9 +449,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;
@@ -617,9 +623,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
@@ -655,6 +662,49 @@ static void signal_cancel(int sig EXT2FS_ATTR((unused)))
 }
 #endif
 
+static void initialize_profile_options(e2fsck_t ctx)
+{
+       char *tmp;
+
+       /* [options] shared=preserve|lost+found|delete */
+       tmp = NULL;
+       ctx->shared = E2F_SHARED_PRESERVE;
+       profile_get_string(ctx->profile, "options", "shared", 0,
+                          "preserve", &tmp);
+       if (tmp) {
+               if (strcmp(tmp, "preserve") == 0)
+                       ctx->shared = E2F_SHARED_PRESERVE;
+               else if (strcmp(tmp, "delete") == 0)
+                       ctx->shared = E2F_SHARED_DELETE;
+               else if (strcmp(tmp, "lost+found") == 0)
+                       ctx->shared = E2F_SHARED_LPF;
+               else {
+                       com_err(ctx->program_name, 0,
+                               _("configuration error: 'shared=%s'"), tmp);
+                       fatal_error(ctx, 0);
+               }
+               free(tmp);
+       }
+
+       /* [options] clone=dup|zero */
+       tmp = NULL;
+       ctx->clone = E2F_CLONE_DUP;
+       profile_get_string(ctx->profile, "options", "clone", 0,
+                          "dup", &tmp);
+       if (tmp) {
+               if (strcmp(tmp, "dup") == 0)
+                       ctx->clone = E2F_CLONE_DUP;
+               else if (strcmp(tmp, "zero") == 0)
+                       ctx->clone = E2F_CLONE_ZERO;
+               else {
+                       com_err(ctx->program_name, 0,
+                               _("configuration error: 'clone=%s'"), tmp);
+                       fatal_error(ctx, 0);
+               }
+               free(tmp);
+       }
+}
+
 static void parse_extended_opts(e2fsck_t ctx, const char *opts)
 {
        char    *buf, *token, *next, *p, *arg;
@@ -705,6 +755,58 @@ static void parse_extended_opts(e2fsck_t ctx, const char *opts)
                } else if (strcmp(token, "fragcheck") == 0) {
                        ctx->options |= E2F_OPT_FRAGCHECK;
                        continue;
+               /* -E shared=preserve|lost+found|delete */
+               } else if (strcmp(token, "shared") == 0) {
+                       if (!arg) {
+                               extended_usage++;
+                               continue;
+                       }
+                       if (strcmp(arg, "preserve") == 0) {
+                               ctx->shared = E2F_SHARED_PRESERVE;
+                       } else if (strcmp(arg, "lost+found") == 0) {
+                               ctx->shared = E2F_SHARED_LPF;
+                       } else if (strcmp(arg, "delete") == 0) {
+                               ctx->shared = E2F_SHARED_DELETE;
+                       } else {
+                               extended_usage++;
+                               continue;
+                       }
+               /* -E clone=dup|zero */
+               } else if (strcmp(token, "clone") == 0) {
+                       if (!arg) {
+                               extended_usage++;
+                               continue;
+                       }
+                       if (strcmp(arg, "dup") == 0) {
+                               ctx->clone = E2F_CLONE_DUP;
+                       } else if (strcmp(arg, "zero") == 0) {
+                               ctx->clone = E2F_CLONE_ZERO;
+                       } else {
+                               extended_usage++;
+                               continue;
+                       }
+               } else if (strcmp(token, "expand_extra_isize") == 0) {
+                       ctx->flags |= E2F_FLAG_EXPAND_EISIZE;
+                       if (arg) {
+                               extended_usage++;
+                               continue;
+                       }
+               /* -E inode_badness_threshold=<value> */
+               } else if (strcmp(token, "inode_badness_threshold") == 0) {
+                       unsigned int val;
+
+                       if (!arg) {
+                               extended_usage++;
+                               continue;
+                       }
+                       val = strtoul(arg, &p, 0);
+                       if (*p != '\0' || (val < 3 && val != 0) || val > 200) {
+                               fprintf(stderr, _("Invalid badness '%s'\n"),
+                                       arg);
+                               extended_usage++;
+                               continue;
+                       }
+                       ctx->inode_badness_threshold = val;
                } else if (strcmp(token, "journal_only") == 0) {
                        if (arg) {
                                extended_usage++;
@@ -735,6 +837,12 @@ static void parse_extended_opts(e2fsck_t ctx, const char *opts)
                        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;
@@ -745,6 +853,14 @@ static void parse_extended_opts(e2fsck_t ctx, const char *opts)
                        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);
@@ -763,6 +879,10 @@ static void parse_extended_opts(e2fsck_t ctx, const char *opts)
                fputs("\tjournal_only\n", stderr);
                fputs("\tdiscard\n", stderr);
                fputs("\tnodiscard\n", stderr);
+               fputs(("\tshared=<preserve|lost+found|delete>\n"), stderr);
+               fputs(("\tclone=<dup|zero>\n"), stderr);
+               fputs(("\texpand_extra_isize\n"), stderr);
+               fputs(("\tinode_badness_threhold=(value)\n"), stderr);
                fputs("\toptimize_extents\n", stderr);
                fputs("\tno_optimize_extents\n", stderr);
                fputs("\tinode_count_fullmap\n", stderr);
@@ -771,6 +891,7 @@ static void parse_extended_opts(e2fsck_t ctx, const char *opts)
                fputs("\tbmap2extent\n", stderr);
                fputs("\tunshare_blocks\n", stderr);
                fputs("\tfixes_only\n", stderr);
+               fputs("\tcheck_encoding\n", stderr);
                fputc('\n', stderr);
                exit(1);
        }
@@ -798,13 +919,16 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx)
 #ifdef HAVE_SIGNAL_H
        struct sigaction        sa;
 #endif
-       char            *extended_opts = 0;
        char            *cp;
        int             res;            /* result of sscanf */
 #ifdef CONFIG_JBD_DEBUG
        char            *jbd_debug;
 #endif
-       unsigned long long phys_mem_kb;
+#ifdef HAVE_PTHREAD
+       char            *pm;
+       unsigned long   thread_num;
+#endif
+       unsigned long long phys_mem_kb, blk;
 
        retval = e2fsck_allocate_context(&ctx);
        if (retval)
@@ -832,9 +956,23 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx)
        else
                ctx->program_name = "e2fsck";
 
+       cp = getenv("E2FSCK_CONFIG");
+       if (cp != NULL)
+               config_fn[0] = cp;
+       profile_set_syntax_err_cb(syntax_err_report);
+       profile_init(config_fn, &ctx->profile);
+
+       initialize_profile_options(ctx);
+
        phys_mem_kb = get_memory_size() / 1024;
        ctx->readahead_kb = ~0ULL;
+       ctx->inode_badness_threshold = BADNESS_THRESHOLD;
+
+#ifdef HAVE_PTHREAD
+       while ((c = getopt(argc, argv, "pam:nyrcC:B:dE:fvtFVM:b:I:j:P:l:L:N:SsDkz:")) != EOF)
+#else
        while ((c = getopt(argc, argv, "panyrcC:B:dE:fvtFVM:b:I:j:P:l:L:N:SsDkz:")) != EOF)
+#endif
                switch (c) {
                case 'C':
                        ctx->progress = e2fsck_update_progress;
@@ -864,7 +1002,7 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx)
                        ctx->options |= E2F_OPT_COMPRESS_DIRS;
                        break;
                case 'E':
-                       extended_opts = optarg;
+                       parse_extended_opts(ctx, optarg);
                        break;
                case 'p':
                case 'a':
@@ -875,6 +1013,22 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx)
                        }
                        ctx->options |= E2F_OPT_PREEN;
                        break;
+#ifdef HAVE_PTHREAD
+               case 'm':
+                       thread_num = strtoul(optarg, &pm, 0);
+                       if (*pm)
+                               fatal_error(ctx,
+                                       _("Invalid multiple thread num.\n"));
+                       if (thread_num > E2FSCK_MAX_THREADS) {
+                               fprintf(stderr,
+                                       _("threads %lu too large (max %u)\n"),
+                                       thread_num, E2FSCK_MAX_THREADS);
+                               fatal_error(ctx, 0);
+                       }
+                       ctx->options |= E2F_OPT_MULTITHREAD;
+                       ctx->pfs_num_threads = thread_num;
+                       break;
+#endif
                case 'n':
                        if (ctx->options & (E2F_OPT_YES|E2F_OPT_PREEN))
                                goto conflict_opt;
@@ -905,7 +1059,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;
@@ -993,6 +1148,20 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx)
                        _("The -n and -l/-L options are incompatible."));
                fatal_error(ctx, 0);
        }
+#ifdef HAVE_PTHREAD
+       if (ctx->options & E2F_OPT_MULTITHREAD) {
+               if ((ctx->options & (E2F_OPT_YES|E2F_OPT_NO|E2F_OPT_PREEN)) == 0) {
+                       com_err(ctx->program_name, 0, "%s",
+                               _("The -m option should be used together with one of -p/-y/-n options."));
+                       fatal_error(ctx, 0);
+               }
+               if (ctx->progress) {
+                       com_err(ctx->program_name, 0, "%s",
+                               _("Only one of the options -C or -m may be specified."));
+                       fatal_error(ctx, 0);
+               }
+       }
+#endif
        if (ctx->options & E2F_OPT_NO)
                ctx->options |= E2F_OPT_READONLY;
 
@@ -1005,8 +1174,6 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx)
                        argv[optind]);
                fatal_error(ctx, 0);
        }
-       if (extended_opts)
-               parse_extended_opts(ctx, extended_opts);
 
        /* Complain about mutually exclusive rebuilding activities */
        if (getenv("E2FSCK_FIXES_ONLY"))
@@ -1024,11 +1191,6 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx)
                fatal_error(ctx, 0);
        }
 
-       if ((cp = getenv("E2FSCK_CONFIG")) != NULL)
-               config_fn[0] = cp;
-       profile_set_syntax_err_cb(syntax_err_report);
-       profile_init(config_fn, &ctx->profile);
-
        profile_get_boolean(ctx->profile, "options", "report_time", 0, 0,
                            &c);
        if (c)
@@ -1099,10 +1261,12 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx)
 #ifdef SA_RESTART
        sa.sa_flags = SA_RESTART;
 #endif
-       sa.sa_handler = signal_progress_on;
-       sigaction(SIGUSR1, &sa, 0);
-       sa.sa_handler = signal_progress_off;
-       sigaction(SIGUSR2, &sa, 0);
+       if ((ctx->options & E2F_OPT_MULTITHREAD) == 0) {
+               sa.sa_handler = signal_progress_on;
+               sigaction(SIGUSR1, &sa, 0);
+               sa.sa_handler = signal_progress_off;
+               sigaction(SIGUSR2, &sa, 0);
+       }
 #endif
 
        /* Update our PATH to include /sbin if we need to run badblocks  */
@@ -1381,6 +1545,7 @@ int main (int argc, char *argv[])
        __u32 features[3];
        char *cp;
        enum quota_type qtype;
+       struct ext2fs_journal_params jparams;
 
        clear_problem_context(&pctx);
        sigcatcher_setup();
@@ -1413,9 +1578,11 @@ int main (int argc, char *argv[])
        }
        reserve_stdio_fds();
 
+       ctx->global_ctx = NULL;
        set_up_logging(ctx);
        if (ctx->logf) {
                int i;
+
                fputs("E2fsck run: ", ctx->logf);
                for (i = 0; i < argc; i++) {
                        if (i)
@@ -1424,6 +1591,19 @@ int main (int argc, char *argv[])
                }
                fputc('\n', ctx->logf);
        }
+       if (ctx->problem_logf) {
+               int i;
+
+               fputs("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n",
+                     ctx->problem_logf);
+               fprintf(ctx->problem_logf, "<problem_log time=\"%lu\">\n",
+                       (unsigned long) ctx->now);
+               fprintf(ctx->problem_logf, "<invocation prog=\"%s\"",
+                       argv[0]);
+               for (i = 1; i < argc; i++)
+                       fprintf(ctx->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)
@@ -1447,7 +1627,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")) {
@@ -1478,6 +1658,7 @@ restart:
        }
 
        ctx->openfs_flags = flags;
+       ctx->io_manager = io_ptr;
        retval = try_open_fs(ctx, flags, io_ptr, &fs);
 
        if (!ctx->superblock && !(ctx->options & E2F_OPT_PREEN) &&
@@ -1584,7 +1765,8 @@ failure:
                         * so that we are able to recover from more errors
                         * (e.g. some tool messing up some value in the sb).
                         */
-                       if (!(flags & EXT2_FLAG_IGNORE_SB_ERRORS)) {
+                       if ((retval == EXT2_ET_CORRUPT_SUPERBLOCK) &&
+                           !(flags & EXT2_FLAG_IGNORE_SB_ERRORS)) {
                                if (fs)
                                        ext2fs_close_free(&fs);
                                log_out(ctx, _("%s: Trying to load superblock "
@@ -1655,6 +1837,9 @@ failure:
 
        ctx->fs = fs;
        fs->now = ctx->now;
+#ifdef HAVE_PTHREAD
+       fs->fs_num_threads = ctx->pfs_num_threads;
+#endif
        sb = fs->super;
 
        if (sb->s_rev_level > E2FSCK_CURRENT_REV) {
@@ -1669,17 +1854,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 dev=\"%s\"",
+                       ctx->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) &&
@@ -1782,6 +1983,20 @@ print_unsupp_features:
                goto get_newer;
        }
 
+       if (ext2fs_has_feature_dirdata(sb) &&
+           ext2fs_has_feature_casefold(sb)) {
+               com_err(ctx->program_name, 0,
+                       _("%s has both casefold and dirdata, aborting fsck"),
+                       ctx->filesystem_name);
+               fatal_error(ctx, 0);
+       }
+
+       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
@@ -1812,6 +2027,52 @@ print_unsupp_features:
        if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
                fatal_error(ctx, 0);
        check_if_skip(ctx);
+
+       if (EXT2_GOOD_OLD_INODE_SIZE + sb->s_want_extra_isize >
+                                                       EXT2_INODE_SIZE(sb)) {
+               if (fix_problem(ctx, PR_0_WANT_EXTRA_ISIZE_INVALID, &pctx))
+                       sb->s_want_extra_isize =
+                               sizeof(struct ext2_inode_large) -
+                               EXT2_GOOD_OLD_INODE_SIZE;
+       }
+       if (EXT2_GOOD_OLD_INODE_SIZE + sb->s_min_extra_isize >
+                                                       EXT2_INODE_SIZE(sb)) {
+               if (fix_problem(ctx, PR_0_MIN_EXTRA_ISIZE_INVALID, &pctx))
+                       sb->s_min_extra_isize = 0;
+       }
+       if (EXT2_INODE_SIZE(sb) > EXT2_GOOD_OLD_INODE_SIZE) {
+               ctx->want_extra_isize = sizeof(struct ext2_inode_large) -
+                                                    EXT2_GOOD_OLD_INODE_SIZE;
+               ctx->min_extra_isize = ~0L;
+               if (EXT2_HAS_RO_COMPAT_FEATURE(sb,
+                                      EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE)) {
+                       if (ctx->want_extra_isize < sb->s_want_extra_isize)
+                               ctx->want_extra_isize = sb->s_want_extra_isize;
+                       if (ctx->want_extra_isize < sb->s_min_extra_isize)
+                               ctx->want_extra_isize = sb->s_min_extra_isize;
+               }
+       } else {
+               /* Leave extra_isize set, it is harmless, and clearing it
+                * here breaks some regression tests by printing an extra
+                * message to the output for very little value. */
+               sb->s_want_extra_isize = 0;
+               sb->s_min_extra_isize = 0;
+               ctx->flags &= ~E2F_FLAG_EXPAND_EISIZE;
+       }
+
+       if (ctx->options & E2F_OPT_READONLY) {
+               if (ctx->flags & (E2F_FLAG_EXPAND_EISIZE)) {
+                       fprintf(stderr, _("Cannot enable EXTRA_ISIZE feature "
+                                         "on read-only filesystem\n"));
+                       exit(1);
+               }
+       } else {
+               if (sb->s_want_extra_isize > sb->s_min_extra_isize &&
+                   (sb->s_feature_ro_compat &
+                    EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE))
+                       ctx->flags |= E2F_FLAG_EXPAND_EISIZE;
+       }
+
        check_resize_inode(ctx);
        if (bad_blocks_file)
                read_bad_blocks_file(ctx, bad_blocks_file, replace_bad_blocks);
@@ -1837,9 +2098,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
@@ -1861,20 +2128,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));