]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
dict quota: Fixed a potential crash if quota recalculation was triggered at deinit.
authorTimo Sirainen <tss@iki.fi>
Tue, 16 Oct 2012 00:34:51 +0000 (03:34 +0300)
committerTimo Sirainen <tss@iki.fi>
Tue, 16 Oct 2012 00:34:51 +0000 (03:34 +0300)
src/plugins/quota/quota-dict.c
src/plugins/quota/quota-dirsize.c
src/plugins/quota/quota-fs.c
src/plugins/quota/quota-maildir.c
src/plugins/quota/quota-private.h
src/plugins/quota/quota-storage.c

index 877589a5caaeccb8b0775531588670829b318cff..8620e87d0e522e7e0a8fb5a86c273b8a3a51462f 100644 (file)
@@ -86,10 +86,8 @@ static void dict_quota_deinit(struct quota_root *_root)
 {
        struct dict_quota_root *root = (struct dict_quota_root *)_root;
 
-       if (root->dict != NULL) {
-               (void)dict_wait(root->dict);
+       if (root->dict != NULL)
                dict_deinit(&root->dict);
-       }
        i_free(root);
 }
 
@@ -208,6 +206,13 @@ dict_quota_update(struct quota_root *_root,
        return 0;
 }
 
+static void dict_quota_flush(struct quota_root *_root)
+{
+       struct dict_quota_root *root = (struct dict_quota_root *)_root;
+
+       (void)dict_wait(root->dict);
+}
+
 struct quota_backend quota_backend_dict = {
        "dict",
 
@@ -221,6 +226,7 @@ struct quota_backend quota_backend_dict = {
                dict_quota_root_get_resources,
                dict_quota_get_resource,
                dict_quota_update,
-               NULL
+               NULL,
+               dict_quota_flush
        }
 };
index 8e527dae5a096ca91bef5ba332ca5c1e9ed363ca..f6cd0e6827be9d471f44f472de17b1e784927b10 100644 (file)
@@ -219,6 +219,7 @@ struct quota_backend quota_backend_dirsize = {
                dirsize_quota_root_get_resources,
                dirsize_quota_get_resource,
                dirsize_quota_update,
+               NULL,
                NULL
        }
 };
index 446dedbdc4c927732017ada54825c277c8dab843..c58e182798c8027c9cf292ae15760521324a4815 100644 (file)
@@ -831,7 +831,8 @@ struct quota_backend quota_backend_fs = {
                fs_quota_get_resource,
                fs_quota_update,
 
-               fs_quota_match_box
+               fs_quota_match_box,
+               NULL
        }
 };
 
index f93e2e011da43b98fd756204b76b83e1089d1aaa..ed27f12d4e78470c7a9cd92d454ac304c94af6d4 100644 (file)
@@ -913,6 +913,7 @@ struct quota_backend quota_backend_maildir = {
                maildir_quota_root_get_resources,
                maildir_quota_get_resource,
                maildir_quota_update,
+               NULL,
                NULL
        }
 };
index fa408f5e63b19379f19bc09634e390d07112b14e..50bbe5edc63009566b021e4f751290dc22ef23b6 100644 (file)
@@ -67,7 +67,7 @@ struct quota_backend_vfuncs {
        int (*update)(struct quota_root *root, 
                      struct quota_transaction_context *ctx);
        bool (*match_box)(struct quota_root *root, struct mailbox *box);
-
+       void (*flush)(struct quota_root *root);
 };
 
 struct quota_backend {
index ee561f332fcd473104ce3ec57bd0c0c5e5126bf1..de4fdfa431e4e2ffe9ac832b95ac7a50f2541790 100644 (file)
@@ -366,14 +366,34 @@ static int quota_mailbox_sync_deinit(struct mailbox_sync_context *ctx,
        return ret;
 }
 
+static void quota_roots_flush(struct quota *quota)
+{
+       struct quota_root *const *roots;
+       unsigned int i, count;
+
+       roots = array_get(&quota->roots, &count);
+       for (i = 0; i < count; i++) {
+               if (roots[i]->backend.v.flush != NULL)
+                       roots[i]->backend.v.flush(roots[i]);
+       }
+}
+
 static void quota_mailbox_close(struct mailbox *box)
 {
        struct quota_mailbox *qbox = QUOTA_CONTEXT(box);
+       struct quota_user *quser = QUOTA_USER_CONTEXT(box->storage->user);
 
        /* sync_notify() may be called outside sync_begin()..sync_deinit().
           make sure we apply changes at close time at latest. */
        quota_mailbox_sync_commit(qbox);
 
+       /* make sure quota backend flushes all data. this could also be done
+          somewhat later, but user.deinit() is too late, since the flushing
+          can trigger quota recalculation which isn't safe to do anymore
+          at user.deinit() when most of the loaded plugins have already been
+          deinitialized. */
+       quota_roots_flush(quser->quota);
+
        qbox->module_ctx.super.close(box);
 }