From: Timo Sirainen Date: Tue, 1 Oct 2019 20:33:47 +0000 (+0300) Subject: lib-index: Don't rewrite dovecot.index if another process has already done it X-Git-Tag: 2.3.11.2~516 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e8754c0e182e3f8dab4c0b1a01032d0e5c82c71f;p=thirdparty%2Fdovecot%2Fcore.git lib-index: Don't rewrite dovecot.index if another process has already done it This mainly happened when there were multiple sessions accessing the index at the same time. --- diff --git a/src/lib-index/mail-index-map-read.c b/src/lib-index/mail-index-map-read.c index bf219320f4..73f0efc11c 100644 --- a/src/lib-index/mail-index-map-read.c +++ b/src/lib-index/mail-index-map-read.c @@ -313,6 +313,7 @@ mail_index_map_latest_file(struct mail_index *index, const char **reason_r) *reason_r = NULL; + index->reopen_main_index = FALSE; ret = mail_index_reopen_if_changed(index, reason_r); if (ret <= 0) { if (ret < 0) @@ -418,7 +419,7 @@ int mail_index_map(struct mail_index *index, index->map = mail_index_map_alloc(index); /* first try updating the existing mapping from transaction log. */ - if (index->initial_mapped) { + if (index->initial_mapped && !index->reopen_main_index) { /* we're not creating/opening the index. sync this as a view from transaction log. */ ret = mail_index_sync_map(&index->map, type, FALSE, "initial mapping"); diff --git a/src/lib-index/mail-index-private.h b/src/lib-index/mail-index-private.h index 67e63d2a7f..5faf525f8d 100644 --- a/src/lib-index/mail-index-private.h +++ b/src/lib-index/mail-index-private.h @@ -223,6 +223,7 @@ struct mail_index { bool modseqs_enabled:1; bool initial_create:1; bool initial_mapped:1; + bool reopen_main_index:1; bool fscked:1; }; diff --git a/src/lib-index/mail-index-write.c b/src/lib-index/mail-index-write.c index 791cf9f1ce..c0fd2f84cb 100644 --- a/src/lib-index/mail-index-write.c +++ b/src/lib-index/mail-index-write.c @@ -1,6 +1,7 @@ /* Copyright (c) 2003-2018 Dovecot authors, see the included COPYING file */ #include "lib.h" +#include "nfs-workarounds.h" #include "read-full.h" #include "write-full.h" #include "ostream.h" @@ -116,6 +117,40 @@ static int mail_index_recreate(struct mail_index *index) return ret; } +static bool mail_index_should_recreate(struct mail_index *index) +{ + struct stat st1, st2; + + if (nfs_safe_stat(index->filepath, &st1) < 0) { + if (errno != ENOENT) { + mail_index_set_syscall_error(index, "stat()"); + return FALSE; + } else if (index->fd == -1) { + /* main index hasn't been created yet */ + return TRUE; + } else { + /* mailbox was just deleted? don't log an error */ + return FALSE; + } + } + if (index->fd == -1) { + /* main index was just created by another process */ + return FALSE; + } + if (fstat(index->fd, &st2) < 0) { + if (!ESTALE_FSTAT(errno)) + mail_index_set_syscall_error(index, "fstat()"); + return FALSE; + } + if (st1.st_ino != st2.st_ino || + !CMP_DEV_T(st1.st_dev, st2.st_dev)) { + /* Index has already been recreated since we last read it. + We can't trust our decisions about whether to recreate it. */ + return FALSE; + } + return TRUE; +} + void mail_index_write(struct mail_index *index, bool want_rotate, const char *reason) { @@ -152,7 +187,12 @@ void mail_index_write(struct mail_index *index, bool want_rotate, } } - if (!MAIL_INDEX_IS_IN_MEMORY(index)) { + if (MAIL_INDEX_IS_IN_MEMORY(index)) + ; + else if (!mail_index_should_recreate(index)) { + /* make sure we don't keep getting back in here */ + index->reopen_main_index = TRUE; + } else { e_debug(index->event, "Recreating %s because: %s", index->filepath, reason); if (mail_index_recreate(index) < 0) {