+diff --git a/loadparm.c b/loadparm.c
+--- a/loadparm.c
++++ b/loadparm.c
+@@ -149,6 +149,7 @@ typedef struct
+ char *temp_dir;
+ char *uid;
+
++ int checksum_files;
+ int max_connections;
+ int max_verbosity;
+ int syslog_facility;
+@@ -200,6 +201,7 @@ static service sDefault =
+ /* temp_dir; */ NULL,
+ /* uid; */ NOBODY_USER,
+
++ /* checksum_files; */ CSF_IGNORE_FILES,
+ /* max_connections; */ 0,
+ /* max_verbosity; */ 1,
+ /* syslog_facility; */ LOG_DAEMON,
+@@ -294,6 +296,12 @@ static struct enum_list enum_facilities[] = {
+ #endif
+ { -1, NULL }};
+
++static struct enum_list enum_csum_modes[] = {
++ { CSF_IGNORE_FILES, "none" },
++ { CSF_LAX_MODE, "lax" },
++ { CSF_STRICT_MODE, "strict" },
++ { -1, NULL }
++};
+
+ /* note that we do not initialise the defaults union - it is not allowed in ANSI C */
+ static struct parm_struct parm_table[] =
+@@ -306,6 +314,7 @@ static struct parm_struct parm_table[] =
+
+ {"auth users", P_STRING, P_LOCAL, &sDefault.auth_users, NULL,0},
+ {"charset", P_STRING, P_LOCAL, &sDefault.charset, NULL,0},
++ {"checksum files", P_ENUM, P_LOCAL, &sDefault.checksum_files, enum_csum_modes,0},
+ {"comment", P_STRING, P_LOCAL, &sDefault.comment, NULL,0},
+ {"dont compress", P_STRING, P_LOCAL, &sDefault.dont_compress, NULL,0},
+ {"exclude from", P_STRING, P_LOCAL, &sDefault.exclude_from, NULL,0},
+@@ -423,6 +432,7 @@ FN_LOCAL_STRING(lp_secrets_file, secrets_file)
+ FN_LOCAL_STRING(lp_temp_dir, temp_dir)
+ FN_LOCAL_STRING(lp_uid, uid)
+
++FN_LOCAL_INTEGER(lp_checksum_files, checksum_files)
+ FN_LOCAL_INTEGER(lp_max_connections, max_connections)
+ FN_LOCAL_INTEGER(lp_max_verbosity, max_verbosity)
+ FN_LOCAL_INTEGER(lp_syslog_facility, syslog_facility)
+diff --git a/options.c b/options.c
+--- a/options.c
++++ b/options.c
+@@ -113,6 +113,7 @@ size_t bwlimit_writemax = 0;
+ int ignore_existing = 0;
+ int ignore_non_existing = 0;
+ int need_messages_from_generator = 0;
++int checksum_files = CSF_IGNORE_FILES;
+ int max_delete = INT_MIN;
+ OFF_T max_size = 0;
+ OFF_T min_size = 0;
+@@ -317,6 +318,7 @@ void usage(enum logcode F)
+ rprintf(F," -q, --quiet suppress non-error messages\n");
+ rprintf(F," --no-motd suppress daemon-mode MOTD (see manpage caveat)\n");
+ rprintf(F," -c, --checksum skip based on checksum, not mod-time & size\n");
++ rprintf(F," --sumfiles=MODE use .rsyncsums to speedup --checksum mode\n");
+ rprintf(F," -a, --archive archive mode; equals -rlptgoD (no -H,-A,-X)\n");
+ rprintf(F," --no-OPTION turn off an implied OPTION (e.g. --no-D)\n");
+ rprintf(F," -r, --recursive recurse into directories\n");
+@@ -446,7 +448,7 @@ enum {OPT_VERSION = 1000, OPT_DAEMON, OPT_SENDER, OPT_EXCLUDE, OPT_EXCLUDE_FROM,
+ OPT_FILTER, OPT_COMPARE_DEST, OPT_COPY_DEST, OPT_LINK_DEST, OPT_HELP,
+ OPT_INCLUDE, OPT_INCLUDE_FROM, OPT_MODIFY_WINDOW, OPT_MIN_SIZE, OPT_CHMOD,
+ OPT_READ_BATCH, OPT_WRITE_BATCH, OPT_ONLY_WRITE_BATCH, OPT_MAX_SIZE,
+- OPT_NO_D, OPT_APPEND, OPT_NO_ICONV,
++ OPT_NO_D, OPT_APPEND, OPT_NO_ICONV, OPT_SUMFILES,
+ OPT_SERVER, OPT_REFUSED_BASE = 9000};
+
+ static struct poptOption long_options[] = {
+@@ -574,6 +576,7 @@ static struct poptOption long_options[] = {
+ {"checksum", 'c', POPT_ARG_VAL, &always_checksum, 1, 0, 0 },
+ {"no-checksum", 0, POPT_ARG_VAL, &always_checksum, 0, 0, 0 },
+ {"no-c", 0, POPT_ARG_VAL, &always_checksum, 0, 0, 0 },
++ {"sumfiles", 0, POPT_ARG_STRING, 0, OPT_SUMFILES, 0, 0 },
+ {"block-size", 'B', POPT_ARG_LONG, &block_size, 0, 0, 0 },
+ {"compare-dest", 0, POPT_ARG_STRING, 0, OPT_COMPARE_DEST, 0, 0 },
+ {"copy-dest", 0, POPT_ARG_STRING, 0, OPT_COPY_DEST, 0, 0 },
+@@ -1228,6 +1231,23 @@ int parse_arguments(int *argc_p, const char ***argv_p)
+ }
+ break;
+
++ case OPT_SUMFILES:
++ arg = poptGetOptArg(pc);
++ checksum_files = 0;
++ if (strcmp(arg, "lax") == 0)
++ checksum_files |= CSF_LAX_MODE;
++ else if (strcmp(arg, "strict") == 0)
++ checksum_files |= CSF_STRICT_MODE;
++ else if (strcmp(arg, "none") == 0)
++ checksum_files = CSF_IGNORE_FILES;
++ else {
++ snprintf(err_buf, sizeof err_buf,
++ "Invalid argument passed to --sumfiles (%s)\n",
++ arg);
++ return 0;
++ }
++ break;
++
+ case OPT_HELP:
+ usage(FINFO);
+ exit_cleanup(0);
+@@ -1332,6 +1352,9 @@ int parse_arguments(int *argc_p, const char ***argv_p)
+ }
+ #endif
+
++ if (!always_checksum)
++ checksum_files = CSF_IGNORE_FILES;
++
+ if (write_batch && read_batch) {
+ snprintf(err_buf, sizeof err_buf,
+ "--write-batch and --read-batch can not be used together\n");
+diff --git a/rsync.h b/rsync.h
+--- a/rsync.h
++++ b/rsync.h
+@@ -682,6 +682,10 @@ extern int xattrs_ndx;
+ #define F_SUM(f) ((char*)OPT_EXTRA(f, LEN64_BUMP(f) + HLINK_BUMP(f) \
+ + SUM_EXTRA_CNT - 1))
+
++/* These are only valid on an entry read from a checksum file. */
++#define F_CTIME(f) OPT_EXTRA(f, LEN64_BUMP(f) + SUM_EXTRA_CNT)->unum
++#define F_INODE(f) OPT_EXTRA(f, LEN64_BUMP(f) + SUM_EXTRA_CNT + 1)->unum
++
+ /* Some utility defines: */
+ #define F_IS_ACTIVE(f) (f)->basename[0]
+ #define F_IS_HLINKED(f) ((f)->flags & FLAG_HLINKED)
+@@ -860,6 +864,13 @@ typedef struct {
+ char fname[1]; /* has variable size */
+ } relnamecache;
+
++#define CSF_ENABLE (1<<1)
++#define CSF_LAX (1<<2)
++
++#define CSF_IGNORE_FILES 0
++#define CSF_LAX_MODE (CSF_ENABLE|CSF_LAX)
++#define CSF_STRICT_MODE (CSF_ENABLE)
++
+ #include "byteorder.h"
+ #include "lib/mdigest.h"
+ #include "lib/wildmatch.h"
+diff --git a/rsync.yo b/rsync.yo
+--- a/rsync.yo
++++ b/rsync.yo
+@@ -317,6 +317,7 @@ to the detailed description below for a complete description. verb(
+ -q, --quiet suppress non-error messages
+ --no-motd suppress daemon-mode MOTD (see caveat)
+ -c, --checksum skip based on checksum, not mod-time & size
++ --sumfiles=MODE use .rsyncsums to speedup --checksum mode
+ -a, --archive archive mode; equals -rlptgoD (no -H,-A,-X)
+ --no-OPTION turn off an implied OPTION (e.g. --no-D)
+ -r, --recursive recurse into directories
+@@ -516,9 +517,9 @@ uses a "quick check" that (by default) checks if each file's size and time
+ of last modification match between the sender and receiver. This option
+ changes this to compare a 128-bit MD4 checksum for each file that has a
+ matching size. Generating the checksums means that both sides will expend
+-a lot of disk I/O reading all the data in the files in the transfer (and
+-this is prior to any reading that will be done to transfer changed files),
+-so this can slow things down significantly.
++a lot of disk I/O reading the data in all the files in the transfer, so
++this can slow things down significantly (and this is prior to any reading
++that will be done to transfer the files that have changed).
+
+ The sending side generates its checksums while it is doing the file-system
+ scan that builds the list of the available files. The receiver generates
+@@ -526,12 +527,44 @@ its checksums when it is scanning for changed files, and will checksum any
+ file that has the same size as the corresponding sender's file: files with
+ either a changed size or a changed checksum are selected for transfer.
+
++See also the bf(--sumfiles) option for a way to use cached checksum data.
++
+ Note that rsync always verifies that each em(transferred) file was
+ correctly reconstructed on the receiving side by checking a whole-file
+ checksum that is generated as the file is transferred, but that
+ automatic after-the-transfer verification has nothing to do with this
+ option's before-the-transfer "Does this file need to be updated?" check.
+
++dit(bf(--sumfiles=MODE)) This option tells rsync to make use of any cached
++checksum information it finds in per-directory .rsyncsums files when the
++current transfer is using the bf(--checksum) option. If the checksum data
++is up-to-date, it is used instead of recomputing it, saving both disk I/O
++and CPU time. If the checksum data is missing or outdated, the checksum is
++computed just as it would be if bf(--sumfiles) was not specified.
++
++The MODE value is either "lax", for relaxed checking (which compares size
++and mtime), "strict" (which also compares ctime and inode), or "none" to
++ignore any .rsyncsums files ("none" is the default). Rsync does not create
++or update these files, but there is a perl script in the support directory
++named "rsyncsums" that can be used for that.
++
++This option has no effect unless bf(--checksum, -c) was also specified. It
++also only affects the current side of the transfer, so if you want the
++remote side to parse its own .rsyncsums files, specify the option via the
++bf(--rsync-path) option (e.g. "--rsync-path="rsync --sumfiles=lax").
++
++To avoid transferring the system's checksum files, you can use an exclude
++(e.g. bf(--exclude=.rsyncsums)). To make this easier to type, you can use
++a popt alias. For instance, adding the following line in your ~/.popt file
++defines a bf(--cc) option that enables lax checksum files and excludes the
++checksum files:
++
++verb( rsync alias --cc -c --sumfiles=lax --exclude=.rsyncsums)
++
++An rsync daemon does not allow the client to control this setting, so see
++the "checksum files" daemon parameter for information on how to make a
++daemon use cached checksum data.
++
+ dit(bf(-a, --archive)) This is equivalent to bf(-rlptgoD). It is a quick
+ way of saying you want recursion and want to preserve almost
+ everything (with -H being a notable omission).
+diff --git a/rsyncd.conf.yo b/rsyncd.conf.yo
+--- a/rsyncd.conf.yo
++++ b/rsyncd.conf.yo
+@@ -281,6 +281,17 @@ locking on this file to ensure that the max connections limit is not
+ exceeded for the modules sharing the lock file.
+ The default is tt(/var/run/rsyncd.lock).
+
++dit(bf(checksum files)) This option tells rsync to make use of any cached
++checksum information it finds in per-directory .rsyncsums files when the
++current transfer is using the bf(--checksum) option. The value can be set
++to either "lax", "strict", or "none" -- see the client's bf(--sumfiles)
++option for what these choices do.
++
++Note also that the client's command-line option, bf(--sumfiles), has no
++effect on a daemon. A daemon will only access checksum files if this
++config option tells it to. See also the bf(exclude) directive for a way
++to hide the .rsyncsums files from the user.
++
+ dit(bf(read only)) The "read only" option determines whether clients
+ will be able to upload files or not. If "read only" is true then any
+ attempted uploads will fail. If "read only" is false then uploads will