]> git.ipfire.org Git - thirdparty/e2fsprogs.git/commitdiff
e2fsck,libquota: Update quota only if its inconsistent
authorAditya Kali <adityakali@google.com>
Tue, 24 Apr 2012 18:46:08 +0000 (14:46 -0400)
committerTheodore Ts'o <tytso@mit.edu>
Tue, 24 Apr 2012 18:51:54 +0000 (14:51 -0400)
Currently fsck recomputes quotas and overwrites quota files
whenever its run. This causes unnecessary modification of
filesystem even when quotas were never inconsistent. We also
lose the limits information because of this. With this patch,
e2fsck compares the computed quotas to the on-disk quotas
(while updating the in-memory limits) and writes out the
quota inode only if it is inconsistent.

Signed-off-by: Aditya Kali <adityakali@google.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
e2fsck/problem.c
e2fsck/problem.h
e2fsck/unix.c
lib/quota/mkquota.c
lib/quota/mkquota.h

index 7293819ca16fd35557d498176397fc37875b4eb3..25f7fe1fb4e3dc96aea397265f28b8337d02d8f4 100644 (file)
@@ -1691,6 +1691,11 @@ static struct e2fsck_problem problem_table[] = {
          N_("Recreate @j"),
          PROMPT_NULL, PR_PREEN_OK | PR_NO_OK },
 
+       /* Update quota information if it is inconsistent */
+       { PR_6_UPDATE_QUOTAS,
+         N_("Update quota info for quota type %N"),
+         PROMPT_NULL, PR_PREEN_OK | PR_NO_OK },
+
        { 0 }
 };
 
index 07df810750517d34ee3e08fdbd9d718613643987..1b5815bc176cd74d203fbc8a7ee9ee0908d0c432 100644 (file)
@@ -1028,6 +1028,9 @@ struct problem_context {
 /* Recreate the journal if E2F_FLAG_JOURNAL_INODE flag is set */
 #define PR_6_RECREATE_JOURNAL          0x060001
 
+/* Update quota information if it is inconsistent */
+#define PR_6_UPDATE_QUOTAS             0x060002
+
 /*
  * Function declarations
  */
index fdefe7a3bb11c8b21d116bcff61da82274e17adb..53fcd04c54af911071118a4e3bb47316348662cb 100644 (file)
@@ -1137,6 +1137,7 @@ int main (int argc, char *argv[])
        int old_bitmaps;
        __u32 features[3];
        char *cp;
+       int qtype;  /* quota type */
 
        clear_problem_context(&pctx);
        sigcatcher_setup();
@@ -1575,7 +1576,6 @@ print_unsupp_features:
                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))
@@ -1619,7 +1619,18 @@ print_unsupp_features:
 no_journal:
 
        if (ctx->qctx) {
-               quota_write_inode(ctx->qctx, -1);
+               int i, needs_writeout;
+               for (i = 0; i < MAXQUOTAS; i++) {
+                       if (qtype != -1 && qtype != i)
+                               continue;
+                       needs_writeout = 0;
+                       pctx.num = i;
+                       retval = quota_compare_and_update(ctx->qctx, i,
+                                                         &needs_writeout);
+                       if ((retval || needs_writeout) &&
+                           fix_problem(ctx, PR_6_UPDATE_QUOTAS, &pctx))
+                               quota_write_inode(ctx->qctx, i);
+               }
                quota_release_context(&ctx->qctx);
        }
 
index fbfde927ddace3d4ccb3fe888d639c4c6dcafc48..13994ad84df8b46254163bb89b73c0a589cac77e 100644 (file)
@@ -412,29 +412,43 @@ errcode_t quota_compute_usage(quota_ctx_t qctx)
 }
 
 struct scan_dquots_data {
-       quota_ctx_t         qctx;
-       int                 limit_only; /* read limit only */
+       dict_t          *quota_dict;
+       int             update_limits; /* update limits from disk */
+       int             update_usage;
+       int             usage_is_inconsistent;
 };
 
 static int scan_dquots_callback(struct dquot *dquot, void *cb_data)
 {
-       struct scan_dquots_data *scan_data =
-               (struct scan_dquots_data *)cb_data;
-       quota_ctx_t qctx = scan_data->qctx;
+       struct scan_dquots_data *scan_data = cb_data;
+       dict_t *quota_dict = scan_data->quota_dict;
        struct dquot *dq;
 
-       dq = get_dq(qctx->quota_dict[dquot->dq_h->qh_type], dquot->dq_id);
-
+       dq = get_dq(quota_dict, dquot->dq_id);
        dq->dq_id = dquot->dq_id;
-       if (scan_data->limit_only) {
-               dq->dq_dqb.u.v2_mdqb.dqb_off = dquot->dq_dqb.u.v2_mdqb.dqb_off;
+
+       /* Check if there is inconsistancy. */
+       if (dq->dq_dqb.dqb_curspace != dquot->dq_dqb.dqb_curspace ||
+           dq->dq_dqb.dqb_curinodes != dquot->dq_dqb.dqb_curinodes) {
+               scan_data->usage_is_inconsistent = 1;
+               log_err("Usage inconsistent for ID %d: (%llu, %llu) != "
+                       "(%llu, %llu)", dq->dq_id, dq->dq_dqb.dqb_curspace,
+                       dq->dq_dqb.dqb_curinodes, dquot->dq_dqb.dqb_curspace,
+                       dquot->dq_dqb.dqb_curinodes);
+       }
+
+       if (scan_data->update_limits) {
                dq->dq_dqb.dqb_ihardlimit = dquot->dq_dqb.dqb_ihardlimit;
                dq->dq_dqb.dqb_isoftlimit = dquot->dq_dqb.dqb_isoftlimit;
                dq->dq_dqb.dqb_bhardlimit = dquot->dq_dqb.dqb_bhardlimit;
                dq->dq_dqb.dqb_bsoftlimit = dquot->dq_dqb.dqb_bsoftlimit;
-       } else {
-               dq->dq_dqb = dquot->dq_dqb;
        }
+
+       if (scan_data->update_usage) {
+               dq->dq_dqb.dqb_curspace = dquot->dq_dqb.dqb_curspace;
+               dq->dq_dqb.dqb_curinodes = dquot->dq_dqb.dqb_curinodes;
+       }
+
        return 0;
 }
 
@@ -442,12 +456,13 @@ static int scan_dquots_callback(struct dquot *dquot, void *cb_data)
  * Read all dquots from quota file into memory
  */
 static errcode_t quota_read_all_dquots(struct quota_handle *qh,
-                                       quota_ctx_t qctx, int limit_only)
+                                       quota_ctx_t qctx, int update_limits)
 {
        struct scan_dquots_data scan_data;
 
-       scan_data.qctx = qctx;
-       scan_data.limit_only = limit_only;
+       scan_data.quota_dict = qctx->quota_dict[qh->qh_type];
+       scan_data.update_limits = update_limits;
+       scan_data.update_usage = 0;
 
        return qh->qh_ops->scan_dquots(qh, scan_dquots_callback, &scan_data);
 }
@@ -507,3 +522,43 @@ out:
        ext2fs_free_mem(&qh);
        return err;
 }
+
+/*
+ * Compares the measured quota in qctx->quota_dict with that in the quota inode
+ * on disk and updates the limits in qctx->quota_dict. 'usage_inconsistent' is
+ * set to 1 if the supplied and on-disk quota usage values are not identical.
+ */
+errcode_t quota_compare_and_update(quota_ctx_t qctx, int qtype,
+                                  int *usage_inconsistent)
+{
+       ext2_filsys fs = qctx->fs;
+       struct quota_handle qh;
+       struct scan_dquots_data scan_data;
+       ext2_ino_t qf_ino;
+       errcode_t err = 0;
+
+       if (!qctx->quota_dict[qtype])
+               goto out;
+
+       qf_ino = qtype == USRQUOTA ? fs->super->s_usr_quota_inum :
+                                    fs->super->s_grp_quota_inum;
+       err = quota_file_open(&qh, fs, qf_ino, qtype, -1, 0);
+       if (err) {
+               log_err("Open quota file failed", "");
+               goto out;
+       }
+
+       scan_data.quota_dict = qctx->quota_dict[qtype];
+       scan_data.update_limits = 1;
+       scan_data.update_usage = 0;
+       scan_data.usage_is_inconsistent = 0;
+       err = qh.qh_ops->scan_dquots(&qh, scan_dquots_callback, &scan_data);
+       if (err) {
+               log_err("Error scanning dquots", "");
+               goto out;
+       }
+       *usage_inconsistent = scan_data.usage_is_inconsistent;
+
+out:
+       return err;
+}
index a5fa74ba4a4109f7f54aca2834be1e01f1fa5d37..ed6fabd4f92bc1c012da681f243cc71d70d0c4e7 100644 (file)
@@ -59,5 +59,7 @@ errcode_t quota_remove_inode(ext2_filsys fs, int qtype);
 int quota_is_on(ext2_filsys fs, int type);
 int quota_file_exists(ext2_filsys fs, int qtype, int fmt);
 void quota_set_sb_inum(ext2_filsys fs, ext2_ino_t ino, int qtype);
+errcode_t quota_compare_and_update(quota_ctx_t qctx, int qtype,
+                                  int *usage_inconsistent);
 
 #endif  /* __QUOTA_QUOTAIO_H__ */