summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAditya Kali <adityakali@google.com>2011-07-20 11:40:06 -0700
committerTheodore Ts'o <tytso@mit.edu>2011-08-31 16:31:13 -0400
commit624e4a6466dba9889f5f80dc168f2bb7c2a3f5d0 (patch)
treed4d5748fc2baea48a1cb6a9ad0e66300cdcc3b3f
parentf239fefc14226f655477179801c734749a04d4b4 (diff)
downloade2fsprogs-624e4a6466dba9889f5f80dc168f2bb7c2a3f5d0.tar.gz
e2fsck: add support for checking the built-in quota files
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>
-rw-r--r--e2fsck/Makefile.in46
-rw-r--r--e2fsck/e2fsck.h9
-rw-r--r--e2fsck/message.c2
-rw-r--r--e2fsck/pass1.c34
-rw-r--r--e2fsck/pass1b.c6
-rw-r--r--e2fsck/pass2.c16
-rw-r--r--e2fsck/pass3.c3
-rw-r--r--e2fsck/pass4.c1
-rw-r--r--e2fsck/problem.c20
-rw-r--r--e2fsck/problem.h12
-rw-r--r--e2fsck/quota.c88
-rw-r--r--e2fsck/super.c5
-rw-r--r--e2fsck/unix.c17
-rw-r--r--lib/ext2fs/ext2fs.h3
14 files changed, 240 insertions, 22 deletions
diff --git a/e2fsck/Makefile.in b/e2fsck/Makefile.in
index b426eaf6..ccbc5c3f 100644
--- a/e2fsck/Makefile.in
+++ b/e2fsck/Makefile.in
@@ -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
diff --git a/e2fsck/e2fsck.h b/e2fsck/e2fsck.h
index f0e1557f..1c1603b9 100644
--- a/e2fsck/e2fsck.h
+++ b/e2fsck/e2fsck.h
@@ -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);
diff --git a/e2fsck/message.c b/e2fsck/message.c
index c4567526..49b861dc 100644
--- a/e2fsck/message.c
+++ b/e2fsck/message.c
@@ -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"),
diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c
index fe5dd9b9..dd18ade0 100644
--- a/e2fsck/pass1.c
+++ b/e2fsck/pass1.c
@@ -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))
diff --git a/e2fsck/pass1b.c b/e2fsck/pass1b.c
index 12a03b01..08584820 100644
--- a/e2fsck/pass1b.c
+++ b/e2fsck/pass1b.c
@@ -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);
}
}
}
diff --git a/e2fsck/pass2.c b/e2fsck/pass2.c
index 28636992..e57afb9b 100644
--- a/e2fsck/pass2.c
+++ b/e2fsck/pass2.c
@@ -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;
diff --git a/e2fsck/pass3.c b/e2fsck/pass3.c
index c0671643..e3d2ef70 100644
--- a/e2fsck/pass3.c
+++ b/e2fsck/pass3.c
@@ -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");
diff --git a/e2fsck/pass4.c b/e2fsck/pass4.c
index 695612b6..4b845f68 100644
--- a/e2fsck/pass4.c
+++ b/e2fsck/pass4.c
@@ -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;
}
}
diff --git a/e2fsck/problem.c b/e2fsck/problem.c
index c5bebf85..eb29bc0c 100644
--- a/e2fsck/problem.c
+++ b/e2fsck/problem.c
@@ -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 */
diff --git a/e2fsck/problem.h b/e2fsck/problem.h
index 8379e0cf..21285dca 100644
--- a/e2fsck/problem.h
+++ b/e2fsck/problem.h
@@ -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
index 00000000..54b8d23b
--- /dev/null
+++ b/e2fsck/quota.c
@@ -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;
+}
diff --git a/e2fsck/super.c b/e2fsck/super.c
index a61eb338..14251abc 100644
--- a/e2fsck/super.c
+++ b/e2fsck/super.c
@@ -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;
}
diff --git a/e2fsck/unix.c b/e2fsck/unix.c
index 7f6ee987..bc18d41c 100644
--- a/e2fsck/unix.c
+++ b/e2fsck/unix.c
@@ -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);
diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
index dc83fb0c..9d68cbee 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -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