dovecot-2.2: lib-storage: Fixed some race condition crashes with...

dovecot at dovecot.org dovecot at dovecot.org
Tue Oct 7 18:36:30 UTC 2014


details:   http://hg.dovecot.org/dovecot-2.2/rev/96f79038038f
changeset: 17910:96f79038038f
user:      Timo Sirainen <tss at iki.fi>
date:      Tue Oct 07 21:35:44 2014 +0300
description:
lib-storage: Fixed some race condition crashes with LAYOUT=index

diffstat:

 src/lib-storage/list/mailbox-list-index-backend.c |  90 +++++++++++++++-------
 src/lib-storage/list/mailbox-list-index.c         |  13 ++-
 src/lib-storage/list/mailbox-list-index.h         |   4 +
 3 files changed, 76 insertions(+), 31 deletions(-)

diffs (193 lines):

diff -r 2b84c33d5d11 -r 96f79038038f src/lib-storage/list/mailbox-list-index-backend.c
--- a/src/lib-storage/list/mailbox-list-index-backend.c	Tue Oct 07 20:29:16 2014 +0300
+++ b/src/lib-storage/list/mailbox-list-index-backend.c	Tue Oct 07 21:35:44 2014 +0300
@@ -66,8 +66,8 @@
 }
 
 static int
-index_list_get_node(struct index_mailbox_list *list, const char *name,
-		    struct mailbox_list_index_node **node_r)
+index_list_get_refreshed_node(struct index_mailbox_list *list, const char *name,
+			      struct mailbox_list_index_node **node_r)
 {
 	struct mailbox_list_index_node *node;
 
@@ -81,6 +81,33 @@
 	return 1;
 }
 
+static int
+index_list_get_refreshed_node_seq(struct index_mailbox_list *list,
+				  struct mail_index_view *view,
+				  const char *name,
+				  struct mailbox_list_index_node **node_r,
+				  uint32_t *seq_r)
+{
+	unsigned int i;
+	int ret;
+
+	*node_r = NULL;
+	*seq_r = 0;
+
+	for (i = 0; i < 2; i++) {
+		if ((ret = index_list_get_refreshed_node(list, name, node_r)) <= 0)
+			return ret;
+		if (mail_index_lookup_seq(view, (*node_r)->uid, seq_r))
+			return 1;
+		/* mailbox was just expunged. refreshing should notice it. */
+		if (mailbox_list_index_refresh_force(&list->list) < 0)
+			return -1;
+	}
+	i_panic("mailbox list index: refreshing doesn't lose expunged uid=%u",
+		(*node_r)->uid);
+	return -1;
+}
+
 static const char *
 index_get_guid_path(struct mailbox_list *_list, const char *root_dir,
 		    const guid_128_t mailbox_guid)
@@ -124,22 +151,35 @@
 	if (!mailbox_list_set_get_root_path(&_list->set, type, &root_dir))
 		return 0;
 
-	if ((ret = index_list_get_node(list, name, &node)) <= 0) {
-		if (ret == 0) {
-			mailbox_list_set_error(_list, MAIL_ERROR_NOTFOUND,
-				T_MAIL_ERR_MAILBOX_NOT_FOUND(name));
+	if (ilist->sync_ctx != NULL) {
+		/* we could get here during sync from
+		   index_list_mailbox_create_selectable() */
+		view = ilist->sync_ctx->view;
+		node = mailbox_list_index_lookup(&list->list, name);
+		if (node == NULL) {
+			seq = 0;
+			ret = 0;
+		} else if (mail_index_lookup_seq(view, node->uid, &seq)) {
+			ret = 1;
+		} else {
+			i_panic("mailbox list index: lost uid=%u", node->uid);
 		}
-		return -1;
+	} else {
+		view = mail_index_view_open(ilist->index);
+		ret = index_list_get_refreshed_node_seq(list, view, name, &node, &seq);
+		if (ret < 0) {
+			mail_index_view_close(&view);
+			return -1;
+		}
 	}
-	/* we could get here during sync from
-	   index_list_mailbox_create_selectable() */
-	view = ilist->sync_ctx == NULL ? mail_index_view_open(ilist->index) :
-		ilist->sync_ctx->view;
-	if (!mail_index_lookup_seq(view, node->uid, &seq))
-		i_panic("mailbox list index: lost uid=%u", node->uid);
-	if (!mailbox_list_index_status(_list, view, seq, 0,
-				       &status, mailbox_guid) ||
-	    guid_128_is_empty(mailbox_guid)) {
+	i_assert(ret == 0 || seq != 0);
+	if (ret == 0) {
+		mailbox_list_set_error(_list, MAIL_ERROR_NOTFOUND,
+				       T_MAIL_ERR_MAILBOX_NOT_FOUND(name));
+		ret = -1;
+	} else if (!mailbox_list_index_status(_list, view, seq, 0,
+					      &status, mailbox_guid) ||
+		   guid_128_is_empty(mailbox_guid)) {
 		mailbox_list_set_error(_list, MAIL_ERROR_NOTFOUND,
 				       T_MAIL_ERR_MAILBOX_NOT_FOUND(name));
 		ret = -1;
@@ -188,7 +228,7 @@
 
 	*existence_r = MAILBOX_EXISTENCE_NONE;
 
-	if ((ret = index_list_get_node(list, name, &node)) < 0)
+	if ((ret = index_list_get_refreshed_node(list, name, &node)) < 0)
 		return -1;
 	if (ret == 0)
 		return 0;
@@ -435,16 +475,12 @@
 	const void *data;
 	bool expunged;
 	uint32_t seq;
-	int ret;
 
 	if (mailbox_list_index_sync_begin(&list->list, &sync_ctx) < 0)
 		return -1;
 
-	if ((ret = index_list_get_node(list, name, &node)) < 0) {
-		(void)mailbox_list_index_sync_end(&sync_ctx, FALSE);
-		return -1;
-	}
-	if (ret == 0) {
+	node = mailbox_list_index_lookup(&list->list, name);
+	if (node == NULL) {
 		(void)mailbox_list_index_sync_end(&sync_ctx, FALSE);
 		mailbox_list_set_error(&list->list, MAIL_ERROR_NOTFOUND,
 				       T_MAIL_ERR_MAILBOX_NOT_FOUND(name));
@@ -552,7 +588,6 @@
 	const void *data;
 	bool created, expunged;
 	uint32_t oldseq, newseq;
-	int ret;
 
 	if (_oldlist != _newlist) {
 		mailbox_list_set_error(_oldlist, MAIL_ERROR_NOTPOSSIBLE,
@@ -563,11 +598,8 @@
 	if (mailbox_list_index_sync_begin(&list->list, &sync_ctx) < 0)
 		return -1;
 
-	if ((ret = index_list_get_node(list, oldname, &oldnode)) < 0) {
-		(void)mailbox_list_index_sync_end(&sync_ctx, FALSE);
-		return -1;
-	}
-	if (ret == 0) {
+	oldnode = mailbox_list_index_lookup(&list->list, oldname);
+	if (oldnode == NULL) {
 		(void)mailbox_list_index_sync_end(&sync_ctx, FALSE);
 		mailbox_list_set_error(&list->list, MAIL_ERROR_NOTFOUND,
 			T_MAIL_ERR_MAILBOX_NOT_FOUND(oldname));
diff -r 2b84c33d5d11 -r 96f79038038f src/lib-storage/list/mailbox-list-index.c
--- a/src/lib-storage/list/mailbox-list-index.c	Tue Oct 07 20:29:16 2014 +0300
+++ b/src/lib-storage/list/mailbox-list-index.c	Tue Oct 07 21:35:44 2014 +0300
@@ -362,8 +362,6 @@
 int mailbox_list_index_refresh(struct mailbox_list *list)
 {
 	struct mailbox_list_index *ilist = INDEX_LIST_CONTEXT(list);
-	struct mail_index_view *view;
-	int ret;
 
 	if (ilist->syncing)
 		return 0;
@@ -376,6 +374,17 @@
 		return 0;
 	}
 
+	return mailbox_list_index_refresh_force(list);
+}
+
+int mailbox_list_index_refresh_force(struct mailbox_list *list)
+{
+	struct mailbox_list_index *ilist = INDEX_LIST_CONTEXT(list);
+	struct mail_index_view *view;
+	int ret;
+
+	i_assert(!ilist->syncing);
+
 	ilist->last_refresh_timeval = ioloop_timeval;
 	if (mailbox_list_index_index_open(list) < 0)
 		return -1;
diff -r 2b84c33d5d11 -r 96f79038038f src/lib-storage/list/mailbox-list-index.h
--- a/src/lib-storage/list/mailbox-list-index.h	Tue Oct 07 20:29:16 2014 +0300
+++ b/src/lib-storage/list/mailbox-list-index.h	Tue Oct 07 21:35:44 2014 +0300
@@ -142,7 +142,11 @@
 int mailbox_list_index_index_open(struct mailbox_list *list);
 bool mailbox_list_index_need_refresh(struct mailbox_list_index *ilist,
 				     struct mail_index_view *view);
+/* Refresh the index, but only if it hasn't been refreshed "recently"
+   (= within this same ioloop run) */
 int mailbox_list_index_refresh(struct mailbox_list *list);
+/* Refresh the index regardless of when the last refresh was done. */
+int mailbox_list_index_refresh_force(struct mailbox_list *list);
 void mailbox_list_index_refresh_later(struct mailbox_list *list);
 
 struct mailbox_list_index_node *


More information about the dovecot-cvs mailing list