changeset 20628:c5438de8fc7f

quota: If quota lookup updates vsize header, lock it earlier to avoid a deadlock.
author Timo Sirainen <timo.sirainen@dovecot.fi>
date Wed, 10 Aug 2016 19:15:56 +0300
parents 464988cb3980
children e23e2b702622
files src/plugins/quota/quota-private.h src/plugins/quota/quota-storage.c src/plugins/quota/quota.c
diffstat 3 files changed, 14 insertions(+), 9 deletions(-) [+]
line wrap: on
line diff
--- a/src/plugins/quota/quota-private.h	Wed Aug 10 19:13:09 2016 +0300
+++ b/src/plugins/quota/quota-private.h	Wed Aug 10 19:15:56 2016 +0300
@@ -210,5 +210,6 @@
 			 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
--- a/src/plugins/quota/quota-storage.c	Wed Aug 10 19:13:09 2016 +0300
+++ b/src/plugins/quota/quota-storage.c	Wed Aug 10 19:15:56 2016 +0300
@@ -230,6 +230,9 @@
 		}
 		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 @@
 		}
 		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);
 }
--- a/src/plugins/quota/quota.c	Wed Aug 10 19:13:09 2016 +0300
+++ b/src/plugins/quota/quota.c	Wed Aug 10 19:15:56 2016 +0300
@@ -783,7 +783,7 @@
 	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 @@
 	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 @@
 	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 @@
 	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,