-@@ -189,6 +190,15 @@ void setup_protocol(int f_out,int f_in)
+@@ -188,6 +189,14 @@ void setup_protocol(int f_out,int f_in)
-+ rprintf(FERROR,
-+ "preallocation is not supported on this %s\n",
-+ am_server ? "server" : "client");
++ rprintf(FERROR, "preallocation is not supported on this %s\n",
++ am_server ? "Server" : "Client");
dnl cygwin iconv.h defines iconv_open as libiconv_open
if test x"$ac_cv_func_iconv_open" != x"yes"; then
dnl cygwin iconv.h defines iconv_open as libiconv_open
if test x"$ac_cv_func_iconv_open" != x"yes"; then
++AC_CACHE_CHECK([for useable fallocate],rsync_cv_have_fallocate,[
++AC_TRY_LINK([#include <fcntl.h>
++#include <sys/types.h>],
++[fallocate(0, 0, 0, 0);],
++rsync_cv_have_fallocate=yes,rsync_cv_have_fallocate=no)])
++if test x"$rsync_cv_have_fallocate" = x"yes"; then
++ AC_DEFINE(HAVE_FALLOCATE, 1, [Define to 1 if you have the fallocate function and it compiles and links without error])
++fi
++
+AC_CACHE_CHECK([for SYS_fallocate],rsync_cv_have_sys_fallocate,[
+AC_TRY_COMPILE([#include <sys/syscall.h>
+#include <sys/types.h>],
+AC_CACHE_CHECK([for SYS_fallocate],rsync_cv_have_sys_fallocate,[
+AC_TRY_COMPILE([#include <sys/syscall.h>
+#include <sys/types.h>],
-+[syscall(SYS_fallocate, 0, 0, (loff_t) 0, (loff_t) 0);],
++[syscall(SYS_fallocate, 0, 0, (loff_t)0, (loff_t)0);],
+rsync_cv_have_sys_fallocate=yes,rsync_cv_have_sys_fallocate=no)])
+if test x"$rsync_cv_have_sys_fallocate" = x"yes"; then
+ AC_DEFINE(HAVE_SYS_FALLOCATE, 1, [Define to 1 if you have the SYS_fallocate syscall number])
+rsync_cv_have_sys_fallocate=yes,rsync_cv_have_sys_fallocate=no)])
+if test x"$rsync_cv_have_sys_fallocate" = x"yes"; then
+ AC_DEFINE(HAVE_SYS_FALLOCATE, 1, [Define to 1 if you have the SYS_fallocate syscall number])
rprintf(F," --fake-super store/recover privileged attrs using xattrs\n");
#endif
rprintf(F," -S, --sparse handle sparse files efficiently\n");
+#ifdef SUPPORT_PREALLOCATION
+ rprintf(F," --preallocate allocate dest files before writing them\n");
rprintf(F," --fake-super store/recover privileged attrs using xattrs\n");
#endif
rprintf(F," -S, --sparse handle sparse files efficiently\n");
+#ifdef SUPPORT_PREALLOCATION
+ rprintf(F," --preallocate allocate dest files before writing them\n");
+#endif
rprintf(F," -n, --dry-run perform a trial run with no changes made\n");
rprintf(F," -W, --whole-file copy files whole (without delta-xfer algorithm)\n");
rprintf(F," -x, --one-file-system don't cross filesystem boundaries\n");
+#endif
rprintf(F," -n, --dry-run perform a trial run with no changes made\n");
rprintf(F," -W, --whole-file copy files whole (without delta-xfer algorithm)\n");
rprintf(F," -x, --one-file-system don't cross filesystem boundaries\n");
{"sparse", 'S', POPT_ARG_VAL, &sparse_files, 1, 0, 0 },
{"no-sparse", 0, POPT_ARG_VAL, &sparse_files, 0, 0, 0 },
{"no-S", 0, POPT_ARG_VAL, &sparse_files, 0, 0, 0 },
{"sparse", 'S', POPT_ARG_VAL, &sparse_files, 1, 0, 0 },
{"no-sparse", 0, POPT_ARG_VAL, &sparse_files, 0, 0, 0 },
{"no-S", 0, POPT_ARG_VAL, &sparse_files, 0, 0, 0 },
{"inplace", 0, POPT_ARG_VAL, &inplace, 1, 0, 0 },
{"no-inplace", 0, POPT_ARG_VAL, &inplace, 0, 0, 0 },
{"append", 0, POPT_ARG_NONE, 0, OPT_APPEND, 0, 0 },
{"inplace", 0, POPT_ARG_VAL, &inplace, 1, 0, 0 },
{"no-inplace", 0, POPT_ARG_VAL, &inplace, 0, 0, 0 },
{"append", 0, POPT_ARG_NONE, 0, OPT_APPEND, 0, 0 },
-@@ -2627,6 +2636,9 @@ void server_options(char **args, int *argc_p)
+@@ -2661,6 +2672,9 @@ void server_options(char **args, int *argc_p)
-@@ -207,6 +208,18 @@ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r,
+@@ -207,6 +208,22 @@ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r,
-+ /* Preallocate enough space for file's eventual length if
-+ * possible; seems to reduce fragmentation on Windows. */
-+ if (do_fallocate(fd, 0, total_size) == 0)
++ /* Try to preallocate enough space for file's eventual length. Can
++ * reduce fragmentation on filesystems like ext4, xfs, and NTFS. */
++ if (do_fallocate(fd, 0, total_size) == 0) {
++#ifdef PREALLOCATE_NEEDS_TRUNCATE
+ rsyserr(FWARNING, errno, "do_fallocate %s", full_fname(fname));
+ }
+#endif
read_sum_head(f_in, &sum);
+ rsyserr(FWARNING, errno, "do_fallocate %s", full_fname(fname));
+ }
+#endif
read_sum_head(f_in, &sum);
-@@ -317,8 +330,14 @@ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r,
+@@ -317,8 +334,14 @@ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r,
+ * preallocate_files: total_size could have been an overestimate.
+ * Cut off any extra preallocated zeros from dest file. */
+ if ((inplace
+ * preallocate_files: total_size could have been an overestimate.
+ * Cut off any extra preallocated zeros from dest file. */
+ if ((inplace
+ || preallocated_len > offset
+#endif
+ ) && fd != -1 && ftruncate(fd, offset) < 0) {
+ || preallocated_len > offset
+#endif
+ ) && fd != -1 && ftruncate(fd, offset) < 0) {
-+#if defined HAVE_FTRUNCATE \
-+ && (defined HAVE_FALLOCATE \
-+ || defined HAVE_SYS_FALLOCATE \
-+ || defined HAVE_EFFICIENT_POSIX_FALLOCATE)
++#if defined HAVE_FALLOCATE || HAVE_SYS_FALLOCATE
++#include <linux/falloc.h>
++#ifdef FALLOC_FL_KEEP_SIZE
++#elif defined HAVE_FTRUNCATE
++#define SUPPORT_PREALLOCATION 1
++#define PREALLOCATE_NEEDS_TRUNCATE 1
++#endif
++#else /* !fallocate */
++#if defined HAVE_EFFICIENT_POSIX_FALLOCATE && defined HAVE_FTRUNCATE
++#define SUPPORT_PREALLOCATION 1
++#define PREALLOCATE_NEEDS_TRUNCATE 1
++#endif
-n, --dry-run perform a trial run with no changes made
-W, --whole-file copy files whole (w/o delta-xfer algorithm)
-x, --one-file-system don't cross filesystem boundaries
-n, --dry-run perform a trial run with no changes made
-W, --whole-file copy files whole (w/o delta-xfer algorithm)
-x, --one-file-system don't cross filesystem boundaries
filesystem. It seems to have problems seeking over null regions,
and ends up corrupting the files.
+dit(bf(--preallocate)) This tells the receiver to allocate each destination
+file to its eventual size before writing data to the file. Rsync will only use
filesystem. It seems to have problems seeking over null regions,
and ends up corrupting the files.
+dit(bf(--preallocate)) This tells the receiver to allocate each destination
+file to its eventual size before writing data to the file. Rsync will only use
-+the real filesystem-level preallocation support provided by bf(fallocate)(2) or
-+Cygwin's bf(posix_fallocate)(3), not the slow glibc implementation that writes
-+a zero byte into each block. If the receiver is remote, this nonstandard
-+option only works if the receiver also has the preallocation patch.
++the real filesystem-level preallocation support provided by Linux's
++bf(fallocate)(2) system call or Cygwin's bf(posix_fallocate)(3), not the slow
++glibc implementation that writes a zero byte into each block.
-+Without this option on MS Windows, very large destination files tend to be
-+broken into thousands of fragments; advising Windows ahead of time of the
-+eventual file size using this option usually reduces the number of
-+fragments to one. The usefulness of this option on Linux is yet to be tested.
++Without this option, larger files may not be entirely contiguous on the
++filesystem, but with this option rsync will probably copy more slowly. If the
++destination is not an extent-supporting filesystem (such as ext4, xfs, NTFS,
++etc.), this option may have no positive effect at all.
+
dit(bf(-n, --dry-run)) This makes rsync perform a trial run that doesn't
make any changes (and produces mostly the same output as a real run). It
+
dit(bf(-n, --dry-run)) This makes rsync perform a trial run that doesn't
make any changes (and produces mostly the same output as a real run). It
-@@ -325,3 +329,21 @@ OFF_T do_lseek(int fd, OFF_T offset, int whence)
+@@ -325,3 +329,25 @@ OFF_T do_lseek(int fd, OFF_T offset, int whence)
+#ifdef SUPPORT_PREALLOCATION
+int do_fallocate(int fd, OFF_T offset, OFF_T length)
+{
+#ifdef SUPPORT_PREALLOCATION
+int do_fallocate(int fd, OFF_T offset, OFF_T length)
+{
+ RETURN_ERROR_IF(dry_run, 0);
+ RETURN_ERROR_IF_RO_OR_LO;
+ RETURN_ERROR_IF(dry_run, 0);
+ RETURN_ERROR_IF_RO_OR_LO;
-+ return fallocate(fd, 0, offset, length);
++ return fallocate(fd, DO_FALLOC_OPTIONS, offset, length);
-+ return syscall(SYS_fallocate, fd, 0, (loff_t) offset, (loff_t) length);
++ return syscall(SYS_fallocate, fd, DO_FALLOC_OPTIONS, (loff_t)offset, (loff_t)length);
+#elif defined HAVE_EFFICIENT_POSIX_FALLOCATE
+ return posix_fallocate(fd, offset, length);
+#else
+#elif defined HAVE_EFFICIENT_POSIX_FALLOCATE
+ return posix_fallocate(fd, offset, length);
+#else
-@@ -332,6 +333,10 @@ int copy_file(const char *source, const char *dest, int ofd, mode_t mode)
+@@ -332,6 +333,9 @@ int copy_file(const char *source, const char *dest, int ofd, mode_t mode)
-+#ifdef SUPPORT_PREALLOCATION
-+ OFF_T preallocated_len = 0;
-+ OFF_T offset = 0;
++#ifdef PREALLOCATE_NEEDS_TRUNCATE
++ OFF_T preallocated_len = 0, offset = 0;
-@@ -357,7 +362,27 @@ int copy_file(const char *source, const char *dest, int ofd, mode_t mode)
+@@ -357,6 +361,25 @@ int copy_file(const char *source, const char *dest, int ofd, mode_t mode)
-+ if (do_fstat(ifd, &srcst) == 0) {
-+ if (srcst.st_size > 0) {
-+ if (do_fallocate(ofd, 0, srcst.st_size) == 0)
-+ preallocated_len = srcst.st_size;
-+ else
-+ rsyserr(FWARNING, errno, "do_fallocate %s", full_fname(dest));
-+ }
-+ } else
++
++ /* Try to preallocate enough space for file's eventual length. Can
++ * reduce fragmentation on filesystems like ext4, xfs, and NTFS. */
++ if (do_fstat(ifd, &srcst) < 0)
+ rsyserr(FWARNING, errno, "fstat %s", full_fname(source));
+ rsyserr(FWARNING, errno, "fstat %s", full_fname(source));
++ else if (srcst.st_size > 0) {
++ if (do_fallocate(ofd, 0, srcst.st_size) == 0) {
++#ifdef PREALLOCATE_NEEDS_TRUNCATE
++ preallocated_len = srcst.st_size;
++#endif
++ } else
++ rsyserr(FWARNING, errno, "do_fallocate %s", full_fname(dest));
++ }
- rsyserr(FERROR_XFER, errno, "write %s", full_fname(dest));
-@@ -382,6 +407,16 @@ int copy_file(const char *source, const char *dest, int ofd, mode_t mode)
+@@ -366,6 +389,9 @@ int copy_file(const char *source, const char *dest, int ofd, mode_t mode)
+ errno = save_errno;
+ return -1;
+ }
++#ifdef PREALLOCATE_NEEDS_TRUNCATE
++ offset += len;
++#endif
+ }
+
+ if (len < 0) {
+@@ -382,6 +408,16 @@ int copy_file(const char *source, const char *dest, int ofd, mode_t mode)
+ /* Source file might have shrunk since we fstatted it.
+ * Cut off any extra preallocated zeros from dest file. */
+ /* Source file might have shrunk since we fstatted it.
+ * Cut off any extra preallocated zeros from dest file. */
-+ if (preallocated_len > offset)
-+ if (ftruncate(ofd, offset) < 0)
-+ /* If we fail to truncate, the dest file may be wrong, so we
-+ * must trigger the "partial transfer" error. */
-+ rsyserr(FERROR_XFER, errno, "ftruncate %s", full_fname(dest));
++ if (offset < preallocated_len && ftruncate(ofd, offset) < 0) {
++ /* If we fail to truncate, the dest file may be wrong, so we
++ * must trigger the "partial transfer" error. */
++ rsyserr(FERROR_XFER, errno, "ftruncate %s", full_fname(dest));
++ }