# 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.
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;
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";
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);
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;
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()");
}
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;
}
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()");
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,
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,
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");
#define MAIL_INDEX_H
#include "file-lock.h"
+#include "fsync-mode.h"
#include "mail-types.h"
#include "seq-range-array.h"
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 */
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). */
}
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,
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. */
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()");
}
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);
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 {
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);
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);
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
unsigned int dotlock_count;
struct dotlock_settings dotlock_settings, new_dotlock_settings;
struct dotlock *dotlock;
+
+ unsigned int nfs_flush:1;
};
void
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);
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) {
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)
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()");
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);
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);
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;
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;
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;
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;
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;
}
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;
/* 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;
}
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));
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 */
}
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);
}
}
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;
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 */
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);
}
}
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;
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));
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,
{
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) {
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);
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);
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),
.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,
{
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
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;
}
#define MAIL_STORAGE_SETTINGS_H
#include "file-lock.h"
+#include "fsync-mode.h"
#define MAIL_STORAGE_SET_DRIVER_NAME "MAIL"
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;
const char *pop3_uidl_format;
enum file_lock_method parsed_lock_method;
+ enum fsync_mode parsed_fsync_mode;
};
struct mail_namespace_settings {
file-dotlock.h \
file-lock.h \
file-set-size.h \
+ fsync-mode.h \
hash.h \
hash2.h \
hex-binary.h \
--- /dev/null
+#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