From d4581cb9a1d178cb31416eb30d501a0e46878e45 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Sun, 9 Aug 2009 15:33:48 -0700 Subject: [PATCH] Add `pcu-sync' command This can be useful for calling fsync(2)/fdatasync(2) on individual files (and/or their containing directories). This can be used when a system-wide sync(2) is too expensive on a busy system. --- .gitignore | 1 + Makefile | 3 +- sync.c | 110 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 sync.c diff --git a/.gitignore b/.gitignore index 4b4583d..e4a8a6f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ pcu-mincore pcu-fadvise +pcu-sync GIT-VERSION-FILE *.1 *.html diff --git a/Makefile b/Makefile index 7871952..5d8a09e 100644 --- a/Makefile +++ b/Makefile @@ -22,8 +22,9 @@ LDFLAGS = -Wl,-O1 pcu-mincore: mincore.c compat-util.h pcu-fadvise: fadvise.c compat-util.h +pcu-sync: sync.c compat-util.h -PCU_BIN := pcu-fadvise pcu-mincore +PCU_BIN := pcu-fadvise pcu-mincore pcu-sync $(PCU_BIN): $(CC) $(CFLAGS) $(LDFLAGS) -o $@+ $< diff --git a/sync.c b/sync.c new file mode 100644 index 0000000..994ca72 --- /dev/null +++ b/sync.c @@ -0,0 +1,110 @@ +#include "compat-util.h" +#include +#include + +#if defined(_POSIX_SYNCHRONIZED_IO) && _POSIX_SYNCHRONIZED_IO > 0 +static int have_fdatasync = 1; +#else +static int have_fdatasync; +#endif + +/* TODO: sync_file_range() if on Linux */ + +static int usage(const char * argv0) +{ + fprintf(stderr, "Usage: %s [-d] [-D] FILE...\n", argv0); + return 1; +} + +static int do_sync(const char *path, int data_only, int directory) +{ + int fd; + const char *errfunc = ""; + + if ((fd = open(path, O_RDWR|O_NOATIME)) < 0) { + if (errno == EISDIR) { + directory = 1; + goto sync_dir; + } + errfunc = "open"; + goto err; + } + + if (data_only && have_fdatasync) { + if (fdatasync(fd) < 0) { + errfunc = "fdatasync"; + goto err; + } + } else { + if (fsync(fd) < 0) { + errfunc = "fsync"; + goto err; + } + } + + if (close(fd) < 0) { + errfunc = "close"; + goto err; + } + +sync_dir: + if (directory) { + char *dpath; + DIR *dir; + + if (!(dpath = strdup(path))){ + errfunc = "strdup"; + goto err; + } + if (!(dir = opendir(dirname(dpath)))) { + errfunc = "opendir"; + goto err; + } + if (fsync(dirfd(dir)) < 0) { + errfunc = "(directory) fsync"; + goto err; + } + if (closedir(dir) < 0) { + errfunc = "closedir"; + goto err; + } + free(dpath); + } + + return 0; +err: + fprintf(stderr, "%s: %s(): %s\n", path, errfunc, strerror(errno)); + return -1; +} + +int main(int argc, char * const argv[]) +{ + int data_only = 0; + int directory = 0; + int opt; + int argi = 1; + + while ((opt = getopt(argc, argv, "dD")) != -1) { + ++argi; + switch(opt) { + case 'd': + data_only = 1; + break; + case 'D': + directory = 1; + break; + default: + return usage(argv[0]); + } + } + + if (argi >= argc) + return usage(argv[0]); + + for (; argi < argc; ++argi) { + if (do_sync(argv[argi], data_only, directory) < 0) + return 1; + } + + return 0; +} -- 2.11.4.GIT