howdy,
i have a patch that enables mmap() and madvise() for copying
regular files. i have only tested it on linux. i havent added tests
for HAVE_MADVISE because "i dont know how" (tm). it should probably be
added. also using madvise() on the latest linux kernels (2.4.4-ac9)
seems to trigger a kernel bug and hang your system. hopefully it will
work on other platforms that implement it. currently it is "#if 0"'ed.
anyway the patch is attached.
matt
diff -ur packages/fileutils-4.1/src/copy.c build/fileutils-4.1/src/copy.c
--- packages/fileutils-4.1/src/copy.c Sun Jan 14 02:49:43 2001
+++ build/fileutils-4.1/src/copy.c Wed May 16 19:01:30 2001
@@ -26,6 +26,10 @@
#include <assert.h>
#include <sys/types.h>
+#ifdef HAVE_MMAP
+ #include <sys/mman.h>
+#endif /* HAVE_MMAP */
+
#include "system.h"
#include "error.h"
#include "backupfile.h"
@@ -182,6 +186,8 @@
copy_reg (const char *src_path, const char *dst_path,
const struct cp_options *x, mode_t dst_mode, int *new_dst)
{
+ char *dest_buf;
+ int dest_buf_size;
char *buf;
int buf_size;
int dest_desc;
@@ -193,6 +199,8 @@
off_t n_read_total = 0;
int last_write_made_hole = 0;
int make_holes = (x->sparse_mode == SPARSE_ALWAYS);
+ int mmap_source = 0;
+ int mmap_dest = 0;
source_desc = open (src_path, O_RDONLY);
if (source_desc < 0)
@@ -214,11 +222,17 @@
The if-block will be taken in move_mode. */
if (*new_dst)
{
- dest_desc = open (dst_path, O_WRONLY | O_CREAT, dst_mode);
+ if (x->mmap_mode)
+ dest_desc = open (dst_path, O_RDWR | O_CREAT, dst_mode);
+ else
+ dest_desc = open (dst_path, O_WRONLY | O_CREAT, dst_mode);
}
else
{
- dest_desc = open (dst_path, O_WRONLY | O_TRUNC, dst_mode);
+ if (x->mmap_mode)
+ dest_desc = open (dst_path, O_RDWR | O_TRUNC, dst_mode);
+ else
+ dest_desc = open (dst_path, O_WRONLY | O_TRUNC, dst_mode);
if (dest_desc < 0 && x->unlink_dest_after_failed_open)
{
@@ -279,11 +293,77 @@
/* Make a buffer with space for a sentinel at the end. */
- buf = (char *) alloca (buf_size + sizeof (int));
+ if (x->mmap_mode)
+ {
+#ifdef HAVE_MMAP
+ if (fstat (source_desc, &sb))
+ {
+ error (0, errno, _("cannot fstat: %s"), quote (src_path));
+ return_val = -1;
+ goto close_src_and_dst_desc;
+ }
+
+ dest_buf_size = sb.st_size;
+
+ /* We don't care if mmap() or madvise() dont work, we use it them we can */
+ /* we need PROT_WRITE for sentinel writing for the hole checking algorithm
+below */
+
+ if ((buf = mmap (NULL, dest_buf_size, PROT_READ | PROT_WRITE, MAP_PRIVATE,
+source_desc, 0)) == (void *) -1)
+ {
+ mmap_source = 0;
+ }
+ else
+ {
+ mmap_source = 1;
+#if 0
+ madvise (buf, dest_buf_size, MADV_SEQUENTIAL);
+#endif
+ }
+
+#if HAVE_FTRUNCATE
+ /* Write a null character and truncate it again. */
+ if (ftruncate (dest_desc, dest_buf_size) < 0)
+#else
+ /* Seek backwards one character and write a null. */
+ if (lseek (dest_desc, (off_t) dest_buf_size, SEEK_SET) < 0L
+ || full_write (dest_desc, "", 1) < 0)
+#endif
+ {
+ error (0, errno, _("writing %s"), quote (dst_path));
+ return_val = -1;
+ }
+
+ if ((dest_buf = mmap (NULL, dest_buf_size, PROT_READ | PROT_WRITE, MAP_SHARED,
+dest_desc, 0)) == (void *) -1)
+ {
+ mmap_dest = 0;
+ }
+ else
+ {
+ mmap_dest = 1;
+#if 0
+ madvise (dest_buf, dest_buf_size, MADV_SEQUENTIAL);
+#endif
+ }
+#endif /* HAVE_MMAP */
+ }
+ else
+ {
+ buf = (char *) alloca (buf_size + sizeof (int));
+ }
for (;;)
{
- int n_read = read (source_desc, buf, buf_size);
+ int n_read;
+
+ if (mmap_source)
+ {
+ n_read = MIN (buf_size, dest_buf_size - n_read_total);
+ }
+ else
+ {
+ n_read = read (source_desc, buf, buf_size);
+ }
+
if (n_read < 0)
{
#ifdef EINTR
@@ -302,6 +382,9 @@
ip = 0;
if (make_holes)
{
+ char tmp;
+
+ tmp = buf[n_read];
buf[n_read] = 1; /* Sentinel to stop loop. */
/* Find first nonzero *word*, or the word with the sentinel. */
@@ -321,26 +404,49 @@
if (cp > buf + n_read)
{
- /* Make a hole. */
- if (lseek (dest_desc, (off_t) n_read, SEEK_CUR) < 0L)
+ /* no need to do anythning if the dest is mmap()'ed */
+ /* that includes any last write_made_hole handling */
+ if (!mmap_dest)
{
- error (0, errno, _("cannot lseek %s"), quote (dst_path));
- return_val = -1;
- goto close_src_and_dst_desc;
+ /* Make a hole. */
+ if (lseek (dest_desc, (off_t) n_read, SEEK_CUR) < 0L)
+ {
+ error (0, errno, _("cannot lseek %s"), quote (dst_path));
+ return_val = -1;
+ goto close_src_and_dst_desc;
+ }
+ last_write_made_hole = 1;
}
- last_write_made_hole = 1;
}
else
/* Clear to indicate that a normal write is needed. */
ip = 0;
+
+ buf[n_read] = tmp;
}
if (ip == 0)
{
- if (full_write (dest_desc, buf, n_read) < 0)
+ if (mmap_dest)
{
- error (0, errno, _("writing %s"), quote (dst_path));
- return_val = -1;
- goto close_src_and_dst_desc;
+ memmove(dest_buf + n_read_total - n_read, buf + n_read_total - n_read,
+n_read);
+ }
+ else if (mmap_source)
+ {
+ if (full_write (dest_desc, buf + n_read_total - n_read, n_read) < 0)
+ {
+ error (0, errno, _("writing %s"), quote (dst_path));
+ return_val = -1;
+ goto close_src_and_dst_desc;
+ }
+ }
+ else
+ {
+ if (full_write (dest_desc, buf, n_read) < 0)
+ {
+ error (0, errno, _("writing %s"), quote (dst_path));
+ return_val = -1;
+ goto close_src_and_dst_desc;
+ }
}
last_write_made_hole = 0;
}
@@ -368,12 +474,46 @@
}
close_src_and_dst_desc:
+#ifdef HAVE_MMAP
+ if (mmap_dest)
+ {
+ /* dont care if madvise() doesnt work */
+#if 0
+ madvise (dest_buf, dest_buf_size, MADV_DONTNEED);
+#endif
+ if (dest_buf_size)
+ {
+ if (munmap (dest_buf, dest_buf_size) < 0)
+ {
+ error (0, errno, _("munmaping %s"), quote (src_path));
+ return_val = -1;
+ }
+ }
+ }
+#endif /* HAVE_MMAP */
if (close (dest_desc) < 0)
{
error (0, errno, _("closing %s"), quote (dst_path));
return_val = -1;
}
close_src_desc:
+#ifdef HAVE_MMAP
+ if (mmap_source)
+ {
+ /* dont care if madvise() doesnt work */
+#if 0
+ madvise (buf, dest_buf_size, MADV_DONTNEED);
+#endif
+ if (dest_buf_size)
+ {
+ if (munmap (buf, dest_buf_size) < 0)
+ {
+ error (0, errno, _("munmaping %s"), quote (dst_path));
+ return_val = -1;
+ }
+ }
+ }
+#endif /* HAVE_MMAP */
if (close (source_desc) < 0)
{
error (0, errno, _("closing %s"), quote (src_path));
diff -ur packages/fileutils-4.1/src/copy.h build/fileutils-4.1/src/copy.h
--- packages/fileutils-4.1/src/copy.h Sun Jan 14 22:03:30 2001
+++ build/fileutils-4.1/src/copy.h Tue May 15 15:34:58 2001
@@ -73,6 +73,10 @@
with regular files. */
int interactive;
+ /* If nonzero, use mmap() and madvise() if possible to avoid
+ polluting the page / buffer cache */
+ int mmap_mode;
+
/* If nonzero, rather than copying, first attempt to use rename.
If that fails, then resort to copying. */
int move_mode;
diff -ur packages/fileutils-4.1/src/cp.c build/fileutils-4.1/src/cp.c
--- packages/fileutils-4.1/src/cp.c Sun Feb 4 03:48:34 2001
+++ build/fileutils-4.1/src/cp.c Wed May 16 19:13:36 2001
@@ -117,6 +117,7 @@
{"sparse", required_argument, NULL, SPARSE_OPTION},
{"interactive", no_argument, NULL, 'i'},
{"link", no_argument, NULL, 'l'},
+ {"mmap", no_argument, NULL, 'M'},
{"no-dereference", no_argument, NULL, 'd'},
{"one-file-system", no_argument, NULL, 'x'},
{"parents", no_argument, NULL, PARENTS_OPTION},
@@ -163,6 +164,7 @@
-H follow command-line symbolic links\n\
-l, --link link files instead of copying\n\
-L, --dereference always follow symbolic links\n\
+ -M, --mmap use mmap() and madvise() to copy files\n\
-p, --preserve preserve file attributes if possible\n\
--parents append source path to DIRECTORY\n\
-P same as `--parents' for now; soon to change to\n\
@@ -672,6 +674,7 @@
x->interactive = 0;
x->myeuid = geteuid ();
x->move_mode = 0;
+ x->mmap_mode = 0;
x->one_file_system = 0;
x->preserve_owner_and_group = 0;
@@ -719,7 +722,7 @@
we'll actually use backup_suffix_string. */
backup_suffix_string = getenv ("SIMPLE_BACKUP_SUFFIX");
- while ((c = getopt_long (argc, argv, "abdfHilLprsuvxPRS:V:", long_opts, NULL))
+ while ((c = getopt_long (argc, argv, "abdfHilLMprsuvxPRS:V:", long_opts, NULL))
!= -1)
{
switch (c)
@@ -777,6 +780,10 @@
case 'L':
x.dereference = DEREF_ALWAYS;
+ break;
+
+ case 'M':
+ x.mmap_mode = 1;
break;
case 'p':
diff -ur packages/fileutils-4.1/src/install.c build/fileutils-4.1/src/install.c
--- packages/fileutils-4.1/src/install.c Wed May 16 18:26:27 2001
+++ build/fileutils-4.1/src/install.c Wed May 16 19:17:09 2001
@@ -155,6 +155,7 @@
x->hard_link = 0;
x->interactive = 0;
x->move_mode = 0;
+ x->mmap_mode = 0;
x->myeuid = geteuid ();
x->one_file_system = 0;
x->preserve_owner_and_group = 0;
@@ -211,7 +212,7 @@
we'll actually use backup_suffix_string. */
backup_suffix_string = getenv ("SIMPLE_BACKUP_SUFFIX");
- while ((optc = getopt_long (argc, argv, "bcsDdg:m:o:pvV:S:", long_options,
+ while ((optc = getopt_long (argc, argv, "bcsDdg:m:Mo:pvV:S:", long_options,
NULL)) != -1)
{
switch (optc)
@@ -251,6 +252,9 @@
case 'm':
specified_mode = optarg;
break;
+ case 'M':
+ x.mmap_mode = 1;
+ break;
case 'o':
owner_name = optarg;
break;
@@ -632,6 +636,7 @@
then copy SOURCE to DEST; useful in the 1st format\n\
-g, --group=GROUP set group ownership, instead of process' current group\n\
-m, --mode=MODE set permission mode (as in chmod), instead of rwxr-xr-x\n\
+ -M, --mmap use mmap() and madvise() to copy files\n\
-o, --owner=OWNER set ownership (super-user only)\n\
-p, --preserve-timestamps apply access/modification times of SOURCE files\n\
to corresponding destination files\n\
diff -ur packages/fileutils-4.1/src/mv.c build/fileutils-4.1/src/mv.c
--- packages/fileutils-4.1/src/mv.c Sun Feb 4 03:48:34 2001
+++ build/fileutils-4.1/src/mv.c Wed May 16 19:15:32 2001
@@ -111,6 +111,7 @@
x->hard_link = 0;
x->interactive = 0;
x->move_mode = 1;
+ x->mmap_mode = 0;
x->myeuid = geteuid ();
x->one_file_system = 0;
x->preserve_owner_and_group = 1;
@@ -341,6 +342,7 @@
-i, --interactive prompt before overwrite\n\
--strip-trailing-slashes remove any trailing slashes from each SOURCE\n\
argument\n\
+ -M, --mmap use mmap() and madvise() to copy files\n\
-S, --suffix=SUFFIX override the usual backup suffix\n\
--target-directory=DIRECTORY move all SOURCE arguments into DIRECTORY\n\
-u, --update move only older or brand new non-directories\n\
@@ -394,7 +396,7 @@
errors = 0;
- while ((c = getopt_long (argc, argv, "bfiuvS:V:", long_options, NULL)) != -1)
+ while ((c = getopt_long (argc, argv, "bfiuvMS:V:", long_options, NULL)) != -1)
{
switch (c)
{
@@ -431,6 +433,9 @@
case 'v':
x.verbose = 1;
break;
+ case 'M':
+ x.mmap_mode = 1;
+ break;
case 'S':
make_backups = 1;
backup_suffix_string = optarg;