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;

Reply via email to