]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
quota: If quota lookup updates vsize header, lock it earlier to avoid a deadlock.
authorTimo Sirainen <timo.sirainen@dovecot.fi>
Wed, 10 Aug 2016 16:15:56 +0000 (19:15 +0300)
committerTimo Sirainen <timo.sirainen@dovecot.fi>
Mon, 15 Aug 2016 13:14:43 +0000 (16:14 +0300)
src/plugins/quota/quota-private.h
src/plugins/quota/quota-storage.c
src/plugins/quota/quota.c

index 49c10e7ceb28f1c0f3045a3c6328ed051e93e671..baba1111f53b704c459d196d22bc3254b1a30e38 100644 (file)
@@ -210,5 +210,6 @@ bool quota_warning_match(const struct quota_warning_rule *w,
                         uint64_t bytes_before, uint64_t bytes_current,
                         uint64_t count_before, uint64_t count_current);
 bool quota_transaction_is_over(struct quota_transaction_context *ctx, uoff_t size);
+int quota_transaction_set_limits(struct quota_transaction_context *ctx);
 
 #endif
index 14270d8df28c2b72142a8f320896fe4b3b44f223..d54059ed9e5ff69700af61e49a1353a24e409df6 100644 (file)
@@ -230,6 +230,9 @@ quota_copy(struct mail_save_context *ctx, struct mail *mail)
                }
                ctx->dest_mail = qt->tmp_mail;
        }
+       /* get quota before copying any mails. this avoids .vsize.lock
+          deadlocks with backends that lock mails for expunging/copying. */
+       (void)quota_transaction_set_limits(qt);
 
        if (qbox->module_ctx.super.copy(ctx, mail) < 0)
                return -1;
@@ -284,6 +287,9 @@ quota_save_begin(struct mail_save_context *ctx, struct istream *input)
                }
                ctx->dest_mail = qt->tmp_mail;
        }
+       /* get quota before copying any mails. this avoids .vsize.lock
+          deadlocks with backends that lock mails for expunging/copying. */
+       (void)quota_transaction_set_limits(qt);
 
        return qbox->module_ctx.super.save_begin(ctx, input);
 }
index 80bf60065dfa42f6011d9f87b5aa2746b1e7930c..05002da445f61f6f5aa00122fd76f23c8da3c066 100644 (file)
@@ -783,7 +783,7 @@ struct quota_transaction_context *quota_transaction_begin(struct mailbox *box)
        return ctx;
 }
 
-static int quota_transaction_set_limits(struct quota_transaction_context *ctx)
+int quota_transaction_set_limits(struct quota_transaction_context *ctx)
 {
        struct quota_root *const *roots;
        const char *mailbox_name;
@@ -792,6 +792,8 @@ static int quota_transaction_set_limits(struct quota_transaction_context *ctx)
        bool use_grace, ignored;
        int ret;
 
+       if (ctx->limits_set)
+               return 0;
        ctx->limits_set = TRUE;
        mailbox_name = mailbox_get_vname(ctx->box);
        /* use quota_grace only for LDA/LMTP */
@@ -1101,10 +1103,8 @@ int quota_try_alloc(struct quota_transaction_context *ctx,
        uoff_t size;
        int ret;
 
-       if (!ctx->limits_set) {
-               if (quota_transaction_set_limits(ctx) < 0)
-                       return -1;
-       }
+       if (quota_transaction_set_limits(ctx) < 0)
+               return -1;
 
        if (ctx->no_quota_updates)
                return 1;
@@ -1142,10 +1142,8 @@ int quota_test_alloc(struct quota_transaction_context *ctx,
        if (ctx->failed)
                return -1;
 
-       if (!ctx->limits_set) {
-               if (quota_transaction_set_limits(ctx) < 0)
-                       return -1;
-       }
+       if (quota_transaction_set_limits(ctx) < 0)
+               return -1;
        if (ctx->no_quota_updates)
                return 1;
        /* this is a virtual function mainly for trash plugin and similar,