From 5b0e1d75a207bb1c662f4495c0d8ba1e81a5bb7d Mon Sep 17 00:00:00 2001 From: Joran Dirk Greef Date: Mon, 2 Oct 2017 17:16:10 +0200 Subject: [PATCH] unix: fall back to fsync() if F_FULLFSYNC fails F_FULLFSYNC may fail on non-Apple block devices. Fixes: https://github.com/libuv/libuv/issues/1579 PR-URL: https://github.com/libuv/libuv/pull/1580 Reviewed-By: Ben Noordhuis Reviewed-By: Colin Ihrig --- src/unix/fs.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/src/unix/fs.c b/src/unix/fs.c index 2684c814..e0969a4c 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -132,26 +132,33 @@ while (0) -static ssize_t uv__fs_fdatasync(uv_fs_t* req) { -#if defined(__linux__) || defined(__sun) || defined(__NetBSD__) - return fdatasync(req->file); -#elif defined(__APPLE__) +static ssize_t uv__fs_fsync(uv_fs_t* req) { +#if defined(__APPLE__) /* Apple's fdatasync and fsync explicitly do NOT flush the drive write cache * to the drive platters. This is in contrast to Linux's fdatasync and fsync * which do, according to recent man pages. F_FULLFSYNC is Apple's equivalent - * for flushing buffered data to permanent storage. + * for flushing buffered data to permanent storage. If F_FULLFSYNC is not + * supported by the file system we should fall back to fsync(). This is the + * same approach taken by sqlite. */ - return fcntl(req->file, F_FULLFSYNC); + int r; + + r = fcntl(req->file, F_FULLFSYNC); + if (r != 0 && errno == ENOTTY) + r = fsync(req->file); + return r; #else return fsync(req->file); #endif } -static ssize_t uv__fs_fsync(uv_fs_t* req) { -#if defined(__APPLE__) - /* See the comment in uv__fs_fdatasync. */ - return fcntl(req->file, F_FULLFSYNC); +static ssize_t uv__fs_fdatasync(uv_fs_t* req) { +#if defined(__linux__) || defined(__sun) || defined(__NetBSD__) + return fdatasync(req->file); +#elif defined(__APPLE__) + /* See the comment in uv__fs_fsync. */ + return uv__fs_fsync(req); #else return fsync(req->file); #endif