X-Git-Url: http://git.linux-vserver.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=util-vserver%2Flib_internal%2Funify-copy.c;h=6b93089ed9c742492a54fef7816c438dd62ac7bc;hb=faa778968d1a7dfeaebc9fe4b847e691dc62fd15;hp=c67b48e79dfab199c984eb0c847447c524d972e8;hpb=9f52547ae6ad8bde3d17856480453498e4bd0ab1;p=util-vserver.git diff --git a/util-vserver/lib_internal/unify-copy.c b/util-vserver/lib_internal/unify-copy.c index c67b48e..6b93089 100644 --- a/util-vserver/lib_internal/unify-copy.c +++ b/util-vserver/lib_internal/unify-copy.c @@ -21,14 +21,25 @@ #endif #include "unify.h" -#include +#include "util.h" + #include #include #include +#include +#include +#include +#include #define ENSC_WRAPPERS_IO 1 #include +#define MMAP_BLOCKSIZE (16 * 1024*1024) + +#ifndef TESTSUITE_COPY_CODE +# define TESTSUITE_COPY_CODE do { } while (false) +#endif + static inline bool verifySource(int fd, struct stat const *exp_stat) { @@ -58,27 +69,125 @@ copyLnk(char const *src, char const *dst) } } +static sigjmp_buf bus_error_restore; +static volatile sig_atomic_t bus_error; + +static void +handlerSIGBUS(int UNUSED num) +{ + bus_error = 1; + siglongjmp(bus_error_restore, 1); +} + +static void +copyMem(void *dst_v, void const *src_v, size_t len_v) +{ +#if 1 + int *dst = dst_v; + int const *src = src_v; + size_t len = len_v / sizeof(int); + size_t rest = len_v - sizeof(int)*len; + size_t i=0; + + for (; i0 && + (lseek(out_fd, in_len-1, SEEK_SET)==-1 || + write(out_fd, "\0", 1)!=1)) // create sparse file + return false; + + bus_error = 0; + if (sigsetjmp(bus_error_restore, 1)==0) { + off_t offset = 0; + + while (offset < in_len) { + buf_size = in_len - offset; + if (buf_size > MMAP_BLOCKSIZE) buf_size = MMAP_BLOCKSIZE; + + if ((in_buf = mmap(0, buf_size, PROT_READ, MAP_SHARED, in_fd, offset))==0 || + (out_buf = mmap(0, buf_size, PROT_WRITE, MAP_SHARED, out_fd, offset))==0) { + perror("mmap()"); + goto out; + } + + offset += buf_size; + madvise(const_cast(void *)(in_buf), buf_size, MADV_SEQUENTIAL); + madvise(out_buf, buf_size, MADV_SEQUENTIAL); + + TESTSUITE_COPY_CODE; + copyMem(out_buf, in_buf, buf_size); + + munmap(const_cast(void *)(in_buf), buf_size); in_buf = 0; + munmap(out_buf, buf_size); out_buf = 0; + } + + res = true; + } + + out: + if (in_buf !=0) munmap(const_cast(void *)(in_buf), buf_size); + if (out_buf!=0) munmap(out_buf, buf_size); + + return res; +} + static inline bool copyReg(char const *src, struct stat const *src_stat, char const *dst) { int in_fd = open(src, O_RDONLY|O_NOCTTY|O_NONBLOCK|O_NOFOLLOW|O_LARGEFILE); - int out_fd = in_fd==-1 ? -1 : open(dst, O_CREAT|O_EXCL, 0200); + int out_fd = in_fd==-1 ? -1 : open(dst, O_RDWR|O_CREAT|O_EXCL, 0200); bool res = false; 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); if (l==-1) goto err; if (l==0) break; - if (!WwriteAll(out_fd, buf, l, 0)) return false; + if (!WwriteAll(out_fd, buf, l, 0)) goto err; } 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;