changeset 11634:7f19062f58fd HEAD

Renamed fsync_disable to mail_fsync=optimized|always|never.
author Timo Sirainen <tss@iki.fi>
date Fri, 25 Jun 2010 16:21:49 +0100
parents 0dc6f14c271d
children 9127a9f4a020
files doc/example-config/conf.d/10-mail.conf src/config/old-set-parser.c src/config/settings-get.pl src/lib-index/mail-cache-compress.c src/lib-index/mail-cache-transaction.c src/lib-index/mail-cache.c src/lib-index/mail-index-private.h src/lib-index/mail-index-write.c src/lib-index/mail-index.c src/lib-index/mail-index.h src/lib-index/mail-transaction-log-append.c src/lib-index/mail-transaction-log-file.c src/lib-index/mail-transaction-log-private.h src/lib-index/mail-transaction-log.c src/lib-index/mailbox-list-index-sync.c src/lib-index/mailbox-list-index.c src/lib-storage/index/cydir/cydir-save.c src/lib-storage/index/cydir/cydir-storage.c src/lib-storage/index/dbox-common/dbox-file.c src/lib-storage/index/dbox-multi/mdbox-map.c src/lib-storage/index/dbox-multi/mdbox-save.c src/lib-storage/index/dbox-multi/mdbox-storage.c src/lib-storage/index/dbox-single/sdbox-save.c src/lib-storage/index/dbox-single/sdbox-storage.c src/lib-storage/index/index-storage.c src/lib-storage/index/maildir/maildir-save.c src/lib-storage/index/maildir/maildir-uidlist.c src/lib-storage/index/mbox/mbox-save.c src/lib-storage/mail-storage-settings.c src/lib-storage/mail-storage-settings.h src/lib/Makefile.am src/lib/fsync-mode.h
diffstat 32 files changed, 130 insertions(+), 82 deletions(-) [+]
line wrap: on
line diff
--- a/doc/example-config/conf.d/10-mail.conf	Fri Jun 25 15:03:44 2010 +0100
+++ b/doc/example-config/conf.d/10-mail.conf	Fri Jun 25 16:21:49 2010 +0100
@@ -139,10 +139,11 @@
 # since version 3, so this should be safe to use nowadays by default.
 #dotlock_use_excl = yes
 
-# Don't use fsync() or fdatasync() calls. This makes the performance better
-# at the cost of potential data loss if the server (or the file server)
-# goes down.
-#fsync_disable = no
+# When to use fsync() or fdatasync() calls:
+#   optimized (default): Whenever necessary to avoid losing important data
+#   always: Useful with e.g. NFS when write()s are delayed
+#   never: Never use it (best performance, but crashes can lose data)
+#mail_fsync = optimized
 
 # Mail storage exists in NFS. Set this to yes to make Dovecot flush NFS caches
 # whenever needed. If you're using only a single mail server this isn't needed.
--- a/src/config/old-set-parser.c	Fri Jun 25 15:03:44 2010 +0100
+++ b/src/config/old-set-parser.c	Fri Jun 25 16:21:49 2010 +0100
@@ -130,6 +130,14 @@
 		set_rename(ctx, key, "ssl", value);
 		return TRUE;
 	}
+	if (strcmp(key, "fsync_disable") == 0) {
+		if (strcasecmp(value, "yes") == 0)
+			value = "never";
+		else if (strcasecmp(value, "no") == 0)
+			value = "optimized";
+		set_rename(ctx, key, "mail_fsync", value);
+		return TRUE;
+	}
 	if (strcmp(key, "dbox_rotate_size") == 0) {
 		set_rename(ctx, key, "mdbox_rotate_size", value);
 		return TRUE;
--- a/src/config/settings-get.pl	Fri Jun 25 15:03:44 2010 +0100
+++ b/src/config/settings-get.pl	Fri Jun 25 16:21:49 2010 +0100
@@ -5,6 +5,7 @@
 print '#include "array.h"'."\n";
 print '#include "var-expand.h"'."\n";
 print '#include "file-lock.h"'."\n";
+print '#include "fsync-mode.h"'."\n";
 print '#include "settings-parser.h"'."\n";
 print '#include "all-settings.h"'."\n";
 print '#include <stddef.h>'."\n";
--- a/src/lib-index/mail-cache-compress.c	Fri Jun 25 15:03:44 2010 +0100
+++ b/src/lib-index/mail-cache-compress.c	Fri Jun 25 16:21:49 2010 +0100
@@ -297,7 +297,7 @@
 
 	o_stream_destroy(&output);
 
-	if ((cache->index->flags & MAIL_INDEX_OPEN_FLAG_NFS_FLUSH) != 0) {
+	if (cache->index->fsync_mode == FSYNC_MODE_ALWAYS) {
 		if (fdatasync(fd) < 0) {
 			mail_cache_set_syscall_error(cache, "fdatasync()");
 			array_free(ext_offsets);
--- a/src/lib-index/mail-cache-transaction.c	Fri Jun 25 15:03:44 2010 +0100
+++ b/src/lib-index/mail-cache-transaction.c	Fri Jun 25 16:21:49 2010 +0100
@@ -836,7 +836,7 @@
 	if (mail_cache_write(cache, buffer->data, size, offset) < 0)
 		return -1;
 
-	if ((cache->index->flags & MAIL_INDEX_OPEN_FLAG_NFS_FLUSH) != 0) {
+	if (cache->index->fsync_mode == FSYNC_MODE_ALWAYS) {
 		if (fdatasync(cache->fd) < 0) {
 			mail_cache_set_syscall_error(cache, "fdatasync()");
 			return -1;
--- a/src/lib-index/mail-cache.c	Fri Jun 25 15:03:44 2010 +0100
+++ b/src/lib-index/mail-cache.c	Fri Jun 25 16:21:49 2010 +0100
@@ -657,7 +657,7 @@
 		mail_cache_update_need_compress(cache);
 	}
 
-	if ((cache->index->flags & MAIL_INDEX_OPEN_FLAG_NFS_FLUSH) != 0) {
+	if (cache->index->fsync_mode == FSYNC_MODE_ALWAYS) {
 		if (fdatasync(cache->fd) < 0)
 			mail_cache_set_syscall_error(cache, "fdatasync()");
 	}
--- a/src/lib-index/mail-index-private.h	Fri Jun 25 15:03:44 2010 +0100
+++ b/src/lib-index/mail-index-private.h	Fri Jun 25 16:21:49 2010 +0100
@@ -172,6 +172,7 @@
 
 	unsigned int open_count;
 	enum mail_index_open_flags flags;
+	enum fsync_mode fsync_mode;
 	enum mail_index_sync_type fsync_mask;
 	mode_t mode;
 	gid_t gid;
--- a/src/lib-index/mail-index-write.c	Fri Jun 25 15:03:44 2010 +0100
+++ b/src/lib-index/mail-index-write.c	Fri Jun 25 16:21:49 2010 +0100
@@ -78,8 +78,7 @@
 	}
 	o_stream_destroy(&output);
 
-	if (ret == 0 &&
-	    (index->flags & MAIL_INDEX_OPEN_FLAG_FSYNC_DISABLE) == 0) {
+	if (ret == 0 && index->fsync_mode != FSYNC_MODE_NEVER) {
 		if (fdatasync(fd) < 0) {
 			mail_index_file_set_syscall_error(index, path,
 							  "fdatasync()");
@@ -245,7 +244,7 @@
 		ret = mail_index_write_map_over(index);
 		if (ret < 0)
 			mail_index_set_syscall_error(index, "pwrite_full()");
-		else if ((index->flags & MAIL_INDEX_OPEN_FLAG_NFS_FLUSH) != 0) {
+		else if (index->fsync_mode == FSYNC_MODE_ALWAYS) {
 			ret = fdatasync(index->fd);
 			if (ret < 0) {
 				mail_index_set_syscall_error(index,
--- a/src/lib-index/mail-index.c	Fri Jun 25 15:03:44 2010 +0100
+++ b/src/lib-index/mail-index.c	Fri Jun 25 16:21:49 2010 +0100
@@ -84,10 +84,12 @@
 	i_free(index);
 }
 
-void mail_index_set_fsync_types(struct mail_index *index,
-				enum mail_index_sync_type fsync_mask)
+void mail_index_set_fsync_mode(struct mail_index *index,
+			       enum fsync_mode mode,
+			       enum mail_index_sync_type mask)
 {
-	index->fsync_mask = fsync_mask;
+	index->fsync_mode = mode;
+	index->fsync_mask = mask;
 }
 
 void mail_index_set_permissions(struct mail_index *index,
@@ -519,8 +521,8 @@
 	index->readonly = (flags & MAIL_INDEX_OPEN_FLAG_READONLY) != 0;
 
 	if ((flags & MAIL_INDEX_OPEN_FLAG_NFS_FLUSH) != 0 &&
-	    (flags & MAIL_INDEX_OPEN_FLAG_FSYNC_DISABLE) != 0)
-		i_fatal("nfs flush requires fsync_disable=no");
+	    index->fsync_mode != FSYNC_MODE_ALWAYS)
+		i_fatal("nfs flush requires mail_fsync=always");
 	if ((flags & MAIL_INDEX_OPEN_FLAG_NFS_FLUSH) != 0 &&
 	    (flags & MAIL_INDEX_OPEN_FLAG_MMAP_DISABLE) == 0)
 		i_fatal("nfs flush requires mmap_disable=yes");
--- a/src/lib-index/mail-index.h	Fri Jun 25 15:03:44 2010 +0100
+++ b/src/lib-index/mail-index.h	Fri Jun 25 16:21:49 2010 +0100
@@ -2,6 +2,7 @@
 #define MAIL_INDEX_H
 
 #include "file-lock.h"
+#include "fsync-mode.h"
 #include "mail-types.h"
 #include "seq-range-array.h"
 
@@ -17,8 +18,6 @@
 	MAIL_INDEX_OPEN_FLAG_MMAP_DISABLE	= 0x04,
 	/* Rely on O_EXCL when creating dotlocks */
 	MAIL_INDEX_OPEN_FLAG_DOTLOCK_USE_EXCL	= 0x10,
-	/* Don't fsync() or fdatasync() */
-	MAIL_INDEX_OPEN_FLAG_FSYNC_DISABLE	= 0x20,
 	/* Flush NFS attr/data/write cache when necessary */
 	MAIL_INDEX_OPEN_FLAG_NFS_FLUSH		= 0x40,
 	/* Open the index read-only */
@@ -207,10 +206,10 @@
 struct mail_index *mail_index_alloc(const char *dir, const char *prefix);
 void mail_index_free(struct mail_index **index);
 
-/* Specify the transaction types that are fsynced after writing.
-   Default is to fsync nothing. */
-void mail_index_set_fsync_types(struct mail_index *index,
-				enum mail_index_sync_type fsync_mask);
+/* Specify how often to do fsyncs. If mode is FSYNC_MODE_OPTIMIZED, the mask
+   can be used to specify which transaction types to fsync. */
+void mail_index_set_fsync_mode(struct mail_index *index, enum fsync_mode mode,
+			       enum mail_index_sync_type mask);
 void mail_index_set_permissions(struct mail_index *index,
 				mode_t mode, gid_t gid, const char *gid_origin);
 /* Set locking method and maximum time to wait for a lock (-1U = default). */
--- a/src/lib-index/mail-transaction-log-append.c	Fri Jun 25 15:03:44 2010 +0100
+++ b/src/lib-index/mail-transaction-log-append.c	Fri Jun 25 16:21:49 2010 +0100
@@ -109,8 +109,8 @@
 	}
 
 	if ((ctx->want_fsync &&
-	     (file->log->flags & MAIL_INDEX_OPEN_FLAG_FSYNC_DISABLE) == 0) ||
-	    (file->log->flags & MAIL_INDEX_OPEN_FLAG_NFS_FLUSH) != 0) {
+	     file->log->index->fsync_mode != FSYNC_MODE_NEVER) ||
+	    file->log->index->fsync_mode == FSYNC_MODE_ALWAYS) {
 		if (fdatasync(file->fd) < 0) {
 			mail_index_file_set_syscall_error(ctx->log->index,
 							  file->filepath,
--- a/src/lib-index/mail-transaction-log-file.c	Fri Jun 25 15:03:44 2010 +0100
+++ b/src/lib-index/mail-transaction-log-file.c	Fri Jun 25 16:21:49 2010 +0100
@@ -548,7 +548,7 @@
 	int fd, ret;
 	bool rename_existing;
 
-	if ((file->log->flags & MAIL_INDEX_OPEN_FLAG_NFS_FLUSH) != 0) {
+	if (file->log->nfs_flush) {
 		/* although we check also mtime and file size below, it's done
 		   only to fix broken log files. we don't bother flushing
 		   attribute cache just for that. */
@@ -614,9 +614,9 @@
 	if (write_full(new_fd, &file->hdr, sizeof(file->hdr)) < 0)
 		return log_file_set_syscall_error(file, "write_full()");
 
-	if ((file->log->flags & MAIL_INDEX_OPEN_FLAG_NFS_FLUSH) != 0) {
+	if (file->log->index->fsync_mode == FSYNC_MODE_ALWAYS) {
 		/* the header isn't important, so don't bother calling
-		   fdatasync() unless NFS is used */
+		   fdatasync() unless it's required */
 		if (fdatasync(new_fd) < 0)
 			return log_file_set_syscall_error(file, "fdatasync()");
 	}
@@ -1333,8 +1333,6 @@
 mail_transaction_log_file_read(struct mail_transaction_log_file *file,
 			       uoff_t start_offset, bool nfs_flush)
 {
-	bool index_nfs_flush =
-		(file->log->flags & MAIL_INDEX_OPEN_FLAG_NFS_FLUSH) != 0;
 	int ret;
 
 	i_assert(file->mmap_base == NULL);
@@ -1344,7 +1342,7 @@
 	   that we really should have read more, flush the cache and try again.
 	   if file is locked, the attribute cache was already flushed when
 	   refreshing the log. */
-	if (index_nfs_flush && nfs_flush) {
+	if (file->log->nfs_flush && nfs_flush) {
 		if (!file->locked)
 			nfs_flush_attr_cache_unlocked(file->filepath);
 		else {
@@ -1369,7 +1367,7 @@
 	if ((ret = mail_transaction_log_file_read_more(file)) <= 0)
 		return ret;
 
-	if (index_nfs_flush && !nfs_flush &&
+	if (file->log->nfs_flush && !nfs_flush &&
 	    mail_transaction_log_file_need_nfs_flush(file)) {
 		/* we didn't read enough data. flush and try again. */
 		return mail_transaction_log_file_read(file, start_offset, TRUE);
@@ -1556,7 +1554,7 @@
 		start_offset = file->sync_offset;
 	}
 
-	if ((file->log->flags & MAIL_INDEX_OPEN_FLAG_MMAP_DISABLE) == 0)
+	if ((file->log->index->flags & MAIL_INDEX_OPEN_FLAG_MMAP_DISABLE) == 0)
 		ret = mail_transaction_log_file_map_mmap(file, start_offset);
 	else {
 		mail_transaction_log_file_munmap(file);
--- a/src/lib-index/mail-transaction-log-private.h	Fri Jun 25 15:03:44 2010 +0100
+++ b/src/lib-index/mail-transaction-log-private.h	Fri Jun 25 16:21:49 2010 +0100
@@ -80,7 +80,6 @@
 struct mail_transaction_log {
 	struct mail_index *index;
         struct mail_transaction_log_view *views;
-	enum mail_index_open_flags flags;
 	char *filepath, *filepath2;
 
 	/* files is a linked list of all the opened log files. the list is
@@ -94,6 +93,8 @@
 	unsigned int dotlock_count;
         struct dotlock_settings dotlock_settings, new_dotlock_settings;
 	struct dotlock *dotlock;
+
+	unsigned int nfs_flush:1;
 };
 
 void
--- a/src/lib-index/mail-transaction-log.c	Fri Jun 25 15:03:44 2010 +0100
+++ b/src/lib-index/mail-transaction-log.c	Fri Jun 25 16:21:49 2010 +0100
@@ -80,15 +80,12 @@
 				    MAIL_TRANSACTION_LOG_SUFFIX, NULL);
 	log->filepath2 = i_strconcat(log->filepath, ".2", NULL);
 
-	log->flags = log->index->flags;
+	log->nfs_flush =
+		(log->index->flags & MAIL_INDEX_OPEN_FLAG_NFS_FLUSH) != 0;
 	log->dotlock_settings.use_excl_lock =
-		(log->flags & MAIL_INDEX_OPEN_FLAG_DOTLOCK_USE_EXCL) != 0;
-	log->dotlock_settings.nfs_flush =
-		(log->flags & MAIL_INDEX_OPEN_FLAG_NFS_FLUSH) != 0;
-	log->new_dotlock_settings.use_excl_lock =
-		(log->flags & MAIL_INDEX_OPEN_FLAG_DOTLOCK_USE_EXCL) != 0;
-	log->new_dotlock_settings.nfs_flush =
-		(log->flags & MAIL_INDEX_OPEN_FLAG_NFS_FLUSH) != 0;
+		(log->index->flags & MAIL_INDEX_OPEN_FLAG_DOTLOCK_USE_EXCL) != 0;
+	log->dotlock_settings.nfs_flush = log->nfs_flush;
+	log->new_dotlock_settings = log->dotlock_settings;
 
 	if (log->open_file != NULL)
 		mail_transaction_log_file_free(&log->open_file);
@@ -299,7 +296,7 @@
 	if (MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(log->head))
 		return 0;
 
-	if (nfs_flush && (log->flags & MAIL_INDEX_OPEN_FLAG_NFS_FLUSH) != 0)
+	if (nfs_flush && log->nfs_flush)
 		nfs_flush_file_handle_cache(log->filepath);
 	if (nfs_safe_stat(log->filepath, &st) < 0) {
 		if (errno != ENOENT) {
@@ -386,8 +383,7 @@
 		if (mail_transaction_log_refresh(log, FALSE) < 0)
 			return -1;
 		if (file_seq > log->head->hdr.file_seq) {
-			if (!nfs_flush ||
-			    (log->flags & MAIL_INDEX_OPEN_FLAG_NFS_FLUSH) == 0)
+			if (!nfs_flush || !log->nfs_flush)
 				return 0;
 			/* try again, this time flush attribute cache */
 			if (mail_transaction_log_refresh(log, TRUE) < 0)
--- a/src/lib-index/mailbox-list-index-sync.c	Fri Jun 25 15:03:44 2010 +0100
+++ b/src/lib-index/mailbox-list-index-sync.c	Fri Jun 25 16:21:49 2010 +0100
@@ -875,8 +875,7 @@
 			ret = -1;
 		}
 		if (ret == 0 &&
-		    (ctx->index->mail_index->flags &
-		     MAIL_INDEX_OPEN_FLAG_NFS_FLUSH) != 0 &&
+		    ctx->index->mail_index->fsync_mode == FSYNC_MODE_ALWAYS &&
 		    fdatasync(ctx->index->fd) < 0) {
 			mailbox_list_index_set_syscall_error(ctx->index,
 							     "fdatasync()");
--- a/src/lib-index/mailbox-list-index.c	Fri Jun 25 15:03:44 2010 +0100
+++ b/src/lib-index/mailbox-list-index.c	Fri Jun 25 16:21:49 2010 +0100
@@ -274,7 +274,7 @@
 		return -1;
 	}
 
-	if ((index->mail_index->flags & MAIL_INDEX_OPEN_FLAG_NFS_FLUSH) != 0 &&
+	if (index->mail_index->fsync_mode == FSYNC_MODE_ALWAYS &&
 	    fdatasync(fd) < 0) {
 		mailbox_list_index_set_syscall_error(index, "fdatasync()");
 		(void)file_dotlock_delete(&dotlock);
--- a/src/lib-storage/index/cydir/cydir-save.c	Fri Jun 25 15:03:44 2010 +0100
+++ b/src/lib-storage/index/cydir/cydir-save.c	Fri Jun 25 16:21:49 2010 +0100
@@ -171,7 +171,7 @@
 		ctx->failed = TRUE;
 	}
 
-	if (!storage->set->fsync_disable) {
+	if (storage->set->parsed_fsync_mode != FSYNC_MODE_NEVER) {
 		if (fsync(ctx->fd) < 0) {
 			mail_storage_set_critical(storage,
 						  "fsync(%s) failed: %m", path);
--- a/src/lib-storage/index/cydir/cydir-storage.c	Fri Jun 25 15:03:44 2010 +0100
+++ b/src/lib-storage/index/cydir/cydir-storage.c	Fri Jun 25 16:21:49 2010 +0100
@@ -55,9 +55,10 @@
 
 	index_storage_mailbox_alloc(&mbox->box, name, flags,
 				    CYDIR_INDEX_PREFIX);
-	mail_index_set_fsync_types(mbox->box.index,
-				   MAIL_INDEX_SYNC_TYPE_APPEND |
-				   MAIL_INDEX_SYNC_TYPE_EXPUNGE);
+	mail_index_set_fsync_mode(mbox->box.index,
+				  storage->set->parsed_fsync_mode,
+				  MAIL_INDEX_SYNC_TYPE_APPEND |
+				  MAIL_INDEX_SYNC_TYPE_EXPUNGE);
 
 	ibox = INDEX_STORAGE_CONTEXT(&mbox->box);
 	ibox->save_commit_pre = cydir_transaction_save_commit_pre;
--- a/src/lib-storage/index/dbox-common/dbox-file.c	Fri Jun 25 15:03:44 2010 +0100
+++ b/src/lib-storage/index/dbox-common/dbox-file.c	Fri Jun 25 16:21:49 2010 +0100
@@ -520,6 +520,8 @@
 
 int dbox_file_append_flush(struct dbox_file_append_context *ctx)
 {
+	struct mail_storage *storage = &ctx->file->storage->storage;
+
 	if (ctx->last_flush_offset == ctx->output->offset)
 		return 0;
 
@@ -528,7 +530,7 @@
 		return -1;
 	}
 
-	if (!ctx->file->storage->storage.set->fsync_disable) {
+	if (storage->set->parsed_fsync_mode != FSYNC_MODE_NEVER) {
 		if (fdatasync(ctx->file->fd) < 0) {
 			dbox_file_set_syscall_error(ctx->file, "fdatasync()");
 			return -1;
@@ -678,6 +680,7 @@
 
 int dbox_file_move(struct dbox_file *file, bool alt_path)
 {
+	struct mail_storage *storage = &file->storage->storage;
 	struct ostream *output;
 	const char *dest_dir, *temp_path, *dest_path, *p;
 	struct stat st;
@@ -716,30 +719,30 @@
 		ret = o_stream_flush(output);
 	if (output->stream_errno != 0) {
 		errno = output->stream_errno;
-		mail_storage_set_critical(&file->storage->storage,
-					  "write(%s) failed: %m", temp_path);
+		mail_storage_set_critical(storage, "write(%s) failed: %m",
+					  temp_path);
 		ret = -1;
 	} else if (file->input->stream_errno != 0) {
 		errno = file->input->stream_errno;
 		dbox_file_set_syscall_error(file, "ftruncate()");
 		ret = -1;
 	} else if (ret < 0) {
-		mail_storage_set_critical(&file->storage->storage,
+		mail_storage_set_critical(storage,
 			"o_stream_send_istream(%s, %s) "
 			"failed with unknown error",
 			temp_path, file->cur_path);
 	}
 	o_stream_unref(&output);
 
-	if (!file->storage->storage.set->fsync_disable && ret == 0) {
+	if (storage->set->parsed_fsync_mode != FSYNC_MODE_NEVER && ret == 0) {
 		if (fsync(out_fd) < 0) {
-			mail_storage_set_critical(&file->storage->storage,
+			mail_storage_set_critical(storage,
 				"fsync(%s) failed: %m", temp_path);
 			ret = -1;
 		}
 	}
 	if (close(out_fd) < 0) {
-		mail_storage_set_critical(&file->storage->storage,
+		mail_storage_set_critical(storage,
 			"close(%s) failed: %m", temp_path);
 		ret = -1;
 	}
@@ -752,14 +755,14 @@
 	   destination file. the destination shouldn't exist, but if it does
 	   its contents should be the same (except for maybe older metadata) */
 	if (rename(temp_path, dest_path) < 0) {
-		mail_storage_set_critical(&file->storage->storage,
+		mail_storage_set_critical(storage,
 			"rename(%s, %s) failed: %m", temp_path, dest_path);
 		(void)unlink(temp_path);
 		return -1;
 	}
-	if (!file->storage->storage.set->fsync_disable) {
+	if (storage->set->parsed_fsync_mode != FSYNC_MODE_NEVER) {
 		if (fdatasync_path(dest_dir) < 0) {
-			mail_storage_set_critical(&file->storage->storage,
+			mail_storage_set_critical(storage,
 				"fdatasync(%s) failed: %m", dest_dir);
 			(void)unlink(dest_path);
 			return -1;
@@ -779,7 +782,7 @@
 	/* file was successfully moved - reopen it */
 	dbox_file_close(file);
 	if (dbox_file_open(file, &deleted) <= 0) {
-		mail_storage_set_critical(&file->storage->storage,
+		mail_storage_set_critical(storage,
 			"dbox_file_move(%s): reopening file failed", dest_path);
 		return -1;
 	}
--- a/src/lib-storage/index/dbox-multi/mdbox-map.c	Fri Jun 25 15:03:44 2010 +0100
+++ b/src/lib-storage/index/dbox-multi/mdbox-map.c	Fri Jun 25 16:21:49 2010 +0100
@@ -57,6 +57,8 @@
 	map->set = storage->set;
 	map->path = i_strdup(path);
 	map->index = mail_index_alloc(path, MDBOX_GLOBAL_INDEX_PREFIX);
+	mail_index_set_fsync_mode(map->index,
+		MAP_STORAGE(map)->set->parsed_fsync_mode, 0);
 	mail_index_set_lock_method(map->index,
 		MAP_STORAGE(map)->set->parsed_lock_method,
 		mail_storage_get_lock_timeout(MAP_STORAGE(map), -1U));
--- a/src/lib-storage/index/dbox-multi/mdbox-save.c	Fri Jun 25 15:03:44 2010 +0100
+++ b/src/lib-storage/index/dbox-multi/mdbox-save.c	Fri Jun 25 16:21:49 2010 +0100
@@ -310,6 +310,7 @@
 					struct mail_index_transaction_commit_result *result)
 {
 	struct mdbox_save_context *ctx = (struct mdbox_save_context *)_ctx;
+	struct mail_storage *storage = _ctx->transaction->box->storage;
 
 	_ctx->transaction = NULL; /* transaction is already freed */
 
@@ -326,9 +327,10 @@
 	}
 	mdbox_map_append_free(&ctx->append_ctx);
 
-	if (!ctx->mbox->storage->storage.storage.set->fsync_disable) {
+	if (storage->set->parsed_fsync_mode != FSYNC_MODE_NEVER) {
 		if (fdatasync_path(ctx->mbox->box.path) < 0) {
-			i_error("fdatasync_path(%s) failed: %m",
+			mail_storage_set_critical(storage,
+				"fdatasync_path(%s) failed: %m",
 				ctx->mbox->box.path);
 		}
 	}
--- a/src/lib-storage/index/dbox-multi/mdbox-storage.c	Fri Jun 25 15:03:44 2010 +0100
+++ b/src/lib-storage/index/dbox-multi/mdbox-storage.c	Fri Jun 25 16:21:49 2010 +0100
@@ -99,9 +99,10 @@
 	mbox->box.mail_vfuncs = &mdbox_mail_vfuncs;
 
 	index_storage_mailbox_alloc(&mbox->box, name, flags, DBOX_INDEX_PREFIX);
-	mail_index_set_fsync_types(mbox->box.index,
-				   MAIL_INDEX_SYNC_TYPE_APPEND |
-				   MAIL_INDEX_SYNC_TYPE_EXPUNGE);
+	mail_index_set_fsync_mode(mbox->box.index,
+				  storage->set->parsed_fsync_mode,
+				  MAIL_INDEX_SYNC_TYPE_APPEND |
+				  MAIL_INDEX_SYNC_TYPE_EXPUNGE);
 
 	ibox = INDEX_STORAGE_CONTEXT(&mbox->box);
 	ibox->save_commit_pre = mdbox_transaction_save_commit_pre;
--- a/src/lib-storage/index/dbox-single/sdbox-save.c	Fri Jun 25 15:03:44 2010 +0100
+++ b/src/lib-storage/index/dbox-single/sdbox-save.c	Fri Jun 25 16:21:49 2010 +0100
@@ -266,6 +266,7 @@
 					struct mail_index_transaction_commit_result *result)
 {
 	struct sdbox_save_context *ctx = (struct sdbox_save_context *)_ctx;
+	struct mail_storage *storage = _ctx->transaction->box->storage;
 
 	_ctx->transaction = NULL; /* transaction is already freed */
 
@@ -280,9 +281,10 @@
 	if (sdbox_sync_finish(&ctx->sync_ctx, TRUE) < 0)
 		ctx->ctx.failed = TRUE;
 
-	if (!ctx->mbox->storage->storage.storage.set->fsync_disable) {
+	if (storage->set->parsed_fsync_mode != FSYNC_MODE_NEVER) {
 		if (fdatasync_path(ctx->mbox->box.path) < 0) {
-			i_error("fdatasync_path(%s) failed: %m",
+			mail_storage_set_critical(storage,
+				"fdatasync_path(%s) failed: %m",
 				ctx->mbox->box.path);
 		}
 	}
--- a/src/lib-storage/index/dbox-single/sdbox-storage.c	Fri Jun 25 15:03:44 2010 +0100
+++ b/src/lib-storage/index/dbox-single/sdbox-storage.c	Fri Jun 25 16:21:49 2010 +0100
@@ -62,9 +62,10 @@
 	mbox->box.mail_vfuncs = &sdbox_mail_vfuncs;
 
 	index_storage_mailbox_alloc(&mbox->box, name, flags, DBOX_INDEX_PREFIX);
-	mail_index_set_fsync_types(mbox->box.index,
-				   MAIL_INDEX_SYNC_TYPE_APPEND |
-				   MAIL_INDEX_SYNC_TYPE_EXPUNGE);
+	mail_index_set_fsync_mode(mbox->box.index,
+				  storage->set->parsed_fsync_mode,
+				  MAIL_INDEX_SYNC_TYPE_APPEND |
+				  MAIL_INDEX_SYNC_TYPE_EXPUNGE);
 
 	ibox = INDEX_STORAGE_CONTEXT(&mbox->box);
 	ibox->save_commit_pre = sdbox_transaction_save_commit_pre;
--- a/src/lib-storage/index/index-storage.c	Fri Jun 25 15:03:44 2010 +0100
+++ b/src/lib-storage/index/index-storage.c	Fri Jun 25 16:21:49 2010 +0100
@@ -287,6 +287,8 @@
 	mail_index_set_permissions(box->index, box->file_create_mode,
 				   box->file_create_gid,
 				   box->file_create_gid_origin);
+	mail_index_set_fsync_mode(box->index,
+				  box->storage->set->parsed_fsync_mode, 0);
 	mail_index_set_lock_method(box->index,
 		box->storage->set->parsed_lock_method,
 		mail_storage_get_lock_timeout(box->storage, -1U));
--- a/src/lib-storage/index/maildir/maildir-save.c	Fri Jun 25 15:03:44 2010 +0100
+++ b/src/lib-storage/index/maildir/maildir-save.c	Fri Jun 25 16:21:49 2010 +0100
@@ -549,7 +549,8 @@
 	output_errno = _ctx->output->stream_errno;
 	o_stream_destroy(&_ctx->output);
 
-	if (!storage->set->fsync_disable && !ctx->failed) {
+	if (storage->set->parsed_fsync_mode != FSYNC_MODE_NEVER &&
+	    !ctx->failed) {
 		if (fsync(ctx->fd) < 0) {
 			if (!mail_storage_set_error_from_errno(storage)) {
 				mail_storage_set_critical(storage,
@@ -675,7 +676,7 @@
 {
 	struct mail_storage *storage = &ctx->mbox->storage->storage;
 
-	if (storage->set->fsync_disable)
+	if (storage->set->parsed_fsync_mode == FSYNC_MODE_NEVER)
 		return 0;
 
 	if (new_changed) {
--- a/src/lib-storage/index/maildir/maildir-uidlist.c	Fri Jun 25 15:03:44 2010 +0100
+++ b/src/lib-storage/index/maildir/maildir-uidlist.c	Fri Jun 25 16:21:49 2010 +0100
@@ -1296,7 +1296,7 @@
 		return -1;
 	}
 
-	if (!storage->set->fsync_disable) {
+	if (storage->set->parsed_fsync_mode != FSYNC_MODE_NEVER) {
 		if (fdatasync(fd) < 0) {
 			mail_storage_set_critical(storage,
 				"fdatasync(%s) failed: %m", path);
--- a/src/lib-storage/index/mbox/mbox-save.c	Fri Jun 25 15:03:44 2010 +0100
+++ b/src/lib-storage/index/mbox/mbox-save.c	Fri Jun 25 16:21:49 2010 +0100
@@ -781,7 +781,7 @@
 		o_stream_flush(ctx->output);
 	}
 	if (mbox->mbox_fd != -1 && !mbox->mbox_writeonly &&
-	    !mbox->storage->storage.set->fsync_disable) {
+	    mbox->storage->storage.set->parsed_fsync_mode != FSYNC_MODE_NEVER) {
 		if (fdatasync(mbox->mbox_fd) < 0) {
 			mbox_set_syscall_error(mbox, "fdatasync()");
 			mbox_save_truncate(ctx);
--- a/src/lib-storage/mail-storage-settings.c	Fri Jun 25 15:03:44 2010 +0100
+++ b/src/lib-storage/mail-storage-settings.c	Fri Jun 25 16:21:49 2010 +0100
@@ -30,7 +30,7 @@
 	DEF(SET_UINT, mail_max_keyword_length),
 	DEF(SET_TIME, mail_max_lock_timeout),
 	DEF(SET_BOOL, mail_save_crlf),
-	DEF(SET_BOOL, fsync_disable),
+	DEF(SET_ENUM, mail_fsync),
 	DEF(SET_BOOL, mmap_disable),
 	DEF(SET_BOOL, dotlock_use_excl),
 	DEF(SET_BOOL, mail_nfs_storage),
@@ -54,7 +54,7 @@
 	.mail_max_keyword_length = 50,
 	.mail_max_lock_timeout = 0,
 	.mail_save_crlf = FALSE,
-	.fsync_disable = FALSE,
+	.mail_fsync = "optimized:never:always",
 	.mmap_disable = FALSE,
 	.dotlock_use_excl = FALSE,
 	.mail_nfs_storage = FALSE,
@@ -239,8 +239,6 @@
 {
 	enum mail_index_open_flags index_flags = 0;
 
-	if (set->fsync_disable)
-		index_flags |= MAIL_INDEX_OPEN_FLAG_FSYNC_DISABLE;
 #ifndef MMAP_CONFLICTS_WRITE
 	if (set->mmap_disable)
 #endif
@@ -291,12 +289,25 @@
 	bool uidl_format_ok;
 	char c;
 
+	if (strcmp(set->mail_fsync, "optimized") == 0)
+		set->parsed_fsync_mode = FSYNC_MODE_OPTIMIZED;
+	else if (strcmp(set->mail_fsync, "never") == 0)
+		set->parsed_fsync_mode = FSYNC_MODE_NEVER;
+	else if (strcmp(set->mail_fsync, "always") == 0)
+		set->parsed_fsync_mode = FSYNC_MODE_ALWAYS;
+	else {
+		*error_r = t_strdup_printf("Unknown mail_fsync: %s",
+					   set->mail_fsync);
+		return FALSE;
+	}
+
 	if (set->mail_nfs_index && !set->mmap_disable) {
 		*error_r = "mail_nfs_index=yes requires mmap_disable=yes";
 		return FALSE;
 	}
-	if (set->mail_nfs_index && set->fsync_disable) {
-		*error_r = "mail_nfs_index=yes requires fsync_disable=no";
+	if (set->mail_nfs_index &&
+	    set->parsed_fsync_mode != FSYNC_MODE_ALWAYS) {
+		*error_r = "mail_nfs_index=yes requires mail_fsync=always";
 		return FALSE;
 	}
 
--- a/src/lib-storage/mail-storage-settings.h	Fri Jun 25 15:03:44 2010 +0100
+++ b/src/lib-storage/mail-storage-settings.h	Fri Jun 25 16:21:49 2010 +0100
@@ -2,6 +2,7 @@
 #define MAIL_STORAGE_SETTINGS_H
 
 #include "file-lock.h"
+#include "fsync-mode.h"
 
 #define MAIL_STORAGE_SET_DRIVER_NAME "MAIL"
 
@@ -17,7 +18,7 @@
 	unsigned int mail_max_keyword_length;
 	unsigned int mail_max_lock_timeout;
 	bool mail_save_crlf;
-	bool fsync_disable;
+	const char *mail_fsync;
 	bool mmap_disable;
 	bool dotlock_use_excl;
 	bool mail_nfs_storage;
@@ -30,6 +31,7 @@
 	const char *pop3_uidl_format;
 
 	enum file_lock_method parsed_lock_method;
+	enum fsync_mode parsed_fsync_mode;
 };
 
 struct mail_namespace_settings {
--- a/src/lib/Makefile.am	Fri Jun 25 15:03:44 2010 +0100
+++ b/src/lib/Makefile.am	Fri Jun 25 16:21:49 2010 +0100
@@ -144,6 +144,7 @@
 	file-dotlock.h \
 	file-lock.h \
 	file-set-size.h \
+	fsync-mode.h \
 	hash.h \
 	hash2.h \
 	hex-binary.h \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/fsync-mode.h	Fri Jun 25 16:21:49 2010 +0100
@@ -0,0 +1,14 @@
+#ifndef FSYNC_MODE_H
+#define FSYNC_MODE_H
+
+enum fsync_mode {
+	/* fsync when it's necessary for data safety. */
+	FSYNC_MODE_OPTIMIZED = 0,
+	/* never fsync (in case of a crash can lose data) */
+	FSYNC_MODE_NEVER,
+	/* fsync after all writes. this is necessary with NFS to avoid
+	   write failures being delayed until file is close(). */
+	FSYNC_MODE_ALWAYS
+};
+
+#endif