implemented copyReg() with mmap(2) instead of read(2)+write(2) sequences
authorEnrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
Fri, 18 Mar 2005 00:21:28 +0000 (00:21 +0000)
committerEnrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
Fri, 18 Mar 2005 00:21:28 +0000 (00:21 +0000)
git-svn-id: http://svn.linux-vserver.org/svn/util-vserver/trunk@1916 94cd875c-1c1d-0410-91d2-eb244daf1a30

util-vserver/lib_internal/unify-copy.c

index 554c077..0264723 100644 (file)
 #endif
 
 #include "unify.h"
-#include <sys/stat.h>
+#include "util.h"
+
 #include <unistd.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
 
 #define ENSC_WRAPPERS_IO       1
 #include <wrappers.h>
 
+  //#define MMAP_BLOCKSIZE             0x10000000
+#define MMAP_BLOCKSIZE         0x4000
+
 static inline bool
 verifySource(int fd, struct stat const *exp_stat)
 {
@@ -58,6 +66,68 @@ copyLnk(char const *src, char const *dst)
   }
 }
 
+static jmp_buf                 bus_error_restore;
+static volatile sig_atomic_t   bus_error;
+
+static void
+handlerSIGBUS(int UNUSED num)
+{
+  bus_error = 1;
+  longjmp(bus_error_restore, 1);
+}
+
+static UNUSED bool
+copyMMap(int in_fd, int out_fd)
+{
+  off_t                        in_len   = lseek(in_fd, 0, SEEK_END);
+  void volatile const  *in_buf  = 0;
+  void volatile                *out_buf = 0;
+  
+  volatile loff_t      in_size  = 0;
+  volatile loff_t      out_size = 0;
+  volatile bool                res      = false;
+
+  if (in_len==-1) return false;
+  if (in_len>0 &&
+      (lseek(out_fd, in_len-1, SEEK_SET)==-1 ||
+       write(out_fd, "\0",     1)!=1))         // create sparse file
+    return false;
+  
+  bus_error = 0;
+  if (setjmp(bus_error_restore)==0) {
+    off_t              offset = 0;
+
+    while (offset < in_len) {
+      in_size = in_len - offset;
+      if (in_size > MMAP_BLOCKSIZE) in_size = MMAP_BLOCKSIZE;
+      
+      in_buf   = mmap(0, in_size,  PROT_READ,  MAP_SHARED, in_fd,  offset);
+      if (in_buf==0)  goto out;
+
+      out_size = in_size;
+      out_buf  = mmap(0, out_size, PROT_WRITE, MAP_SHARED, out_fd, offset);
+      if (out_buf==0) goto out;
+
+      offset  += in_size;
+      madvise(const_cast(void *)(in_buf),  in_size,  MADV_SEQUENTIAL);
+      madvise(out_buf,                     out_size, MADV_SEQUENTIAL);
+
+      memcpy(out_buf, in_buf, in_size);
+
+      munmap(const_cast(void *)(in_buf),  in_size);  in_buf  = 0;
+      munmap(out_buf,                     out_size); out_buf = 0;
+    }
+
+    res = true;
+  }
+
+  out:
+  if (in_buf!=0)  munmap(const_cast(void *)(in_buf),  in_size);
+  if (out_buf!=0) munmap(out_buf,                     out_size);
+
+  return res;
+}
+
 static inline bool
 copyReg(char const *src, struct stat const *src_stat,
        char const *dst)
@@ -69,6 +139,7 @@ copyReg(char const *src, struct stat const *src_stat,
   if (in_fd==-1 || out_fd==-1 ||
       !verifySource(in_fd, src_stat)) goto err;
 
+#if 0  
   for (;;) {
     char       buf[2048];
     ssize_t    l = read(in_fd, buf, sizeof buf);
@@ -78,7 +149,14 @@ copyReg(char const *src, struct stat const *src_stat,
   }
 
   res = true;
-  
+#else
+  void         (*old_handler)(int) = signal(SIGBUS, handlerSIGBUS);
+
+  res = copyMMap(in_fd, out_fd);
+
+  signal(SIGBUS, old_handler);
+#endif
+
   err:
   if (out_fd!=-1 && close(out_fd)==-1) res=false;
   if (in_fd!=-1  && close(in_fd)==-1)  res=false;