From: Timo Sirainen Date: Sun, 16 May 2004 20:20:24 +0000 (+0300) Subject: Locking fixes X-Git-Tag: 1.1.alpha1~4085 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ec1e30ecc38f0deddaf655413cf02d5972ddbc70;p=thirdparty%2Fdovecot%2Fcore.git Locking fixes --HG-- branch : HEAD --- diff --git a/src/lib-index/mail-index-lock.c b/src/lib-index/mail-index-lock.c index 6cf2d5019d..eb7937a93d 100644 --- a/src/lib-index/mail-index-lock.c +++ b/src/lib-index/mail-index-lock.c @@ -149,7 +149,7 @@ static int mail_index_lock(struct mail_index *index, int lock_type, unsigned int timeout_secs, int update_index, unsigned int *lock_id_r) { - int ret; + int ret, ret2; i_assert(lock_type == F_RDLCK || lock_type == F_WRLCK); @@ -166,8 +166,11 @@ static int mail_index_lock(struct mail_index *index, int lock_type, } if (update_index && index->excl_lock_count == 0) { - if (mail_index_has_changed(index) < 0) + if ((ret2 = mail_index_has_changed(index)) < 0) return -1; + if (ret > 0 && ret2 == 0) + return 1; + ret = 0; } if (ret > 0) @@ -192,16 +195,36 @@ static int mail_index_lock(struct mail_index *index, int lock_type, return 1; } - ret = file_wait_lock_full(index->fd, lock_type, timeout_secs, - NULL, NULL); - if (ret <= 0) { - if (ret == 0 || errno == EDEADLK) { - /* deadlock equals to timeout */ - return 0; + if (lock_type == F_RDLCK || !index->log_locked) { + ret = file_wait_lock_full(index->fd, lock_type, timeout_secs, + NULL, NULL); + if (ret < 0) { + mail_index_set_syscall_error(index, "file_wait_lock()"); + return -1; + } + } else { + /* this is kind of kludgy. we wish to avoid deadlocks while + trying to lock transaction log, but it can happen if our + process is holding transaction log lock and waiting for + index write lock, while the other process is holding index + read lock and waiting for transaction log lock. + + we don't have a problem with grabbing read index lock + because the only way for it to block is if it's + write-locked, which isn't allowed unless transaction log + is also locked. + + so, the workaround for this problem is that we simply try + locking once. if it doesn't work, just rewrite the file. + hopefully there won't be any other deadlocking issues. :) */ + ret = file_try_lock(index->fd, lock_type); + if (ret < 0) { + mail_index_set_syscall_error(index, "file_try_lock()"); + return -1; } - mail_index_set_syscall_error(index, "file_wait_lock()"); - return -1; } + if (ret == 0) + return 0; if (index->lock_type == F_UNLCK) index->lock_id += 2; @@ -291,7 +314,7 @@ static int mail_index_lock_exclusive_copy(struct mail_index *index) old_lock_type = index->lock_type; index->lock_type = F_WRLCK; - index->excl_lock_count++; + index->excl_lock_count++; if (mail_index_reopen(index, fd) < 0) { i_assert(index->excl_lock_count == 1); @@ -422,5 +445,10 @@ void mail_index_unlock(struct mail_index *index, unsigned int lock_id) int mail_index_is_locked(struct mail_index *index, unsigned int lock_id) { - return (index->lock_id ^ lock_id) <= 1; + if ((index->lock_id ^ lock_id) <= 1) { + i_assert(index->lock_type != F_UNLCK); + return TRUE; + } + + return FALSE; } diff --git a/src/lib-index/mail-index-view.c b/src/lib-index/mail-index-view.c index 4142392754..6b1a5ed410 100644 --- a/src/lib-index/mail-index-view.c +++ b/src/lib-index/mail-index-view.c @@ -50,11 +50,6 @@ int mail_index_view_lock_head(struct mail_index_view *view, int update_index) { unsigned int lock_id; - if (view->map != view->index->map) { - if (mail_index_view_map_protect(view) < 0) - return -1; - } - if (!mail_index_is_locked(view->index, view->lock_id)) { if (mail_index_lock_shared(view->index, update_index, &view->lock_id) < 0) @@ -78,6 +73,15 @@ int mail_index_view_lock_head(struct mail_index_view *view, int update_index) view->lock_id = lock_id; } + i_assert(view->index->lock_type != F_UNLCK); + + /* mail_index_lock_shared() may have reopened the file, + so do this after it. */ + if (view->map != view->index->map) { + if (mail_index_view_map_protect(view) < 0) + return -1; + } + return 0; } diff --git a/src/lib-index/mail-index.c b/src/lib-index/mail-index.c index ac4a8a4f42..0ae31dcfa6 100644 --- a/src/lib-index/mail-index.c +++ b/src/lib-index/mail-index.c @@ -574,6 +574,7 @@ int mail_index_open(struct mail_index *index, enum mail_index_open_flags flags) index->shared_lock_count = 0; index->excl_lock_count = 0; index->lock_type = F_UNLCK; + index->lock_id = 2; index->nodiskspace = FALSE; index->index_lock_timeout = FALSE;