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

Reply via email to