Whamcloud - gitweb
tune2fs: if turning off csum_seed and the UUID has changed, require fsck
[tools/e2fsprogs.git] / misc / tune2fs.c
index 083d548..b11b2e3 100644 (file)
@@ -116,9 +116,11 @@ struct blk_move {
 
 errcode_t ext2fs_run_ext3_journal(ext2_filsys *fs);
 
-static const char *please_fsck = N_("Please run e2fsck on the filesystem.\n");
+static const char *fsck_explain = N_("\nThis operation requires a freshly checked filesystem.\n");
+
+static const char *please_fsck = N_("Please run e2fsck -f on the filesystem.\n");
 static const char *please_dir_fsck =
-               N_("Please run e2fsck -D on the filesystem.\n");
+               N_("Please run e2fsck -fD on the filesystem.\n");
 
 #ifdef CONFIG_BUILD_FINDFS
 void do_findfs(int argc, char **argv);
@@ -135,9 +137,8 @@ static void usage(void)
                  "[-g group]\n"
                  "\t[-i interval[d|m|w]] [-j] [-J journal_options] [-l]\n"
                  "\t[-m reserved_blocks_percent] [-o [^]mount_options[,...]]\n"
-                 "\t[-p mmp_update_interval] [-r reserved_blocks_count] "
-                 "[-u user]\n"
-                 "\t[-C mount_count] [-L volume_label] [-M last_mounted_dir]\n"
+                 "\t[-r reserved_blocks_count] [-u user] [-C mount_count]\n"
+                 "\t[-L volume_label] [-M last_mounted_dir]\n"
                  "\t[-O [^]feature[,...]] [-Q quota_options]\n"
                  "\t[-E extended-option[,...]] [-T last_check_time] "
                  "[-U UUID]\n\t[-I new_inode_size] [-z undo_file] device\n"),
@@ -188,6 +189,7 @@ static __u32 clear_ok_features[3] = {
                EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE|
                EXT4_FEATURE_RO_COMPAT_GDT_CSUM |
                EXT4_FEATURE_RO_COMPAT_QUOTA |
+               EXT4_FEATURE_RO_COMPAT_PROJECT |
                EXT4_FEATURE_RO_COMPAT_METADATA_CSUM |
                EXT4_FEATURE_RO_COMPAT_READONLY
 };
@@ -418,7 +420,8 @@ static void check_fsck_needed(ext2_filsys fs, const char *prompt)
        if (!(fs->super->s_state & EXT2_VALID_FS) ||
            (fs->super->s_state & EXT2_ERROR_FS) ||
            (fs->super->s_lastcheck < fs->super->s_mtime)) {
-               printf("\n%s\n", _(please_fsck));
+               puts(_(fsck_explain));
+               puts(_(please_fsck));
                if (mount_flags & EXT2_MF_READONLY)
                        printf("%s", _("(and reboot afterwards!)\n"));
                exit(1);
@@ -440,7 +443,8 @@ static void request_dir_fsck_afterwards(ext2_filsys fs)
                return;
        fsck_requested++;
        fs->super->s_state &= ~EXT2_VALID_FS;
-       printf("\n%s\n", _(please_dir_fsck));
+       puts(_(fsck_explain));
+       puts(_(please_dir_fsck));
        if (mount_flags & EXT2_MF_READONLY)
                printf("%s", _("(and reboot afterwards!)\n"));
 }
@@ -460,9 +464,6 @@ static void request_fsck_afterwards(ext2_filsys fs)
 
 static void convert_64bit(ext2_filsys fs, int direction)
 {
-       if (!direction)
-               return;
-
        /*
         * Is resize2fs going to demand a fsck run? Might as well tell the
         * user now.
@@ -729,7 +730,7 @@ static void rewrite_inodes(ext2_filsys fs)
        blk64_t         file_acl_block;
        int             inode_dirty;
 
-       if (fs->super->s_creator_os != EXT2_OS_LINUX)
+       if (fs->super->s_creator_os == EXT2_OS_HURD)
                return;
 
        retval = ext2fs_open_inode_scan(fs, 0, &scan);
@@ -1308,15 +1309,23 @@ mmp_error:
        }
 
        if (FEATURE_ON(E2P_FEATURE_RO_INCOMPAT,
-                               EXT4_FEATURE_RO_COMPAT_PROJECT)) {
-               if (!Q_flag && !ext2fs_has_feature_quota(sb))
-                       fputs(_("\nWarning: enabled project without quota together\n"),
-                               stderr);
+                      EXT4_FEATURE_RO_COMPAT_PROJECT)) {
+               if (fs->super->s_inode_size == EXT2_GOOD_OLD_INODE_SIZE) {
+                       fprintf(stderr, _("Cannot enable project feature; "
+                                         "inode size too small.\n"));
+                       exit(1);
+               }
                Q_flag = 1;
                quota_enable[PRJQUOTA] = QOPT_ENABLE;
        }
 
        if (FEATURE_OFF(E2P_FEATURE_RO_INCOMPAT,
+                       EXT4_FEATURE_RO_COMPAT_PROJECT)) {
+               Q_flag = 1;
+               quota_enable[PRJQUOTA] = QOPT_DISABLE;
+       }
+
+       if (FEATURE_OFF(E2P_FEATURE_RO_INCOMPAT,
                                EXT4_FEATURE_RO_COMPAT_QUOTA)) {
                /*
                 * Set the Q_flag here and handle the quota options in the code
@@ -1357,16 +1366,18 @@ mmp_error:
 
                uuid_seed = ext2fs_crc32c_le(~0, fs->super->s_uuid,
                                        sizeof(fs->super->s_uuid));
-               if (fs->super->s_checksum_seed != uuid_seed &&
-                   (mount_flags & EXT2_MF_MOUNTED)) {
-                       fputs(_("UUID has changed since enabling "
-                               "metadata_csum.  Filesystem must be unmounted "
-                               "\nto safely rewrite all metadata to "
-                               "match the new UUID.\n"), stderr);
-                       return 1;
+               if (fs->super->s_checksum_seed != uuid_seed) {
+                       if (mount_flags & (EXT2_MF_BUSY|EXT2_MF_MOUNTED)) {
+                               fputs(_("UUID has changed since enabling "
+               "metadata_csum.  Filesystem must be unmounted "
+               "\nto safely rewrite all metadata to match the new UUID.\n"),
+                                     stderr);
+                               return 1;
+                       }
+                       check_fsck_needed(fs, _("Recalculating checksums "
+                                               "could take some time."));
+                       rewrite_checksums = 1;
                }
-
-               rewrite_checksums = 1;
        }
 
        if (sb->s_rev_level == EXT2_GOOD_OLD_REV &&
@@ -1479,10 +1490,12 @@ err:
 
 static void handle_quota_options(ext2_filsys fs)
 {
+       errcode_t retval;
        quota_ctx_t qctx;
        ext2_ino_t qf_ino;
        enum quota_type qtype;
-       int enable = 0;
+       unsigned int qtype_bits = 0;
+       int need_dirty = 0;
 
        for (qtype = 0 ; qtype < MAXQUOTAS; qtype++)
                if (quota_enable[qtype] != 0)
@@ -1491,47 +1504,91 @@ static void handle_quota_options(ext2_filsys fs)
                /* Nothing to do. */
                return;
 
-       quota_init_context(&qctx, fs, QUOTA_ALL_BIT);
-       for (qtype = 0 ; qtype < MAXQUOTAS; qtype++) {
-               if (quota_enable[qtype] == QOPT_ENABLE) {
-                       enable = 1;
-                       break;
-               }
+       if (quota_enable[PRJQUOTA] == QOPT_ENABLE &&
+           fs->super->s_inode_size == EXT2_GOOD_OLD_INODE_SIZE) {
+               fprintf(stderr, _("Cannot enable project quota; "
+                                 "inode size too small.\n"));
+               exit(1);
+       }
+
+       for (qtype = 0; qtype < MAXQUOTAS; qtype++) {
+               if (quota_enable[qtype] == QOPT_ENABLE)
+                       qtype_bits |= 1 << qtype;
+       }
+
+       retval = quota_init_context(&qctx, fs, qtype_bits);
+       if (retval) {
+               com_err(program_name, retval,
+                       _("while initializing quota context in support library"));
+               exit(1);
        }
-       if (enable)
+
+       if (qtype_bits)
                quota_compute_usage(qctx);
 
        for (qtype = 0 ; qtype < MAXQUOTAS; qtype++) {
                if (quota_enable[qtype] == QOPT_ENABLE &&
                    *quota_sb_inump(fs->super, qtype) == 0) {
-                       if ((qf_ino = quota_file_exists(fs, qtype)) > 0)
-                               quota_update_limits(qctx, qf_ino, qtype);
-                       quota_write_inode(qctx, 1 << qtype);
+                       if ((qf_ino = quota_file_exists(fs, qtype)) > 0) {
+                               retval = quota_update_limits(qctx, qf_ino,
+                                                            qtype);
+                               if (retval) {
+                                       com_err(program_name, retval,
+                                               _("while updating quota limits (%d)"),
+                                               qtype);
+                                       exit(1);
+                               }
+                       }
+                       retval = quota_write_inode(qctx, 1 << qtype);
+                       if (retval) {
+                               com_err(program_name, retval,
+                                       _("while writing quota file (%d)"),
+                                       qtype);
+                               exit(1);
+                       }
+                       /* Enable Quota feature if one of quota enabled */
+                       if (!ext2fs_has_feature_quota(fs->super)) {
+                               ext2fs_set_feature_quota(fs->super);
+                               need_dirty = 1;
+                       }
+                       if (qtype == PRJQUOTA &&
+                           !ext2fs_has_feature_project(fs->super)) {
+                               ext2fs_set_feature_project(fs->super);
+                               need_dirty = 1;
+                       }
                } else if (quota_enable[qtype] == QOPT_DISABLE) {
-                       quota_remove_inode(fs, qtype);
+                       retval = quota_remove_inode(fs, qtype);
+                       if (retval) {
+                               com_err(program_name, retval,
+                                       _("while removing quota file (%d)"),
+                                       qtype);
+                               exit(1);
+                       }
+                       if (qtype == PRJQUOTA) {
+                               ext2fs_clear_feature_project(fs->super);
+                               need_dirty = 1;
+                       }
                }
        }
 
        quota_release_context(&qctx);
-
-       if (enable) {
-               ext2fs_set_feature_quota(fs->super);
-               ext2fs_mark_super_dirty(fs);
-       } else {
+       /* Clear Quota feature if all quota types disabled. */
+       if (!qtype_bits) {
                for (qtype = 0 ; qtype < MAXQUOTAS; qtype++)
-                       if (*quota_sb_inump(fs->super, qtype) != 0)
+                       if (*quota_sb_inump(fs->super, qtype))
                                break;
                if (qtype == MAXQUOTAS) {
-                       fs->super->s_feature_ro_compat &=
-                                       ~EXT4_FEATURE_RO_COMPAT_QUOTA;
-                       ext2fs_mark_super_dirty(fs);
+                       ext2fs_clear_feature_quota(fs->super);
+                       need_dirty = 1;
                }
-       }
 
+       }
+       if (need_dirty)
+               ext2fs_mark_super_dirty(fs);
        return;
 }
 
-static int option_handle_function(char *token, void *data)
+static int option_handle_function(char *token)
 {
        if (strncmp(token, "usr", 3) == 0) {
                quota_enable[USRQUOTA] = QOPT_ENABLE;
@@ -1779,8 +1836,7 @@ static void parse_tune2fs_options(int argc, char **argv)
                        break;
                case 'Q':
                        Q_flag = 1;
-                       ret = parse_quota_opts(optarg, option_handle_function,
-                                              NULL);
+                       ret = parse_quota_opts(optarg, option_handle_function);
                        if (ret)
                                exit(1);
                        open_flag = EXT2_FLAG_RW;
@@ -2030,6 +2086,7 @@ static int parse_extended_opts(ext2_filsys fs, const char *opts)
                        "\tclear_mmp\n"
                        "\thash_alg=<hash algorithm>\n"
                        "\tmount_opts=<extended default mount options>\n"
+                       "\tmmp_update_interval=<mmp update interval in seconds>\n"
                        "\tstride=<RAID per-disk chunk size in blocks>\n"
                        "\tstripe_width=<RAID stride*data disks in blocks>\n"
                        "\ttest_fs\n"
@@ -2855,6 +2912,36 @@ retry_open:
                rc = 1;
                goto closefs;
        }
+
+#ifdef NO_RECOVERY
+       /* Warn if file system needs recovery and it is opened for writing. */
+       if ((open_flag & EXT2_FLAG_RW) && !(mount_flags & EXT2_MF_MOUNTED) &&
+           (sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) &&
+           (sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER)) {
+               fprintf(stderr,
+_("Warning: The journal is dirty. You may wish to replay the journal like:\n\n"
+  "\te2fsck -E journal_only %s\n\n"
+  "then rerun this command.  Otherwise, any changes made may be overwritten\n"
+  "by journal recovery.\n"), device_name);
+       }
+#else
+       /* Recover the journal if possible. */
+       if ((open_flag & EXT2_FLAG_RW) && !(mount_flags & (EXT2_MF_BUSY | EXT2_MF_MOUNTED)) &&
+           ext2fs_has_feature_journal_needs_recovery(fs->super)) {
+               errcode_t err;
+
+               printf(_("Recovering journal.\n"));
+               err = ext2fs_run_ext3_journal(&fs);
+               if (err) {
+                       com_err("tune2fs", err, "while recovering journal.\n");
+                       printf(_("Please run e2fsck -fy %s.\n"), argv[1]);
+                       if (fs)
+                               ext2fs_close_free(&fs);
+                       exit(1);
+               }
+       }
+#endif
+
        /* Normally we only need to write out the superblock */
        fs->flags |= EXT2_FLAG_SUPER_ONLY;
 
@@ -3158,35 +3245,6 @@ retry_open:
                free(ext_mount_opts);
        }
 
-#ifdef NO_RECOVERY
-       /* Warn if file system needs recovery and it is opened for writing. */
-       if ((open_flag & EXT2_FLAG_RW) && !(mount_flags & EXT2_MF_MOUNTED) &&
-           (sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) &&
-           (sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER)) {
-               fprintf(stderr,
-_("Warning: The journal is dirty. You may wish to replay the journal like:\n\n"
-  "\te2fsck -E journal_only %s\n\n"
-  "then rerun this command.  Otherwise, any changes made may be overwritten\n"
-  "by journal recovery.\n"), device_name);
-       }
-#else
-       /* Recover the journal if possible. */
-       if ((open_flag & EXT2_FLAG_RW) && !(mount_flags & EXT2_MF_MOUNTED) &&
-           ext2fs_has_feature_journal_needs_recovery(fs->super)) {
-               errcode_t err;
-
-               printf(_("Recovering journal.\n"));
-               err = ext2fs_run_ext3_journal(&fs);
-               if (err) {
-                       com_err("tune2fs", err, "while recovering journal.\n");
-                       printf(_("Please run e2fsck -fy %s.\n"), argv[1]);
-                       goto closefs;
-               }
-               ext2fs_clear_feature_journal_needs_recovery(fs->super);
-               ext2fs_mark_super_dirty(fs);
-       }
-#endif
-
        free(device_name);
        remove_error_table(&et_ext2_error_table);
 
@@ -3198,6 +3256,7 @@ closefs:
 #endif
        }
 
-       convert_64bit(fs, feature_64bit);
+       if (feature_64bit)
+               convert_64bit(fs, feature_64bit);
        return (ext2fs_close_free(&fs) ? 1 : 0);
 }