From e11a55dee1f5ad36bfb6f5a9b2484ef63522df41 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Thu, 15 Nov 2012 03:42:50 +0000 Subject: [PATCH] pcu-fsync: add support for syncfs() on Linux (-f flag) Sometimes it is useful to just commit a single filesystem. This transparently falls back to using sync(2) if syncfs(2) is not available. --- Makefile | 2 ++ compat-util.h | 1 + fsync.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++++--- pcu-fsync.1.txt | 7 ++++++- 4 files changed, 58 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 0027fdd..b7d4ede 100644 --- a/Makefile +++ b/Makefile @@ -26,6 +26,8 @@ pcu-fsync: fsync.c compat-util.h PCU_BIN := pcu-fadvise pcu-mincore pcu-fsync +pcu-fsync: LDFLAGS += -ldl + $(PCU_BIN): $(CC) $(CFLAGS) $(LDFLAGS) -o $@+ $< mv $@+ $@ diff --git a/compat-util.h b/compat-util.h index 413dab7..d3520e1 100644 --- a/compat-util.h +++ b/compat-util.h @@ -1,6 +1,7 @@ #ifndef OS_COMPAT_H #define OS_COMPAT_H +#define _GNU_SOURCE #define _LARGE_FILES #define _FILE_OFFSET_BITS 64 #define _BSD_SOURCE /* for mincore */ diff --git a/fsync.c b/fsync.c index 994ca72..ebf039f 100644 --- a/fsync.c +++ b/fsync.c @@ -1,6 +1,7 @@ #include "compat-util.h" #include #include +#include #if defined(_POSIX_SYNCHRONIZED_IO) && _POSIX_SYNCHRONIZED_IO > 0 static int have_fdatasync = 1; @@ -16,6 +17,42 @@ static int usage(const char * argv0) return 1; } +#define FN_NOT_FOUND ((void *)(1)) + +static int fs_sync(const char *path) +{ + int rc = 0; +#if defined(__linux__) && defined(RTLD_NEXT) + static int (*syncfs_fn)(int); + + if (syncfs_fn == NULL) { + syncfs_fn = dlsym(RTLD_DEFAULT, "syncfs"); + if (syncfs_fn == NULL || dlerror()) + syncfs_fn = FN_NOT_FOUND; + } + if (syncfs_fn != NULL && syncfs_fn != FN_NOT_FOUND) { + int fd = open(path, O_RDONLY|O_NOATIME); + + if (fd >= 0) { + int err; + rc = syncfs_fn(fd); + err = errno; + close(fd); + + /* + * if glibc has syncfs(2) but we're running an + * old kernel, fall back to sync(2) below + */ + if (err != ENOSYS) + return rc; + rc = 0; + } + } +#endif /* ! __linux__ */ + sync(); + return rc; +} + static int do_sync(const char *path, int data_only, int directory) { int fd; @@ -80,11 +117,12 @@ err: int main(int argc, char * const argv[]) { int data_only = 0; + int fs = 0; int directory = 0; int opt; int argi = 1; - while ((opt = getopt(argc, argv, "dD")) != -1) { + while ((opt = getopt(argc, argv, "dDf")) != -1) { ++argi; switch(opt) { case 'd': @@ -93,6 +131,9 @@ int main(int argc, char * const argv[]) case 'D': directory = 1; break; + case 'f': + fs = 1; + break; default: return usage(argv[0]); } @@ -102,8 +143,13 @@ int main(int argc, char * const argv[]) return usage(argv[0]); for (; argi < argc; ++argi) { - if (do_sync(argv[argi], data_only, directory) < 0) - return 1; + if (fs) { + if (fs_sync(argv[argi]) < 0) + return 1; + } else { + if (do_sync(argv[argi], data_only, directory) < 0) + return 1; + } } return 0; diff --git a/pcu-fsync.1.txt b/pcu-fsync.1.txt index 958f0d3..3cafe08 100644 --- a/pcu-fsync.1.txt +++ b/pcu-fsync.1.txt @@ -6,7 +6,7 @@ pcu-fsync - synchronizes a files in-core state with storage device # SYNOPSIS -pcu-fsync [-D] [-d] FILE... +pcu-fsync [-D] [-d] [-f] FILE... # DESCRIPTION A command-line interface to the fsync(2) and fdatasync(2) system calls @@ -25,6 +25,11 @@ using applications that fail to explicitly do so. special cases where applications do not require the performance overhead of flushing metadata to the storage device. +-f +: Flush data on the filesystem containing the specified file + (or directory). This uses the syncfs(2) syscall under Linux, + and falls back to sync(2) if unavailable. + # OUTPUT Errors only. -- 2.11.4.GIT