other locking fixes.
--HG--
branch : HEAD
# 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
}
}
+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)
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);
*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;
}
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 *
mail_index_unlock(index, lock_id);
- *lock_id_r = 0;
+ *lock_id_r = index->lock_id + 1;
return mail_index_lock_exclusive_copy(index);
}
"file_try_lock()");
return -1;
}
- index->lock_id--;
}
if (fsync(index->fd) < 0) {
}
} 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);
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()");
}
}
#ifndef __MAIL_INDEX_PRIVATE_H
#define __MAIL_INDEX_PRIVATE_H
+#include "file-dotlock.h"
#include "mail-index.h"
struct mail_transaction_header;
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;
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;
};
(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, "/",
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 {
#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 {
char *filepath;
int fd;
int lock_type;
+ struct dotlock dotlock;
ino_t st_ino;
dev_t st_dev;
#include <stddef.h>
#include <sys/stat.h>
+/* 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;
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)
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) {
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()");
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);
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)
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),
#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",
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;