dovecot-2.2: lib-index, lib-storage: Fixed race conditions with ...

dovecot at dovecot.org dovecot at dovecot.org
Thu Aug 28 17:15:19 UTC 2014


details:   http://hg.dovecot.org/dovecot-2.2/rev/6980c53bf7d7
changeset: 17758:6980c53bf7d7
user:      Timo Sirainen <tss at iki.fi>
date:      Fri Aug 29 02:14:43 2014 +0900
description:
lib-index, lib-storage: Fixed race conditions with deleting mailbox.
Now only one process can successfully finish mailbox_mark_index_deleted().

diffstat:

 src/lib-index/mail-index-sync.c           |  31 +++++++++++++++++++------------
 src/lib-index/mail-index.h                |   6 +++++-
 src/lib-index/mail-transaction-log-file.c |   1 +
 src/lib-storage/index/index-sync.c        |   7 +++++--
 src/lib-storage/mail-storage-private.h    |   2 ++
 src/lib-storage/mail-storage.c            |   5 ++++-
 6 files changed, 36 insertions(+), 16 deletions(-)

diffs (141 lines):

diff -r 2324dea38a03 -r 6980c53bf7d7 src/lib-index/mail-index-sync.c
--- a/src/lib-index/mail-index-sync.c	Fri Aug 29 00:41:07 2014 +0900
+++ b/src/lib-index/mail-index-sync.c	Fri Aug 29 02:14:43 2014 +0900
@@ -360,13 +360,21 @@
 		}
 	}
 
-	if (!mail_index_need_sync(index, flags,
-				  log_file_seq, log_file_offset)) {
+	if (!mail_index_need_sync(index, flags, log_file_seq, log_file_offset) &&
+	    !index->index_deleted) {
 		if (locked)
 			mail_transaction_log_sync_unlock(index->log);
 		return 0;
 	}
 
+	if (!locked) {
+		/* it looks like we have something to sync. lock the file and
+		   check again. */
+		flags &= ~MAIL_INDEX_SYNC_FLAG_REQUIRE_CHANGES;
+		return mail_index_sync_begin_init(index, flags, log_file_seq,
+						  log_file_offset);
+	}
+
 	if (index->index_deleted &&
 	    (flags & MAIL_INDEX_SYNC_FLAG_DELETING_INDEX) == 0) {
 		/* index is already deleted. we can't sync. */
@@ -375,14 +383,6 @@
 		return -1;
 	}
 
-	if (!locked) {
-		/* it looks like we have something to sync. lock the file and
-		   check again. */
-		flags &= ~MAIL_INDEX_SYNC_FLAG_REQUIRE_CHANGES;
-		return mail_index_sync_begin_init(index, flags, log_file_seq,
-						  log_file_offset);
-	}
-
 	hdr = &index->map->hdr;
 	if (hdr->log_file_tail_offset > hdr->log_file_head_offset ||
 	    hdr->log_file_seq > seq ||
@@ -482,7 +482,8 @@
 	ctx->ext_trans = mail_index_transaction_begin(ctx->view, trans_flags);
 	ctx->ext_trans->sync_transaction = TRUE;
 	ctx->ext_trans->commit_deleted_index =
-		(flags & MAIL_INDEX_SYNC_FLAG_DELETING_INDEX) != 0;
+		(flags & (MAIL_INDEX_SYNC_FLAG_DELETING_INDEX |
+			  MAIL_INDEX_SYNC_FLAG_TRY_DELETING_INDEX)) != 0;
 
 	*ctx_r = ctx;
 	*view_r = ctx->view;
@@ -789,10 +790,16 @@
 
 	index_undeleted = ctx->ext_trans->index_undeleted;
 	delete_index = index->index_delete_requested && !index_undeleted &&
-		(ctx->flags & MAIL_INDEX_SYNC_FLAG_DELETING_INDEX) != 0;
+		(ctx->flags & (MAIL_INDEX_SYNC_FLAG_DELETING_INDEX |
+			       MAIL_INDEX_SYNC_FLAG_TRY_DELETING_INDEX)) != 0;
 	if (delete_index) {
 		/* finish this sync by marking the index deleted */
 		mail_index_set_deleted(ctx->ext_trans);
+	} else if (index->index_deleted && !index_undeleted &&
+		   (ctx->flags & MAIL_INDEX_SYNC_FLAG_TRY_DELETING_INDEX) == 0) {
+		/* another process just marked the index deleted.
+		   finish the sync, but return error. */
+		ret = -1;
 	}
 
 	mail_index_sync_update_mailbox_offset(ctx);
diff -r 2324dea38a03 -r 6980c53bf7d7 src/lib-index/mail-index.h
--- a/src/lib-index/mail-index.h	Fri Aug 29 00:41:07 2014 +0900
+++ b/src/lib-index/mail-index.h	Fri Aug 29 02:14:43 2014 +0900
@@ -159,7 +159,11 @@
 	MAIL_INDEX_SYNC_FLAG_FSYNC		= 0x10,
 	/* If we see "delete index" request transaction, finish it.
 	   This flag also allows committing more changes to a deleted index. */
-	MAIL_INDEX_SYNC_FLAG_DELETING_INDEX	= 0x20
+	MAIL_INDEX_SYNC_FLAG_DELETING_INDEX	= 0x20,
+	/* Same as MAIL_INDEX_SYNC_FLAG_DELETING_INDEX, but finish index
+	   deletion only once and fail the rest (= avoid race conditions when
+	   multiple processes try to mark the index deleted) */
+	MAIL_INDEX_SYNC_FLAG_TRY_DELETING_INDEX	= 0x40
 };
 
 enum mail_index_view_sync_flags {
diff -r 2324dea38a03 -r 6980c53bf7d7 src/lib-index/mail-transaction-log-file.c
--- a/src/lib-index/mail-transaction-log-file.c	Fri Aug 29 00:41:07 2014 +0900
+++ b/src/lib-index/mail-transaction-log-file.c	Fri Aug 29 02:14:43 2014 +0900
@@ -1284,6 +1284,7 @@
 		if (file->sync_offset < file->index_undeleted_offset)
 			break;
 		file->log->index->index_deleted = TRUE;
+		file->log->index->index_delete_requested = FALSE;
 		file->index_deleted_offset = file->sync_offset + trans_size;
 		break;
 	case MAIL_TRANSACTION_INDEX_UNDELETED:
diff -r 2324dea38a03 -r 6980c53bf7d7 src/lib-storage/index/index-sync.c
--- a/src/lib-storage/index/index-sync.c	Fri Aug 29 00:41:07 2014 +0900
+++ b/src/lib-storage/index/index-sync.c	Fri Aug 29 02:14:43 2014 +0900
@@ -17,8 +17,11 @@
 
 	if ((box->flags & MAILBOX_FLAG_DROP_RECENT) != 0)
 		sync_flags |= MAIL_INDEX_SYNC_FLAG_DROP_RECENT;
-	if (box->deleting)
-		sync_flags |= MAIL_INDEX_SYNC_FLAG_DELETING_INDEX;
+	if (box->deleting) {
+		sync_flags |= box->delete_sync_check ?
+			MAIL_INDEX_SYNC_FLAG_TRY_DELETING_INDEX :
+			MAIL_INDEX_SYNC_FLAG_DELETING_INDEX;
+	}
 	return sync_flags;
 }
 
diff -r 2324dea38a03 -r 6980c53bf7d7 src/lib-storage/mail-storage-private.h
--- a/src/lib-storage/mail-storage-private.h	Fri Aug 29 00:41:07 2014 +0900
+++ b/src/lib-storage/mail-storage-private.h	Fri Aug 29 02:14:43 2014 +0900
@@ -332,6 +332,8 @@
 	unsigned int creating:1;
 	/* Mailbox is being deleted */
 	unsigned int deleting:1;
+	/* Don't use MAIL_INDEX_SYNC_FLAG_DELETING_INDEX for sync flag */
+	unsigned int delete_sync_check:1;
 	/* Delete mailbox only if it's empty */
 	unsigned int deleting_must_be_empty:1;
 	/* The backend wants to skip checking if there are 0 messages before
diff -r 2324dea38a03 -r 6980c53bf7d7 src/lib-storage/mail-storage.c
--- a/src/lib-storage/mail-storage.c	Fri Aug 29 00:41:07 2014 +0900
+++ b/src/lib-storage/mail-storage.c	Fri Aug 29 02:14:43 2014 +0900
@@ -1319,7 +1319,10 @@
 	/* sync the mailbox. this finishes the index deletion and it can
 	   succeed only for a single session. we do it here, so the rest of
 	   the deletion code doesn't have to worry about race conditions. */
-	if (mailbox_sync(box, MAILBOX_SYNC_FLAG_FULL_READ) < 0)
+	box->delete_sync_check = TRUE;
+	ret = mailbox_sync(box, MAILBOX_SYNC_FLAG_FULL_READ);
+	box->delete_sync_check = FALSE;
+	if (ret < 0)
 		return -1;
 
 	box->marked_deleted = del;


More information about the dovecot-cvs mailing list