From: Timo Sirainen Date: Wed, 28 Apr 2004 02:00:39 +0000 (+0300) Subject: Added fcntl_lock_disable setting to allow indexes to work with NFS. Some X-Git-Tag: 1.1.alpha1~4186 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=18398a5d21c88cbb34c601c6b6c1f9dea502e1ca;p=thirdparty%2Fdovecot%2Fcore.git Added fcntl_lock_disable setting to allow indexes to work with NFS. Some other locking fixes. --HG-- branch : HEAD --- diff --git a/dovecot-example.conf b/dovecot-example.conf index 9dea0ded5d..9a4dece6c3 100644 --- a/dovecot-example.conf +++ b/dovecot-example.conf @@ -255,6 +255,10 @@ # which use separate caches for them, such as OpenBSD. #mmap_no_write = no +# Don't use fcntl() locking. Alternatives are dotlocking and other tricks +# which may be slower. Required for NFS. +#fcntl_locks_disable = no + # Copy mail to another folders using hard links. This is much faster than # actually copying the file. This is problematic only if something modifies # the mail in one folder but doesn't want it modified in the others. I don't diff --git a/src/lib-index/mail-index-lock.c b/src/lib-index/mail-index-lock.c index 4cc057ec44..098dfa642d 100644 --- a/src/lib-index/mail-index-lock.c +++ b/src/lib-index/mail-index-lock.c @@ -76,6 +76,24 @@ static int mail_index_has_changed(struct mail_index *index) } } +static int mail_index_lock_mprotect(struct mail_index *index, int lock_type) +{ + int prot; + + if (index->map != NULL && + !MAIL_INDEX_MAP_IS_IN_MEMORY(index->map)) { + prot = lock_type == F_UNLCK ? PROT_NONE : + lock_type == F_WRLCK ? (PROT_READ|PROT_WRITE) : + PROT_READ; + if (mprotect(index->map->mmap_base, + index->map->file_size, prot) < 0) { + mail_index_set_syscall_error(index, "mprotect()"); + return -1; + } + } + return 0; +} + static int mail_index_lock(struct mail_index *index, int lock_type, unsigned int timeout_secs, int update_index, unsigned int *lock_id_r) @@ -84,6 +102,15 @@ static int mail_index_lock(struct mail_index *index, int lock_type, i_assert(lock_type == F_RDLCK || lock_type == F_WRLCK); + if (index->fcntl_locks_disable) { + /* FIXME: exclusive locking will rewrite the index file every + time. shouldn't really be needed.. reading doesn't require + locks then, though */ + if (lock_type == F_WRLCK) + return 0; + } else { + } + if (lock_type == F_WRLCK && index->lock_type == F_RDLCK) { /* drop shared locks */ i_assert(index->excl_lock_count == 0); @@ -148,16 +175,8 @@ static int mail_index_lock(struct mail_index *index, int lock_type, *lock_id_r = index->lock_id + 1; } - if (index->map != NULL && - !MAIL_INDEX_MAP_IS_IN_MEMORY(index->map)) { - int prot = PROT_READ | (lock_type == F_WRLCK ? PROT_WRITE : 0); - if (mprotect(index->map->mmap_base, - index->map->file_size, prot) < 0) { - mail_index_set_syscall_error(index, "mprotect()"); - return -1; - } - } - + if (mail_index_lock_mprotect(index, lock_type) < 0) + return -1; return 1; } @@ -189,6 +208,8 @@ static int mail_index_copy(struct mail_index *index) if (fd == -1) return -1; + (void)mail_index_lock_mprotect(index, F_RDLCK); + ret = write_full(fd, index->map->hdr, sizeof(*index->map->hdr)); if (ret < 0 || write_full(fd, index->map->records, index->map->records_count * @@ -300,7 +321,7 @@ int mail_index_lock_exclusive(struct mail_index *index, mail_index_unlock(index, lock_id); - *lock_id_r = 0; + *lock_id_r = index->lock_id + 1; return mail_index_lock_exclusive_copy(index); } @@ -314,7 +335,6 @@ static int mail_index_copy_lock_finish(struct mail_index *index) "file_try_lock()"); return -1; } - index->lock_id--; } if (fsync(index->fd) < 0) { @@ -367,7 +387,7 @@ void mail_index_unlock(struct mail_index *index, unsigned int lock_id) } } else { /* exclusive lock */ - i_assert(lock_id == index->lock_id+1); + i_assert(lock_id == index->lock_id + 1); i_assert(index->excl_lock_count > 0); if (--index->excl_lock_count == 0) mail_index_excl_unlock_finish(index); @@ -376,15 +396,13 @@ void mail_index_unlock(struct mail_index *index, unsigned int lock_id) if (index->shared_lock_count == 0 && index->excl_lock_count == 0) { index->lock_id += 2; index->lock_type = F_UNLCK; - if (index->map != NULL && - !MAIL_INDEX_MAP_IS_IN_MEMORY(index->map)) { - if (mprotect(index->map->mmap_base, - index->map->file_size, PROT_NONE) < 0) + (void)mail_index_lock_mprotect(index, F_UNLCK); + if (!index->fcntl_locks_disable) { + if (file_wait_lock(index->fd, F_UNLCK) < 0) { mail_index_set_syscall_error(index, - "mprotect()"); + "file_wait_lock()"); + } } - if (file_wait_lock(index->fd, F_UNLCK) < 0) - mail_index_set_syscall_error(index, "file_wait_lock()"); } } diff --git a/src/lib-index/mail-index-private.h b/src/lib-index/mail-index-private.h index bc8aac73fa..d99bef075e 100644 --- a/src/lib-index/mail-index-private.h +++ b/src/lib-index/mail-index-private.h @@ -1,6 +1,7 @@ #ifndef __MAIL_INDEX_PRIVATE_H #define __MAIL_INDEX_PRIVATE_H +#include "file-dotlock.h" #include "mail-index.h" struct mail_transaction_header; @@ -70,6 +71,7 @@ struct mail_index { int lock_type, shared_lock_count, excl_lock_count; unsigned int lock_id, copy_lock_id; char *copy_lock_path; + struct dotlock dotlock; char *error; unsigned int nodiskspace:1; @@ -79,6 +81,7 @@ struct mail_index { unsigned int log_locked:1; unsigned int mmap_disable:1; unsigned int mmap_no_write:1; + unsigned int fcntl_locks_disable:1; unsigned int readonly:1; unsigned int fsck:1; }; diff --git a/src/lib-index/mail-index.c b/src/lib-index/mail-index.c index 1439177757..cc0119ee89 100644 --- a/src/lib-index/mail-index.c +++ b/src/lib-index/mail-index.c @@ -575,6 +575,8 @@ int mail_index_open(struct mail_index *index, enum mail_index_open_flags flags) (flags & MAIL_INDEX_OPEN_FLAG_MMAP_DISABLE) != 0; index->mmap_no_write = (flags & MAIL_INDEX_OPEN_FLAG_MMAP_NO_WRITE) != 0; + index->fcntl_locks_disable = + (flags & MAIL_INDEX_OPEN_FLAG_FCNTL_LOCKS_DISABLE) != 0; index->readonly = FALSE; index->filepath = i_strconcat(index->dir, "/", diff --git a/src/lib-index/mail-index.h b/src/lib-index/mail-index.h index 78fa542fb4..02d813a77f 100644 --- a/src/lib-index/mail-index.h +++ b/src/lib-index/mail-index.h @@ -24,8 +24,8 @@ enum mail_index_open_flags { OSes that don't have unified buffer cache (currently OpenBSD <= 3.5) */ MAIL_INDEX_OPEN_FLAG_MMAP_NO_WRITE = 0x08, - /* Use only dotlocking, no fcntl() */ - MAIL_INDEX_OPEN_FLAG_USE_DOTLOCKS = 0x10 + /* Don't use fcntl() locking */ + MAIL_INDEX_OPEN_FLAG_FCNTL_LOCKS_DISABLE= 0x10 }; enum mail_index_header_compat_flags { diff --git a/src/lib-index/mail-transaction-log-private.h b/src/lib-index/mail-transaction-log-private.h index 801ace6c07..5cc8529dbf 100644 --- a/src/lib-index/mail-transaction-log-private.h +++ b/src/lib-index/mail-transaction-log-private.h @@ -1,6 +1,7 @@ #ifndef __MAIL_TRANSACTION_LOG_VIEW_H #define __MAIL_TRANSACTION_LOG_VIEW_H +#include "file-dotlock.h" #include "mail-transaction-log.h" struct mail_transaction_log_file { @@ -12,6 +13,7 @@ struct mail_transaction_log_file { char *filepath; int fd; int lock_type; + struct dotlock dotlock; ino_t st_ino; dev_t st_dev; diff --git a/src/lib-index/mail-transaction-log.c b/src/lib-index/mail-transaction-log.c index c75cac8871..7c2e2cf751 100644 --- a/src/lib-index/mail-transaction-log.c +++ b/src/lib-index/mail-transaction-log.c @@ -16,6 +16,11 @@ #include #include +/* this lock should never exist for a long time.. */ +#define LOG_DOTLOCK_TIMEOUT 30 +#define LOG_DOTLOCK_STALE_TIMEOUT 0 +#define LOG_DOTLOCK_IMMEDIATE_STALE_TIMEOUT 120 + struct mail_transaction_add_ctx { struct mail_transaction_log *log; struct mail_index_view *view; @@ -116,6 +121,54 @@ void mail_transaction_log_close(struct mail_transaction_log *log) i_free(log); } +static int +mail_transaction_log_file_dotlock(struct mail_transaction_log_file *file, + int lock_type) +{ + int ret; + + if (lock_type == F_UNLCK) { + ret = file_unlock_dotlock(file->filepath, &file->dotlock); + if (ret < 0) { + mail_index_file_set_syscall_error(file->log->index, + file->filepath, "file_unlock_dotlock()"); + return -1; + } + file->lock_type = F_UNLCK; + + if (ret == 0) { + mail_index_set_error(file->log->index, + "Dotlock was lost for transaction log file %s", + file->filepath); + return -1; + } + return 0; + } + + ret = file_lock_dotlock(file->filepath, NULL, FALSE, + LOG_DOTLOCK_TIMEOUT, + LOG_DOTLOCK_STALE_TIMEOUT, + LOG_DOTLOCK_IMMEDIATE_STALE_TIMEOUT, + NULL, NULL, &file->dotlock); + if (ret > 0) { + file->lock_type = F_WRLCK; + return 0; + } + if (ret < 0) { + mail_index_file_set_syscall_error(file->log->index, + file->filepath, + "file_lock_dotlock()"); + return -1; + } + + mail_index_set_error(file->log->index, + "Timeout while waiting for release of " + "dotlock for transaction log file %s", + file->filepath); + file->log->index->index_lock_timeout = TRUE; + return -1; +} + static int mail_transaction_log_file_lock(struct mail_transaction_log_file *file, int lock_type) @@ -128,6 +181,9 @@ mail_transaction_log_file_lock(struct mail_transaction_log_file *file, i_assert(file->lock_type == F_UNLCK); } + if (file->log->index->fcntl_locks_disable) + return mail_transaction_log_file_dotlock(file, lock_type); + ret = file_wait_lock_full(file->fd, lock_type, DEFAULT_LOCK_TIMEOUT, NULL, NULL); if (ret > 0) { @@ -233,8 +289,9 @@ static int mail_transaction_log_file_create(struct mail_transaction_log *log, unsigned int lock_id; int fd, fd2, ret; - /* this lock should never exist for a long time.. */ - fd = file_dotlock_open(path, NULL, 30, 0, 120, NULL, NULL); + fd = file_dotlock_open(path, NULL, LOG_DOTLOCK_TIMEOUT, + LOG_DOTLOCK_STALE_TIMEOUT, + LOG_DOTLOCK_IMMEDIATE_STALE_TIMEOUT, NULL, NULL); if (fd == -1) { mail_index_file_set_syscall_error(index, path, "file_dotlock_open()"); diff --git a/src/lib-storage/index/index-storage.c b/src/lib-storage/index/index-storage.c index dcc574029f..a5646c5fd7 100644 --- a/src/lib-storage/index/index-storage.c +++ b/src/lib-storage/index/index-storage.c @@ -316,6 +316,8 @@ index_storage_mailbox_init(struct index_storage *storage, struct mailbox *box, index_flags |= MAIL_INDEX_OPEN_FLAG_MMAP_DISABLE; if (getenv("MMAP_NO_WRITE") != NULL) index_flags |= MAIL_INDEX_OPEN_FLAG_MMAP_NO_WRITE; + if (getenv("FCNTL_LOCKS_DISABLE") != NULL) + index_flags |= MAIL_INDEX_OPEN_FLAG_FCNTL_LOCKS_DISABLE; do { ibox = i_new(struct index_mailbox, 1); diff --git a/src/master/mail-process.c b/src/master/mail-process.c index 0fe2c5a1c5..7b42a2fa54 100644 --- a/src/master/mail-process.c +++ b/src/master/mail-process.c @@ -265,6 +265,8 @@ int create_mail_process(struct login_group *group, int socket, env_put("MMAP_DISABLE=1"); if (set->mmap_no_write) env_put("MMAP_NO_WRITE=1"); + if (set->fcntl_locks_disable) + env_put("FCNTL_LOCKS_DISABLE=1"); if (set->maildir_copy_with_hardlinks) env_put("MAILDIR_COPY_WITH_HARDLINKS=1"); if (set->maildir_check_content_changes) diff --git a/src/master/master-settings.c b/src/master/master-settings.c index 58b0bfff69..5730887ce7 100644 --- a/src/master/master-settings.c +++ b/src/master/master-settings.c @@ -90,6 +90,7 @@ static struct setting_def setting_defs[] = { DEF(SET_BOOL, mail_read_mmaped), DEF(SET_BOOL, mmap_disable), DEF(SET_BOOL, mmap_no_write), + DEF(SET_BOOL, fcntl_locks_disable), DEF(SET_BOOL, maildir_copy_with_hardlinks), DEF(SET_BOOL, maildir_check_content_changes), DEF(SET_STR, mbox_locks), @@ -214,6 +215,7 @@ struct settings default_settings = { #else MEMBER(mmap_no_write) FALSE, #endif + MEMBER(fcntl_locks_disable) FALSE, MEMBER(maildir_copy_with_hardlinks) FALSE, MEMBER(maildir_check_content_changes) FALSE, MEMBER(mbox_locks) "dotlock fcntl", diff --git a/src/master/master-settings.h b/src/master/master-settings.h index 31c3095e46..d6ca4109c5 100644 --- a/src/master/master-settings.h +++ b/src/master/master-settings.h @@ -65,6 +65,7 @@ struct settings { int mail_read_mmaped; int mmap_disable; int mmap_no_write; + int fcntl_locks_disable; int maildir_copy_with_hardlinks; int maildir_check_content_changes; const char *mbox_locks;