diff -u -r rsync-3.0.9.orig/flist.c rsync-3.0.9/flist.c --- rsync-3.0.9.orig/flist.c 2011-08-27 23:58:04.000000000 +0200 +++ rsync-3.0.9/flist.c 2011-11-12 16:39:22.000000000 +0100 @@ -62,6 +62,7 @@ extern int copy_unsafe_links; extern int protocol_version; extern int sanitize_paths; +extern unsigned long sleep_asec; extern int munge_symlinks; extern int use_safe_inc_flist; extern int need_unsorted_flist; @@ -1611,6 +1612,33 @@ * file list in memory without sending it over the wire. Also, get_dirlist() * might call this with f set to -2, which also indicates that local filter * rules should be ignored. */ + +struct dirent_s { + unsigned long long d_ino; + long long d_off; + unsigned short int d_reclen; + unsigned char d_type; + char *d_name; +}; + +static int ino_cmp(const void *a, const void *b) +{ + const struct dirent_s *ds_a = (const struct dirent_s *) a; + const struct dirent_s *ds_b = (const struct dirent_s *) b; + unsigned int i_a, i_b; + i_a = ds_a->d_ino; + i_b = ds_b->d_ino; + return (i_a - i_b); +} + +static int pot (int n) +{ + int p = 1; + while (p <= n) + p *= 2; + return p; +} + static void send_directory(int f, struct file_list *flist, char *fbuf, int len, int flags) { @@ -1621,6 +1649,9 @@ int divert_dirs = (flags & FLAG_DIVERT_DIRS) != 0; int start = flist->used; int filter_level = f == -2 ? SERVER_FILTERS : ALL_FILTERS; + struct dirent_s *ds = NULL; + long n_files=0; + long i; assert(flist != NULL); @@ -1645,12 +1676,35 @@ } else remainder = 0; - for (errno = 0, di = readdir(d); di; errno = 0, di = readdir(d)) { + + errno = 0; + while ((di = readdir (d))) { + ds = realloc (ds, sizeof (struct dirent_s) * pot (n_files)); + if (!ds){ + rsyserr(FERROR, errno, "realloc for dircache failed (%s)", full_fname(fbuf)); + errno = 0; + return; + } + ds[n_files].d_name = strdup (d_name(di)); + ds[n_files].d_ino = di->d_ino; + n_files++; + } + closedir(d); + if (errno) { + io_error |= IOERR_GENERAL; + rsyserr(FERROR, errno, "readdir(%s)", full_fname(fbuf)); + } + qsort(ds, n_files, sizeof(struct dirent_s), ino_cmp); /* see http://lkml.org/lkml/2008/4/27/141 */ + + + for (errno = 0,i = 0; i < n_files; errno = 0,++i) { unsigned name_len; - char *dname = d_name(di); + char *dname = ds[i].d_name; if (dname[0] == '.' && (dname[1] == '\0' - || (dname[1] == '.' && dname[2] == '\0'))) + || (dname[1] == '.' && dname[2] == '\0'))) { + free(dname); continue; + } name_len = strlcpy(p, dname, remainder); if (name_len >= remainder) { char save = fbuf[len]; @@ -1667,23 +1721,19 @@ rprintf(FERROR_XFER, "cannot send file with empty name in %s\n", full_fname(fbuf)); + free(dname); continue; } send_file_name(f, flist, fbuf, NULL, flags, filter_level); + free(dname); } fbuf[len] = '\0'; - - if (errno) { - io_error |= IOERR_GENERAL; - rsyserr(FERROR_XFER, errno, "readdir(%s)", full_fname(fbuf)); - } - - closedir(d); + free(ds); if (f >= 0 && recurse && !divert_dirs) { - int i, end = flist->used - 1; + int end = flist->used - 1; /* send_if_directory() bumps flist->used, so use "end". */ for (i = start; i <= end; i++) send_if_directory(f, flist, flist->files[i], fbuf, len, flags); diff -u -r rsync-3.0.9.orig/options.c rsync-3.0.9/options.c --- rsync-3.0.9.orig/options.c 2011-09-14 00:41:26.000000000 +0200 +++ rsync-3.0.9/options.c 2011-11-12 16:16:45.000000000 +0100 @@ -107,6 +107,7 @@ int daemon_bwlimit = 0; int bwlimit = 0; int fuzzy_basis = 0; +unsigned long sleep_asec = 0; size_t bwlimit_writemax = 0; int ignore_existing = 0; int ignore_non_existing = 0; @@ -423,6 +424,7 @@ rprintf(F," --password-file=FILE read daemon-access password from FILE\n"); rprintf(F," --list-only list the files instead of copying them\n"); rprintf(F," --bwlimit=KBPS limit I/O bandwidth; KBytes per second\n"); + rprintf(F," --slow-down=USECs sleep N usec while creating the filelist\n"); rprintf(F," --write-batch=FILE write a batched update to FILE\n"); rprintf(F," --only-write-batch=FILE like --write-batch but w/o updating destination\n"); rprintf(F," --read-batch=FILE read a batched update from FILE\n"); @@ -604,6 +606,7 @@ {"no-itemize-changes",0, POPT_ARG_VAL, &itemize_changes, 0, 0, 0 }, {"no-i", 0, POPT_ARG_VAL, &itemize_changes, 0, 0, 0 }, {"bwlimit", 0, POPT_ARG_INT, &bwlimit, 0, 0, 0 }, + {"slow-down", 0, POPT_ARG_LONG, &sleep_asec, 0, 0, 0 }, {"no-bwlimit", 0, POPT_ARG_VAL, &bwlimit, 0, 0, 0 }, {"backup", 'b', POPT_ARG_VAL, &make_backups, 1, 0, 0 }, {"no-backup", 0, POPT_ARG_VAL, &make_backups, 0, 0, 0 }, @@ -1924,6 +1927,12 @@ args[ac++] = arg; } + if (sleep_asec) { + if (asprintf(&arg, "--slow-down=%lu", sleep_asec) < 0) + goto oom; + args[ac++] = arg; + } + if (backup_dir) { args[ac++] = "--backup-dir"; args[ac++] = backup_dir; diff -u -r rsync-3.0.9.orig/syscall.c rsync-3.0.9/syscall.c --- rsync-3.0.9.orig/syscall.c 2011-02-21 20:32:51.000000000 +0100 +++ rsync-3.0.9/syscall.c 2011-11-12 16:16:45.000000000 +0100 @@ -34,6 +34,7 @@ extern int read_only; extern int list_only; extern int preserve_perms; +extern unsigned long sleep_asec; extern int preserve_executability; #define RETURN_ERROR_IF(x,e) \ @@ -64,6 +65,13 @@ int do_link(const char *fname1, const char *fname2) { if (dry_run) return 0; + + /* Meta-Data updates don't seem to get scheduled very well. + So lets sleep for a bit, to avoid hammering the disk. + and rendering the system unusable */ + if (sleep_asec) + usleep(sleep_asec*5); + RETURN_ERROR_IF_RO_OR_LO; return link(fname1, fname2); }