This patch adds the --direct-io option, which opens files with O_DIRECT.
TODO: we probably need to make our I/O aligned on 512-byte boundaries.
Written by: Dag Wieers
To use this patch, run these commands for a successful build:
patch -p1 <patches/direct-io.diff
./configure (optional if already run)
make
based-on: d73762eea3f15f2c56bb3fa9394ad1883c25c949
diff --git a/options.c b/options.c
--- a/options.c
+++ b/options.c
@@ -24,6 +24,7 @@
#include <popt.h>
#include <zlib.h>
+extern int direct_io;
extern int module_id;
extern int local_server;
extern int sanitize_paths;
@@ -747,6 +748,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 xfer file I/O\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");
@@ -982,6 +984,8 @@ 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_VAL, &direct_io, 1, 0, 0 },
+ {"no-direct-io", 0, POPT_ARG_VAL, &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 },
diff --git a/rsync.yo b/rsync.yo
--- a/rsync.yo
+++ b/rsync.yo
@@ -405,6 +405,7 @@ to the detailed description below for a complete description. verb(
--partial keep partially transferred files
--partial-dir=DIR put a partially transferred file into DIR
--delay-updates put all updated files into place at end
+ --direct-io don't use buffer cache for xfer file I/O
-m, --prune-empty-dirs prune empty directory chains from file-list
--numeric-ids don't map uid/gid values by user/group name
--usermap=STRING custom username mapping
@@ -2435,6 +2436,14 @@ See also the "atomic-rsync" perl script in the "support" subdir for an
update algorithm that is even more atomic (it uses bf(--link-dest) and a
parallel hierarchy of files).
+dit(bf(--direct-io)) This option opens files with a direct-I/O flag that
+makes the file I/O avoid the buffer cache. The option only affects one
+side of the transfer (unless the transfer is local). If you want it to
+affect both sides, use the bf(--remote-option) (bf(-M)) option to specify
+it for the remote side. For instance, this specifies it for both sides:
+
+quote(tt( rsync -av {,-M}--direct-io /src/ host:/dest/))
+
dit(bf(-m, --prune-empty-dirs)) This option tells the receiving rsync to get
rid of empty directories from the file-list, including nested directories
that have no non-directory children. This is useful for avoiding the
diff --git a/syscall.c b/syscall.c
--- a/syscall.c
+++ b/syscall.c
@@ -43,6 +43,8 @@ extern int preallocate_files;
extern int preserve_perms;
extern int preserve_executability;
+int direct_io = 0;
+
#ifndef S_BLKSIZE
# if defined hpux || defined __hpux__ || defined __hpux
# define S_BLKSIZE 1024
@@ -81,7 +83,12 @@ 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;
@@ -202,6 +209,9 @@ 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);
}
@@ -545,6 +555,9 @@ 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
diff -Nurp a/rsync.1 b/rsync.1
--- a/rsync.1
+++ b/rsync.1
@@ -481,6 +481,7 @@ to the detailed description below for a
\-\-partial keep partially transferred files
\-\-partial\-dir=DIR put a partially transferred file into DIR
\-\-delay\-updates put all updated files into place at end
+ \-\-direct\-io don'\&t use buffer cache for xfer file I/O
\-m, \-\-prune\-empty\-dirs prune empty directory chains from file\-list
\-\-numeric\-ids don'\&t map uid/gid values by user/group name
\-\-usermap=STRING custom username mapping
@@ -2761,6 +2762,18 @@ See also the \(dq\&atomic\-rsync\(dq\& p
update algorithm that is even more atomic (it uses \fB\-\-link\-dest\fP and a
parallel hierarchy of files).
.IP
+.IP "\fB\-\-direct\-io\fP"
+This option opens files with a direct\-I/O flag that
+makes the file I/O avoid the buffer cache. The option only affects one
+side of the transfer (unless the transfer is local). If you want it to
+affect both sides, use the \fB\-\-remote\-option\fP (\fB\-M\fP) option to specify
+it for the remote side. For instance, this specifies it for both sides:
+.IP
+.RS
+\f(CW rsync \-av {,\-M}\-\-direct\-io /src/ host:/dest/\fP
+.RE
+
+.IP
.IP "\fB\-m, \-\-prune\-empty\-dirs\fP"
This option tells the receiving rsync to get
rid of empty directories from the file\-list, including nested directories