From: Timo Sirainen Date: Fri, 25 Jun 2010 15:21:49 +0000 (+0100) Subject: Renamed fsync_disable to mail_fsync=optimized|always|never. X-Git-Tag: 2.0.rc1~84 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b780aa272b742a43579cdb523cc79cc8d4521306;p=thirdparty%2Fdovecot%2Fcore.git Renamed fsync_disable to mail_fsync=optimized|always|never. --HG-- branch : HEAD --- diff --git a/doc/example-config/conf.d/10-mail.conf b/doc/example-config/conf.d/10-mail.conf index 67193adae3..5fffaaf1b0 100644 --- a/doc/example-config/conf.d/10-mail.conf +++ b/doc/example-config/conf.d/10-mail.conf @@ -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. diff --git a/src/config/old-set-parser.c b/src/config/old-set-parser.c index 8095e89f01..244e91020a 100644 --- a/src/config/old-set-parser.c +++ b/src/config/old-set-parser.c @@ -130,6 +130,14 @@ old_settings_handle_root(struct config_parser_context *ctx, 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; diff --git a/src/config/settings-get.pl b/src/config/settings-get.pl index 58a6c1522c..61c2674337 100755 --- a/src/config/settings-get.pl +++ b/src/config/settings-get.pl @@ -5,6 +5,7 @@ print '#include "lib.h"'."\n"; 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 '."\n"; diff --git a/src/lib-index/mail-cache-compress.c b/src/lib-index/mail-cache-compress.c index 35129b41a9..86311d823e 100644 --- a/src/lib-index/mail-cache-compress.c +++ b/src/lib-index/mail-cache-compress.c @@ -297,7 +297,7 @@ mail_cache_copy(struct mail_cache *cache, struct mail_index_transaction *trans, 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); diff --git a/src/lib-index/mail-cache-transaction.c b/src/lib-index/mail-cache-transaction.c index ff1befba45..149724504a 100644 --- a/src/lib-index/mail-cache-transaction.c +++ b/src/lib-index/mail-cache-transaction.c @@ -836,7 +836,7 @@ mail_cache_header_fields_write(struct mail_cache_transaction_ctx *ctx, 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; diff --git a/src/lib-index/mail-cache.c b/src/lib-index/mail-cache.c index 77fb4f7f16..9c8c749ff9 100644 --- a/src/lib-index/mail-cache.c +++ b/src/lib-index/mail-cache.c @@ -657,7 +657,7 @@ int mail_cache_unlock(struct mail_cache *cache) 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()"); } diff --git a/src/lib-index/mail-index-private.h b/src/lib-index/mail-index-private.h index f31ee057bd..8d6c58535e 100644 --- a/src/lib-index/mail-index-private.h +++ b/src/lib-index/mail-index-private.h @@ -172,6 +172,7 @@ struct mail_index { 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; diff --git a/src/lib-index/mail-index-write.c b/src/lib-index/mail-index-write.c index b4d5e01147..659ee1748c 100644 --- a/src/lib-index/mail-index-write.c +++ b/src/lib-index/mail-index-write.c @@ -78,8 +78,7 @@ static int mail_index_recreate(struct mail_index *index) } 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 @@ void mail_index_write(struct mail_index *index, bool want_rotate) 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, diff --git a/src/lib-index/mail-index.c b/src/lib-index/mail-index.c index 667bde5667..9b56a274ac 100644 --- a/src/lib-index/mail-index.c +++ b/src/lib-index/mail-index.c @@ -84,10 +84,12 @@ void mail_index_free(struct mail_index **_index) 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 @@ int mail_index_open(struct mail_index *index, enum mail_index_open_flags flags) 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"); diff --git a/src/lib-index/mail-index.h b/src/lib-index/mail-index.h index dddde3542d..c59d03d975 100644 --- a/src/lib-index/mail-index.h +++ b/src/lib-index/mail-index.h @@ -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 @@ enum mail_index_open_flags { 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_view_sync_ctx; 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). */ diff --git a/src/lib-index/mail-transaction-log-append.c b/src/lib-index/mail-transaction-log-append.c index 3dc13e08ed..cf099bfb36 100644 --- a/src/lib-index/mail-transaction-log-append.c +++ b/src/lib-index/mail-transaction-log-append.c @@ -109,8 +109,8 @@ static int log_buffer_write(struct mail_transaction_log_append_ctx *ctx) } 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, diff --git a/src/lib-index/mail-transaction-log-file.c b/src/lib-index/mail-transaction-log-file.c index cb6a555887..ca761d209b 100644 --- a/src/lib-index/mail-transaction-log-file.c +++ b/src/lib-index/mail-transaction-log-file.c @@ -548,7 +548,7 @@ mail_transaction_log_file_create2(struct mail_transaction_log_file *file, 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 @@ mail_transaction_log_file_create2(struct mail_transaction_log_file *file, 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 @@ static int 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 @@ mail_transaction_log_file_read(struct mail_transaction_log_file *file, 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 @@ mail_transaction_log_file_read(struct mail_transaction_log_file *file, 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 @@ int mail_transaction_log_file_map(struct mail_transaction_log_file *file, 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); diff --git a/src/lib-index/mail-transaction-log-private.h b/src/lib-index/mail-transaction-log-private.h index c92c2758ff..cf62854696 100644 --- a/src/lib-index/mail-transaction-log-private.h +++ b/src/lib-index/mail-transaction-log-private.h @@ -80,7 +80,6 @@ struct mail_transaction_log_file { 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 @@ struct mail_transaction_log { unsigned int dotlock_count; struct dotlock_settings dotlock_settings, new_dotlock_settings; struct dotlock *dotlock; + + unsigned int nfs_flush:1; }; void diff --git a/src/lib-index/mail-transaction-log.c b/src/lib-index/mail-transaction-log.c index 7be2a762fd..c4e411efe6 100644 --- a/src/lib-index/mail-transaction-log.c +++ b/src/lib-index/mail-transaction-log.c @@ -80,15 +80,12 @@ int mail_transaction_log_open(struct mail_transaction_log *log) 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 @@ mail_transaction_log_refresh(struct mail_transaction_log *log, bool nfs_flush) 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 @@ int mail_transaction_log_find_file(struct mail_transaction_log *log, 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) diff --git a/src/lib-index/mailbox-list-index-sync.c b/src/lib-index/mailbox-list-index-sync.c index d09672e7cb..6acc86fa13 100644 --- a/src/lib-index/mailbox-list-index-sync.c +++ b/src/lib-index/mailbox-list-index-sync.c @@ -875,8 +875,7 @@ mailbox_list_index_sync_write(struct mailbox_list_index_sync_ctx *ctx) 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()"); diff --git a/src/lib-index/mailbox-list-index.c b/src/lib-index/mailbox-list-index.c index d7d0898419..23ac6e96c5 100644 --- a/src/lib-index/mailbox-list-index.c +++ b/src/lib-index/mailbox-list-index.c @@ -274,7 +274,7 @@ int mailbox_list_index_file_create(struct mailbox_list_index *index, 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); diff --git a/src/lib-storage/index/cydir/cydir-save.c b/src/lib-storage/index/cydir/cydir-save.c index a86b3b7c36..4015dfc7f6 100644 --- a/src/lib-storage/index/cydir/cydir-save.c +++ b/src/lib-storage/index/cydir/cydir-save.c @@ -171,7 +171,7 @@ int cydir_save_finish(struct mail_save_context *_ctx) 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); diff --git a/src/lib-storage/index/cydir/cydir-storage.c b/src/lib-storage/index/cydir/cydir-storage.c index 8b6c46bbe7..0132486487 100644 --- a/src/lib-storage/index/cydir/cydir-storage.c +++ b/src/lib-storage/index/cydir/cydir-storage.c @@ -55,9 +55,10 @@ cydir_mailbox_alloc(struct mail_storage *storage, struct mailbox_list *list, 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; diff --git a/src/lib-storage/index/dbox-common/dbox-file.c b/src/lib-storage/index/dbox-common/dbox-file.c index 3a61fbf7c3..fcdeed50ae 100644 --- a/src/lib-storage/index/dbox-common/dbox-file.c +++ b/src/lib-storage/index/dbox-common/dbox-file.c @@ -520,6 +520,8 @@ void dbox_file_append_rollback(struct dbox_file_append_context **_ctx) 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 @@ int dbox_file_append_flush(struct dbox_file_append_context *ctx) 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 @@ const char *dbox_file_metadata_get(struct dbox_file *file, 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 @@ int dbox_file_move(struct dbox_file *file, bool alt_path) 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 @@ int dbox_file_move(struct dbox_file *file, bool alt_path) 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 @@ int dbox_file_move(struct dbox_file *file, bool alt_path) /* 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; } diff --git a/src/lib-storage/index/dbox-multi/mdbox-map.c b/src/lib-storage/index/dbox-multi/mdbox-map.c index 046f638127..c831037847 100644 --- a/src/lib-storage/index/dbox-multi/mdbox-map.c +++ b/src/lib-storage/index/dbox-multi/mdbox-map.c @@ -57,6 +57,8 @@ mdbox_map_init(struct mdbox_storage *storage, struct mailbox_list *root_list, 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)); diff --git a/src/lib-storage/index/dbox-multi/mdbox-save.c b/src/lib-storage/index/dbox-multi/mdbox-save.c index 0211d0c402..87e3f1222f 100644 --- a/src/lib-storage/index/dbox-multi/mdbox-save.c +++ b/src/lib-storage/index/dbox-multi/mdbox-save.c @@ -310,6 +310,7 @@ void mdbox_transaction_save_commit_post(struct mail_save_context *_ctx, 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 @@ void mdbox_transaction_save_commit_post(struct mail_save_context *_ctx, } 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); } } diff --git a/src/lib-storage/index/dbox-multi/mdbox-storage.c b/src/lib-storage/index/dbox-multi/mdbox-storage.c index 12148f3697..cb727b3e2d 100644 --- a/src/lib-storage/index/dbox-multi/mdbox-storage.c +++ b/src/lib-storage/index/dbox-multi/mdbox-storage.c @@ -99,9 +99,10 @@ mdbox_mailbox_alloc(struct mail_storage *storage, struct mailbox_list *list, 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; diff --git a/src/lib-storage/index/dbox-single/sdbox-save.c b/src/lib-storage/index/dbox-single/sdbox-save.c index 1ff094caa1..491fe6267f 100644 --- a/src/lib-storage/index/dbox-single/sdbox-save.c +++ b/src/lib-storage/index/dbox-single/sdbox-save.c @@ -266,6 +266,7 @@ void sdbox_transaction_save_commit_post(struct mail_save_context *_ctx, 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 @@ void sdbox_transaction_save_commit_post(struct mail_save_context *_ctx, 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); } } diff --git a/src/lib-storage/index/dbox-single/sdbox-storage.c b/src/lib-storage/index/dbox-single/sdbox-storage.c index 4150c60bd8..3d5ea02c68 100644 --- a/src/lib-storage/index/dbox-single/sdbox-storage.c +++ b/src/lib-storage/index/dbox-single/sdbox-storage.c @@ -62,9 +62,10 @@ sdbox_mailbox_alloc(struct mail_storage *storage, struct mailbox_list *list, 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; diff --git a/src/lib-storage/index/index-storage.c b/src/lib-storage/index/index-storage.c index ca67f08479..356cd799a2 100644 --- a/src/lib-storage/index/index-storage.c +++ b/src/lib-storage/index/index-storage.c @@ -287,6 +287,8 @@ void index_storage_mailbox_alloc(struct mailbox *box, const char *name, 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)); diff --git a/src/lib-storage/index/maildir/maildir-save.c b/src/lib-storage/index/maildir/maildir-save.c index 163e5f7681..2f715d9d3f 100644 --- a/src/lib-storage/index/maildir/maildir-save.c +++ b/src/lib-storage/index/maildir/maildir-save.c @@ -549,7 +549,8 @@ static int maildir_save_finish_real(struct mail_save_context *_ctx) 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 @@ static int maildir_transaction_fsync_dirs(struct maildir_save_context *ctx, { 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) { diff --git a/src/lib-storage/index/maildir/maildir-uidlist.c b/src/lib-storage/index/maildir/maildir-uidlist.c index d373e98ef9..d5fc253116 100644 --- a/src/lib-storage/index/maildir/maildir-uidlist.c +++ b/src/lib-storage/index/maildir/maildir-uidlist.c @@ -1296,7 +1296,7 @@ static int maildir_uidlist_write_fd(struct maildir_uidlist *uidlist, int fd, 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); diff --git a/src/lib-storage/index/mbox/mbox-save.c b/src/lib-storage/index/mbox/mbox-save.c index f9a3891489..9911ec4bb2 100644 --- a/src/lib-storage/index/mbox/mbox-save.c +++ b/src/lib-storage/index/mbox/mbox-save.c @@ -781,7 +781,7 @@ int mbox_transaction_save_commit_pre(struct mail_save_context *_ctx) 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); diff --git a/src/lib-storage/mail-storage-settings.c b/src/lib-storage/mail-storage-settings.c index f58f2699aa..d67df15623 100644 --- a/src/lib-storage/mail-storage-settings.c +++ b/src/lib-storage/mail-storage-settings.c @@ -30,7 +30,7 @@ static const struct setting_define mail_storage_setting_defines[] = { 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 @@ const struct mail_storage_settings mail_storage_default_settings = { .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 @@ mail_storage_settings_to_index_flags(const struct mail_storage_settings *set) { 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 @@ static bool mail_storage_settings_check(void *_set, pool_t pool ATTR_UNUSED, 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; } diff --git a/src/lib-storage/mail-storage-settings.h b/src/lib-storage/mail-storage-settings.h index c4465fb617..aeb6b36ef1 100644 --- a/src/lib-storage/mail-storage-settings.h +++ b/src/lib-storage/mail-storage-settings.h @@ -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 @@ struct mail_storage_settings { 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 @@ struct mail_storage_settings { const char *pop3_uidl_format; enum file_lock_method parsed_lock_method; + enum fsync_mode parsed_fsync_mode; }; struct mail_namespace_settings { diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index 78f626f80c..61754327b7 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -144,6 +144,7 @@ headers = \ file-dotlock.h \ file-lock.h \ file-set-size.h \ + fsync-mode.h \ hash.h \ hash2.h \ hex-binary.h \ diff --git a/src/lib/fsync-mode.h b/src/lib/fsync-mode.h new file mode 100644 index 0000000000..58736144b0 --- /dev/null +++ b/src/lib/fsync-mode.h @@ -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