From: Timo Sirainen Date: Wed, 10 Aug 2016 16:15:56 +0000 (+0300) Subject: quota: If quota lookup updates vsize header, lock it earlier to avoid a deadlock. X-Git-Tag: 2.2.26~373 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=19e19b1b2d69114096dd66b74df2539da663054b;p=thirdparty%2Fdovecot%2Fcore.git quota: If quota lookup updates vsize header, lock it earlier to avoid a deadlock. --- diff --git a/src/plugins/quota/quota-private.h b/src/plugins/quota/quota-private.h index 49c10e7ceb..baba1111f5 100644 --- a/src/plugins/quota/quota-private.h +++ b/src/plugins/quota/quota-private.h @@ -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 diff --git a/src/plugins/quota/quota-storage.c b/src/plugins/quota/quota-storage.c index 14270d8df2..d54059ed9e 100644 --- a/src/plugins/quota/quota-storage.c +++ b/src/plugins/quota/quota-storage.c @@ -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); } diff --git a/src/plugins/quota/quota.c b/src/plugins/quota/quota.c index 80bf60065d..05002da445 100644 --- a/src/plugins/quota/quota.c +++ b/src/plugins/quota/quota.c @@ -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,