dovecot-1.2: Maildir saving: Fixed race condition bugs in uidlis...

dovecot at dovecot.org dovecot at dovecot.org
Mon May 4 23:48:59 EEST 2009


details:   http://hg.dovecot.org/dovecot-1.2/rev/6770f46971af
changeset: 9016:6770f46971af
user:      Timo Sirainen <tss at iki.fi>
date:      Mon May 04 14:28:31 2009 -0400
description:
Maildir saving: Fixed race condition bugs in uidlist handling, causing files to be given new UIDs sometimes.

diffstat:

1 file changed, 18 insertions(+), 10 deletions(-)
src/lib-storage/index/maildir/maildir-uidlist.c |   28 ++++++++++++++---------

diffs (103 lines):

diff -r 05a98aaf0aaf -r 6770f46971af src/lib-storage/index/maildir/maildir-uidlist.c
--- a/src/lib-storage/index/maildir/maildir-uidlist.c	Mon May 04 12:32:59 2009 -0400
+++ b/src/lib-storage/index/maildir/maildir-uidlist.c	Mon May 04 14:28:31 2009 -0400
@@ -91,6 +91,7 @@ struct maildir_uidlist {
 	unsigned int initial_hdr_read:1;
 	unsigned int initial_sync:1;
 	unsigned int retry_rewind:1;
+	unsigned int locked_refresh:1;
 };
 
 struct maildir_uidlist_sync_ctx {
@@ -171,6 +172,7 @@ static int maildir_uidlist_lock_timeout(
 	}
 
 	uidlist->lock_count++;
+	uidlist->locked_refresh = FALSE;
 
 	if (refresh) {
 		/* make sure we have the latest changes before
@@ -212,6 +214,7 @@ void maildir_uidlist_unlock(struct maild
 	if (--uidlist->lock_count > 0)
 		return;
 
+	uidlist->locked_refresh = FALSE;
 	(void)file_dotlock_delete(&uidlist->dotlock);
 }
 
@@ -814,6 +817,8 @@ int maildir_uidlist_refresh(struct maild
 	if (ret >= 0) {
 		uidlist->initial_read = TRUE;
 		uidlist->initial_hdr_read = TRUE;
+		if (UIDLIST_IS_LOCKED(uidlist))
+			uidlist->locked_refresh = TRUE;
 	}
         return ret;
 }
@@ -1021,7 +1026,10 @@ maildir_uidlist_set_ext_real(struct mail
 	rec->extensions = p_malloc(uidlist->record_pool, buf->used);
 	memcpy(rec->extensions, buf->data, buf->used);
 
-	uidlist->recreate = TRUE;
+	if (rec->uid != (uint32_t)-1) {
+		/* message already exists in uidlist, need to recreate it */
+		uidlist->recreate = TRUE;
+	}
 }
 
 void maildir_uidlist_set_ext(struct maildir_uidlist *uidlist, uint32_t uid,
@@ -1212,8 +1220,10 @@ static bool maildir_uidlist_want_compres
 {
 	unsigned int min_rewrite_count;
 
-	if (!ctx->uidlist->initial_read)
+	if (!ctx->uidlist->locked_refresh)
 		return FALSE;
+	if (ctx->uidlist->recreate)
+		return TRUE;
 
 	min_rewrite_count =
 		(ctx->uidlist->read_records_count + ctx->new_files_count) *
@@ -1225,12 +1235,10 @@ static bool maildir_uidlist_want_recreat
 {
 	struct maildir_uidlist *uidlist = ctx->uidlist;
 
-	if (uidlist->recreate ||
-	    ctx->finish_change_counter != uidlist->change_counter)
+	if (!uidlist->locked_refresh)
+		return FALSE;
+	if (ctx->finish_change_counter != uidlist->change_counter)
 		return TRUE;
-
-	if (!uidlist->initial_read)
-		return FALSE;
 
 	if (uidlist->fd == -1 || uidlist->version != UIDLIST_VERSION)
 		return TRUE;
@@ -1290,7 +1298,7 @@ static int maildir_uidlist_sync_update(s
 	if ((uoff_t)st.st_size != file_size) {
 		i_warning("%s: file size changed unexpectedly after write",
 			  uidlist->path);
-	} else {
+	} else if (uidlist->locked_refresh) {
 		uidlist->fd_size = st.st_size;
 		uidlist->last_read_offset = st.st_size;
 		maildir_uidlist_update_hdr(uidlist, &st);
@@ -1525,6 +1533,7 @@ void maildir_uidlist_sync_remove(struct 
 	unsigned int idx;
 
 	i_assert(ctx->partial);
+	i_assert(ctx->uidlist->locked_refresh);
 
 	rec = hash_table_lookup(ctx->uidlist->files, filename);
 	i_assert(rec != NULL);
@@ -1661,8 +1670,7 @@ void maildir_uidlist_sync_finish(struct 
 	ctx->uidlist->initial_sync = TRUE;
 
 	i_assert(ctx->locked || !ctx->changed);
-	if ((ctx->changed || ctx->uidlist->recreate ||
-	     maildir_uidlist_want_compress(ctx)) &&
+	if ((ctx->changed || maildir_uidlist_want_compress(ctx)) &&
 	    !ctx->failed && ctx->locked) T_BEGIN {
 		if (maildir_uidlist_sync_update(ctx) < 0)
 			ctx->failed = TRUE;


More information about the dovecot-cvs mailing list