diff -ur rsync-3.0.7/flist.c rsync-3.0.7-slowdown/flist.c --- rsync-3.0.7/flist.c 2009-12-21 23:40:41.000000000 +0100 +++ rsync-3.0.7-slowdown/flist.c 2010-06-30 14:33:09.000000000 +0200 @@ -65,6 +65,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; @@ -1615,6 +1616,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) { @@ -1625,6 +1653,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,16 +1676,38 @@ *p = '\0'; remainder = MAXPATHLEN - (p - fbuf); - for (errno = 0, di = readdir(d); di; errno = 0, di = readdir(d)) { - char *dname = d_name(di); + + 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)); + 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 (i = 0; i < n_files; ++i) { + 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; + } if (strlcpy(p, dname, remainder) >= remainder) { io_error |= IOERR_GENERAL; rprintf(FERROR_XFER, "cannot send long-named file %s\n", full_fname(fbuf)); + free(dname); continue; } if (dname[0] == '\0') { @@ -1669,16 +1722,10 @@ } 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 -ur rsync-3.0.7/options.c rsync-3.0.7-slowdown/options.c --- rsync-3.0.7/options.c 2009-12-21 23:40:41.000000000 +0100 +++ rsync-3.0.7-slowdown/options.c 2010-06-30 14:33:48.000000000 +0200 @@ -108,6 +108,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; @@ -424,6 +425,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"); @@ -605,6 +607,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 }, @@ -1919,6 +1922,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 -ur rsync-3.0.7/syscall.c rsync-3.0.7-slowdown/syscall.c --- rsync-3.0.7/syscall.c 2009-01-17 22:41:35.000000000 +0100 +++ rsync-3.0.7-slowdown/syscall.c 2010-06-30 14:29:17.000000000 +0200 @@ -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); }