Hi,Since a --direct-io feature was requested a few times the past decade with little response and the actual patch is quite trivial, I patched both v3.0.9 and master branch and included the patches here.
If this functionality is acceptable I don't mind spending the additional effort to update the documentation, etc.
Beware that the underlying filesystem needs Direct I/O support, therefore for this to work on NFS, one needs the kernel CONFIG_NFS_DIRECTIO enabled (probably default these days anyway). This is the reason why --direct-io is not enabled by default and should be used with care. I don't know what the behavior is if the local or remote side do not support O_DIRECT.
In my tests it provides a much more stable copy process (on NFS) with improved performance, but I didn't do any prolonged repeated tests yet (I only used it during a large copy that was ongoing so I prefer not to juggle with numbers here). Please test yourself and report back.
Kind regards, -- -- dag wieers, d...@wieers.com, http://dag.wieers.com/ -- dagit linux solutions, i...@dagit.net, http://dagit.net/ [Any errors in spelling, tact or fact are transmission errors]
diff --git a/options.c b/options.c index 088202e..4f2a3f5 100644 --- a/options.c +++ b/options.c @@ -122,6 +122,7 @@ int blocking_io = -1; int checksum_seed = 0; int inplace = 0; int delay_updates = 0; +int direct_io = 0; long block_size = 0; /* "long" because popt can't set an int32. */ char number_separator; char *skip_compress = NULL; @@ -746,6 +747,7 @@ void usage(enum logcode F) rprintf(F," --partial keep partially transferred files\n"); rprintf(F," --partial-dir=DIR put a partially transferred file into DIR\n"); rprintf(F," --delay-updates put all updated files into place at transfer's end\n"); + rprintf(F," --direct-io don't use buffer cache for files being transfered\n"); rprintf(F," -m, --prune-empty-dirs prune empty directory chains from the file-list\n"); rprintf(F," --numeric-ids don't map uid/gid values by user/group name\n"); rprintf(F," --usermap=STRING custom username mapping\n"); @@ -977,6 +979,7 @@ static struct poptOption long_options[] = { {"partial-dir", 0, POPT_ARG_STRING, &partial_dir, 0, 0, 0 }, {"delay-updates", 0, POPT_ARG_VAL, &delay_updates, 1, 0, 0 }, {"no-delay-updates", 0, POPT_ARG_VAL, &delay_updates, 0, 0, 0 }, + {"direct-io", 'n', POPT_ARG_NONE, &direct_io, 0, 0, 0 }, {"prune-empty-dirs",'m', POPT_ARG_VAL, &prune_empty_dirs, 1, 0, 0 }, {"no-prune-empty-dirs",0,POPT_ARG_VAL, &prune_empty_dirs, 0, 0, 0 }, {"no-m", 0, POPT_ARG_VAL, &prune_empty_dirs, 0, 0, 0 }, @@ -2654,6 +2657,9 @@ void server_options(char **args, int *argc_p) } else if (keep_partial && am_sender) args[ac++] = "--partial"; + if (direct_io) + args[ac++] = "--direct-io"; + if (ignore_errors) args[ac++] = "--ignore-errors"; diff --git a/syscall.c b/syscall.c index fd23d15..9d432c0 100644 --- a/syscall.c +++ b/syscall.c @@ -34,6 +34,7 @@ #endif extern int dry_run; +extern int direct_io; extern int am_root; extern int am_sender; extern int read_only; @@ -69,7 +70,11 @@ int do_symlink(const char *lnk, const char *fname) * and write the lnk into it. */ if (am_root < 0) { int ok, len = strlen(lnk); - int fd = open(fname, O_WRONLY|O_CREAT|O_TRUNC, S_IWUSR|S_IRUSR); + int flags = O_WRONLY|O_CREAT|O_TRUNC; + + if (direct_io) flags |= O_DIRECT; + + int fd = open(fname, flags, S_IWUSR|S_IRUSR); if (fd < 0) return -1; ok = write(fd, lnk, len) == len; @@ -190,6 +195,8 @@ int do_open(const char *pathname, int flags, mode_t mode) RETURN_ERROR_IF_RO_OR_LO; } + if (direct_io) flags |= O_DIRECT; + return open(pathname, flags | O_BINARY, mode); } @@ -461,6 +468,8 @@ int do_open_nofollow(const char *pathname, int flags) #endif } + if (direct_io) flags |= O_DIRECT; + #ifdef O_NOFOLLOW fd = open(pathname, flags|O_NOFOLLOW); #else
--- options.c.orig 2013-02-14 13:36:19.000000000 +0100 +++ options.c 2013-02-14 13:36:33.000000000 +0100 @@ -120,6 +120,7 @@ int checksum_seed = 0; int inplace = 0; int delay_updates = 0; +int direct_io = 0; long block_size = 0; /* "long" because popt can't set an int32. */ char *skip_compress = NULL; @@ -381,6 +382,7 @@ rprintf(F," --partial keep partially transferred files\n"); rprintf(F," --partial-dir=DIR put a partially transferred file into DIR\n"); rprintf(F," --delay-updates put all updated files into place at transfer's end\n"); + rprintf(F," --direct-io don't use buffer cache for files being transferedd\n"); rprintf(F," -m, --prune-empty-dirs prune empty directory chains from the file-list\n"); rprintf(F," --numeric-ids don't map uid/gid values by user/group name\n"); rprintf(F," --timeout=SECONDS set I/O timeout in seconds\n"); @@ -593,6 +595,7 @@ {"partial-dir", 0, POPT_ARG_STRING, &partial_dir, 0, 0, 0 }, {"delay-updates", 0, POPT_ARG_VAL, &delay_updates, 1, 0, 0 }, {"no-delay-updates", 0, POPT_ARG_VAL, &delay_updates, 0, 0, 0 }, + {"direct-io", 'n', POPT_ARG_NONE, &direct_io, 0, 0, 0 }, {"prune-empty-dirs",'m', POPT_ARG_VAL, &prune_empty_dirs, 1, 0, 0 }, {"no-prune-empty-dirs",0,POPT_ARG_VAL, &prune_empty_dirs, 0, 0, 0 }, {"no-m", 0, POPT_ARG_VAL, &prune_empty_dirs, 0, 0, 0 }, @@ -2002,6 +2005,9 @@ } else if (keep_partial && am_sender) args[ac++] = "--partial"; + if (direct_io) + args[ac++] = "--direct-io"; + if (ignore_errors) args[ac++] = "--ignore-errors"; --- syscall.c.direct-io 2011-02-21 20:32:51.000000000 +0100 +++ syscall.c 2013-02-14 13:39:40.000000000 +0100 @@ -30,6 +30,7 @@ #endif extern int dry_run; +extern int direct_io; extern int am_root; extern int read_only; extern int list_only; @@ -143,6 +144,8 @@ RETURN_ERROR_IF_RO_OR_LO; } + if (direct_io) flags |= O_DIRECT; + return open(pathname, flags | O_BINARY, mode); }
-- Please use reply-all for most replies to avoid omitting the mailing list. To unsubscribe or change options: https://lists.samba.org/mailman/listinfo/rsync Before posting, read: http://www.catb.org/~esr/faqs/smart-questions.html