From: Timo Sirainen Date: Tue, 15 Jul 2003 18:26:42 +0000 (+0300) Subject: index_mmap_invalidate = yes now invalidate memory maps before accessing X-Git-Tag: 1.1.alpha1~4484 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=290d0477ac0fed6e0c5faa17d55364a971696923;p=thirdparty%2Fdovecot%2Fcore.git index_mmap_invalidate = yes now invalidate memory maps before accessing them. Setting this on should fix some problems with OpenBSD. It should also make it possible to use index files over NFS as long as lock daemon is used. It might be such a good idea however. --HG-- branch : HEAD --- diff --git a/configure.in b/configure.in index e72d4e700a..ca9ad24ea9 100644 --- a/configure.in +++ b/configure.in @@ -593,6 +593,44 @@ AC_TRY_COMPILE([ AC_MSG_RESULT(no) ]) +dnl * If mmap() plays nicely with write() +AC_MSG_CHECKING([whether we need to use MS_INVALIDATE with mmaps]) +AC_TRY_RUN([ + #include + #include + #include + #include + #include + #include + int main() { + /* return 0 if we're signed */ + int f = open("conftest.mmap", O_RDWR|O_CREAT|O_TRUNC); + void *mem; + if (f == -1) { + perror("open()"); + return 1; + } + write(f, "1", 2); + mem = mmap(NULL, 2, PROT_READ|PROT_WRITE, MAP_SHARED, f, 0); + if (mem == MAP_FAILED) { + perror("mmap()"); + return 1; + } + strcpy(mem, "2"); + msync(mem, 2, MS_SYNC); + lseek(f, 0, SEEK_SET); + write(f, "3", 2); + + return strcmp(mem, "3") == 0 ? 0 : 1; + } +], + AC_MSG_RESULT(no) +], [ + AC_MSG_RESULT(yes) + AC_DEFINE(NEED_MS_INVALIDATE,, Define if your mmap() implementation requires use of MS_INVALIDATE to work with write()) +]) + + dnl * Solaris compatible sendfilev() AC_CHECK_LIB(sendfile, sendfilev, [ LIBS="$LIBS -lsendfile" diff --git a/dovecot-example.conf b/dovecot-example.conf index a00311255b..2911a14e00 100644 --- a/dovecot-example.conf +++ b/dovecot-example.conf @@ -234,6 +234,7 @@ # Use mmap() instead of read() to read mail files. read() seems to be a bit # faster with my Linux/x86 and it's better with NFS, so that's the default. +# Note that OpenBSD 3.3 and older don't work right with mail_read_mmaped = yes. #mail_read_mmaped = no # Copy mail to another folders using hard links. This is much faster than @@ -286,6 +287,11 @@ # for multiple users, as the users could ptrace() each others processes then. #mail_drop_priv_before_exec = no +# Call mmap() with MS_INVALIDATE flag each time before accessing message +# indexes. This is currently required with OpenBSD 3.3 and older versions. +# It's also required if you insist on saving index files over NFS. +#index_mmap_invalidate = no + # Set max. process size in megabytes. Most of the memory goes to mmap()ing # files, so it shouldn't harm much even if this limit is set pretty high. #mail_process_size = 256 diff --git a/src/imap/cmd-append.c b/src/imap/cmd-append.c index d84759bebe..1380f21de9 100644 --- a/src/imap/cmd-append.c +++ b/src/imap/cmd-append.c @@ -67,7 +67,8 @@ int cmd_append(struct client *client) return TRUE; box = client->storage->open_mailbox(client->storage, - mailbox, FALSE, TRUE); + mailbox, mailbox_open_flags | + MAILBOX_OPEN_FAST); if (box == NULL) { client_send_storage_error(client); return TRUE; diff --git a/src/imap/cmd-copy.c b/src/imap/cmd-copy.c index 8428a89178..5245759fde 100644 --- a/src/imap/cmd-copy.c +++ b/src/imap/cmd-copy.c @@ -21,7 +21,8 @@ int cmd_copy(struct client *client) return TRUE; destbox = client->storage->open_mailbox(client->storage, - mailbox, FALSE, TRUE); + mailbox, mailbox_open_flags | + MAILBOX_OPEN_FAST); if (destbox == NULL) { client_send_storage_error(client); return TRUE; diff --git a/src/imap/cmd-select.c b/src/imap/cmd-select.c index 770db9544e..634e3260da 100644 --- a/src/imap/cmd-select.c +++ b/src/imap/cmd-select.c @@ -7,6 +7,7 @@ int _cmd_select_full(struct client *client, int readonly) { struct mailbox *box; struct mailbox_status status; + enum mailbox_open_flags flags; const char *mailbox; /* */ @@ -20,8 +21,10 @@ int _cmd_select_full(struct client *client, int readonly) client_send_untagged_storage_error(client); } - box = client->storage->open_mailbox(client->storage, mailbox, - readonly, FALSE); + flags = mailbox_open_flags; + if (readonly) + flags |= MAILBOX_OPEN_READONLY; + box = client->storage->open_mailbox(client->storage, mailbox, flags); if (box == NULL) { client_send_storage_error(client); return TRUE; diff --git a/src/imap/cmd-status.c b/src/imap/cmd-status.c index d53fe1822b..62c04a377d 100644 --- a/src/imap/cmd-status.c +++ b/src/imap/cmd-status.c @@ -65,7 +65,10 @@ static int get_mailbox_status(struct client *client, const char *mailbox, } else { /* open the mailbox */ box = client->storage->open_mailbox(client->storage, - mailbox, TRUE, TRUE); + mailbox, + mailbox_open_flags | + MAILBOX_OPEN_FAST | + MAILBOX_OPEN_READONLY); if (box == NULL) return FALSE; } diff --git a/src/imap/common.h b/src/imap/common.h index edcb7979af..667716e115 100644 --- a/src/imap/common.h +++ b/src/imap/common.h @@ -17,6 +17,7 @@ extern struct ioloop *ioloop; extern unsigned int max_custom_flag_length, mailbox_check_interval; extern unsigned int imap_max_line_length; +extern enum mailbox_open_flags mailbox_open_flags; extern string_t *capability_string; diff --git a/src/imap/main.c b/src/imap/main.c index f30ce7716a..a9be7d701a 100644 --- a/src/imap/main.c +++ b/src/imap/main.c @@ -24,6 +24,7 @@ struct ioloop *ioloop; unsigned int max_custom_flag_length, mailbox_check_interval; unsigned int imap_max_line_length; +enum mailbox_open_flags mailbox_open_flags; static struct module *modules; static char log_prefix[128]; /* syslog() needs this to be permanent */ @@ -147,6 +148,9 @@ static void main_init(void) mailbox_check_interval = str == NULL ? 0 : (unsigned int)strtoul(str, NULL, 10); + mailbox_open_flags = getenv("MMAP_INVALIDATE") != NULL ? + MAILBOX_OPEN_MMAP_INVALIDATE : 0; + client = client_create(hin, hout, storage); o_stream_cork(client->output); diff --git a/src/lib-index/mail-index-data.c b/src/lib-index/mail-index-data.c index c2f258ba74..cf30e2a9c5 100644 --- a/src/lib-index/mail-index-data.c +++ b/src/lib-index/mail-index-data.c @@ -133,6 +133,12 @@ static int mmap_update(struct mail_index_data *data, uoff_t pos, size_t size) { struct mail_index_data_header *hdr; + if (data->index->mmap_invalidate && data->mmap_base != NULL) { + if (msync(data->mmap_base, data->mmap_used_length, + MS_SYNC | MS_INVALIDATE) < 0) + return index_data_set_syscall_error(data, "msync()"); + } + if (data->header != NULL && data->header->indexid != data->index->indexid) { if (data->header->indexid != 0) { diff --git a/src/lib-index/mail-index.c b/src/lib-index/mail-index.c index 7efe0c8657..4d3c8ff234 100644 --- a/src/lib-index/mail-index.c +++ b/src/lib-index/mail-index.c @@ -89,6 +89,15 @@ int mail_index_mmap_update(struct mail_index *index) if (index->mmap_base != NULL) { index->header = (struct mail_index_header *) index->mmap_base; + if (index->mmap_invalidate) { + if (msync(index->mmap_base, + index->mmap_used_length, + MS_SYNC | MS_INVALIDATE) < 0) { + index_set_syscall_error(index, "msync()"); + return FALSE; + } + } + /* make sure file size hasn't changed */ if (index->header->sync_id == index->sync_id) { index->mmap_used_length = index->header->used_file_size; @@ -99,9 +108,13 @@ int mail_index_mmap_update(struct mail_index *index) return TRUE; } - if (msync(index->mmap_base, - index->mmap_used_length, MS_SYNC) < 0) - return index_set_syscall_error(index, "msync()"); + if (!index->mmap_invalidate) { + if (msync(index->mmap_base, + index->mmap_used_length, MS_SYNC) < 0) { + index_set_syscall_error(index, "msync()"); + return FALSE; + } + } if (munmap(index->mmap_base, index->mmap_full_length) < 0) return index_set_syscall_error(index, "munmap()"); diff --git a/src/lib-index/mail-index.h b/src/lib-index/mail-index.h index e72db06e8e..d6864b92ad 100644 --- a/src/lib-index/mail-index.h +++ b/src/lib-index/mail-index.h @@ -16,9 +16,11 @@ enum mail_index_open_flags { MAIL_INDEX_OPEN_FLAG_UPDATE_RECENT = 0x02, /* Compressing and cache updates are not performed */ MAIL_INDEX_OPEN_FLAG_FAST = 0x04, + /* Invalidate memory maps before accessing them */ + MAIL_INDEX_OPEN_FLAG_MMAP_INVALIDATE = 0x08, /* internal: we're creating the index */ - _MAIL_INDEX_OPEN_FLAG_CREATING = 0x10 + _MAIL_INDEX_OPEN_FLAG_CREATING = 0x100 }; enum mail_index_header_compat { @@ -433,6 +435,7 @@ struct mail_index { enum mail_data_field set_cache_fields; unsigned int anon_mmap:1; + unsigned int mmap_invalidate:1; unsigned int opened:1; unsigned int rebuilding:1; unsigned int mail_read_mmaped:1; @@ -460,7 +463,7 @@ struct mail_index { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ - 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0 #endif /* defaults - same as above but prefixed with mail_index_. */ diff --git a/src/lib-index/mail-modifylog.c b/src/lib-index/mail-modifylog.c index 2738970a4b..f198be9244 100644 --- a/src/lib-index/mail-modifylog.c +++ b/src/lib-index/mail-modifylog.c @@ -176,6 +176,12 @@ static int mmap_update(struct modify_log_file *file, int forced) struct modify_log_header *hdr; unsigned int extra; + if (file->log->index->mmap_invalidate && file->mmap_base != NULL) { + if (msync(file->mmap_base, file->mmap_used_length, + MS_SYNC | MS_INVALIDATE) < 0) + return modifylog_set_syscall_error(file, "msync()"); + } + if (!forced && file->header != NULL && file->mmap_full_length >= file->header->used_file_size) { file->mmap_used_length = file->header->used_file_size; diff --git a/src/lib-index/mail-tree.c b/src/lib-index/mail-tree.c index 75d173cb45..e6a1353cc6 100644 --- a/src/lib-index/mail-tree.c +++ b/src/lib-index/mail-tree.c @@ -131,6 +131,12 @@ static int mmap_verify(struct mail_tree *tree) int _mail_tree_mmap_update(struct mail_tree *tree, int forced) { + if (tree->index->mmap_invalidate && tree->mmap_base != NULL) { + if (msync(tree->mmap_base, tree->mmap_used_length, + MS_SYNC | MS_INVALIDATE) < 0) + return tree_set_syscall_error(tree, "msync()"); + } + debug_mprotect(tree->mmap_base, tree->mmap_full_length, tree->index); diff --git a/src/lib-storage/index/index-storage.c b/src/lib-storage/index/index-storage.c index c8dd2a830a..a3b0049763 100644 --- a/src/lib-storage/index/index-storage.c +++ b/src/lib-storage/index/index-storage.c @@ -299,20 +299,28 @@ int index_storage_lock(struct index_mailbox *ibox, struct index_mailbox * index_storage_mailbox_init(struct mail_storage *storage, struct mailbox *box, struct mail_index *index, const char *name, - int readonly, int fast) + enum mailbox_open_flags flags) { struct index_mailbox *ibox; - enum mail_index_open_flags flags; + enum mail_index_open_flags index_flags; i_assert(name != NULL); + index_flags = MAIL_INDEX_OPEN_FLAG_CREATE; + if ((flags & MAILBOX_OPEN_FAST) != 0) + index_flags |= MAIL_INDEX_OPEN_FLAG_FAST; + if ((flags & MAILBOX_OPEN_READONLY) != 0) + index_flags |= MAIL_INDEX_OPEN_FLAG_UPDATE_RECENT; + if ((flags & MAILBOX_OPEN_MMAP_INVALIDATE) != 0) + index_flags |= MAIL_INDEX_OPEN_FLAG_MMAP_INVALIDATE; + do { ibox = i_new(struct index_mailbox, 1); ibox->box = *box; ibox->box.storage = storage; ibox->box.name = i_strdup(name); - ibox->box.readonly = readonly; + ibox->box.readonly = (flags & MAILBOX_OPEN_READONLY) != 0; ibox->index = index; @@ -326,13 +334,7 @@ index_storage_mailbox_init(struct mail_storage *storage, struct mailbox *box, index->never_cache_fields = get_never_cache_fields(); - flags = MAIL_INDEX_OPEN_FLAG_CREATE; - if (fast) - flags |= MAIL_INDEX_OPEN_FLAG_FAST; - if (!readonly) - flags |= MAIL_INDEX_OPEN_FLAG_UPDATE_RECENT; - - if (!index->open(index, flags)) + if (!index->open(index, index_flags)) break; if (INDEX_IS_IN_MEMORY(index) && diff --git a/src/lib-storage/index/index-storage.h b/src/lib-storage/index/index-storage.h index 2ea1e0dcfa..0a5a4469a9 100644 --- a/src/lib-storage/index/index-storage.h +++ b/src/lib-storage/index/index-storage.h @@ -52,7 +52,7 @@ void index_storage_deinit(struct mail_storage *storage); struct index_mailbox * index_storage_mailbox_init(struct mail_storage *storage, struct mailbox *box, struct mail_index *index, const char *name, - int readonly, int fast); + enum mailbox_open_flags flags); int index_storage_mailbox_free(struct mailbox *box); int index_storage_sync_and_lock(struct index_mailbox *ibox, diff --git a/src/lib-storage/index/maildir/maildir-storage.c b/src/lib-storage/index/maildir/maildir-storage.c index ece3c050df..0c1292f8d1 100644 --- a/src/lib-storage/index/maildir/maildir-storage.c +++ b/src/lib-storage/index/maildir/maildir-storage.c @@ -321,7 +321,7 @@ static int verify_inbox(struct mail_storage *storage) static struct mailbox * maildir_open(struct mail_storage *storage, const char *name, - int readonly, int fast) + enum mailbox_open_flags flags) { struct index_mailbox *ibox; struct mail_index *index; @@ -338,7 +338,7 @@ maildir_open(struct mail_storage *storage, const char *name, } ibox = index_storage_mailbox_init(storage, &maildir_mailbox, - index, name, readonly, fast); + index, name, flags); if (ibox != NULL) ibox->expunge_locked = maildir_expunge_locked; return (struct mailbox *) ibox; @@ -359,7 +359,7 @@ static const char *inbox_fix_case(struct mail_storage *storage, static struct mailbox * maildir_open_mailbox(struct mail_storage *storage, - const char *name, int readonly, int fast) + const char *name, enum mailbox_open_flags flags) { const char *path; struct stat st; @@ -370,7 +370,7 @@ maildir_open_mailbox(struct mail_storage *storage, if (strcmp(name, "INBOX") == 0) { if (!verify_inbox(storage)) return NULL; - return maildir_open(storage, "INBOX", readonly, fast); + return maildir_open(storage, "INBOX", flags); } if (!maildir_is_valid_existing_name(name)) { @@ -386,7 +386,7 @@ maildir_open_mailbox(struct mail_storage *storage, !create_control_dir(storage, name)) return FALSE; - return maildir_open(storage, name, readonly, fast); + return maildir_open(storage, name, flags); } else if (errno == ENOENT) { mail_storage_set_error(storage, "Mailbox doesn't exist: %s", name); diff --git a/src/lib-storage/index/mbox/mbox-storage.c b/src/lib-storage/index/mbox/mbox-storage.c index af6648d53a..92bd9d326b 100644 --- a/src/lib-storage/index/mbox/mbox-storage.c +++ b/src/lib-storage/index/mbox/mbox-storage.c @@ -320,7 +320,7 @@ static const char *mbox_get_path(struct mail_storage *storage, const char *name) } static struct mailbox *mbox_open(struct mail_storage *storage, const char *name, - int readonly, int fast) + enum mailbox_open_flags flags) { struct index_mailbox *ibox; struct mail_index *index; @@ -347,7 +347,7 @@ static struct mailbox *mbox_open(struct mail_storage *storage, const char *name, } ibox = index_storage_mailbox_init(storage, &mbox_mailbox, index, - name, readonly, fast); + name, flags); if (ibox != NULL) ibox->expunge_locked = mbox_expunge_locked; return (struct mailbox *) ibox; @@ -355,7 +355,7 @@ static struct mailbox *mbox_open(struct mail_storage *storage, const char *name, static struct mailbox * mbox_open_mailbox(struct mail_storage *storage, - const char *name, int readonly, int fast) + const char *name, enum mailbox_open_flags flags) { const char *path; struct stat st; @@ -367,7 +367,7 @@ mbox_open_mailbox(struct mail_storage *storage, /* make sure inbox exists */ if (!verify_inbox(storage)) return FALSE; - return mbox_open(storage, "INBOX", readonly, fast); + return mbox_open(storage, "INBOX", flags); } if (!mbox_is_valid_existing_name(name)) { @@ -387,7 +387,7 @@ mbox_open_mailbox(struct mail_storage *storage, if (!create_mbox_index_dirs(storage, name)) return NULL; - return mbox_open(storage, name, readonly, fast); + return mbox_open(storage, name, flags); } if (ENOTFOUND(errno)) { diff --git a/src/lib-storage/mail-storage.h b/src/lib-storage/mail-storage.h index 08f88a73c9..757605cc52 100644 --- a/src/lib-storage/mail-storage.h +++ b/src/lib-storage/mail-storage.h @@ -5,6 +5,12 @@ struct message_size; #include "imap-util.h" +enum mailbox_open_flags { + MAILBOX_OPEN_READONLY = 0x01, + MAILBOX_OPEN_FAST = 0x02, + MAILBOX_OPEN_MMAP_INVALIDATE = 0x04 +}; + enum mailbox_list_flags { MAILBOX_LIST_SUBSCRIBED = 0x01, MAILBOX_LIST_FAST_FLAGS = 0x02, @@ -148,7 +154,7 @@ struct mail_storage { with possibly different readonly-state. */ struct mailbox *(*open_mailbox)(struct mail_storage *storage, const char *name, - int readonly, int fast); + enum mailbox_open_flags flags); /* name is allowed to contain multiple new hierarchy levels. If only_hierarchy is TRUE, the mailbox itself isn't created, just diff --git a/src/master/mail-process.c b/src/master/mail-process.c index b4e5f4b4ba..a57f207e23 100644 --- a/src/master/mail-process.c +++ b/src/master/mail-process.c @@ -214,6 +214,8 @@ int create_mail_process(struct login_group *group, int socket, env_put("MAILDIR_CHECK_CONTENT_CHANGES=1"); if (set->mail_full_filesystem_access) env_put("FULL_FILESYSTEM_ACCESS=1"); + if (set->index_mmap_invalidate) + env_put("MMAP_INVALIDATE=1"); (void)umask(set->umask); env_put(t_strconcat("MBOX_LOCKS=", set->mbox_locks, NULL)); diff --git a/src/master/master-settings.c b/src/master/master-settings.c index eccf2a7a80..59f634dfed 100644 --- a/src/master/master-settings.c +++ b/src/master/master-settings.c @@ -92,6 +92,7 @@ static struct setting_def setting_defs[] = { DEF(SET_INT, mbox_dotlock_change_timeout), DEF(SET_INT, umask), DEF(SET_BOOL, mail_drop_priv_before_exec), + DEF(SET_BOOL, index_mmap_invalidate), DEF(SET_STR, mail_executable), DEF(SET_INT, mail_process_size), @@ -193,6 +194,11 @@ struct settings default_settings = { MEMBER(mbox_dotlock_change_timeout) 30, MEMBER(umask) 0077, MEMBER(mail_drop_priv_before_exec) FALSE, +#ifdef NEED_MS_INVALIDATE + MEMBER(index_mmap_invalidate) TRUE, +#else + MEMBER(index_mmap_invalidate) FALSE, +#endif MEMBER(mail_executable) PKG_LIBEXECDIR"/imap", MEMBER(mail_process_size) 256, diff --git a/src/master/master-settings.h b/src/master/master-settings.h index 76583b2db6..64eb416470 100644 --- a/src/master/master-settings.h +++ b/src/master/master-settings.h @@ -79,6 +79,7 @@ struct settings { unsigned int mbox_dotlock_change_timeout; unsigned int umask; int mail_drop_priv_before_exec; + int index_mmap_invalidate; const char *mail_executable; unsigned int mail_process_size; diff --git a/src/pop3/client.c b/src/pop3/client.c index 339b1f5a23..91968d3434 100644 --- a/src/pop3/client.c +++ b/src/pop3/client.c @@ -106,6 +106,7 @@ static int init_mailbox(struct client *client) struct client *client_create(int hin, int hout, struct mail_storage *storage) { struct client *client; + enum mailbox_open_flags flags; client = i_new(struct client, 1); client->input = i_stream_create_file(hin, default_pool, @@ -122,7 +123,9 @@ struct client *client_create(int hin, int hout, struct mail_storage *storage) storage->set_callbacks(storage, &mail_storage_callbacks, client); - client->mailbox = storage->open_mailbox(storage, "INBOX", FALSE, FALSE); + flags = getenv("MMAP_INVALIDATE") != NULL ? + MAILBOX_OPEN_MMAP_INVALIDATE : 0; + client->mailbox = storage->open_mailbox(storage, "INBOX", flags); if (client->mailbox == NULL) { client_send_line(client, "-ERR No INBOX for user."); return NULL;