]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
Fixed deadlocking and other locking issues.
authorTimo Sirainen <tss@iki.fi>
Tue, 6 May 2008 00:25:49 +0000 (03:25 +0300)
committerTimo Sirainen <tss@iki.fi>
Tue, 6 May 2008 00:25:49 +0000 (03:25 +0300)
--HG--
branch : HEAD

src/imap/imap-thread.c
src/lib-index/mail-hash.c
src/lib-index/mail-hash.h

index 79113cc8e6aa24f00ff2d243ee3655a813ab751b..75270c37a0ef9c50308ba7b11f9edad8993653bc 100644 (file)
@@ -224,7 +224,8 @@ imap_thread_try_use_hash(struct imap_thread_context *ctx,
                return FALSE;
        if (ret == 0) {
                /* doesn't exist, creating a new hash */
-               if (mail_hash_lock_exclusive(hash, TRUE) <= 0)
+               if (mail_hash_lock_exclusive(hash,
+                               MAIL_HASH_LOCK_FLAG_CREATE_MISSING) <= 0)
                        return FALSE;
                ctx->thread_ctx.hash_trans =
                        mail_hash_transaction_begin(hash, status->messages);
@@ -281,7 +282,8 @@ again:
        if (can_use && !shared_lock) {
                mail_hash_transaction_end(&hash_trans);
                mail_hash_unlock(hash);
-               if (mail_hash_lock_exclusive(hash, TRUE) <= 0)
+               if (mail_hash_lock_exclusive(hash,
+                               MAIL_HASH_LOCK_FLAG_CREATE_MISSING) <= 0)
                        return FALSE;
                shared_lock = TRUE;
                goto again;
@@ -323,7 +325,8 @@ imap_thread_context_init(struct imap_thread_mailbox *tbox,
                                       mail_thread_hash_cmp,
                                       mail_thread_hash_remap,
                                       tbox);
-               if (mail_hash_lock_exclusive(hash, TRUE) <= 0)
+               if (mail_hash_lock_exclusive(hash,
+                               MAIL_HASH_LOCK_FLAG_CREATE_MISSING) <= 0)
                        i_unreached();
                ctx->thread_ctx.hash_trans =
                        mail_hash_transaction_begin(hash, 0);
@@ -487,7 +490,9 @@ imap_thread_expunge_handler(struct mail_index_sync_map_ctx *sync_ctx,
                /* init */
                tbox->ctx = ctx = i_new(struct thread_context, 1);
 
-               if (mail_hash_lock_exclusive(tbox->hash, FALSE) <= 0)
+               /* we can't wait the lock in here or we could deadlock. */
+               if (mail_hash_lock_exclusive(tbox->hash,
+                                            MAIL_HASH_LOCK_FLAG_TRY) <= 0)
                        return 0;
 
                ctx->hash = tbox->hash;
index 842aef9a476a4d6cba257dabf072729fd29fa339..b6a3b5b8cce76ff370f5ca3f50c73ea66594835c 100644 (file)
@@ -479,7 +479,8 @@ int mail_hash_lock_shared(struct mail_hash *hash)
 }
 
 static int
-mail_hash_lock_exclusive_fd(struct mail_hash *hash, bool create_missing)
+mail_hash_lock_exclusive_fd(struct mail_hash *hash,
+                           enum mail_hash_lock_flags flags)
 {
        bool exists = TRUE;
        int ret;
@@ -490,7 +491,8 @@ mail_hash_lock_exclusive_fd(struct mail_hash *hash, bool create_missing)
        if (hash->index->lock_method == FILE_LOCK_METHOD_DOTLOCK) {
                /* use dotlocking */
        } else if (hash->fd == -1 && (ret = mail_hash_open_fd(hash)) <= 0) {
-               if (ret < 0 || !create_missing)
+               if (ret < 0 ||
+                   (flags & MAIL_HASH_LOCK_FLAG_CREATE_MISSING) == 0)
                        return ret;
                /* the file doesn't exist - we need to use dotlocking */
                exists = FALSE;
@@ -501,6 +503,8 @@ mail_hash_lock_exclusive_fd(struct mail_hash *hash, bool create_missing)
                        /* success / error */
                        return ret;
                }
+               if ((flags & MAIL_HASH_LOCK_FLAG_TRY) != 0)
+                       return 0;
 
                /* already locked. if it's only read-locked, we can
                   overwrite the file. first wait for a shared lock. */
@@ -529,9 +533,7 @@ mail_hash_lock_exclusive_fd(struct mail_hash *hash, bool create_missing)
 
                        /* the file was created - we need to have it locked,
                           so retry this operation */
-                       (void)file_dotlock_delete(&hash->dotlock);
-                       return mail_hash_lock_exclusive_fd(hash,
-                                                          create_missing);
+                       return mail_hash_lock_exclusive_fd(hash, flags);
                }
        }
        /* other sessions are reading the file, we must not overwrite */
@@ -539,8 +541,10 @@ mail_hash_lock_exclusive_fd(struct mail_hash *hash, bool create_missing)
        return 1;
 }
 
-int mail_hash_lock_exclusive(struct mail_hash *hash, bool create_missing)
+int mail_hash_lock_exclusive(struct mail_hash *hash,
+                            enum mail_hash_lock_flags flags)
 {
+       bool create_missing = (flags & MAIL_HASH_LOCK_FLAG_CREATE_MISSING) != 0;
        int ret;
 
        i_assert(hash->lock_type == F_UNLCK);
@@ -552,7 +556,7 @@ int mail_hash_lock_exclusive(struct mail_hash *hash, bool create_missing)
                return 1;
        }
 
-       if ((ret = mail_hash_lock_exclusive_fd(hash, create_missing)) <= 0) {
+       if ((ret = mail_hash_lock_exclusive_fd(hash, flags)) <= 0) {
                mail_hash_unlock(hash);
                return ret;
        }
@@ -565,7 +569,7 @@ int mail_hash_lock_exclusive(struct mail_hash *hash, bool create_missing)
                if (ret == 0 && create_missing) {
                        /* the broken file was unlinked - try again */
                        mail_hash_file_close(hash);
-                       return mail_hash_lock_exclusive(hash, create_missing);
+                       return mail_hash_lock_exclusive(hash, flags);
                }
                return ret;
        }
index 286e4bf2f160ae853b4cc6aea040af2b4d02fa46..d1d2f77d15fdda7f32023f28f5fe4bdefc0d728f 100644 (file)
@@ -59,6 +59,11 @@ ARRAY_DEFINE_TYPE(mail_hash_record, struct mail_hash_record);
 #define MAIL_HASH_RECORD_IS_DELETED(rec) \
        ((rec)->next_idx == (uint32_t)-1)
 
+enum mail_hash_lock_flags {
+       MAIL_HASH_LOCK_FLAG_TRY                 = 0x01,
+       MAIL_HASH_LOCK_FLAG_CREATE_MISSING      = 0x02
+};
+
 /* Returns 0 if the pointers are equal. */
 typedef bool mail_hash_ctx_cmp_callback_t(struct mail_hash_transaction *trans,
                                          const void *key, uint32_t idx,
@@ -82,7 +87,10 @@ void mail_hash_free(struct mail_hash **hash);
 /* Lock the file. Returns 1 if locking was successful, 0 if file doesn't exist,
    -1 if error. */
 int mail_hash_lock_shared(struct mail_hash *hash);
-int mail_hash_lock_exclusive(struct mail_hash *hash, bool create_missing);
+/* If FLAG_TRY_LOCK is set and file is already locked, return 0.
+   Otherwise return values are identical with mail_hash_lock_shared() */
+int mail_hash_lock_exclusive(struct mail_hash *hash,
+                            enum mail_hash_lock_flags flags);
 void mail_hash_unlock(struct mail_hash *hash);
 
 struct mail_hash_transaction *