]> git.ipfire.org Git - thirdparty/e2fsprogs.git/commitdiff
e2fsck: add support for checking the built-in quota files
authorAditya Kali <adityakali@google.com>
Wed, 20 Jul 2011 18:40:06 +0000 (11:40 -0700)
committerTheodore Ts'o <tytso@mit.edu>
Wed, 31 Aug 2011 20:31:13 +0000 (16:31 -0400)
This patch adds support for doing quota accounting during full
e2fsck scan if the 'quota' feature was set on the superblock.
If user-visible quota inodes are in use, they will be hidden
and converted to the reserved quota inodes.

Signed-off-by: Aditya Kali <adityakali@google.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
14 files changed:
e2fsck/Makefile.in
e2fsck/e2fsck.h
e2fsck/message.c
e2fsck/pass1.c
e2fsck/pass1b.c
e2fsck/pass2.c
e2fsck/pass3.c
e2fsck/pass4.c
e2fsck/problem.c
e2fsck/problem.h
e2fsck/quota.c [new file with mode: 0644]
e2fsck/super.c
e2fsck/unix.c
lib/ext2fs/ext2fs.h

index b426eaf69b9e0f9b0352eaa79affa1b38cc4b9fc..ccbc5c3ff8fdcfc1fdda240f9b6549559eea2593 100644 (file)
@@ -16,19 +16,23 @@ MANPAGES=   e2fsck.8
 FMANPAGES=     e2fsck.conf.5
 XTRA_CFLAGS=   -DRESOURCE_TRACK -I.
 
-LIBS= $(LIBEXT2FS) $(LIBCOM_ERR) $(LIBBLKID) $(LIBUUID) $(LIBINTL) $(LIBE2P)
-DEPLIBS= $(LIBEXT2FS) $(DEPLIBCOM_ERR) $(DEPLIBBLKID) $(DEPLIBUUID) \
-       $(DEPLIBE2P)
-
-STATIC_LIBS= $(STATIC_LIBEXT2FS) $(STATIC_LIBCOM_ERR) $(STATIC_LIBBLKID) \
-       $(STATIC_LIBUUID) $(LIBINTL) $(STATIC_LIBE2P)
-STATIC_DEPLIBS= $(STATIC_LIBEXT2FS) $(DEPSTATIC_LIBCOM_ERR) \
-       $(DEPSTATIC_LIBBLKID) $(DEPSTATIC_LIBUUID) $(DEPSTATIC_LIBE2P)
-
-PROFILED_LIBS= $(PROFILED_LIBEXT2FS) $(PROFILED_LIBCOM_ERR) \
-       $(PROFILED_LIBBLKID) $(PROFILED_LIBUUID) $(PROFILED_LIBE2P) $(LIBINTL)
-PROFILED_DEPLIBS= $(PROFILED_LIBEXT2FS) $(DEPPROFILED_LIBCOM_ERR) \
-       $(DEPPROFILED_LIBBLKID) $(DEPPROFILED_LIBUUID) $(DEPPROFILED_LIBE2P)
+LIBS= $(LIBQUOTA) $(LIBEXT2FS) $(LIBCOM_ERR) $(LIBBLKID) $(LIBUUID) \
+       $(LIBINTL) $(LIBE2P)
+DEPLIBS= $(DEPLIBQUOTA) $(LIBEXT2FS) $(DEPLIBCOM_ERR) $(DEPLIBBLKID) \
+        $(DEPLIBUUID) $(DEPLIBE2P)
+
+STATIC_LIBS= $(STATIC_LIBQUOTA) $(STATIC_LIBEXT2FS) $(STATIC_LIBCOM_ERR) \
+            $(STATIC_LIBBLKID) $(STATIC_LIBUUID) $(LIBINTL) $(STATIC_LIBE2P)
+STATIC_DEPLIBS= $(DEPSTATIC_LIBQUOTA) $(STATIC_LIBEXT2FS) \
+               $(DEPSTATIC_LIBCOM_ERR) $(DEPSTATIC_LIBBLKID) \
+               $(DEPSTATIC_LIBUUID) $(DEPSTATIC_LIBE2P)
+
+PROFILED_LIBS= $(PROFILED_LIBQUOTA) $(PROFILED_LIBEXT2FS) \
+              $(PROFILED_LIBCOM_ERR) $(PROFILED_LIBBLKID) $(PROFILED_LIBUUID) \
+              $(PROFILED_LIBE2P) $(LIBINTL) \
+PROFILED_DEPLIBS= $(DEPPROFILED_LIBQUOTA) $(PROFILED_LIBEXT2FS) \
+                 $(DEPPROFILED_LIBCOM_ERR) $(DEPPROFILED_LIBBLKID) \
+                 $(DEPPROFILED_LIBUUID) $(DEPPROFILED_LIBE2P)
 
 COMPILE_ET=$(top_builddir)/lib/et/compile_et --build-tree
 
@@ -63,16 +67,16 @@ COMPILE_ET=$(top_builddir)/lib/et/compile_et --build-tree
 
 OBJS= crc32.o dict.o unix.o e2fsck.o super.o pass1.o pass1b.o pass2.o \
        pass3.o pass4.o pass5.o journal.o badblocks.o util.o dirinfo.o \
-       dx_dirinfo.o ehandler.o problem.o message.o recovery.o region.o \
-       revoke.o ea_refcount.o rehash.o profile.o prof_err.o sigcatcher.o \
-       $(MTRACE_OBJ)
+       dx_dirinfo.o ehandler.o problem.o message.o quota.o recovery.o \
+       region.o revoke.o ea_refcount.o rehash.o profile.o prof_err.o \
+       sigcatcher.o $(MTRACE_OBJ)
 
 PROFILED_OBJS= profiled/dict.o profiled/unix.o profiled/e2fsck.o \
        profiled/super.o profiled/pass1.o profiled/pass1b.o \
        profiled/pass2.o profiled/pass3.o profiled/pass4.o profiled/pass5.o \
        profiled/journal.o profiled/badblocks.o profiled/util.o \
        profiled/dirinfo.o profiled/dx_dirinfo.o profiled/ehandler.o \
-       profiled/message.o profiled/problem.o \
+       profiled/message.o profiled/problem.o profiled/quota.o \
        profiled/recovery.o profiled/region.o profiled/revoke.o \
        profiled/ea_refcount.o profiled/rehash.o profiled/profile.o \
        profiled/crc32.o profiled/prof_err.o profiled/sigcatcher.o
@@ -105,6 +109,7 @@ SRCS= $(srcdir)/e2fsck.c \
        $(srcdir)/profile.c \
        $(srcdir)/sigcatcher.c \
        prof_err.c \
+       $(srcdir)/quota.c \
        $(MTRACE_SRC)
 
 all:: profiled $(PROGS) e2fsck $(MANPAGES) $(FMANPAGES)
@@ -452,3 +457,10 @@ sigcatcher.o: $(srcdir)/sigcatcher.c $(srcdir)/e2fsck.h \
  $(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/bitops.h \
  $(srcdir)/profile.h prof_err.h
 prof_err.o: prof_err.c
+quota.o: $(srcdir)/quota.c $(srcdir)/e2fsck.h $(top_srcdir)/lib/quota/mkquota.h\
+ $(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \
+ $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/ext3_extents.h \
+ $(top_srcdir)/lib/et/com_err.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
+ $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/bitops.h \
+ $(srcdir)/profile.h prof_err.h $(srcdir)/problem.h
index f0e1557f721ed31e10920e6240d9ae122ddc2e5c..1c1603b9eee9995526cd30ad4ad0a6a0417a1c29 100644 (file)
@@ -61,6 +61,8 @@
 #define P_(singular, plural, n) ((n) == 1 ? (singular) : (plural))
 #endif
 
+#include "quota/mkquota.h"
+
 /*
  * Exit codes used by fsck-type programs
  */
@@ -305,6 +307,10 @@ struct e2fsck_struct {
        io_channel      journal_io;
        char    *journal_name;
 
+       /*
+        * Ext4 quota support
+        */
+       quota_ctx_t qctx;
 #ifdef RESOURCE_TRACK
        /*
         * For timing purposes
@@ -441,6 +447,9 @@ extern int e2fsck_run_ext3_journal(e2fsck_t ctx);
 extern void e2fsck_move_ext3_journal(e2fsck_t ctx);
 extern int e2fsck_fix_ext3_journal_hint(e2fsck_t ctx);
 
+/* quota.c */
+extern void e2fsck_hide_quota(e2fsck_t ctx);
+
 /* pass1.c */
 extern void e2fsck_setup_tdb_icount(e2fsck_t ctx, int flags,
                                    ext2_icount_t *ret);
index c4567526122b411637f146d4039b5f8dd254097f..49b861dc613a7cfabdeb62dc20636ef27c2a6dd9 100644 (file)
@@ -76,6 +76,7 @@
  *     @n      invalid
  *     @o      orphaned
  *     @p      problem in
+ *     @q      quota
  *     @r      root inode
  *     @s      should be
  *     @S      superblock
@@ -131,6 +132,7 @@ static const char *abbrevs[] = {
        N_("ninvalid"),
        N_("oorphaned"),
        N_("pproblem in"),
+       N_("qquota"),
        N_("rroot @i"),
        N_("sshould be"),
        N_("Ssuper@b"),
index fe5dd9b9282edb7a932c6b919d1e09a78c2eaa0d..dd18ade08fad752f6b6b23bba4b623cd7ef75bb3 100644 (file)
@@ -893,6 +893,33 @@ void e2fsck_pass1(e2fsck_t ctx)
                                e2fsck_write_inode_full(ctx, ino, inode,
                                                        inode_size, "pass1");
                        }
+               } else if ((ino == EXT4_USR_QUOTA_INO) ||
+                          (ino == EXT4_GRP_QUOTA_INO)) {
+                       ext2fs_mark_inode_bitmap2(ctx->inode_used_map, ino);
+                       if ((fs->super->s_feature_ro_compat &
+                                       EXT4_FEATURE_RO_COMPAT_QUOTA) &&
+                           (fs->super->s_usr_quota_inum == ino) ||
+                           (fs->super->s_grp_quota_inum == ino)) {
+                               if (!LINUX_S_ISREG(inode->i_mode) &&
+                                   fix_problem(ctx, PR_1_QUOTA_BAD_MODE,
+                                                       &pctx)) {
+                                       inode->i_mode = LINUX_S_IFREG;
+                                       e2fsck_write_inode(ctx, ino, inode,
+                                                       "pass1");
+                               }
+                               check_blocks(ctx, &pctx, block_buf);
+                               continue;
+                       }
+                       if ((inode->i_links_count ||
+                            inode->i_blocks || inode->i_block[0]) &&
+                           fix_problem(ctx, PR_1_QUOTA_INODE_NOT_CLEAR,
+                                       &pctx)) {
+                               memset(inode, 0, inode_size);
+                               ext2fs_icount_store(ctx->inode_link_info,
+                                                   ino, 0);
+                               e2fsck_write_inode_full(ctx, ino, inode,
+                                                       inode_size, "pass1");
+                       }
                } else if (ino < EXT2_FIRST_INODE(fs->super)) {
                        int     problem = 0;
 
@@ -918,6 +945,7 @@ void e2fsck_pass1(e2fsck_t ctx)
                        check_blocks(ctx, &pctx, block_buf);
                        continue;
                }
+
                /*
                 * Check for inodes who might have been part of the
                 * orphaned list linked list.  They should have gotten
@@ -1978,6 +2006,12 @@ static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
                }
        }
 
+       if (ino == EXT2_ROOT_INO || ino >= EXT2_FIRST_INODE(ctx->fs->super)) {
+               quota_data_add(ctx->qctx, inode, ino,
+                              pb.num_blocks * fs->blocksize);
+               quota_data_inodes(ctx->qctx, inode, ino, +1);
+       }
+
        if (!(fs->super->s_feature_ro_compat &
              EXT4_FEATURE_RO_COMPAT_HUGE_FILE) ||
            !(inode->i_flags & EXT4_HUGE_FILE_FL))
index 12a03b01ee2962895b54141c2df43f11ffff38ae..08584820b1f73f20f0699b4ad62f6950e4251d1c 100644 (file)
@@ -596,6 +596,7 @@ static int delete_file_block(ext2_filsys fs,
        } else {
                ext2fs_unmark_block_bitmap2(ctx->block_found_map, *block_nr);
                ext2fs_block_alloc_stats2(fs, *block_nr, -1);
+               pb->dup_blocks++;
        }
 
        return 0;
@@ -612,7 +613,7 @@ static void delete_file(e2fsck_t ctx, ext2_ino_t ino,
 
        clear_problem_context(&pctx);
        pctx.ino = pb.ino = ino;
-       pb.dup_blocks = dp->num_dupblocks;
+       pb.dup_blocks = 0;
        pb.ctx = ctx;
        pctx.str = "delete_file";
 
@@ -625,6 +626,8 @@ static void delete_file(e2fsck_t ctx, ext2_ino_t ino,
        if (ctx->inode_bad_map)
                ext2fs_unmark_inode_bitmap2(ctx->inode_bad_map, ino);
        ext2fs_inode_alloc_stats2(fs, ino, -1, LINUX_S_ISDIR(inode.i_mode));
+       quota_data_sub(ctx->qctx, &inode, ino, pb.dup_blocks * fs->blocksize);
+       quota_data_inodes(ctx->qctx, &inode, ino, -1);
 
        /* Inode may have changed by block_iterate, so reread it */
        e2fsck_read_inode(ctx, ino, &inode, "delete_file");
@@ -656,6 +659,7 @@ static void delete_file(e2fsck_t ctx, ext2_ino_t ino,
                        delete_file_block(fs, &blk,
                                          BLOCK_COUNT_EXTATTR, 0, 0, &pb);
                        ext2fs_file_acl_block_set(&inode, blk);
+                       quota_data_sub(ctx->qctx, &inode, ino, fs->blocksize);
                }
        }
 }
index 2863699232d49a9396c21e8f813ac2070d3e889c..e57afb9b6f298ae5564956ebd01eddd54e469c62 100644 (file)
@@ -1149,6 +1149,11 @@ abort_free_dict:
        return DIRENT_ABORT;
 }
 
+struct del_block {
+       e2fsck_t        ctx;
+       e2_blkcnt_t     num;
+};
+
 /*
  * This function is called to deallocate a block, and is an interator
  * functioned called by deallocate inode via ext2fs_iterate_block().
@@ -1160,15 +1165,16 @@ static int deallocate_inode_block(ext2_filsys fs,
                                  int ref_offset EXT2FS_ATTR((unused)),
                                  void *priv_data)
 {
-       e2fsck_t        ctx = (e2fsck_t) priv_data;
+       struct del_block *p = priv_data;
 
        if (HOLE_BLKADDR(*block_nr))
                return 0;
        if ((*block_nr < fs->super->s_first_data_block) ||
            (*block_nr >= ext2fs_blocks_count(fs->super)))
                return 0;
-       ext2fs_unmark_block_bitmap2(ctx->block_found_map, *block_nr);
+       ext2fs_unmark_block_bitmap2(p->ctx->block_found_map, *block_nr);
        ext2fs_block_alloc_stats2(fs, *block_nr, -1);
+       p->num++;
        return 0;
 }
 
@@ -1181,6 +1187,7 @@ static void deallocate_inode(e2fsck_t ctx, ext2_ino_t ino, char* block_buf)
        struct ext2_inode       inode;
        struct problem_context  pctx;
        __u32                   count;
+       struct del_block        del_block;
 
        e2fsck_read_inode(ctx, ino, &inode, "deallocate_inode");
        e2fsck_clear_inode(ctx, ino, &inode, 0, "deallocate_inode");
@@ -1223,8 +1230,11 @@ static void deallocate_inode(e2fsck_t ctx, ext2_ino_t ino, char* block_buf)
        if (LINUX_S_ISREG(inode.i_mode) && EXT2_I_SIZE(&inode) >= 0x80000000UL)
                ctx->large_files--;
 
+       del_block.ctx = ctx;
+       del_block.num = 0;
        pctx.errcode = ext2fs_block_iterate3(fs, ino, 0, block_buf,
-                                            deallocate_inode_block, ctx);
+                                            deallocate_inode_block,
+                                            &del_block);
        if (pctx.errcode) {
                fix_problem(ctx, PR_2_DEALLOC_INODE, &pctx);
                ctx->flags |= E2F_FLAG_ABORT;
index c0671643af9beef422da8e0cf12d91edc83ac0fc..e3d2ef70d28bad7472bcc4bdc080835b24f92dc9 100644 (file)
@@ -488,6 +488,8 @@ ext2_ino_t e2fsck_get_lost_and_found(e2fsck_t ctx, int fix)
        ext2fs_icount_store(ctx->inode_count, ino, 2);
        ext2fs_icount_store(ctx->inode_link_info, ino, 2);
        ctx->lost_and_found = ino;
+       quota_data_add(ctx->qctx, &inode, ino, fs->blocksize);
+       quota_data_inodes(ctx->qctx, &inode, ino, +1);
 #if 0
        printf("/lost+found created; inode #%lu\n", ino);
 #endif
@@ -790,6 +792,7 @@ errcode_t e2fsck_expand_directory(e2fsck_t ctx, ext2_ino_t dir,
 
        inode.i_size = (es.last_block + 1) * fs->blocksize;
        ext2fs_iblk_add_blocks(fs, &inode, es.newblocks);
+       quota_data_add(ctx->qctx, &inode, dir, es.newblocks * fs->blocksize);
 
        e2fsck_write_inode(ctx, dir, &inode, "expand_directory");
 
index 695612b61cf1ea81878f69edc9e99f24aefc678b..4b845f6893c8dae72d69038b585800a4c5ebc2e3 100644 (file)
@@ -63,6 +63,7 @@ static int disconnect_inode(e2fsck_t ctx, ext2_ino_t i,
                        e2fsck_read_bitmaps(ctx);
                        ext2fs_inode_alloc_stats2(fs, i, -1,
                                                  LINUX_S_ISDIR(inode->i_mode));
+                       quota_data_inodes(ctx->qctx, inode, i, -1);
                        return 0;
                }
        }
index c5bebf85bdc9ed2313ac3c8c427de2a119990bac..eb29bc0cb20f6cc148f1bda8f15dc8b2f578812b 100644 (file)
@@ -412,6 +412,11 @@ static struct e2fsck_problem problem_table[] = {
          N_("Setting free @bs count to %c (was %b)\n"),
          PROMPT_NONE, PR_PREEN_NOMSG },
 
+       /* Making quota file hidden */
+       { PR_0_HIDE_QUOTA,
+         N_("Making @q @is hidden.\n\n"),
+         PROMPT_NONE, PR_PREEN_OK },
+
        /* Pass 1 errors */
 
        /* Pass 1: Checking inodes, blocks, and sizes */
@@ -905,6 +910,21 @@ static struct e2fsck_problem problem_table[] = {
          N_("Error converting subcluster @b @B: %m\n"),
          PROMPT_NONE, PR_FATAL },
 
+       /* Quota inode has bad mode */
+       { PR_1_QUOTA_BAD_MODE,
+         N_("@q is not regular file.  "),
+         PROMPT_CLEAR, PR_PREEN_OK },
+
+       /* Quota inode is not in use, but contains data */
+       { PR_1_QUOTA_INODE_NOT_CLEAR,
+         N_("@q @i is not in use, but contains data.  "),
+         PROMPT_CLEAR, PR_PREEN_OK },
+
+       /* Quota inode is user visible */
+       { PR_1_QUOTA_INODE_NOT_HIDDEN,
+         N_("@q @i is visible to the user.  "),
+         PROMPT_CLEAR, PR_PREEN_OK },
+
        /* Pass 1b errors */
 
        /* Pass 1B: Rescan for duplicate/bad blocks */
index 8379e0cf542a9d45ca8690b7c41c27699fd8570c..21285dcaea76e95cdbf76a4b292e1fc4eb66b1c0 100644 (file)
@@ -233,6 +233,9 @@ struct problem_context {
 /* Free blocks count wrong */
 #define PR_0_FREE_BLOCK_COUNT                  0x000040
 
+/* Make quota file hidden */
+#define        PR_0_HIDE_QUOTA                         0x000041
+
 
 /*
  * Pass 1 errors
@@ -529,6 +532,15 @@ struct problem_context {
 /* Failed to convert subcluster bitmap */
 #define PR_1_CONVERT_SUBCLUSTER                0x010061
 
+/* Quota inode has wrong mode */
+#define PR_1_QUOTA_BAD_MODE            0x010062
+
+/* Quota inode is not in use, but contains data */
+#define PR_1_QUOTA_INODE_NOT_CLEAR     0x010063
+
+/* Quota inode is user visible */
+#define PR_1_QUOTA_INODE_NOT_HIDDEN    0x010064
+
 /*
  * Pass 1b errors
  */
diff --git a/e2fsck/quota.c b/e2fsck/quota.c
new file mode 100644 (file)
index 0000000..54b8d23
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * quota.c --- code for handling ext4 quota inodes
+ *
+ */
+
+#ifdef HAVE_SYS_MOUNT_H
+#include <sys/param.h>
+#include <sys/mount.h>
+#define MNT_FL (MS_MGC_VAL | MS_RDONLY)
+#endif
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+
+#include "e2fsck.h"
+#include "problem.h"
+#include "quota/mkquota.h"
+
+static void move_quota_inode(ext2_filsys fs, ext2_ino_t from_ino,
+                            ext2_ino_t to_ino, int qtype)
+{
+       struct ext2_super_block *sb = fs->super;
+       ext2_ino_t              ino;
+       struct ext2_inode       inode;
+       errcode_t               retval;
+       char                    qf_name[255];
+
+       if (ext2fs_read_inode(fs, from_ino, &inode))
+               return;
+
+       inode.i_links_count = 1;
+       inode.i_mode = LINUX_S_IFREG | 0600;
+       inode.i_flags = EXT2_IMMUTABLE_FL;
+       if (fs->super->s_feature_incompat &
+                       EXT3_FEATURE_INCOMPAT_EXTENTS)
+               inode.i_flags |= EXT4_EXTENTS_FL;
+
+       ext2fs_write_new_inode(fs, to_ino, &inode);
+       /* unlink the old inode */
+       get_qf_name(qtype, QFMT_VFS_V1, qf_name);
+       ext2fs_unlink(fs, EXT2_ROOT_INO, qf_name, from_ino, 0);
+       ext2fs_inode_alloc_stats(fs, from_ino, -1);
+}
+
+void e2fsck_hide_quota(e2fsck_t ctx)
+{
+       struct ext2_super_block *sb = ctx->fs->super;
+       struct problem_context  pctx;
+       ext2_filsys             fs = ctx->fs;
+
+       clear_problem_context(&pctx);
+
+       if ((ctx->options & E2F_OPT_READONLY) ||
+           !(sb->s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_QUOTA))
+               return;
+
+       /* We need the inode bitmap to be loaded */
+       if (ext2fs_read_bitmaps(fs))
+               return;
+
+       if (!sb->s_usr_quota_inum && !sb->s_grp_quota_inum)
+               /* nothing to do */
+               return;
+
+       if (sb->s_usr_quota_inum == EXT4_USR_QUOTA_INO &&
+           sb->s_grp_quota_inum == EXT4_GRP_QUOTA_INO)
+               /* nothing to do */
+               return;
+
+       if (!fix_problem(ctx, PR_0_HIDE_QUOTA, &pctx))
+               return;
+
+       if (sb->s_usr_quota_inum &&
+           sb->s_usr_quota_inum != EXT4_USR_QUOTA_INO) {
+               move_quota_inode(fs, sb->s_usr_quota_inum, EXT4_USR_QUOTA_INO,
+                                USRQUOTA);
+               sb->s_usr_quota_inum = EXT4_USR_QUOTA_INO;
+       }
+
+       if (sb->s_grp_quota_inum &&
+           sb->s_grp_quota_inum != EXT4_GRP_QUOTA_INO) {
+               move_quota_inode(fs, sb->s_grp_quota_inum, EXT4_GRP_QUOTA_INO,
+                                GRPQUOTA);
+               sb->s_grp_quota_inum = EXT4_GRP_QUOTA_INO;
+       }
+
+       return;
+}
index a61eb338dafa3d56cb074da7efdab878f7b074ea..14251abc9fb865a0dfc177ca9e77c936ea019c3e 100644 (file)
@@ -856,6 +856,11 @@ void check_super_block(e2fsck_t ctx)
         */
        e2fsck_fix_dirhash_hint(ctx);
 
+       /*
+        * Hide quota inodes if necessary.
+        */
+       e2fsck_hide_quota(ctx);
+
        return;
 }
 
index 7f6ee987de9cdf707335ddaab5d01f21f17687e5..bc18d41cfdb358a4532755dd68b9eaa496bf5003 100644 (file)
@@ -1411,6 +1411,18 @@ print_unsupp_features:
        else
                journal_size = -1;
 
+       if (sb->s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_QUOTA) {
+               int qtype;
+               /* Quotas were enabled. Do quota accounting during fsck. */
+               if ((sb->s_usr_quota_inum && sb->s_grp_quota_inum) ||
+                   (!sb->s_usr_quota_inum && !sb->s_grp_quota_inum))
+                       qtype = -1;
+               else
+                       qtype = sb->s_usr_quota_inum ? USRQUOTA : GRPQUOTA;
+
+               init_quota_context(&ctx->qctx, ctx->fs, qtype);
+       }
+
        run_result = e2fsck_run(ctx);
        e2fsck_clear_progbar(ctx);
 
@@ -1443,6 +1455,11 @@ print_unsupp_features:
        }
 no_journal:
 
+       if (ctx->qctx) {
+               write_quota_inode(ctx->qctx, -1);
+               release_quota_context(&ctx->qctx);
+       }
+
        if (run_result == E2F_FLAG_RESTART) {
                printf(_("Restarting e2fsck from the beginning...\n"));
                retval = e2fsck_reset_context(ctx);
index dc83fb0cf58cff866f932ab84cecb79d4557451c..9d68cbeeb2b17795550e5450acff5fc37df31c1d 100644 (file)
@@ -564,7 +564,8 @@ typedef struct ext2_icount *ext2_icount_t;
                                         EXT4_FEATURE_RO_COMPAT_DIR_NLINK|\
                                         EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE|\
                                         EXT4_FEATURE_RO_COMPAT_GDT_CSUM|\
-                                        EXT4_FEATURE_RO_COMPAT_BIGALLOC)
+                                        EXT4_FEATURE_RO_COMPAT_BIGALLOC|\
+                                        EXT4_FEATURE_RO_COMPAT_QUOTA)
 
 /*
  * These features are only allowed if EXT2_FLAG_SOFTSUPP_FEATURES is passed