├── patch ├── mutil-1.822.5.patch ├── mutil-1.822.4.patch ├── mutil-1.822.3.patch ├── mutil-1.822.2.patch └── mutil-1.822.1.patch ├── README.md ├── CHANGES ├── INSTALL ├── doc └── usage.txt └── COPYING /patch/mutil-1.822.5.patch: -------------------------------------------------------------------------------- 1 | diff -rupN old5/src/cp.c new/src/cp.c 2 | --- old5/src/cp.c 2018-01-18 14:44:17.939924128 -0800 3 | +++ new/src/cp.c 2019-10-09 14:45:38.688430184 -0700 4 | @@ -143,7 +143,7 @@ GCRY_THREAD_OPTION_PTHREAD_IMPL; 5 | 6 | /* The official name of this program (e.g., no 'g' prefix). */ 7 | // PZK > 8 | -#define PROGRAM_NAME "mcp 1.822.5" 9 | +#define PROGRAM_NAME "mcp 1.822.6" 10 | 11 | #define AUTHORS \ 12 | proper_name_utf8 ("Torbjorn Granlund", "Torbj\303\266rn Granlund"), \ 13 | diff -rupN old5/src/md5sum.c new/src/md5sum.c 14 | --- old5/src/md5sum.c 2018-01-18 14:44:17.939924128 -0800 15 | +++ new/src/md5sum.c 2019-10-09 14:45:27.456116389 -0700 16 | @@ -139,7 +139,7 @@ GCRY_THREAD_OPTION_PTHREAD_IMPL; 17 | /* The official name of this program (e.g., no 'g' prefix). */ 18 | #if HASH_ALGO_MD5 19 | // PZK > 20 | -# define PROGRAM_NAME "msum 1.822.5" 21 | +# define PROGRAM_NAME "msum 1.822.6" 22 | // < PZK 23 | # define DIGEST_TYPE_STRING "MD5" 24 | # define DIGEST_STREAM md5_stream 25 | @@ -1061,7 +1061,7 @@ split_3 (char *s, size_t s_len, 26 | i += digest_hex_bytes; 27 | // PZK > 28 | //TODO: put this in for checktree 29 | - while (!ISWHITE (s[i])) 30 | + while (isxdigit(s[i])) 31 | i++; 32 | // < PZK 33 | if (!ISWHITE (s[i])) 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Multi-Threaded/Multi-Node Utilities (Mutil) 2 | =========================================== 3 | 4 | Copies between local file systems are a daily activity. Files are 5 | constantly being moved to locations accessible by systems with different 6 | functions and/or storage limits, being backed up and restored, or being 7 | moved due to upgraded and/or replaced hardware. Hence, maximizing the 8 | performance of copies as well as checksums that ensure the integrity of 9 | copies is desirable to minimize the turnaround time of user and 10 | administrator activities. Modern parallel file systems provide very 11 | high performance for such operations using a variety of techniques such 12 | as striping files across multiple disks to increase aggregate I/O 13 | bandwidth and spreading disks across multiple servers to increase 14 | aggregate interconnect bandwidth. 15 | 16 | To achieve peak performance from such systems, it is typically 17 | necessary to utilize multiple concurrent readers/writers from multiple 18 | systems to overcome various single-system limitations such as number of 19 | processors and network bandwidth. The standard cp and md5sum tools of 20 | GNU coreutils found on every modern Unix/Linux system, however, utilize 21 | a single execution thread on a single CPU core of a single system, hence 22 | cannot take full advantage of the increased performance of clustered 23 | file systems. 24 | 25 | Mutil provides mcp and msum, which are drop-in replacements for cp and 26 | md5sum that utilize multiple types of parallelism to achieve maximum 27 | copy and checksum performance on clustered file systems. 28 | Multi-threading is used to ensure that nodes are kept as busy as 29 | possible. Read/write parallelism allows individual operations of a 30 | single copy to be overlapped using asynchronous I/O. Multi-node 31 | cooperation allows different nodes to take part in the same 32 | copy/checksum. Split file processing allows multiple threads to 33 | operate concurrently on the same file. Finally, hash trees allow 34 | inherently serial checksums to be performed in parallel. 35 | 36 | For full details of the mcp and msum implementations and their (old) 37 | expected performance, see https://pkolano.github.io/papers/lisa10.pdf. 38 | For installation details, see "INSTALL". For usage details, see 39 | "doc/usage.txt". 40 | 41 | Questions, comments, fixes, and/or enhancements welcome. 42 | 43 | --Paul Kolano 44 | 45 | -------------------------------------------------------------------------------- /CHANGES: -------------------------------------------------------------------------------- 1 | CHANGES 2 | ======= 3 | 4 | * Mutil 1.76.1 (10/27/10) 5 | - First public release 6 | 7 | * Mutil 1.76.2 (01/04/11) 8 | - Removed Makefile that was used to create distribution 9 | - Added patch to upgrade from previous version 10 | - Added deallocation code for semaphores and queues 11 | - Fixed high memory utilization when using hash trees 12 | - Removed MPI thread limitation that prevented memory overruns 13 | since problem was caused by old hash tree code 14 | 15 | * Mutil 1.76.3 (08/25/11) 16 | - Added note about need for static version of libgpg-error 17 | - Hash of stdin (i.e. piped input and file name "-") now works in msum 18 | - Hash output format of mcp now exactly matches msum 19 | - Added --check-tree option to isolate corruption 20 | - Added --offset and --length options to copy/sum a specific file subset 21 | - Added file restriping to mcp based on file size for Lustre targets 22 | - Added --print-stripe to mcp to print striping changes to stderr 23 | - Fixed divide by 0 when hash leaf size is 0 due to default split size 24 | - Changed hash output so non-standard output is reported in comments 25 | - Now adjust split size to buffer size when 0 < split size < buffer size 26 | - Fixed making of holes in mcp in double buffer case 27 | - Split --fadvise into --fadvise-read and --fadvise-write 28 | - Added --skip-chmod to mcp to retain temporary permissions used during copy 29 | - Fixed --direct-read errors on some file systems due to last unaligned read 30 | 31 | * Mutil 1.76.4 (09/01/11) 32 | - Fixed race condition between last unaligned read and disabling direct I/O 33 | when --direct-read and --double-buffer enabled 34 | 35 | * Mutil 1.76.5 (09/12/11) 36 | - Fixed references to fadvise/--fadvise instead of 37 | fadvise_read/--fadvise-read (bug report by W. Kettler) 38 | - Fixed error messages referencing --read_stdin instead of --read-stdin 39 | 40 | * Mutil 1.76.6 (10/15/12) 41 | - Fixed various compiler warnings 42 | - Fixed last zero-length read when --double-buffer enabled 43 | - Fixed improper off_t parsing of various options 44 | - Fixed offset of last posix_fadvise on write buffer 45 | - Fixed unaligned file offsets during --direct-read 46 | - Fixed alignment multiple, which must be higher than open man page states 47 | - Added ability to set posix_fadvise as default in reads and/or writes 48 | 49 | * Mutil 1.76.7 (01/24/14) 50 | - Fixed segfault when hashing multiple portions of the same file 51 | that are larger than the split size during --read-stdin 52 | - Fixed segfault when hashing unreadable file 53 | - Added --dst-offset option to copy to specific position in target 54 | - Added --stripe-count option to set absolute/size-relative striping 55 | - Added --print-src option to show src file instead of dst during 56 | --print-stats and --print-hash 57 | - Added ability to copy/hash zero length subsets of files 58 | - Removed --store-hash option since not viable given xattr performance 59 | - Added some notes about CentOS/RHEL in INSTALL 60 | 61 | * Mutil 1.76.8 (05/19/14) 62 | - Fixed intermittent deadlock due to misbehaving OpenMP locks 63 | (bug report and debugging support by G. Butler) 64 | 65 | * Mutil 1.822.1 (01/08/15) 66 | - Updated to 8.x coreutils with improved sparse file handling/performance 67 | - Added ability to enable/disable static linking of gcrypt/gnutls 68 | - Added --preallocate option to minimize extents of non-sparse files 69 | - Fixed gnutls tests to check for srp functions missing on centos/rhel 70 | - Fixed missing ENONMEM during gcrypt thread enable on centos/rhel 71 | - Fixed no longer used parameters to hash functions 72 | - Fixed final file size during partial copy with hole at end 73 | 74 | * Mutil 1.822.2 (01/14/15) 75 | - Fixed ignored #mutil# prefix in msum during -c 76 | - Fixed compiler warnings for gnutls_transport_set_ptr/LOV_MAX_STRIPE_COUNT 77 | - Removed references to gnutls-extra since no longer exists in recent gnutls 78 | - Removed note about hash leaf size adjustment during some cases 79 | - Removed --as-needed from ld args since not always supported (e.g. OSX) 80 | - Added workarounds when clock_gettime does not exist (e.g. OSX) 81 | - Changed to System V semaphores since POSIX semaphores broken on OSX 82 | - Now supports OSX (note that default gcc 4.2.1 does not support OpenMP) 83 | 84 | * Mutil 1.822.3 (03/03/15) 85 | - Fixed write error handling when double buffering enabled 86 | - Added additional asynchronous i/o error handling 87 | 88 | * Mutil 1.822.4 (04/14/16) 89 | - Fixed final file size in some cases when src ends with hole 90 | - Fixed --sparse=never corruption in some cases when --double-buffer enabled 91 | 92 | * Mutil 1.822.5 (01/18/18) 93 | - Fixed preservation of execute permission on recent lustre versions 94 | - Fixed compiler warnings for direct include of liblustreapi.h 95 | - Fixed handling of long input lines when using --read-stdin 96 | 97 | * Mutil 1.822.6 (10/09/19) 98 | - Fixed segfault in msum when -c input contains certain malformed hashes 99 | -------------------------------------------------------------------------------- /patch/mutil-1.822.4.patch: -------------------------------------------------------------------------------- 1 | diff -rupN old4/configure new/configure 2 | --- old4/configure 2015-01-14 15:14:48.000000000 -0800 3 | +++ new/configure 2018-01-18 14:44:19.271960028 -0800 4 | @@ -8646,12 +8646,12 @@ fi 5 | fi 6 | 7 | 8 | - for ac_header in lustre/liblustreapi.h 9 | + for ac_header in lustre/lustreapi.h 10 | do : 11 | - ac_fn_c_check_header_mongrel "$LINENO" "lustre/liblustreapi.h" "ac_cv_header_lustre_liblustreapi_h" "$ac_includes_default" 12 | -if test "x$ac_cv_header_lustre_liblustreapi_h" = xyes; then : 13 | + ac_fn_c_check_header_mongrel "$LINENO" "lustre/lustreapi.h" "ac_cv_header_lustre_lustreapi_h" "$ac_includes_default" 14 | +if test "x$ac_cv_header_lustre_lustreapi_h" = xyes; then : 15 | cat >>confdefs.h <<_ACEOF 16 | -#define HAVE_LUSTRE_LIBLUSTREAPI_H 1 17 | +#define HAVE_LUSTRE_LUSTREAPI_H 1 18 | _ACEOF 19 | 20 | fi 21 | diff -rupN old4/lib/config.hin new/lib/config.hin 22 | --- old4/lib/config.hin 2015-01-14 15:14:49.000000000 -0800 23 | +++ new/lib/config.hin 2018-01-18 14:44:19.183957656 -0800 24 | @@ -1693,8 +1693,8 @@ 25 | /* Define to 1 if you have the `lstat' function. */ 26 | #undef HAVE_LSTAT 27 | 28 | -/* Define to 1 if you have the header file. */ 29 | -#undef HAVE_LUSTRE_LIBLUSTREAPI_H 30 | +/* Define to 1 if you have the header file. */ 31 | +#undef HAVE_LUSTRE_LUSTREAPI_H 32 | 33 | /* Define to 1 if you have the `lutimes' function. */ 34 | #undef HAVE_LUTIMES 35 | diff -rupN old4/m4/mutil.m4 new/m4/mutil.m4 36 | --- old4/m4/mutil.m4 2015-01-14 15:02:53.000000000 -0800 37 | +++ new/m4/mutil.m4 2018-01-18 14:44:17.079900948 -0800 38 | @@ -84,7 +84,7 @@ AC_DEFUN([mutil_LIBGCRYPT], [ 39 | ]) 40 | 41 | AC_DEFUN([mutil_LIBLUSTREAPI], [ 42 | - AC_CHECK_HEADERS([lustre/liblustreapi.h]) 43 | + AC_CHECK_HEADERS([lustre/lustreapi.h]) 44 | AC_CHECK_LIB([lustreapi], [llapi_file_get_stripe]) 45 | ]) 46 | 47 | diff -rupN old4/src/copy.c new/src/copy.c 48 | --- old4/src/copy.c 2016-04-14 15:25:49.000000000 -0700 49 | +++ new/src/copy.c 2018-01-18 14:44:17.935924020 -0800 50 | @@ -163,8 +163,7 @@ static inline int sync_file_range( 51 | 52 | #if HAVE_LIBLUSTREAPI 53 | # include 54 | -# include 55 | -# include 56 | +# include 57 | # include 58 | # define MAX_OSTS 1024 59 | # define LOV_EA_SIZE(lum, num) (sizeof(*lum) + num * sizeof(*lum->lmm_objects)) 60 | @@ -1718,19 +1717,15 @@ copy_reg (char const *src_name, char con 61 | } 62 | } 63 | if (scount > MUTIL_MAX_STRIPE_COUNT) scount = MUTIL_MAX_STRIPE_COUNT; 64 | - if (!llapi_file_create(dst_name, ssize, -1, scount, 0)) { 65 | - dest_desc = open (dst_name, open_flags | O_LOV_DELAY_CREATE, 66 | - wdst_mode & ~omitted_permissions); 67 | - if (dest_desc && !llapi_file_get_stripe(dst_name, lum) && 68 | - lum->lmm_stripe_count != scount) { 69 | - //TODO: this probably shouldn't be printed for every 70 | - // file, especially when physical OST counts differ 71 | - // between file systems 72 | - error(0, 0, _("warning: allocated stripe count of %s does not match original stripe count of %s"), 73 | - quote_n(0, dst_name), quote_n(1, src_name)); 74 | - } 75 | - } else { 76 | - dest_desc = -1; 77 | + dest_desc = llapi_file_open(dst_name, open_flags, 78 | + wdst_mode & ~omitted_permissions, ssize, -1, scount, 0); 79 | + if (dest_desc > 0 && !llapi_file_get_stripe(dst_name, lum) && 80 | + lum->lmm_stripe_count != scount) { 81 | + //TODO: this probably shouldn't be printed for every 82 | + // file, especially when physical OST counts differ 83 | + // between file systems 84 | + error(0, 0, _("warning: allocated stripe count of %s does not match original stripe count of %s"), 85 | + quote_n(0, dst_name), quote_n(1, src_name)); 86 | } 87 | free(lum); 88 | } else 89 | diff -rupN old4/src/cp.c new/src/cp.c 90 | --- old4/src/cp.c 2016-04-14 15:25:51.000000000 -0700 91 | +++ new/src/cp.c 2019-10-09 14:45:38.688430184 -0700 92 | @@ -143,7 +143,7 @@ GCRY_THREAD_OPTION_PTHREAD_IMPL; 93 | 94 | /* The official name of this program (e.g., no 'g' prefix). */ 95 | // PZK > 96 | -#define PROGRAM_NAME "mcp 1.822.4" 97 | +#define PROGRAM_NAME "mcp 1.822.6" 98 | 99 | #define AUTHORS \ 100 | proper_name_utf8 ("Torbjorn Granlund", "Torbj\303\266rn Granlund"), \ 101 | @@ -1997,22 +1997,16 @@ do_copy (int n_files, char **file, const 102 | // PZK > 103 | else if (x->read_stdin) 104 | { 105 | - /* Start with a buffer larger than PATH_MAX, but beware of systems 106 | - on which PATH_MAX is very large -- e.g., INT_MAX. */ 107 | - size_t buf_max = MIN(2 * PATH_MAX, 32 * 1024); 108 | - char *buf = xmalloc(buf_max); 109 | + char *buf = NULL; 110 | + size_t buf_max = 0; 111 | 112 | char *new_dest; 113 | char *source; 114 | char *dest; 115 | bool unused; 116 | 117 | - while (fgets(buf, buf_max, stdin) != NULL) { 118 | + while (getline(&buf, &buf_max, stdin) > 0) { 119 | buf[strcspn(buf, "\n")] = '\0'; 120 | - if (buf[0] == '\0') { 121 | - //TODO: error handling if string too long 122 | - continue; 123 | - } 124 | size_t ifile2 = strcspn(buf, " "); 125 | if (buf[ifile2] == '\0') continue; 126 | buf[ifile2++] = '\0'; 127 | @@ -2123,6 +2117,7 @@ do_copy (int n_files, char **file, const 128 | free(source); 129 | free(dest); 130 | } 131 | + free(buf); 132 | } 133 | // < PZK 134 | else /* !target_directory */ 135 | diff -rupN old4/src/md5sum.c new/src/md5sum.c 136 | --- old4/src/md5sum.c 2016-04-14 15:53:31.000000000 -0700 137 | +++ new/src/md5sum.c 2019-10-09 14:45:27.456116389 -0700 138 | @@ -139,7 +139,7 @@ GCRY_THREAD_OPTION_PTHREAD_IMPL; 139 | /* The official name of this program (e.g., no 'g' prefix). */ 140 | #if HASH_ALGO_MD5 141 | // PZK > 142 | -# define PROGRAM_NAME "msum 1.822.4" 143 | +# define PROGRAM_NAME "msum 1.822.6" 144 | // < PZK 145 | # define DIGEST_TYPE_STRING "MD5" 146 | # define DIGEST_STREAM md5_stream 147 | @@ -1061,7 +1061,7 @@ split_3 (char *s, size_t s_len, 148 | i += digest_hex_bytes; 149 | // PZK > 150 | //TODO: put this in for checktree 151 | - while (!ISWHITE (s[i])) 152 | + while (isxdigit(s[i])) 153 | i++; 154 | // < PZK 155 | if (!ISWHITE (s[i])) 156 | @@ -2581,15 +2581,11 @@ main (int argc, char **argv) 157 | char *file = argv[optind]; 158 | // PZK > 159 | if (x.read_stdin) { 160 | - size_t buf_max = MIN(PATH_MAX, 32 * 1024); 161 | - char *buf = xmalloc(buf_max); 162 | + char *buf = NULL; 163 | + size_t buf_max = 0; 164 | 165 | - while (fgets(buf, buf_max, stdin) != NULL) { 166 | + while (getline(&buf, &buf_max, stdin) > 0) { 167 | buf[strcspn(buf, "\n")] = '\0'; 168 | - if (file[0] == '\0') { 169 | - //TODO: error handling if string too long 170 | - continue; 171 | - } 172 | size_t irange = strcspn(buf, " "); 173 | if (buf[irange] == '\0') irange = 0; 174 | else buf[irange++] = '\0'; 175 | @@ -2616,6 +2612,7 @@ main (int argc, char **argv) 176 | ok = false; 177 | } 178 | } 179 | + free(buf); 180 | break; 181 | } 182 | // < PZK 183 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | Mutil Installation 2 | ================== 3 | 4 | 1. Prerequisites 5 | 6 | o GNU coreutils 8.22 7 | 8 | The Mutil patch is only applicable against coreutils 8.22. 9 | 10 | o Compiler with OpenMP support 11 | 12 | For example, the GNU C Compiler >= 4.2 or Intel C Compiler >= 9.1. 13 | Note that the default gcc 4.2.1 on OSX does not support OpenMP 14 | for some reason. Tested with gcc 4.4.4 on Linux and 4.9.1 on OSX. 15 | 16 | o GNU TLS library (optional but required for multi-node TCP support) 17 | 18 | Tested with gnutls 2.8.6/2.10.5/3.3.11 (using --with-included-tasn1). 19 | Note that CentOS and RHEL may include versions of gnutls with 20 | the required SRP functionality removed (due to potential patent 21 | issues). In those cases, gnutls must be built from source. 22 | Also note that a static version of libz is required when Mutil 23 | is configured with --with-static-gcrypt, which may be missing on 24 | CentOS/RHEL systems and may result in unusual configure output 25 | (e.g. "could not determine how to read list of mounted file 26 | systems"). 27 | 28 | o Libgcrypt library (optional but required for hashing support) 29 | 30 | Note that msum is not functional without this, but mcp is still 31 | usable. Tested with libgcrypt 1.4.5/1.6.2. 32 | 33 | o Libgpg-error library (optional but required for hashing support) 34 | 35 | Note that if Mutil is configured with --with-static-gcrypt, 36 | libgpg-error must be configured with --enable-static to ensure 37 | that the static version of this library exists. In this case, 38 | libgpg-error should be built before libgcrypt, which should be 39 | built before gnutls. Tested with libgpg-error 1.7/1.17. 40 | 41 | o MPI library (optional but required for multi-node MPI support) 42 | 43 | Tested with SGI Message Passing Toolkit 1.25/1.26/2.11r13. 44 | 45 | 46 | 2. Installation 47 | 48 | Note that while coreutils compiles on many types of systems, Mutil 49 | has only been tested on Linux and OSX. It is unknown if it will 50 | compile and/or operate properly on other types of systems. 51 | 52 | 2.1. Preparation 53 | 54 | 2.1.1. New Installation 55 | 56 | Mutil is created by applying the "coreutils-8.22" patch to an 57 | unpacked coreutils 8.22 distribution. This is done via the 58 | "patch" command: 59 | 60 | cd coreutils-8.22 61 | patch -p1 < /path/to/patch/coreutils-8.22.patch 62 | 63 | The output should be similar to the following: 64 | 65 | patching file COPYING 66 | patching file Makefile.in 67 | patching file aclocal.m4 68 | patching file configure 69 | patching file gnulib-tests/Makefile.in 70 | patching file lib/config.hin 71 | patching file m4/gnulib-common.m4 72 | patching file m4/mutil.m4 73 | patching file src/copy.c 74 | patching file src/copy.h 75 | patching file src/cp.c 76 | patching file src/extent-scan.c 77 | patching file src/extent-scan.h 78 | patching file src/local.mk 79 | patching file src/md5sum.c 80 | patching file src/mutil-q.h 81 | patching file src/mutil.c 82 | patching file src/mutil.h 83 | patching file tests/cp/backup-is-src.sh 84 | 85 | 2.1.2. Upgrade Installation 86 | 87 | If you have previously patched coreutils 8.22 to produce 88 | Mutil 1.822.N, you may upgrade to the latest by applying 89 | the corresponding "mutil-1.822.N" patch: 90 | 91 | cd coreutils-8.22 92 | patch -p1 < /path/to/patch/mutil-1.822.N.patch 93 | 94 | The output should be the following for Mutil 1.822.1: 95 | 96 | patching file configure 97 | patching file lib/config.hin 98 | patching file m4/gnulib-common.m4 99 | patching file m4/mutil.m4 100 | patching file src/copy.c 101 | patching file src/cp.c 102 | patching file src/md5sum.c 103 | patching file src/mutil-q.h 104 | patching file src/mutil.c 105 | patching file src/mutil.h 106 | 107 | The output should be the following for Mutil 1.822.2: 108 | 109 | patching file src/copy.c 110 | patching file src/cp.c 111 | patching file src/md5sum.c 112 | 113 | The output should be the following for Mutil 1.822.3: 114 | 115 | patching file src/copy.c 116 | patching file src/cp.c 117 | patching file src/md5sum.c 118 | 119 | The output should be the following for Mutil 1.822.4: 120 | 121 | patching file configure 122 | patching file lib/config.hin 123 | patching file m4/mutil.m4 124 | patching file src/copy.c 125 | patching file src/cp.c 126 | patching file src/md5sum.c 127 | 128 | 2.2. Configuration 129 | 130 | Mutil supports auto-detection of its prerequisites through the 131 | normal "configure" process. If any prerequisites are installed 132 | in non-standard locations, you must set CFLAGS and LDFLAGS 133 | before invoking configure. For example (using sh syntax): 134 | 135 | export CFLAGS=-I/my/include 136 | export LDFLAGS=-L/my/lib 137 | 138 | would search for additional include files in /my/include and 139 | additional libraries in /my/lib. Note that gnutls and libgcrypt 140 | are statically linked into the executables so need only be 141 | available during compilation. 142 | 143 | For OpenMP and/or MPI libraries that are in non-standard 144 | locations, but accessible by all users, a run-time path can be 145 | supplied to the linker so users do not need to set environment 146 | variables such as LD_LIBRARY_PATH. For example: 147 | 148 | export LDFLAGS=-L/gcc/4.4.4/lib64 -lgomp -Wl,-rpath /gcc/4.4.4/lib64' 149 | 150 | would always search for the gcc OpenMP libraries in /gcc/4.4.4/lib64 151 | even if that path is not in the user's or system's environment. 152 | 153 | The default values of some options can be changed by adding 154 | additional definitions into CFLAGS. The following settings 155 | may be configured at compile-time (defaults in brackets): 156 | 157 | DEFAULT_BUFFER_SIZE [4] (MB) 158 | DEFAULT_DIRECT_READ [0] 159 | DEFAULT_DIRECT_WRITE [0] 160 | DEFAULT_DOUBLE_BUFFER [0] 161 | DEFAULT_FADVISE_READ [0] 162 | DEFAULT_FADVISE_WRITE [0] 163 | DEFAULT_HASH_TYPE [GCRY_MD_MD5] 164 | DEFAULT_LUSTRE_STRIPES [1] 165 | DEFAULT_SPLIT_SIZE [0] (MB) 166 | DEFAULT_THREADS [4] 167 | 168 | For example: 169 | 170 | export CFLAGS="-I/my/include -DDEFAULT_BUFFER_SIZE=1" 171 | 172 | would set the default buffer size to 1 MB. 173 | 174 | Note that no validation is done on default parameters so make 175 | sure they conform to expected values. Namely, the split size 176 | should be a non-negative integer, the buffer size and number of 177 | threads should be positive integers, and the direct read, direct 178 | write, double buffer, fadvise read, and fadvise write values 179 | should be 0 or 1. The default hash type must be a Libgcrypt 180 | definition beginning with "GCRY_" corresponding to a supported 181 | hash defined in gcrypt.h. The default lustre stripes setting 182 | should match the configured lustre stripe count default. 183 | 184 | Also note that setting the default split size to any value 185 | besides zero breaks drop-in compatibility of the hashing 186 | functionality as files larger than this size will produce a 187 | sum based on a hash tree instead of a plain hash. The benefit 188 | of using a non-zero split size is that performance can be 189 | increased dramatically on large files by default. 190 | 191 | Some file systems do not support direct I/O so care should be 192 | taken enabling it by default. Note that if any of direct read, 193 | direct write, double buffer, fadvise read, or fadvise write is 194 | enabled by default, the corresponding command-line options will 195 | become --no-direct-read, --no-direct-write, --no-double-buffer, 196 | --no-fadvise-read, and --no-fadvise-write. 197 | 198 | Once the environment has been configured, run: 199 | 200 | ./configure 201 | 202 | To statically link libgcrypt, libgpg-error, and gnutls (if 203 | available) into the resulting executables so they only need to 204 | exist on the build system, use: 205 | 206 | ./configure --with-static-gcrypt 207 | 208 | Otherwise, these dependencies must exist as shared libraries 209 | on any system on which mcp/msum are invoked. See notes in 210 | "Prerequisites" section regarding the use of --with-static-gcrypt. 211 | Run "./configure --help" for additional configuration options. 212 | 213 | 2.3. Compilation 214 | 215 | To compile, run: 216 | 217 | make 218 | 219 | Mutil does not rename the resulting files, so after compilation: 220 | 221 | o src/cp is the mcp executable 222 | o src/md5sum is the msum executable 223 | o man/cp.1 is the mcp man file 224 | o man/md5sum.1 is the msum man file 225 | 226 | The options listed in the man pages and when the executables are 227 | run with "--help" will vary depending on which prerequisites 228 | were available during the build process. 229 | 230 | 2.4. Installation 231 | 232 | *DO NOT* run "make install". It is unknown and untested whether 233 | or not the Mutil modifications affect the behavior of other 234 | coreutils components so is safest to install Mutil manually by 235 | copying the executables and man files to the appropriate 236 | directories. For example, to install to "/usr/local", use: 237 | 238 | install -m 755 src/cp /usr/local/bin/mcp 239 | install -m 755 src/md5sum /usr/local/bin/msum 240 | install -m 644 man/cp.1 /usr/local/man/man1/mcp.1 241 | install -m 644 man/md5sum.1 /usr/local/man/man1/msum.1 242 | 243 | Note that in this example, the files have been renamed to 244 | mcp/msum. Alternatively, these files can be copied to the 245 | default system locations to transparently obtain Mutil 246 | performance benefits, but this should only be done after 247 | validating their behavior within the target environment. 248 | 249 | If the system md5sum is going to be replaced, it is advised to 250 | keep the DEFAULT_SPLIT_SIZE setting at zero to ensure that 251 | externally computed md5sum checksums will match locally computed 252 | values by default. Note that this will negatively affect the 253 | default (i.e. "option-less") performance of single file 254 | copies, however, since each file will be single-threaded unless 255 | a positive --split-size value is explicitly specified 256 | (multi-file copies will still operate in multi-threaded fashion 257 | by default). 258 | 259 | -------------------------------------------------------------------------------- /patch/mutil-1.822.3.patch: -------------------------------------------------------------------------------- 1 | diff -rupN old3/configure new/configure 2 | --- old3/configure 2015-01-14 15:14:48.000000000 -0800 3 | +++ new/configure 2018-01-18 14:44:19.271960028 -0800 4 | @@ -8646,12 +8646,12 @@ fi 5 | fi 6 | 7 | 8 | - for ac_header in lustre/liblustreapi.h 9 | + for ac_header in lustre/lustreapi.h 10 | do : 11 | - ac_fn_c_check_header_mongrel "$LINENO" "lustre/liblustreapi.h" "ac_cv_header_lustre_liblustreapi_h" "$ac_includes_default" 12 | -if test "x$ac_cv_header_lustre_liblustreapi_h" = xyes; then : 13 | + ac_fn_c_check_header_mongrel "$LINENO" "lustre/lustreapi.h" "ac_cv_header_lustre_lustreapi_h" "$ac_includes_default" 14 | +if test "x$ac_cv_header_lustre_lustreapi_h" = xyes; then : 15 | cat >>confdefs.h <<_ACEOF 16 | -#define HAVE_LUSTRE_LIBLUSTREAPI_H 1 17 | +#define HAVE_LUSTRE_LUSTREAPI_H 1 18 | _ACEOF 19 | 20 | fi 21 | diff -rupN old3/lib/config.hin new/lib/config.hin 22 | --- old3/lib/config.hin 2015-01-14 15:14:49.000000000 -0800 23 | +++ new/lib/config.hin 2018-01-18 14:44:19.183957656 -0800 24 | @@ -1693,8 +1693,8 @@ 25 | /* Define to 1 if you have the `lstat' function. */ 26 | #undef HAVE_LSTAT 27 | 28 | -/* Define to 1 if you have the header file. */ 29 | -#undef HAVE_LUSTRE_LIBLUSTREAPI_H 30 | +/* Define to 1 if you have the header file. */ 31 | +#undef HAVE_LUSTRE_LUSTREAPI_H 32 | 33 | /* Define to 1 if you have the `lutimes' function. */ 34 | #undef HAVE_LUTIMES 35 | diff -rupN old3/m4/mutil.m4 new/m4/mutil.m4 36 | --- old3/m4/mutil.m4 2015-01-14 15:02:53.000000000 -0800 37 | +++ new/m4/mutil.m4 2018-01-18 14:44:17.079900948 -0800 38 | @@ -84,7 +84,7 @@ AC_DEFUN([mutil_LIBGCRYPT], [ 39 | ]) 40 | 41 | AC_DEFUN([mutil_LIBLUSTREAPI], [ 42 | - AC_CHECK_HEADERS([lustre/liblustreapi.h]) 43 | + AC_CHECK_HEADERS([lustre/lustreapi.h]) 44 | AC_CHECK_LIB([lustreapi], [llapi_file_get_stripe]) 45 | ]) 46 | 47 | diff -rupN old3/src/copy.c new/src/copy.c 48 | --- old3/src/copy.c 2015-03-03 09:17:41.000000000 -0800 49 | +++ new/src/copy.c 2018-01-18 14:44:17.935924020 -0800 50 | @@ -163,8 +163,7 @@ static inline int sync_file_range( 51 | 52 | #if HAVE_LIBLUSTREAPI 53 | # include 54 | -# include 55 | -# include 56 | +# include 57 | # include 58 | # define MAX_OSTS 1024 59 | # define LOV_EA_SIZE(lum, num) (sizeof(*lum) + num * sizeof(*lum->lmm_objects)) 60 | @@ -728,7 +727,8 @@ extent_copy (copy_reg_t *crt, struct cp_ 61 | || (!empty_extent && sparse_mode != SPARSE_NEVER)) 62 | { 63 | // PZK > 64 | - if (lseek (crt->dst_fd, ext_start, SEEK_SET) < 0) 65 | + if (lseek (crt->dst_fd, crt->dst_offset - crt->start_offset + 66 | + ext_start, SEEK_SET) < 0) 67 | { 68 | error (0, errno, _("cannot lseek %s"), quote (crt->dst_name)); 69 | // < PZK 70 | @@ -745,7 +745,13 @@ extent_copy (copy_reg_t *crt, struct cp_ 71 | if (empty_extent) 72 | // PZK > 73 | nzeros = MIN (crt->stop_offset - dest_pos, hole_size); 74 | - 75 | + // when double buffering, dst_fd may not even be set 76 | + if (co->double_buffer && lseek(crt->dst_fd, 77 | + crt->dst_offset - crt->start_offset + 78 | + crt->stop_offset - nzeros, SEEK_SET) < 0L) { 79 | + error (0, errno, _("cannot lseek %s"), quote (crt->dst_name)); 80 | + goto fail; 81 | + } 82 | if (! write_zeros (crt->dst_fd, nzeros)) 83 | { 84 | error (0, errno, _("%s: write failed"), quote (crt->dst_name)); 85 | @@ -836,25 +842,30 @@ extent_copy (copy_reg_t *crt, struct cp_ 86 | here in order to record the proper length in the destination. */ 87 | 88 | // PZK > 89 | - if (wrote_hole_at_eof && crt->dst_offset == 0 && 90 | - crt->stop_offset == src_total_size && 91 | - (sparse_mode != SPARSE_NEVER 92 | - ? ftruncate (crt->dst_fd, src_total_size) 93 | - : ! write_zeros (crt->dst_fd, src_total_size - dest_pos))) 94 | - { 95 | - error (0, errno, _("failed to extend %s"), quote (crt->dst_name)); 96 | - return false; 97 | - } 98 | - else if (wrote_hole_at_eof && crt->split + 1 == crt->nsplits && 99 | - (lseek (crt->dst_fd, (off_t) -1, SEEK_CUR) < 0L 100 | - || co->write_mode 101 | - && fcntl (crt->dst_fd, F_SETFL, 102 | - fcntl (crt->dst_fd, F_GETFL) & ~O_DIRECT) 103 | - || full_write (crt->dst_fd, "", 1) != 1)) 104 | - { 105 | - error (0, errno, _("writing %s"), quote (crt->dst_name)); 106 | - return false; 107 | + if (wrote_hole_at_eof || dest_pos < crt->stop_offset) { 108 | + if (sparse_mode == SPARSE_NEVER) { 109 | + if (lseek (crt->dst_fd, crt->dst_offset - crt->start_offset + 110 | + dest_pos, SEEK_SET) < 0L || 111 | + !write_zeros(crt->dst_fd, crt->stop_offset - dest_pos)) { 112 | + error (0, errno, _("%s: write failed"), quote (crt->dst_name)); 113 | + return false; 114 | + } 115 | + } else if (crt->dst_offset == 0 && crt->stop_offset == src_total_size) { 116 | + if (ftruncate(crt->dst_fd, src_total_size)) { 117 | + error (0, errno, _("failed to extend %s"), quote (crt->dst_name)); 118 | + return false; 119 | + } 120 | + } else if (crt->split + 1 == crt->nsplits) { 121 | + if (lseek (crt->dst_fd, crt->dst_offset - crt->start_offset + 122 | + crt->stop_offset - 1, SEEK_SET) < 0L || 123 | + co->write_mode && fcntl (crt->dst_fd, F_SETFL, 124 | + fcntl (crt->dst_fd, F_GETFL) & ~O_DIRECT) || 125 | + full_write (crt->dst_fd, "", 1) != 1) { 126 | + error (0, errno, _("%s: write failed"), quote (crt->dst_name)); 127 | + return false; 128 | + } 129 | } 130 | + } 131 | 132 | #if HAVE_LIBGCRYPT 133 | if (dest_pos < crt->stop_offset) { 134 | @@ -1441,27 +1452,36 @@ copy_reg_task (copy_reg_t *crt, struct c 135 | , &ctx, &htt 136 | #endif 137 | ); 138 | - if (copy_ok && wrote_hole_at_eof && crt->dst_offset == 0 && 139 | - crt->stop_offset == src_open_sb.st_size && 140 | - ftruncate (crt->dst_fd, src_open_sb.st_size) < 0) 141 | - { 142 | - error (0, errno, _("failed to extend %s"), quote (crt->dst_name)); 143 | - return_val = false; 144 | - goto task_close_src_and_dst_desc; 145 | - } 146 | - else if (copy_ok && wrote_hole_at_eof && crt->split + 1 == crt->nsplits && 147 | - (lseek (crt->dst_fd, (off_t) -1, SEEK_CUR) < 0L 148 | // PZK > 149 | - || co->write_mode 150 | - && fcntl (crt->dst_fd, F_SETFL, 151 | - fcntl (crt->dst_fd, F_GETFL) & ~O_DIRECT) 152 | + off_t dest_pos = crt->start_offset + n_read; 153 | + if (copy_ok && (wrote_hole_at_eof || dest_pos < crt->stop_offset)) { 154 | + if (co->sparse_mode == SPARSE_NEVER) { 155 | + if (lseek (crt->dst_fd, crt->dst_offset - crt->start_offset + 156 | + dest_pos, SEEK_SET) < 0L || 157 | + !write_zeros(crt->dst_fd, crt->stop_offset - dest_pos)) { 158 | + error (0, errno, _("%s: write failed"), quote (crt->dst_name)); 159 | + return_val = false; 160 | + goto task_close_src_and_dst_desc; 161 | + } 162 | + } else if (crt->dst_offset == 0 && crt->stop_offset == src_open_sb.st_size) { 163 | + if (ftruncate(crt->dst_fd, src_open_sb.st_size)) { 164 | + error (0, errno, _("failed to extend %s"), quote (crt->dst_name)); 165 | + return_val = false; 166 | + goto task_close_src_and_dst_desc; 167 | + } 168 | + } else if (crt->split + 1 == crt->nsplits) { 169 | + if (lseek (crt->dst_fd, crt->dst_offset - crt->start_offset + 170 | + crt->stop_offset - 1, SEEK_SET) < 0L || 171 | + co->write_mode && fcntl (crt->dst_fd, F_SETFL, 172 | + fcntl (crt->dst_fd, F_GETFL) & ~O_DIRECT) || 173 | + full_write (crt->dst_fd, "", 1) != 1) { 174 | + error (0, errno, _("%s: write failed"), quote (crt->dst_name)); 175 | + return_val = false; 176 | + goto task_close_src_and_dst_desc; 177 | + } 178 | + } 179 | + } 180 | // < PZK 181 | - || full_write (crt->dst_fd, "", 1) != 1)) 182 | - { 183 | - error (0, errno, _("writing %s"), quote (crt->dst_name)); 184 | - return_val = false; 185 | - goto task_close_src_and_dst_desc; 186 | - } 187 | 188 | task_preserve_metadata: 189 | if (co->preserve_timestamps) 190 | @@ -1697,19 +1717,15 @@ copy_reg (char const *src_name, char con 191 | } 192 | } 193 | if (scount > MUTIL_MAX_STRIPE_COUNT) scount = MUTIL_MAX_STRIPE_COUNT; 194 | - if (!llapi_file_create(dst_name, ssize, -1, scount, 0)) { 195 | - dest_desc = open (dst_name, open_flags | O_LOV_DELAY_CREATE, 196 | - wdst_mode & ~omitted_permissions); 197 | - if (dest_desc && !llapi_file_get_stripe(dst_name, lum) && 198 | - lum->lmm_stripe_count != scount) { 199 | - //TODO: this probably shouldn't be printed for every 200 | - // file, especially when physical OST counts differ 201 | - // between file systems 202 | - error(0, 0, _("warning: allocated stripe count of %s does not match original stripe count of %s"), 203 | - quote_n(0, dst_name), quote_n(1, src_name)); 204 | - } 205 | - } else { 206 | - dest_desc = -1; 207 | + dest_desc = llapi_file_open(dst_name, open_flags, 208 | + wdst_mode & ~omitted_permissions, ssize, -1, scount, 0); 209 | + if (dest_desc > 0 && !llapi_file_get_stripe(dst_name, lum) && 210 | + lum->lmm_stripe_count != scount) { 211 | + //TODO: this probably shouldn't be printed for every 212 | + // file, especially when physical OST counts differ 213 | + // between file systems 214 | + error(0, 0, _("warning: allocated stripe count of %s does not match original stripe count of %s"), 215 | + quote_n(0, dst_name), quote_n(1, src_name)); 216 | } 217 | free(lum); 218 | } else 219 | diff -rupN old3/src/cp.c new/src/cp.c 220 | --- old3/src/cp.c 2015-03-03 09:17:45.000000000 -0800 221 | +++ new/src/cp.c 2019-10-09 14:45:38.688430184 -0700 222 | @@ -143,7 +143,7 @@ GCRY_THREAD_OPTION_PTHREAD_IMPL; 223 | 224 | /* The official name of this program (e.g., no 'g' prefix). */ 225 | // PZK > 226 | -#define PROGRAM_NAME "mcp 1.822.3" 227 | +#define PROGRAM_NAME "mcp 1.822.6" 228 | 229 | #define AUTHORS \ 230 | proper_name_utf8 ("Torbjorn Granlund", "Torbj\303\266rn Granlund"), \ 231 | @@ -1997,22 +1997,16 @@ do_copy (int n_files, char **file, const 232 | // PZK > 233 | else if (x->read_stdin) 234 | { 235 | - /* Start with a buffer larger than PATH_MAX, but beware of systems 236 | - on which PATH_MAX is very large -- e.g., INT_MAX. */ 237 | - size_t buf_max = MIN(2 * PATH_MAX, 32 * 1024); 238 | - char *buf = xmalloc(buf_max); 239 | + char *buf = NULL; 240 | + size_t buf_max = 0; 241 | 242 | char *new_dest; 243 | char *source; 244 | char *dest; 245 | bool unused; 246 | 247 | - while (fgets(buf, buf_max, stdin) != NULL) { 248 | + while (getline(&buf, &buf_max, stdin) > 0) { 249 | buf[strcspn(buf, "\n")] = '\0'; 250 | - if (buf[0] == '\0') { 251 | - //TODO: error handling if string too long 252 | - continue; 253 | - } 254 | size_t ifile2 = strcspn(buf, " "); 255 | if (buf[ifile2] == '\0') continue; 256 | buf[ifile2++] = '\0'; 257 | @@ -2123,6 +2117,7 @@ do_copy (int n_files, char **file, const 258 | free(source); 259 | free(dest); 260 | } 261 | + free(buf); 262 | } 263 | // < PZK 264 | else /* !target_directory */ 265 | diff -rupN old3/src/md5sum.c new/src/md5sum.c 266 | --- old3/src/md5sum.c 2015-03-03 09:17:49.000000000 -0800 267 | +++ new/src/md5sum.c 2019-10-09 14:45:27.456116389 -0700 268 | @@ -139,7 +139,7 @@ GCRY_THREAD_OPTION_PTHREAD_IMPL; 269 | /* The official name of this program (e.g., no 'g' prefix). */ 270 | #if HASH_ALGO_MD5 271 | // PZK > 272 | -# define PROGRAM_NAME "msum 1.822.3" 273 | +# define PROGRAM_NAME "msum 1.822.6" 274 | // < PZK 275 | # define DIGEST_TYPE_STRING "MD5" 276 | # define DIGEST_STREAM md5_stream 277 | @@ -1061,7 +1061,7 @@ split_3 (char *s, size_t s_len, 278 | i += digest_hex_bytes; 279 | // PZK > 280 | //TODO: put this in for checktree 281 | - while (!ISWHITE (s[i])) 282 | + while (isxdigit(s[i])) 283 | i++; 284 | // < PZK 285 | if (!ISWHITE (s[i])) 286 | @@ -2581,15 +2581,11 @@ main (int argc, char **argv) 287 | char *file = argv[optind]; 288 | // PZK > 289 | if (x.read_stdin) { 290 | - size_t buf_max = MIN(PATH_MAX, 32 * 1024); 291 | - char *buf = xmalloc(buf_max); 292 | + char *buf = NULL; 293 | + size_t buf_max = 0; 294 | 295 | - while (fgets(buf, buf_max, stdin) != NULL) { 296 | + while (getline(&buf, &buf_max, stdin) > 0) { 297 | buf[strcspn(buf, "\n")] = '\0'; 298 | - if (file[0] == '\0') { 299 | - //TODO: error handling if string too long 300 | - continue; 301 | - } 302 | size_t irange = strcspn(buf, " "); 303 | if (buf[irange] == '\0') irange = 0; 304 | else buf[irange++] = '\0'; 305 | @@ -2616,6 +2612,7 @@ main (int argc, char **argv) 306 | ok = false; 307 | } 308 | } 309 | + free(buf); 310 | break; 311 | } 312 | // < PZK 313 | -------------------------------------------------------------------------------- /doc/usage.txt: -------------------------------------------------------------------------------- 1 | Using Mutil 2 | =========== 3 | 4 | The mcp and msum utilities of Mutil are drop-in replacements for the 5 | standard cp and md5sum programs from GNU coreutils. Hence, they can be 6 | used in exactly the same manner with the same options. The Mutil 7 | versions, however, contain performance and functionality enhancements 8 | accessed through additional command-line options. 9 | 10 | 11 | 1. Mcp-specific options 12 | 13 | Note that the defaults shown in brackets will vary depending on 14 | the compile-time options utilized. 15 | 16 | --buffer-size=MBYTES read/write buffer size [4] 17 | --check-tree print hash subtrees to pinpoint corruption 18 | --direct-read enable use of direct I/O for reads 19 | --direct-write enable use of direct I/O for writes 20 | --double-buffer enable use of double buffering during file I/O 21 | --dst-offset=POS copy to destination file beginning at POS 22 | --fadvise-read enable use of posix_fadvise during reads 23 | --fadvise-write enable use of posix_fadvise during writes 24 | --hash-leaf-size=KBYTES granularity of hash tree [1048576] 25 | --hash-type=TYPE hash type [MD5], with TYPE one of: 26 | md5 sha1 sha256 sha384 sha512 sha224 crc32 27 | crc32rfc1510 crc24rfc2440 28 | --length=LEN copy LEN bytes beginning at --offset 29 | (or from 0 if --offset not specified) 30 | --listen-port=PORT listen on port PORT for requests from 31 | cooperating hosts 32 | --manager-host=HOST host name or IP address of management thread 33 | for multi-node/multi-host copies 34 | --manager-port=PORT port on which to contact management thread 35 | --mpi enable use of MPI for multi-node copies 36 | --offset=POS copy --length bytes beginning at POS 37 | (or to end if --length not specified) 38 | --password-file=FILE file to use for passwords (will be created 39 | if does not exist) 40 | --print-hash print hash of each file to stdout similar to 41 | md5sum, with sum of the src file computed, 42 | but dst file name printed so that md5sum -c 43 | can be used on the output to check that the 44 | data written to disk was what was read 45 | --print-src print src instead of dst in --print-{hash,stats} 46 | --print-stats print performance per file to stderr 47 | --print-stripe print striping changes to stderr 48 | --read-stdin perform a batch of operations read over stdin 49 | in the form 'SRC DST RANGES' where SRC and DST 50 | must be URI-escaped (RFC 3986) file names and 51 | RANGES is zero or more comma-separated ranges of 52 | the form 'START-END' for 0 <= START < END 53 | --skip-chmod retain temporary permissions used during copy 54 | --split-size=MBYTES size to split files for parallelization [1024] 55 | --stripe-count=COUNT absolute number of stripes, stripes per src GBs 56 | when followed by 's', or stripes per --length 57 | GBs when followed by 'l' [1s] 58 | --threads=NUMBER number of OpenMP worker threads to use [4] 59 | 60 | 61 | 2. Msum-specific options 62 | 63 | Note that the defaults shown in brackets will vary depending on 64 | the compile-time options utilized. 65 | 66 | --buffer-size=MBYTES read/write buffer size [4] 67 | --check-tree print/check hash subtrees to pinpoint corruption 68 | --direct-read enable use of direct I/O for reads 69 | --double-buffer enable use of double buffering during file I/O 70 | --fadvise-read enable use of posix_fadvise during reads 71 | --hash-leaf-size=KBYTES granularity of hash tree [1048576] 72 | --hash-type=TYPE hash type [MD5], with TYPE one of: 73 | md5 sha1 sha256 sha384 sha512 sha224 crc32 74 | crc32rfc1510 crc24rfc2440 75 | --length=LEN hash LEN bytes beginning at --offset 76 | (or 0 if --offset not specified) 77 | --listen-port=PORT listen on port PORT for requests from 78 | cooperating hosts 79 | --manager-host=HOST host name or IP address of management thread 80 | for multi-node/multi-host copies 81 | --manager-port=PORT port on which to contact management thread 82 | --mpi enable use of MPI for multi-node checksums 83 | --offset=POS hash --length bytes beginning at POS 84 | (or to end if --length not specified) 85 | --password-file=FILE file to use for passwords (will be created 86 | if does not exist) 87 | --read-stdin perform a batch of operations read over stdin 88 | in the form 'FILE RANGES' where FILE must be 89 | a URI-escaped (RFC 3986) file name and RANGES 90 | is zero or more comma-separated ranges of the 91 | form 'START-END' for 0 <= START < END 92 | --split-size=MBYTES size to split files for parallelization [0] 93 | --threads=NUMBER number of OpenMP worker threads to use [4] 94 | 95 | 96 | 3. Option notes 97 | 98 | 3.1. Buffer management 99 | 100 | 3.1.1. Buffer size 101 | 102 | The --buffer-size option defines the buffer size that is 103 | used in reads and writes. In general, the larger the buffer 104 | size, the greater the performance. Note, however, that a 105 | large buffer size may not be practical on multi-user systems 106 | due to additional resource consumption. 107 | 108 | 3.1.2. Double buffering 109 | 110 | The --double-buffer option enables the use of double 111 | buffering for reading/writing (mcp w/o hashing), 112 | reading/hashing (msum), and writing/hashing (mcp w/ 113 | hashing). This option allows individual operations to be 114 | overlapped with each other and should always be used to 115 | maximize performance. 116 | 117 | 3.1.3. Direct I/O 118 | 119 | The --direct-read and --direct-write options enable the 120 | use of direct I/O between memory and disk, bypassing kernel 121 | buffers. Always enable these options if possible for 122 | fastest performance from a single node. If a file system 123 | does not support direct I/O, --fadvise-read is recommended 124 | as an alternative. 125 | 126 | Note that --direct-read and --direct-write are mutually 127 | exclusive with --fadvise-read and --fadvise-write, 128 | respectively, and that --direct-write is not applicable to 129 | msum. 130 | 131 | 3.1.4. posix_fadvise 132 | 133 | The --fadvise-read and --fadvise-write options enable the 134 | use of posix_fadvise() to inform the kernel about buffer 135 | access patterns. These options are useful for preventing 136 | thrashing of the buffer cache for other processes running 137 | on the same system. The --fadvise-write option has a large 138 | negative impact on performance due to the synchronization of 139 | each block that must be performed for it to have any effect. 140 | 141 | Note that --fadvise-read and --fadvise-write are mutually 142 | exclusive with --direct-read and --direct-write, 143 | respectively. 144 | 145 | 3.2. File splitting 146 | 147 | The --split-size option defines the point at which file 148 | processing will be divided amongst multiple threads/nodes. 149 | This option is required to achieve maximum performance on large 150 | files. 151 | 152 | Note that the split size must be a power of 2 and will be 153 | adjusted up as needed. The split size must also be greater than 154 | the buffer size and hash leaf size. Setting the split size to 155 | less than 1 GB is not recommended as overhead increases with 156 | the number of splits. 157 | 158 | 3.3. Multi-threading 159 | 160 | The --threads option defines how many OpenMP worker threads will 161 | be used for file operations. Note that --split-size must be 162 | greater than zero for this to have any benefit on large files. 163 | Also note that either direct I/O or posix_fadvise should always 164 | be used with multiple threads or else thrashing of the buffer 165 | cache will likely eliminate any benefits of multi-threading. 166 | 167 | 3.4. Multi-node processing 168 | 169 | Mcp and msum support two mutually-exclusive multi-node models: 170 | TCP and MPI. MPI has simpler command-line parameters for 171 | environments that support it, but TCP is more portable. 172 | 173 | 3.4.1. TCP multi-node processing 174 | 175 | 3.4.1.1. Manager node 176 | 177 | In the TCP model, one host is defined to be the manager 178 | node using the --listen-port option, which defines the 179 | TCP port through which worker nodes will contact the 180 | manager. Communication is secured using TLS-SRP 181 | initialized with a plaintext password stored in the 182 | file defined by the --password-file option. 183 | 184 | Note that the contents of --password-file should *NOT* 185 | be you login password. The password is not used for 186 | login...it is only used to secure network communication. 187 | Mcp and msum will automatically generate a strong 188 | password if the file does not exist (recommended). 189 | The same password file can be used for multiple 190 | invocations. 191 | 192 | The manager generates two additional files it needs for 193 | authentication at the same location as the password 194 | file, but with ".mg" and ".pw" extensions. These 195 | files are only used by the manager. 196 | 197 | 3.4.1.2. Worker nodes 198 | 199 | A worker node processes various file tasks parceled out 200 | by the manager node. The --manager-host option defines 201 | the host name or IP address of the manager node that 202 | is listening on the TCP port defined by the 203 | --manager-port option. Each worker must also be given a 204 | --password-file option that defines the location of the 205 | password file given to the manager. This file may need 206 | to be copied to worker nodes if they do not have access 207 | to the same file system. The ".mg" and ".pw" files do 208 | not need to be copied. 209 | 210 | Note that all other options given to workers should be 211 | identical to those given to the manager. The file 212 | arguments, however, should be omitted. Changing the 213 | other options will have unknown and/or undesirable 214 | results. 215 | 216 | 3.4.2. MPI multi-node processing 217 | 218 | The --mpi option enables the use of MPI for multi-node 219 | processing. The same exact options and arguments are given 220 | to all nodes. 221 | 222 | 3.5. Hashing 223 | 224 | The --print-hash option to mcp will enable the computation of 225 | hashes for each file that will be printed to standard out. 226 | In msum, this option is unnecessary as hashes are printed by 227 | default. By default, the target file name is shown. The 228 | --print-src option can be used to alternatively show the source 229 | file name. 230 | 231 | The --hash-type option changes the type of hash computed. The 232 | hash types supported by mcp and msum are dependent on the hash 233 | types compiled into the local Libgcrypt installation. Consult 234 | the corresponding man page or invoke mcp/msum with --help to 235 | see the list of supported hashes. 236 | 237 | Note that when --split-size is greater than zero, hash trees 238 | are used to combine the hash results of individual file chunks. 239 | Hence, the output will not conform to the output of the 240 | corresponding hash type without splitting. The benefit of 241 | splitting, however, is much greater performance on large files. 242 | When the file size is less than the split size, the hash tree 243 | value will match the standard hash value. 244 | 245 | The --check-tree option will print the root hashes of each split 246 | subtree instead of combining the result into a single hash 247 | value. When used with msum's -c option, msum will print the 248 | ranges of the file that are corrupted, if applicable, at the 249 | granularity of the split size. 250 | 251 | The --hash-leaf-size can be used to change the granularity of 252 | the hash tree. This option, however, is mainly intended to be 253 | used with another option that is currently disabled. 254 | 255 | The output of mcp using --print-hash will conform to the 256 | output of msum as long as the same --check-tree, --hash-type, 257 | --hash-leaf-size, and --split-size options are used. 258 | 259 | 3.6. Statistics 260 | 261 | The --print-stats option will print various performance stats to 262 | standard error for each individual file or file split together 263 | with total stats. By default, the target file name is shown. 264 | The --print-src option can be used to alternatively show the 265 | source file name. 266 | 267 | 3.7. Partial transfers 268 | 269 | The --offset and --length options can be used to copy/sum a 270 | portion of a file. The offset specifies the starting position 271 | in the source file and the length specifies the number of bytes 272 | to copy/sum. By default, the same offset will be used in both 273 | the source and destination files. The --dst-offset option can 274 | be used to specify a different offset in the destination file. 275 | 276 | 3.8. Batch transfers 277 | 278 | The --read-stdin option allows an arbitrary batch of file copies 279 | or checksums to be performed. For mcp, each line read on stdin 280 | must be of the form "SRC DST RANGES", where SRC and DST are file 281 | names and RANGES is zero or more comma-separated ranges. For 282 | msum, each line must be of the form "FILE RANGES". All files 283 | must be URI-escaped (not URIs but escaped in a similar manner) 284 | according to RFC 3986. The following perl function demonstrates 285 | how file names can be escaped: 286 | 287 | sub escape { 288 | my $text = shift; 289 | $text =~ s/([^A-Za-z0-9\-_.!~*'()\/])/sprintf("%%%02X", ord($1))/eg 290 | if (defined $text); 291 | return $text; 292 | } 293 | 294 | Each range in the set of optional ranges is defined "START-END", 295 | where 0 <= START < END. For example, "1-3,10-12" would operate 296 | on bytes 1,2,10,11. 297 | 298 | 3.9. Temporary permissions 299 | 300 | During a copy of read-only files, mcp temporarily uses 301 | permissions on the target file that are the same as the source 302 | file, but with owner write permission. For some purposes, it 303 | desirable to retain these temporary permissions instead of 304 | restoring the original permissions. For example, this can be 305 | used when detecting corruption that may have occurred due to 306 | transient errors and the corrupted portion must be written 307 | again. To skip the final chmod that will bring the target file 308 | back to the source permissions, the --skip-chmod option 309 | can be used. 310 | 311 | 3.10. Lustre striping 312 | 313 | By default, the striping of files transferred from one Lustre 314 | file system to another that have a stripe count other than the 315 | system default will be preserved. Files that have the default 316 | stripe count or come from a non-Lustre file system will be 317 | restriped to one stripe per GB. The --stripe-count option 318 | allows files to be striped either to an absolute number of 319 | stripes (e.g. 4), a number of stripes per source GBs when the 320 | given value is followed by 's' (e.g. 0.25s), or a number of 321 | stripes per --length GBs when the given value is followed by 'l' 322 | (e.g. 4.5l). 323 | 324 | 325 | 4. Performance 326 | 327 | See https://pkolano.github.io/papers/lisa10.pdf for (old) expected 328 | performance numbers. Note that the results reported in this paper 329 | were measured using dedicated compute nodes and near-idle file 330 | systems. The actual performance observed in practice will depend 331 | upon the characteristics of your environment. 332 | 333 | 334 | 5. Examples 335 | 336 | Note that all examples should use either direct I/O or 337 | posix_fadvise, but these were omitted for readability. 338 | 339 | 5.1. Recursively copy /src to /dst 340 | 341 | mcp -r /src /dst 342 | 343 | 5.2. Recursively copy /src to /dst while printing stats and 344 | storing hashes in /tmp/sums 345 | 346 | mcp --print-stats --print-hash -r /src /dst >/tmp/sums 347 | 348 | 5.3. Check the sums stored in the file /tmp/sums 349 | 350 | msum --print-stats -c /tmp/sums 351 | 352 | 5.3. Recursively copy /src to /dst while listening for other worker 353 | nodes on port 1234 with password file /my/pw 354 | 355 | mcp --listen-port=1234 --password-file=/my/pw -r /src /dst 356 | 357 | 5.4. Join into a copy started on manager "mhost" using port 1234 and 358 | password file /my/pw 359 | 360 | mcp --manager-host=mhost --manager-port=1234 --password-file=/my/pw 361 | 362 | 5.5. Recursively copy /src to /dst using 8 MPI nodes 363 | 364 | mpiexec -np 8 mcp --mpi -r /src /dst 365 | 366 | 5.6. Recursively copy /src to /dst using TCP in a PBS job using port 367 | 1234 and password file /my/pw 368 | 369 | export mhost=`hostname` 370 | mcp -r --listen-port=1234 --password-file=/my/pw /src /dst & 371 | for n in `grep -v $mgr $PBS_NODEFILE |sort -u`; do 372 | ssh $n "setsid mcp --password-file=/my/pw --manager-host=$mhost \ 373 | --manager-port=1234 &" & 374 | 375 | -------------------------------------------------------------------------------- /patch/mutil-1.822.2.patch: -------------------------------------------------------------------------------- 1 | diff -rupN old2/configure new/configure 2 | --- old2/configure 2015-01-14 15:14:48.000000000 -0800 3 | +++ new/configure 2018-01-18 14:44:19.271960028 -0800 4 | @@ -8646,12 +8646,12 @@ fi 5 | fi 6 | 7 | 8 | - for ac_header in lustre/liblustreapi.h 9 | + for ac_header in lustre/lustreapi.h 10 | do : 11 | - ac_fn_c_check_header_mongrel "$LINENO" "lustre/liblustreapi.h" "ac_cv_header_lustre_liblustreapi_h" "$ac_includes_default" 12 | -if test "x$ac_cv_header_lustre_liblustreapi_h" = xyes; then : 13 | + ac_fn_c_check_header_mongrel "$LINENO" "lustre/lustreapi.h" "ac_cv_header_lustre_lustreapi_h" "$ac_includes_default" 14 | +if test "x$ac_cv_header_lustre_lustreapi_h" = xyes; then : 15 | cat >>confdefs.h <<_ACEOF 16 | -#define HAVE_LUSTRE_LIBLUSTREAPI_H 1 17 | +#define HAVE_LUSTRE_LUSTREAPI_H 1 18 | _ACEOF 19 | 20 | fi 21 | diff -rupN old2/lib/config.hin new/lib/config.hin 22 | --- old2/lib/config.hin 2015-01-14 15:14:49.000000000 -0800 23 | +++ new/lib/config.hin 2018-01-18 14:44:19.183957656 -0800 24 | @@ -1693,8 +1693,8 @@ 25 | /* Define to 1 if you have the `lstat' function. */ 26 | #undef HAVE_LSTAT 27 | 28 | -/* Define to 1 if you have the header file. */ 29 | -#undef HAVE_LUSTRE_LIBLUSTREAPI_H 30 | +/* Define to 1 if you have the header file. */ 31 | +#undef HAVE_LUSTRE_LUSTREAPI_H 32 | 33 | /* Define to 1 if you have the `lutimes' function. */ 34 | #undef HAVE_LUTIMES 35 | diff -rupN old2/m4/mutil.m4 new/m4/mutil.m4 36 | --- old2/m4/mutil.m4 2015-01-14 15:02:53.000000000 -0800 37 | +++ new/m4/mutil.m4 2018-01-18 14:44:17.079900948 -0800 38 | @@ -84,7 +84,7 @@ AC_DEFUN([mutil_LIBGCRYPT], [ 39 | ]) 40 | 41 | AC_DEFUN([mutil_LIBLUSTREAPI], [ 42 | - AC_CHECK_HEADERS([lustre/liblustreapi.h]) 43 | + AC_CHECK_HEADERS([lustre/lustreapi.h]) 44 | AC_CHECK_LIB([lustreapi], [llapi_file_get_stripe]) 45 | ]) 46 | 47 | diff -rupN old2/src/copy.c new/src/copy.c 48 | --- old2/src/copy.c 2015-01-14 15:03:11.000000000 -0800 49 | +++ new/src/copy.c 2018-01-18 14:44:17.935924020 -0800 50 | @@ -163,8 +163,7 @@ static inline int sync_file_range( 51 | 52 | #if HAVE_LIBLUSTREAPI 53 | # include 54 | -# include 55 | -# include 56 | +# include 57 | # include 58 | # define MAX_OSTS 1024 59 | # define LOV_EA_SIZE(lum, num) (sizeof(*lum) + num * sizeof(*lum->lmm_objects)) 60 | @@ -308,11 +307,31 @@ sparse_copy (copy_reg_t *crt, struct cp_ 61 | 62 | ssize_t n_read; 63 | if (raiol[0] != NULL) { 64 | - // this will be skipped during the first double buffer iteration 65 | - aio_suspend((const struct aiocb * const *) raiol, 1, NULL); 66 | + // this will be skipped during the first double buffer iteration 67 | + // wait for previous asynchronous read to complete 68 | + while (aio_suspend((const struct aiocb * const *) raiol, 1, NULL) && errno == EINTR); 69 | if (co->print_stats) clock_gettime(0, &rts[1]); 70 | if (waiol[0] != NULL) { 71 | - aio_suspend((const struct aiocb * const *) waiol, 1, NULL); 72 | + while (1) { 73 | + // wait for previous asynchronous write to complete 74 | + while (aio_suspend((const struct aiocb * const *) waiol, 1, NULL) && errno == EINTR); 75 | + ssize_t n_write = aio_return(waiol[0]); 76 | + if (n_write < 0 && errno == EINTR || 77 | + n_write >= 0 && n_write < waiol[0]->aio_nbytes) { 78 | + // retry if write interrupted or short write 79 | + if (aio_write(waiol[0]) < 0) { 80 | + error (0, errno, _("failed to initiate aio_write: %s"), 81 | + quote (crt->dst_name)); 82 | + return false; 83 | + } 84 | + continue; 85 | + } else if (n_write < 0) { 86 | + // abort if write error 87 | + error (0, errno, _("writing %s"), quote (crt->dst_name)); 88 | + return false; 89 | + } 90 | + break; 91 | + } 92 | if (co->print_stats) { 93 | clock_gettime(0, &wts[1]); 94 | crt->write_time += (double) ( 95 | @@ -412,8 +431,11 @@ sparse_copy (copy_reg_t *crt, struct cp_ 96 | raio.aio_buf = buf[!aio_buf]; 97 | raio.aio_nbytes = to_read; 98 | raiol[0] = &raio; 99 | - //TODO: error handling for bad aio_read 100 | - int rc = aio_read(&raio); 101 | + if (aio_read(&raio) < 0) { 102 | + error (0, errno, _("failed to initiate aio_read: %s"), 103 | + quote (crt->src_name)); 104 | + return false; 105 | + } 106 | } 107 | // < PZK 108 | 109 | @@ -468,7 +490,11 @@ sparse_copy (copy_reg_t *crt, struct cp_ 110 | waio.aio_buf = buf[aio_buf]; 111 | waio.aio_nbytes = n; 112 | waiol[0] = &waio; 113 | - n_write = aio_write(&waio); 114 | + if (aio_write(&waio) < 0) { 115 | + error (0, errno, _("failed to initiate aio_write: %s"), 116 | + quote (crt->dst_name)); 117 | + return false; 118 | + } 119 | } else { 120 | n_write = full_write (crt->dst_fd, buf[aio_buf], n); 121 | if (co->print_stats) { 122 | @@ -481,7 +507,6 @@ sparse_copy (copy_reg_t *crt, struct cp_ 123 | } 124 | } 125 | 126 | - //TODO: check wrote n bytes in double buffer case? 127 | if (!co->double_buffer && n_write != n) 128 | { 129 | error (0, errno, _("writing %s"), quote (crt->dst_name)); 130 | @@ -507,18 +532,38 @@ sparse_copy (copy_reg_t *crt, struct cp_ 131 | if (co->double_buffer) aio_buf = !aio_buf; 132 | } 133 | 134 | - if (waiol[0] != NULL) 135 | - aio_suspend((const struct aiocb * const *) waiol, 1, NULL); 136 | + if (waiol[0] != NULL) { 137 | + while (1) { 138 | + // wait for final asynchronous write to complete 139 | + while (aio_suspend((const struct aiocb * const *) waiol, 1, NULL) && errno == EINTR); 140 | + ssize_t n_write = aio_return(waiol[0]); 141 | + if (n_write < 0 && errno == EINTR || 142 | + n_write >= 0 && n_write < waiol[0]->aio_nbytes) { 143 | + // retry if write interrupted or short write 144 | + if (aio_write(waiol[0]) < 0) { 145 | + error (0, errno, _("failed to initiate aio_write: %s"), 146 | + quote (crt->dst_name)); 147 | + return false; 148 | + } 149 | + continue; 150 | + } else if (n_write < 0) { 151 | + // abort if write error 152 | + error (0, errno, _("writing %s"), quote (crt->dst_name)); 153 | + return false; 154 | + } 155 | + break; 156 | + } 157 | #ifdef POSIX_FADV_DONTNEED 158 | - if (co->fadvise_write) { 159 | + if (co->fadvise_write) { 160 | # ifdef __linux__ 161 | - sync_file_range(crt->dst_fd, waiol[0]->aio_offset, waiol[0]->aio_nbytes, 162 | - SYNC_FILE_RANGE_WRITE|SYNC_FILE_RANGE_WAIT_AFTER); 163 | + sync_file_range(crt->dst_fd, waiol[0]->aio_offset, waiol[0]->aio_nbytes, 164 | + SYNC_FILE_RANGE_WRITE|SYNC_FILE_RANGE_WAIT_AFTER); 165 | # endif 166 | - posix_fadvise(crt->dst_fd, waiol[0]->aio_offset, waiol[0]->aio_nbytes, 167 | - POSIX_FADV_DONTNEED); 168 | + posix_fadvise(crt->dst_fd, waiol[0]->aio_offset, waiol[0]->aio_nbytes, 169 | + POSIX_FADV_DONTNEED); 170 | } 171 | #endif 172 | + } 173 | // < PZK 174 | 175 | return true; 176 | @@ -682,7 +727,8 @@ extent_copy (copy_reg_t *crt, struct cp_ 177 | || (!empty_extent && sparse_mode != SPARSE_NEVER)) 178 | { 179 | // PZK > 180 | - if (lseek (crt->dst_fd, ext_start, SEEK_SET) < 0) 181 | + if (lseek (crt->dst_fd, crt->dst_offset - crt->start_offset + 182 | + ext_start, SEEK_SET) < 0) 183 | { 184 | error (0, errno, _("cannot lseek %s"), quote (crt->dst_name)); 185 | // < PZK 186 | @@ -699,7 +745,13 @@ extent_copy (copy_reg_t *crt, struct cp_ 187 | if (empty_extent) 188 | // PZK > 189 | nzeros = MIN (crt->stop_offset - dest_pos, hole_size); 190 | - 191 | + // when double buffering, dst_fd may not even be set 192 | + if (co->double_buffer && lseek(crt->dst_fd, 193 | + crt->dst_offset - crt->start_offset + 194 | + crt->stop_offset - nzeros, SEEK_SET) < 0L) { 195 | + error (0, errno, _("cannot lseek %s"), quote (crt->dst_name)); 196 | + goto fail; 197 | + } 198 | if (! write_zeros (crt->dst_fd, nzeros)) 199 | { 200 | error (0, errno, _("%s: write failed"), quote (crt->dst_name)); 201 | @@ -790,25 +842,30 @@ extent_copy (copy_reg_t *crt, struct cp_ 202 | here in order to record the proper length in the destination. */ 203 | 204 | // PZK > 205 | - if (wrote_hole_at_eof && crt->dst_offset == 0 && 206 | - crt->stop_offset == src_total_size && 207 | - (sparse_mode != SPARSE_NEVER 208 | - ? ftruncate (crt->dst_fd, src_total_size) 209 | - : ! write_zeros (crt->dst_fd, src_total_size - dest_pos))) 210 | - { 211 | - error (0, errno, _("failed to extend %s"), quote (crt->dst_name)); 212 | - return false; 213 | - } 214 | - else if (wrote_hole_at_eof && crt->split + 1 == crt->nsplits && 215 | - (lseek (crt->dst_fd, (off_t) -1, SEEK_CUR) < 0L 216 | - || co->write_mode 217 | - && fcntl (crt->dst_fd, F_SETFL, 218 | - fcntl (crt->dst_fd, F_GETFL) & ~O_DIRECT) 219 | - || full_write (crt->dst_fd, "", 1) != 1)) 220 | - { 221 | - error (0, errno, _("writing %s"), quote (crt->dst_name)); 222 | - return false; 223 | + if (wrote_hole_at_eof || dest_pos < crt->stop_offset) { 224 | + if (sparse_mode == SPARSE_NEVER) { 225 | + if (lseek (crt->dst_fd, crt->dst_offset - crt->start_offset + 226 | + dest_pos, SEEK_SET) < 0L || 227 | + !write_zeros(crt->dst_fd, crt->stop_offset - dest_pos)) { 228 | + error (0, errno, _("%s: write failed"), quote (crt->dst_name)); 229 | + return false; 230 | + } 231 | + } else if (crt->dst_offset == 0 && crt->stop_offset == src_total_size) { 232 | + if (ftruncate(crt->dst_fd, src_total_size)) { 233 | + error (0, errno, _("failed to extend %s"), quote (crt->dst_name)); 234 | + return false; 235 | + } 236 | + } else if (crt->split + 1 == crt->nsplits) { 237 | + if (lseek (crt->dst_fd, crt->dst_offset - crt->start_offset + 238 | + crt->stop_offset - 1, SEEK_SET) < 0L || 239 | + co->write_mode && fcntl (crt->dst_fd, F_SETFL, 240 | + fcntl (crt->dst_fd, F_GETFL) & ~O_DIRECT) || 241 | + full_write (crt->dst_fd, "", 1) != 1) { 242 | + error (0, errno, _("%s: write failed"), quote (crt->dst_name)); 243 | + return false; 244 | + } 245 | } 246 | + } 247 | 248 | #if HAVE_LIBGCRYPT 249 | if (dest_pos < crt->stop_offset) { 250 | @@ -1395,27 +1452,36 @@ copy_reg_task (copy_reg_t *crt, struct c 251 | , &ctx, &htt 252 | #endif 253 | ); 254 | - if (copy_ok && wrote_hole_at_eof && crt->dst_offset == 0 && 255 | - crt->stop_offset == src_open_sb.st_size && 256 | - ftruncate (crt->dst_fd, src_open_sb.st_size) < 0) 257 | - { 258 | - error (0, errno, _("failed to extend %s"), quote (crt->dst_name)); 259 | - return_val = false; 260 | - goto task_close_src_and_dst_desc; 261 | - } 262 | - else if (copy_ok && wrote_hole_at_eof && crt->split + 1 == crt->nsplits && 263 | - (lseek (crt->dst_fd, (off_t) -1, SEEK_CUR) < 0L 264 | // PZK > 265 | - || co->write_mode 266 | - && fcntl (crt->dst_fd, F_SETFL, 267 | - fcntl (crt->dst_fd, F_GETFL) & ~O_DIRECT) 268 | + off_t dest_pos = crt->start_offset + n_read; 269 | + if (copy_ok && (wrote_hole_at_eof || dest_pos < crt->stop_offset)) { 270 | + if (co->sparse_mode == SPARSE_NEVER) { 271 | + if (lseek (crt->dst_fd, crt->dst_offset - crt->start_offset + 272 | + dest_pos, SEEK_SET) < 0L || 273 | + !write_zeros(crt->dst_fd, crt->stop_offset - dest_pos)) { 274 | + error (0, errno, _("%s: write failed"), quote (crt->dst_name)); 275 | + return_val = false; 276 | + goto task_close_src_and_dst_desc; 277 | + } 278 | + } else if (crt->dst_offset == 0 && crt->stop_offset == src_open_sb.st_size) { 279 | + if (ftruncate(crt->dst_fd, src_open_sb.st_size)) { 280 | + error (0, errno, _("failed to extend %s"), quote (crt->dst_name)); 281 | + return_val = false; 282 | + goto task_close_src_and_dst_desc; 283 | + } 284 | + } else if (crt->split + 1 == crt->nsplits) { 285 | + if (lseek (crt->dst_fd, crt->dst_offset - crt->start_offset + 286 | + crt->stop_offset - 1, SEEK_SET) < 0L || 287 | + co->write_mode && fcntl (crt->dst_fd, F_SETFL, 288 | + fcntl (crt->dst_fd, F_GETFL) & ~O_DIRECT) || 289 | + full_write (crt->dst_fd, "", 1) != 1) { 290 | + error (0, errno, _("%s: write failed"), quote (crt->dst_name)); 291 | + return_val = false; 292 | + goto task_close_src_and_dst_desc; 293 | + } 294 | + } 295 | + } 296 | // < PZK 297 | - || full_write (crt->dst_fd, "", 1) != 1)) 298 | - { 299 | - error (0, errno, _("writing %s"), quote (crt->dst_name)); 300 | - return_val = false; 301 | - goto task_close_src_and_dst_desc; 302 | - } 303 | 304 | task_preserve_metadata: 305 | if (co->preserve_timestamps) 306 | @@ -1651,19 +1717,15 @@ copy_reg (char const *src_name, char con 307 | } 308 | } 309 | if (scount > MUTIL_MAX_STRIPE_COUNT) scount = MUTIL_MAX_STRIPE_COUNT; 310 | - if (!llapi_file_create(dst_name, ssize, -1, scount, 0)) { 311 | - dest_desc = open (dst_name, open_flags | O_LOV_DELAY_CREATE, 312 | - wdst_mode & ~omitted_permissions); 313 | - if (dest_desc && !llapi_file_get_stripe(dst_name, lum) && 314 | - lum->lmm_stripe_count != scount) { 315 | - //TODO: this probably shouldn't be printed for every 316 | - // file, especially when physical OST counts differ 317 | - // between file systems 318 | - error(0, 0, _("warning: allocated stripe count of %s does not match original stripe count of %s"), 319 | - quote_n(0, dst_name), quote_n(1, src_name)); 320 | - } 321 | - } else { 322 | - dest_desc = -1; 323 | + dest_desc = llapi_file_open(dst_name, open_flags, 324 | + wdst_mode & ~omitted_permissions, ssize, -1, scount, 0); 325 | + if (dest_desc > 0 && !llapi_file_get_stripe(dst_name, lum) && 326 | + lum->lmm_stripe_count != scount) { 327 | + //TODO: this probably shouldn't be printed for every 328 | + // file, especially when physical OST counts differ 329 | + // between file systems 330 | + error(0, 0, _("warning: allocated stripe count of %s does not match original stripe count of %s"), 331 | + quote_n(0, dst_name), quote_n(1, src_name)); 332 | } 333 | free(lum); 334 | } else 335 | diff -rupN old2/src/cp.c new/src/cp.c 336 | --- old2/src/cp.c 2015-01-14 15:03:16.000000000 -0800 337 | +++ new/src/cp.c 2019-10-09 14:45:38.688430184 -0700 338 | @@ -143,7 +143,7 @@ GCRY_THREAD_OPTION_PTHREAD_IMPL; 339 | 340 | /* The official name of this program (e.g., no 'g' prefix). */ 341 | // PZK > 342 | -#define PROGRAM_NAME "mcp 1.822.2" 343 | +#define PROGRAM_NAME "mcp 1.822.6" 344 | 345 | #define AUTHORS \ 346 | proper_name_utf8 ("Torbjorn Granlund", "Torbj\303\266rn Granlund"), \ 347 | @@ -1997,22 +1997,16 @@ do_copy (int n_files, char **file, const 348 | // PZK > 349 | else if (x->read_stdin) 350 | { 351 | - /* Start with a buffer larger than PATH_MAX, but beware of systems 352 | - on which PATH_MAX is very large -- e.g., INT_MAX. */ 353 | - size_t buf_max = MIN(2 * PATH_MAX, 32 * 1024); 354 | - char *buf = xmalloc(buf_max); 355 | + char *buf = NULL; 356 | + size_t buf_max = 0; 357 | 358 | char *new_dest; 359 | char *source; 360 | char *dest; 361 | bool unused; 362 | 363 | - while (fgets(buf, buf_max, stdin) != NULL) { 364 | + while (getline(&buf, &buf_max, stdin) > 0) { 365 | buf[strcspn(buf, "\n")] = '\0'; 366 | - if (buf[0] == '\0') { 367 | - //TODO: error handling if string too long 368 | - continue; 369 | - } 370 | size_t ifile2 = strcspn(buf, " "); 371 | if (buf[ifile2] == '\0') continue; 372 | buf[ifile2++] = '\0'; 373 | @@ -2123,6 +2117,7 @@ do_copy (int n_files, char **file, const 374 | free(source); 375 | free(dest); 376 | } 377 | + free(buf); 378 | } 379 | // < PZK 380 | else /* !target_directory */ 381 | diff -rupN old2/src/md5sum.c new/src/md5sum.c 382 | --- old2/src/md5sum.c 2015-01-14 15:03:26.000000000 -0800 383 | +++ new/src/md5sum.c 2019-10-09 14:45:27.456116389 -0700 384 | @@ -139,7 +139,7 @@ GCRY_THREAD_OPTION_PTHREAD_IMPL; 385 | /* The official name of this program (e.g., no 'g' prefix). */ 386 | #if HASH_ALGO_MD5 387 | // PZK > 388 | -# define PROGRAM_NAME "msum 1.822.2" 389 | +# define PROGRAM_NAME "msum 1.822.6" 390 | // < PZK 391 | # define DIGEST_TYPE_STRING "MD5" 392 | # define DIGEST_STREAM md5_stream 393 | @@ -491,7 +491,8 @@ sum_task(sum_task_t *stt, struct sum_opt 394 | ssize_t n_read; 395 | if (aiol[0] != NULL) { 396 | // this will be skipped during the first double buffer iteration 397 | - aio_suspend((const struct aiocb * const *) aiol, 1, NULL); 398 | + // wait for previous asynchronous read to complete 399 | + while (aio_suspend((const struct aiocb * const *) aiol, 1, NULL) && errno == EINTR); 400 | n_read = aio_return(aiol[0]); 401 | } else { 402 | off_t to_read = MIN(buf_size, 403 | @@ -572,8 +573,12 @@ sum_task(sum_task_t *stt, struct sum_opt 404 | aio.aio_buf = buf[!aio_buf]; 405 | aio.aio_nbytes = to_read; 406 | aiol[0] = &aio; 407 | - //TODO: error handling for bad aio_read 408 | - aio_read(&aio); 409 | + if (aio_read(&aio) < 0) { 410 | + error (0, errno, _("failed to initiate aio_read: %s"), 411 | + quote (stt->src_name)); 412 | + return_val = false; 413 | + goto task_close_src_and_dst_desc; 414 | + } 415 | } 416 | 417 | if (so->print_stats) clock_gettime(0, &hts[0]); 418 | @@ -1056,7 +1061,7 @@ split_3 (char *s, size_t s_len, 419 | i += digest_hex_bytes; 420 | // PZK > 421 | //TODO: put this in for checktree 422 | - while (!ISWHITE (s[i])) 423 | + while (isxdigit(s[i])) 424 | i++; 425 | // < PZK 426 | if (!ISWHITE (s[i])) 427 | @@ -2576,15 +2581,11 @@ main (int argc, char **argv) 428 | char *file = argv[optind]; 429 | // PZK > 430 | if (x.read_stdin) { 431 | - size_t buf_max = MIN(PATH_MAX, 32 * 1024); 432 | - char *buf = xmalloc(buf_max); 433 | + char *buf = NULL; 434 | + size_t buf_max = 0; 435 | 436 | - while (fgets(buf, buf_max, stdin) != NULL) { 437 | + while (getline(&buf, &buf_max, stdin) > 0) { 438 | buf[strcspn(buf, "\n")] = '\0'; 439 | - if (file[0] == '\0') { 440 | - //TODO: error handling if string too long 441 | - continue; 442 | - } 443 | size_t irange = strcspn(buf, " "); 444 | if (buf[irange] == '\0') irange = 0; 445 | else buf[irange++] = '\0'; 446 | @@ -2611,6 +2612,7 @@ main (int argc, char **argv) 447 | ok = false; 448 | } 449 | } 450 | + free(buf); 451 | break; 452 | } 453 | // < PZK 454 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | ##################################################################### 2 | #### NOTE: ADDITIONAL TERMS APPLY PER SECTION 7 OF THIS LICENSE. #### 3 | #### SEE INDIVIDUAL SOURCE FILES FOR THESE TERMS. #### 4 | ##################################################################### 5 | 6 | GNU GENERAL PUBLIC LICENSE 7 | Version 3, 29 June 2007 8 | 9 | Copyright (C) 2007 Free Software Foundation, Inc. 10 | Everyone is permitted to copy and distribute verbatim copies 11 | of this license document, but changing it is not allowed. 12 | 13 | Preamble 14 | 15 | The GNU General Public License is a free, copyleft license for 16 | software and other kinds of works. 17 | 18 | The licenses for most software and other practical works are designed 19 | to take away your freedom to share and change the works. By contrast, 20 | the GNU General Public License is intended to guarantee your freedom to 21 | share and change all versions of a program--to make sure it remains free 22 | software for all its users. We, the Free Software Foundation, use the 23 | GNU General Public License for most of our software; it applies also to 24 | any other work released this way by its authors. You can apply it to 25 | your programs, too. 26 | 27 | When we speak of free software, we are referring to freedom, not 28 | price. Our General Public Licenses are designed to make sure that you 29 | have the freedom to distribute copies of free software (and charge for 30 | them if you wish), that you receive source code or can get it if you 31 | want it, that you can change the software or use pieces of it in new 32 | free programs, and that you know you can do these things. 33 | 34 | To protect your rights, we need to prevent others from denying you 35 | these rights or asking you to surrender the rights. Therefore, you have 36 | certain responsibilities if you distribute copies of the software, or if 37 | you modify it: responsibilities to respect the freedom of others. 38 | 39 | For example, if you distribute copies of such a program, whether 40 | gratis or for a fee, you must pass on to the recipients the same 41 | freedoms that you received. You must make sure that they, too, receive 42 | or can get the source code. And you must show them these terms so they 43 | know their rights. 44 | 45 | Developers that use the GNU GPL protect your rights with two steps: 46 | (1) assert copyright on the software, and (2) offer you this License 47 | giving you legal permission to copy, distribute and/or modify it. 48 | 49 | For the developers' and authors' protection, the GPL clearly explains 50 | that there is no warranty for this free software. For both users' and 51 | authors' sake, the GPL requires that modified versions be marked as 52 | changed, so that their problems will not be attributed erroneously to 53 | authors of previous versions. 54 | 55 | Some devices are designed to deny users access to install or run 56 | modified versions of the software inside them, although the manufacturer 57 | can do so. This is fundamentally incompatible with the aim of 58 | protecting users' freedom to change the software. The systematic 59 | pattern of such abuse occurs in the area of products for individuals to 60 | use, which is precisely where it is most unacceptable. Therefore, we 61 | have designed this version of the GPL to prohibit the practice for those 62 | products. If such problems arise substantially in other domains, we 63 | stand ready to extend this provision to those domains in future versions 64 | of the GPL, as needed to protect the freedom of users. 65 | 66 | Finally, every program is threatened constantly by software patents. 67 | States should not allow patents to restrict development and use of 68 | software on general-purpose computers, but in those that do, we wish to 69 | avoid the special danger that patents applied to a free program could 70 | make it effectively proprietary. To prevent this, the GPL assures that 71 | patents cannot be used to render the program non-free. 72 | 73 | The precise terms and conditions for copying, distribution and 74 | modification follow. 75 | 76 | TERMS AND CONDITIONS 77 | 78 | 0. Definitions. 79 | 80 | "This License" refers to version 3 of the GNU General Public License. 81 | 82 | "Copyright" also means copyright-like laws that apply to other kinds of 83 | works, such as semiconductor masks. 84 | 85 | "The Program" refers to any copyrightable work licensed under this 86 | License. Each licensee is addressed as "you". "Licensees" and 87 | "recipients" may be individuals or organizations. 88 | 89 | To "modify" a work means to copy from or adapt all or part of the work 90 | in a fashion requiring copyright permission, other than the making of an 91 | exact copy. The resulting work is called a "modified version" of the 92 | earlier work or a work "based on" the earlier work. 93 | 94 | A "covered work" means either the unmodified Program or a work based 95 | on the Program. 96 | 97 | To "propagate" a work means to do anything with it that, without 98 | permission, would make you directly or secondarily liable for 99 | infringement under applicable copyright law, except executing it on a 100 | computer or modifying a private copy. Propagation includes copying, 101 | distribution (with or without modification), making available to the 102 | public, and in some countries other activities as well. 103 | 104 | To "convey" a work means any kind of propagation that enables other 105 | parties to make or receive copies. Mere interaction with a user through 106 | a computer network, with no transfer of a copy, is not conveying. 107 | 108 | An interactive user interface displays "Appropriate Legal Notices" 109 | to the extent that it includes a convenient and prominently visible 110 | feature that (1) displays an appropriate copyright notice, and (2) 111 | tells the user that there is no warranty for the work (except to the 112 | extent that warranties are provided), that licensees may convey the 113 | work under this License, and how to view a copy of this License. If 114 | the interface presents a list of user commands or options, such as a 115 | menu, a prominent item in the list meets this criterion. 116 | 117 | 1. Source Code. 118 | 119 | The "source code" for a work means the preferred form of the work 120 | for making modifications to it. "Object code" means any non-source 121 | form of a work. 122 | 123 | A "Standard Interface" means an interface that either is an official 124 | standard defined by a recognized standards body, or, in the case of 125 | interfaces specified for a particular programming language, one that 126 | is widely used among developers working in that language. 127 | 128 | The "System Libraries" of an executable work include anything, other 129 | than the work as a whole, that (a) is included in the normal form of 130 | packaging a Major Component, but which is not part of that Major 131 | Component, and (b) serves only to enable use of the work with that 132 | Major Component, or to implement a Standard Interface for which an 133 | implementation is available to the public in source code form. A 134 | "Major Component", in this context, means a major essential component 135 | (kernel, window system, and so on) of the specific operating system 136 | (if any) on which the executable work runs, or a compiler used to 137 | produce the work, or an object code interpreter used to run it. 138 | 139 | The "Corresponding Source" for a work in object code form means all 140 | the source code needed to generate, install, and (for an executable 141 | work) run the object code and to modify the work, including scripts to 142 | control those activities. However, it does not include the work's 143 | System Libraries, or general-purpose tools or generally available free 144 | programs which are used unmodified in performing those activities but 145 | which are not part of the work. For example, Corresponding Source 146 | includes interface definition files associated with source files for 147 | the work, and the source code for shared libraries and dynamically 148 | linked subprograms that the work is specifically designed to require, 149 | such as by intimate data communication or control flow between those 150 | subprograms and other parts of the work. 151 | 152 | The Corresponding Source need not include anything that users 153 | can regenerate automatically from other parts of the Corresponding 154 | Source. 155 | 156 | The Corresponding Source for a work in source code form is that 157 | same work. 158 | 159 | 2. Basic Permissions. 160 | 161 | All rights granted under this License are granted for the term of 162 | copyright on the Program, and are irrevocable provided the stated 163 | conditions are met. This License explicitly affirms your unlimited 164 | permission to run the unmodified Program. The output from running a 165 | covered work is covered by this License only if the output, given its 166 | content, constitutes a covered work. This License acknowledges your 167 | rights of fair use or other equivalent, as provided by copyright law. 168 | 169 | You may make, run and propagate covered works that you do not 170 | convey, without conditions so long as your license otherwise remains 171 | in force. You may convey covered works to others for the sole purpose 172 | of having them make modifications exclusively for you, or provide you 173 | with facilities for running those works, provided that you comply with 174 | the terms of this License in conveying all material for which you do 175 | not control copyright. Those thus making or running the covered works 176 | for you must do so exclusively on your behalf, under your direction 177 | and control, on terms that prohibit them from making any copies of 178 | your copyrighted material outside their relationship with you. 179 | 180 | Conveying under any other circumstances is permitted solely under 181 | the conditions stated below. Sublicensing is not allowed; section 10 182 | makes it unnecessary. 183 | 184 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 185 | 186 | No covered work shall be deemed part of an effective technological 187 | measure under any applicable law fulfilling obligations under article 188 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 189 | similar laws prohibiting or restricting circumvention of such 190 | measures. 191 | 192 | When you convey a covered work, you waive any legal power to forbid 193 | circumvention of technological measures to the extent such circumvention 194 | is effected by exercising rights under this License with respect to 195 | the covered work, and you disclaim any intention to limit operation or 196 | modification of the work as a means of enforcing, against the work's 197 | users, your or third parties' legal rights to forbid circumvention of 198 | technological measures. 199 | 200 | 4. Conveying Verbatim Copies. 201 | 202 | You may convey verbatim copies of the Program's source code as you 203 | receive it, in any medium, provided that you conspicuously and 204 | appropriately publish on each copy an appropriate copyright notice; 205 | keep intact all notices stating that this License and any 206 | non-permissive terms added in accord with section 7 apply to the code; 207 | keep intact all notices of the absence of any warranty; and give all 208 | recipients a copy of this License along with the Program. 209 | 210 | You may charge any price or no price for each copy that you convey, 211 | and you may offer support or warranty protection for a fee. 212 | 213 | 5. Conveying Modified Source Versions. 214 | 215 | You may convey a work based on the Program, or the modifications to 216 | produce it from the Program, in the form of source code under the 217 | terms of section 4, provided that you also meet all of these conditions: 218 | 219 | a) The work must carry prominent notices stating that you modified 220 | it, and giving a relevant date. 221 | 222 | b) The work must carry prominent notices stating that it is 223 | released under this License and any conditions added under section 224 | 7. This requirement modifies the requirement in section 4 to 225 | "keep intact all notices". 226 | 227 | c) You must license the entire work, as a whole, under this 228 | License to anyone who comes into possession of a copy. This 229 | License will therefore apply, along with any applicable section 7 230 | additional terms, to the whole of the work, and all its parts, 231 | regardless of how they are packaged. This License gives no 232 | permission to license the work in any other way, but it does not 233 | invalidate such permission if you have separately received it. 234 | 235 | d) If the work has interactive user interfaces, each must display 236 | Appropriate Legal Notices; however, if the Program has interactive 237 | interfaces that do not display Appropriate Legal Notices, your 238 | work need not make them do so. 239 | 240 | A compilation of a covered work with other separate and independent 241 | works, which are not by their nature extensions of the covered work, 242 | and which are not combined with it such as to form a larger program, 243 | in or on a volume of a storage or distribution medium, is called an 244 | "aggregate" if the compilation and its resulting copyright are not 245 | used to limit the access or legal rights of the compilation's users 246 | beyond what the individual works permit. Inclusion of a covered work 247 | in an aggregate does not cause this License to apply to the other 248 | parts of the aggregate. 249 | 250 | 6. Conveying Non-Source Forms. 251 | 252 | You may convey a covered work in object code form under the terms 253 | of sections 4 and 5, provided that you also convey the 254 | machine-readable Corresponding Source under the terms of this License, 255 | in one of these ways: 256 | 257 | a) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by the 259 | Corresponding Source fixed on a durable physical medium 260 | customarily used for software interchange. 261 | 262 | b) Convey the object code in, or embodied in, a physical product 263 | (including a physical distribution medium), accompanied by a 264 | written offer, valid for at least three years and valid for as 265 | long as you offer spare parts or customer support for that product 266 | model, to give anyone who possesses the object code either (1) a 267 | copy of the Corresponding Source for all the software in the 268 | product that is covered by this License, on a durable physical 269 | medium customarily used for software interchange, for a price no 270 | more than your reasonable cost of physically performing this 271 | conveying of source, or (2) access to copy the 272 | Corresponding Source from a network server at no charge. 273 | 274 | c) Convey individual copies of the object code with a copy of the 275 | written offer to provide the Corresponding Source. This 276 | alternative is allowed only occasionally and noncommercially, and 277 | only if you received the object code with such an offer, in accord 278 | with subsection 6b. 279 | 280 | d) Convey the object code by offering access from a designated 281 | place (gratis or for a charge), and offer equivalent access to the 282 | Corresponding Source in the same way through the same place at no 283 | further charge. You need not require recipients to copy the 284 | Corresponding Source along with the object code. If the place to 285 | copy the object code is a network server, the Corresponding Source 286 | may be on a different server (operated by you or a third party) 287 | that supports equivalent copying facilities, provided you maintain 288 | clear directions next to the object code saying where to find the 289 | Corresponding Source. Regardless of what server hosts the 290 | Corresponding Source, you remain obligated to ensure that it is 291 | available for as long as needed to satisfy these requirements. 292 | 293 | e) Convey the object code using peer-to-peer transmission, provided 294 | you inform other peers where the object code and Corresponding 295 | Source of the work are being offered to the general public at no 296 | charge under subsection 6d. 297 | 298 | A separable portion of the object code, whose source code is excluded 299 | from the Corresponding Source as a System Library, need not be 300 | included in conveying the object code work. 301 | 302 | A "User Product" is either (1) a "consumer product", which means any 303 | tangible personal property which is normally used for personal, family, 304 | or household purposes, or (2) anything designed or sold for incorporation 305 | into a dwelling. In determining whether a product is a consumer product, 306 | doubtful cases shall be resolved in favor of coverage. For a particular 307 | product received by a particular user, "normally used" refers to a 308 | typical or common use of that class of product, regardless of the status 309 | of the particular user or of the way in which the particular user 310 | actually uses, or expects or is expected to use, the product. A product 311 | is a consumer product regardless of whether the product has substantial 312 | commercial, industrial or non-consumer uses, unless such uses represent 313 | the only significant mode of use of the product. 314 | 315 | "Installation Information" for a User Product means any methods, 316 | procedures, authorization keys, or other information required to install 317 | and execute modified versions of a covered work in that User Product from 318 | a modified version of its Corresponding Source. The information must 319 | suffice to ensure that the continued functioning of the modified object 320 | code is in no case prevented or interfered with solely because 321 | modification has been made. 322 | 323 | If you convey an object code work under this section in, or with, or 324 | specifically for use in, a User Product, and the conveying occurs as 325 | part of a transaction in which the right of possession and use of the 326 | User Product is transferred to the recipient in perpetuity or for a 327 | fixed term (regardless of how the transaction is characterized), the 328 | Corresponding Source conveyed under this section must be accompanied 329 | by the Installation Information. But this requirement does not apply 330 | if neither you nor any third party retains the ability to install 331 | modified object code on the User Product (for example, the work has 332 | been installed in ROM). 333 | 334 | The requirement to provide Installation Information does not include a 335 | requirement to continue to provide support service, warranty, or updates 336 | for a work that has been modified or installed by the recipient, or for 337 | the User Product in which it has been modified or installed. Access to a 338 | network may be denied when the modification itself materially and 339 | adversely affects the operation of the network or violates the rules and 340 | protocols for communication across the network. 341 | 342 | Corresponding Source conveyed, and Installation Information provided, 343 | in accord with this section must be in a format that is publicly 344 | documented (and with an implementation available to the public in 345 | source code form), and must require no special password or key for 346 | unpacking, reading or copying. 347 | 348 | 7. Additional Terms. 349 | 350 | "Additional permissions" are terms that supplement the terms of this 351 | License by making exceptions from one or more of its conditions. 352 | Additional permissions that are applicable to the entire Program shall 353 | be treated as though they were included in this License, to the extent 354 | that they are valid under applicable law. If additional permissions 355 | apply only to part of the Program, that part may be used separately 356 | under those permissions, but the entire Program remains governed by 357 | this License without regard to the additional permissions. 358 | 359 | When you convey a copy of a covered work, you may at your option 360 | remove any additional permissions from that copy, or from any part of 361 | it. (Additional permissions may be written to require their own 362 | removal in certain cases when you modify the work.) You may place 363 | additional permissions on material, added by you to a covered work, 364 | for which you have or can give appropriate copyright permission. 365 | 366 | Notwithstanding any other provision of this License, for material you 367 | add to a covered work, you may (if authorized by the copyright holders of 368 | that material) supplement the terms of this License with terms: 369 | 370 | a) Disclaiming warranty or limiting liability differently from the 371 | terms of sections 15 and 16 of this License; or 372 | 373 | b) Requiring preservation of specified reasonable legal notices or 374 | author attributions in that material or in the Appropriate Legal 375 | Notices displayed by works containing it; or 376 | 377 | c) Prohibiting misrepresentation of the origin of that material, or 378 | requiring that modified versions of such material be marked in 379 | reasonable ways as different from the original version; or 380 | 381 | d) Limiting the use for publicity purposes of names of licensors or 382 | authors of the material; or 383 | 384 | e) Declining to grant rights under trademark law for use of some 385 | trade names, trademarks, or service marks; or 386 | 387 | f) Requiring indemnification of licensors and authors of that 388 | material by anyone who conveys the material (or modified versions of 389 | it) with contractual assumptions of liability to the recipient, for 390 | any liability that these contractual assumptions directly impose on 391 | those licensors and authors. 392 | 393 | All other non-permissive additional terms are considered "further 394 | restrictions" within the meaning of section 10. If the Program as you 395 | received it, or any part of it, contains a notice stating that it is 396 | governed by this License along with a term that is a further 397 | restriction, you may remove that term. If a license document contains 398 | a further restriction but permits relicensing or conveying under this 399 | License, you may add to a covered work material governed by the terms 400 | of that license document, provided that the further restriction does 401 | not survive such relicensing or conveying. 402 | 403 | If you add terms to a covered work in accord with this section, you 404 | must place, in the relevant source files, a statement of the 405 | additional terms that apply to those files, or a notice indicating 406 | where to find the applicable terms. 407 | 408 | Additional terms, permissive or non-permissive, may be stated in the 409 | form of a separately written license, or stated as exceptions; 410 | the above requirements apply either way. 411 | 412 | 8. Termination. 413 | 414 | You may not propagate or modify a covered work except as expressly 415 | provided under this License. Any attempt otherwise to propagate or 416 | modify it is void, and will automatically terminate your rights under 417 | this License (including any patent licenses granted under the third 418 | paragraph of section 11). 419 | 420 | However, if you cease all violation of this License, then your 421 | license from a particular copyright holder is reinstated (a) 422 | provisionally, unless and until the copyright holder explicitly and 423 | finally terminates your license, and (b) permanently, if the copyright 424 | holder fails to notify you of the violation by some reasonable means 425 | prior to 60 days after the cessation. 426 | 427 | Moreover, your license from a particular copyright holder is 428 | reinstated permanently if the copyright holder notifies you of the 429 | violation by some reasonable means, this is the first time you have 430 | received notice of violation of this License (for any work) from that 431 | copyright holder, and you cure the violation prior to 30 days after 432 | your receipt of the notice. 433 | 434 | Termination of your rights under this section does not terminate the 435 | licenses of parties who have received copies or rights from you under 436 | this License. If your rights have been terminated and not permanently 437 | reinstated, you do not qualify to receive new licenses for the same 438 | material under section 10. 439 | 440 | 9. Acceptance Not Required for Having Copies. 441 | 442 | You are not required to accept this License in order to receive or 443 | run a copy of the Program. Ancillary propagation of a covered work 444 | occurring solely as a consequence of using peer-to-peer transmission 445 | to receive a copy likewise does not require acceptance. However, 446 | nothing other than this License grants you permission to propagate or 447 | modify any covered work. These actions infringe copyright if you do 448 | not accept this License. Therefore, by modifying or propagating a 449 | covered work, you indicate your acceptance of this License to do so. 450 | 451 | 10. Automatic Licensing of Downstream Recipients. 452 | 453 | Each time you convey a covered work, the recipient automatically 454 | receives a license from the original licensors, to run, modify and 455 | propagate that work, subject to this License. You are not responsible 456 | for enforcing compliance by third parties with this License. 457 | 458 | An "entity transaction" is a transaction transferring control of an 459 | organization, or substantially all assets of one, or subdividing an 460 | organization, or merging organizations. If propagation of a covered 461 | work results from an entity transaction, each party to that 462 | transaction who receives a copy of the work also receives whatever 463 | licenses to the work the party's predecessor in interest had or could 464 | give under the previous paragraph, plus a right to possession of the 465 | Corresponding Source of the work from the predecessor in interest, if 466 | the predecessor has it or can get it with reasonable efforts. 467 | 468 | You may not impose any further restrictions on the exercise of the 469 | rights granted or affirmed under this License. For example, you may 470 | not impose a license fee, royalty, or other charge for exercise of 471 | rights granted under this License, and you may not initiate litigation 472 | (including a cross-claim or counterclaim in a lawsuit) alleging that 473 | any patent claim is infringed by making, using, selling, offering for 474 | sale, or importing the Program or any portion of it. 475 | 476 | 11. Patents. 477 | 478 | A "contributor" is a copyright holder who authorizes use under this 479 | License of the Program or a work on which the Program is based. The 480 | work thus licensed is called the contributor's "contributor version". 481 | 482 | A contributor's "essential patent claims" are all patent claims 483 | owned or controlled by the contributor, whether already acquired or 484 | hereafter acquired, that would be infringed by some manner, permitted 485 | by this License, of making, using, or selling its contributor version, 486 | but do not include claims that would be infringed only as a 487 | consequence of further modification of the contributor version. For 488 | purposes of this definition, "control" includes the right to grant 489 | patent sublicenses in a manner consistent with the requirements of 490 | this License. 491 | 492 | Each contributor grants you a non-exclusive, worldwide, royalty-free 493 | patent license under the contributor's essential patent claims, to 494 | make, use, sell, offer for sale, import and otherwise run, modify and 495 | propagate the contents of its contributor version. 496 | 497 | In the following three paragraphs, a "patent license" is any express 498 | agreement or commitment, however denominated, not to enforce a patent 499 | (such as an express permission to practice a patent or covenant not to 500 | sue for patent infringement). To "grant" such a patent license to a 501 | party means to make such an agreement or commitment not to enforce a 502 | patent against the party. 503 | 504 | If you convey a covered work, knowingly relying on a patent license, 505 | and the Corresponding Source of the work is not available for anyone 506 | to copy, free of charge and under the terms of this License, through a 507 | publicly available network server or other readily accessible means, 508 | then you must either (1) cause the Corresponding Source to be so 509 | available, or (2) arrange to deprive yourself of the benefit of the 510 | patent license for this particular work, or (3) arrange, in a manner 511 | consistent with the requirements of this License, to extend the patent 512 | license to downstream recipients. "Knowingly relying" means you have 513 | actual knowledge that, but for the patent license, your conveying the 514 | covered work in a country, or your recipient's use of the covered work 515 | in a country, would infringe one or more identifiable patents in that 516 | country that you have reason to believe are valid. 517 | 518 | If, pursuant to or in connection with a single transaction or 519 | arrangement, you convey, or propagate by procuring conveyance of, a 520 | covered work, and grant a patent license to some of the parties 521 | receiving the covered work authorizing them to use, propagate, modify 522 | or convey a specific copy of the covered work, then the patent license 523 | you grant is automatically extended to all recipients of the covered 524 | work and works based on it. 525 | 526 | A patent license is "discriminatory" if it does not include within 527 | the scope of its coverage, prohibits the exercise of, or is 528 | conditioned on the non-exercise of one or more of the rights that are 529 | specifically granted under this License. You may not convey a covered 530 | work if you are a party to an arrangement with a third party that is 531 | in the business of distributing software, under which you make payment 532 | to the third party based on the extent of your activity of conveying 533 | the work, and under which the third party grants, to any of the 534 | parties who would receive the covered work from you, a discriminatory 535 | patent license (a) in connection with copies of the covered work 536 | conveyed by you (or copies made from those copies), or (b) primarily 537 | for and in connection with specific products or compilations that 538 | contain the covered work, unless you entered into that arrangement, 539 | or that patent license was granted, prior to 28 March 2007. 540 | 541 | Nothing in this License shall be construed as excluding or limiting 542 | any implied license or other defenses to infringement that may 543 | otherwise be available to you under applicable patent law. 544 | 545 | 12. No Surrender of Others' Freedom. 546 | 547 | If conditions are imposed on you (whether by court order, agreement or 548 | otherwise) that contradict the conditions of this License, they do not 549 | excuse you from the conditions of this License. If you cannot convey a 550 | covered work so as to satisfy simultaneously your obligations under this 551 | License and any other pertinent obligations, then as a consequence you may 552 | not convey it at all. For example, if you agree to terms that obligate you 553 | to collect a royalty for further conveying from those to whom you convey 554 | the Program, the only way you could satisfy both those terms and this 555 | License would be to refrain entirely from conveying the Program. 556 | 557 | 13. Use with the GNU Affero General Public License. 558 | 559 | Notwithstanding any other provision of this License, you have 560 | permission to link or combine any covered work with a work licensed 561 | under version 3 of the GNU Affero General Public License into a single 562 | combined work, and to convey the resulting work. The terms of this 563 | License will continue to apply to the part which is the covered work, 564 | but the special requirements of the GNU Affero General Public License, 565 | section 13, concerning interaction through a network will apply to the 566 | combination as such. 567 | 568 | 14. Revised Versions of this License. 569 | 570 | The Free Software Foundation may publish revised and/or new versions of 571 | the GNU General Public License from time to time. Such new versions will 572 | be similar in spirit to the present version, but may differ in detail to 573 | address new problems or concerns. 574 | 575 | Each version is given a distinguishing version number. If the 576 | Program specifies that a certain numbered version of the GNU General 577 | Public License "or any later version" applies to it, you have the 578 | option of following the terms and conditions either of that numbered 579 | version or of any later version published by the Free Software 580 | Foundation. If the Program does not specify a version number of the 581 | GNU General Public License, you may choose any version ever published 582 | by the Free Software Foundation. 583 | 584 | If the Program specifies that a proxy can decide which future 585 | versions of the GNU General Public License can be used, that proxy's 586 | public statement of acceptance of a version permanently authorizes you 587 | to choose that version for the Program. 588 | 589 | Later license versions may give you additional or different 590 | permissions. However, no additional obligations are imposed on any 591 | author or copyright holder as a result of your choosing to follow a 592 | later version. 593 | 594 | 15. Disclaimer of Warranty. 595 | 596 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 597 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 598 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 599 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 600 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 601 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 602 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 603 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 604 | 605 | 16. Limitation of Liability. 606 | 607 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 608 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 609 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 610 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 611 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 612 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 613 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 614 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 615 | SUCH DAMAGES. 616 | 617 | 17. Interpretation of Sections 15 and 16. 618 | 619 | If the disclaimer of warranty and limitation of liability provided 620 | above cannot be given local legal effect according to their terms, 621 | reviewing courts shall apply local law that most closely approximates 622 | an absolute waiver of all civil liability in connection with the 623 | Program, unless a warranty or assumption of liability accompanies a 624 | copy of the Program in return for a fee. 625 | 626 | END OF TERMS AND CONDITIONS 627 | 628 | How to Apply These Terms to Your New Programs 629 | 630 | If you develop a new program, and you want it to be of the greatest 631 | possible use to the public, the best way to achieve this is to make it 632 | free software which everyone can redistribute and change under these terms. 633 | 634 | To do so, attach the following notices to the program. It is safest 635 | to attach them to the start of each source file to most effectively 636 | state the exclusion of warranty; and each file should have at least 637 | the "copyright" line and a pointer to where the full notice is found. 638 | 639 | 640 | Copyright (C) 641 | 642 | This program is free software: you can redistribute it and/or modify 643 | it under the terms of the GNU General Public License as published by 644 | the Free Software Foundation, either version 3 of the License, or 645 | (at your option) any later version. 646 | 647 | This program is distributed in the hope that it will be useful, 648 | but WITHOUT ANY WARRANTY; without even the implied warranty of 649 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 650 | GNU General Public License for more details. 651 | 652 | You should have received a copy of the GNU General Public License 653 | along with this program. If not, see . 654 | 655 | Also add information on how to contact you by electronic and paper mail. 656 | 657 | If the program does terminal interaction, make it output a short 658 | notice like this when it starts in an interactive mode: 659 | 660 | Copyright (C) 661 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 662 | This is free software, and you are welcome to redistribute it 663 | under certain conditions; type `show c' for details. 664 | 665 | The hypothetical commands `show w' and `show c' should show the appropriate 666 | parts of the General Public License. Of course, your program's commands 667 | might be different; for a GUI interface, you would use an "about box". 668 | 669 | You should also get your employer (if you work as a programmer) or school, 670 | if any, to sign a "copyright disclaimer" for the program, if necessary. 671 | For more information on this, and how to apply and follow the GNU GPL, see 672 | . 673 | 674 | The GNU General Public License does not permit incorporating your program 675 | into proprietary programs. If your program is a subroutine library, you 676 | may consider it more useful to permit linking proprietary applications with 677 | the library. If this is what you want to do, use the GNU Lesser General 678 | Public License instead of this License. But first, please read 679 | . 680 | -------------------------------------------------------------------------------- /patch/mutil-1.822.1.patch: -------------------------------------------------------------------------------- 1 | diff -rupN old1/configure new/configure 2 | --- old1/configure 2015-01-08 11:43:53.000000000 -0800 3 | +++ new/configure 2018-01-18 14:44:19.271960028 -0800 4 | @@ -8393,7 +8393,7 @@ fi 5 | $as_echo "$ac_cv_lib_gcrypt_gcry_md_open" >&6; } 6 | if test "x$ac_cv_lib_gcrypt_gcry_md_open" = xyes; then : 7 | 8 | - LIBS="$LIBS -Wl,--as-needed -lgcrypt -Wl,--no-as-needed" 9 | + LIBS="$LIBS -lgcrypt" 10 | 11 | $as_echo "#define HAVE_LIBGCRYPT 1" >>confdefs.h 12 | 13 | @@ -8438,7 +8438,7 @@ fi 14 | $as_echo "$ac_cv_lib_gpg_error_gpg_err_init" >&6; } 15 | if test "x$ac_cv_lib_gpg_error_gpg_err_init" = xyes; then : 16 | 17 | - LIBS="$LIBS -Wl,--as-needed -lgpg-error -Wl,--no-as-needed" 18 | + LIBS="$LIBS -lgpg-error" 19 | 20 | $as_echo "#define HAVE_LIBGPG_ERROR 1" >>confdefs.h 21 | 22 | @@ -8591,7 +8591,7 @@ fi 23 | $as_echo "$ac_cv_lib_gnutls_gnutls_srp_verifier" >&6; } 24 | if test "x$ac_cv_lib_gnutls_gnutls_srp_verifier" = xyes; then : 25 | 26 | - LIBS="$LIBS -Wl,--as-needed -lgnutls -Wl,--no-as-needed" 27 | + LIBS="$LIBS -lgnutls" 28 | 29 | $as_echo "#define HAVE_LIBGNUTLS 1" >>confdefs.h 30 | 31 | @@ -8636,7 +8636,7 @@ fi 32 | $as_echo "$ac_cv_lib_z_zlibVersion" >&6; } 33 | if test "x$ac_cv_lib_z_zlibVersion" = xyes; then : 34 | 35 | - LIBS="$LIBS -Wl,--as-needed -lz -Wl,--no-as-needed" 36 | + LIBS="$LIBS -lz" 37 | 38 | $as_echo "#define HAVE_LIBZ 1" >>confdefs.h 39 | 40 | @@ -8646,108 +8646,12 @@ fi 41 | fi 42 | 43 | 44 | - 45 | - if test $MUTIL_STATIC_GCRYPT = yes; then 46 | - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gnutls_extra_check_version in -lgnutls-extra" >&5 47 | -$as_echo_n "checking for gnutls_extra_check_version in -lgnutls-extra... " >&6; } 48 | -if ${ac_cv_lib_gnutls_extra_gnutls_extra_check_version+:} false; then : 49 | - $as_echo_n "(cached) " >&6 50 | -else 51 | - ac_check_lib_save_LIBS=$LIBS 52 | -LIBS="-lgnutls-extra $LIBS" 53 | -cat confdefs.h - <<_ACEOF >conftest.$ac_ext 54 | -/* end confdefs.h. */ 55 | - 56 | -/* Override any GCC internal prototype to avoid an error. 57 | - Use char because int might match the return type of a GCC 58 | - builtin and then its argument prototype would still apply. */ 59 | -#ifdef __cplusplus 60 | -extern "C" 61 | -#endif 62 | -char gnutls_extra_check_version (); 63 | -int 64 | -main () 65 | -{ 66 | -return gnutls_extra_check_version (); 67 | - ; 68 | - return 0; 69 | -} 70 | -_ACEOF 71 | -if ac_fn_c_try_link "$LINENO"; then : 72 | - ac_cv_lib_gnutls_extra_gnutls_extra_check_version=yes 73 | -else 74 | - ac_cv_lib_gnutls_extra_gnutls_extra_check_version=no 75 | -fi 76 | -rm -f core conftest.err conftest.$ac_objext \ 77 | - conftest$ac_exeext conftest.$ac_ext 78 | -LIBS=$ac_check_lib_save_LIBS 79 | -fi 80 | -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_gnutls_extra_gnutls_extra_check_version" >&5 81 | -$as_echo "$ac_cv_lib_gnutls_extra_gnutls_extra_check_version" >&6; } 82 | -if test "x$ac_cv_lib_gnutls_extra_gnutls_extra_check_version" = xyes; then : 83 | - 84 | - LIBS="$LIBS -Wl,-Bstatic -lgnutls-extra -Wl,-Bdynamic" 85 | - 86 | -$as_echo "#define HAVE_LIBGNUTLS_EXTRA 1" >>confdefs.h 87 | - 88 | - 89 | -fi 90 | - 91 | - else 92 | - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gnutls_extra_check_version in -lgnutls-extra" >&5 93 | -$as_echo_n "checking for gnutls_extra_check_version in -lgnutls-extra... " >&6; } 94 | -if ${ac_cv_lib_gnutls_extra_gnutls_extra_check_version+:} false; then : 95 | - $as_echo_n "(cached) " >&6 96 | -else 97 | - ac_check_lib_save_LIBS=$LIBS 98 | -LIBS="-lgnutls-extra $LIBS" 99 | -cat confdefs.h - <<_ACEOF >conftest.$ac_ext 100 | -/* end confdefs.h. */ 101 | - 102 | -/* Override any GCC internal prototype to avoid an error. 103 | - Use char because int might match the return type of a GCC 104 | - builtin and then its argument prototype would still apply. */ 105 | -#ifdef __cplusplus 106 | -extern "C" 107 | -#endif 108 | -char gnutls_extra_check_version (); 109 | -int 110 | -main () 111 | -{ 112 | -return gnutls_extra_check_version (); 113 | - ; 114 | - return 0; 115 | -} 116 | -_ACEOF 117 | -if ac_fn_c_try_link "$LINENO"; then : 118 | - ac_cv_lib_gnutls_extra_gnutls_extra_check_version=yes 119 | -else 120 | - ac_cv_lib_gnutls_extra_gnutls_extra_check_version=no 121 | -fi 122 | -rm -f core conftest.err conftest.$ac_objext \ 123 | - conftest$ac_exeext conftest.$ac_ext 124 | -LIBS=$ac_check_lib_save_LIBS 125 | -fi 126 | -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_gnutls_extra_gnutls_extra_check_version" >&5 127 | -$as_echo "$ac_cv_lib_gnutls_extra_gnutls_extra_check_version" >&6; } 128 | -if test "x$ac_cv_lib_gnutls_extra_gnutls_extra_check_version" = xyes; then : 129 | - 130 | - LIBS="$LIBS -Wl,--as-needed -lgnutls-extra -Wl,--no-as-needed" 131 | - 132 | -$as_echo "#define HAVE_LIBGNUTLS_EXTRA 1" >>confdefs.h 133 | - 134 | - 135 | -fi 136 | - 137 | - fi 138 | - 139 | - 140 | - for ac_header in lustre/liblustreapi.h 141 | + for ac_header in lustre/lustreapi.h 142 | do : 143 | - ac_fn_c_check_header_mongrel "$LINENO" "lustre/liblustreapi.h" "ac_cv_header_lustre_liblustreapi_h" "$ac_includes_default" 144 | -if test "x$ac_cv_header_lustre_liblustreapi_h" = xyes; then : 145 | + ac_fn_c_check_header_mongrel "$LINENO" "lustre/lustreapi.h" "ac_cv_header_lustre_lustreapi_h" "$ac_includes_default" 146 | +if test "x$ac_cv_header_lustre_lustreapi_h" = xyes; then : 147 | cat >>confdefs.h <<_ACEOF 148 | -#define HAVE_LUSTRE_LIBLUSTREAPI_H 1 149 | +#define HAVE_LUSTRE_LUSTREAPI_H 1 150 | _ACEOF 151 | 152 | fi 153 | @@ -25462,7 +25366,6 @@ fi 154 | 155 | 156 | 157 | - 158 | gl_source_base='lib' 159 | 160 | 161 | @@ -55087,7 +54990,6 @@ done 162 | 163 | 164 | 165 | - 166 | 167 | 168 | 169 | diff -rupN old1/lib/config.hin new/lib/config.hin 170 | --- old1/lib/config.hin 2015-01-08 11:43:54.000000000 -0800 171 | +++ new/lib/config.hin 2018-01-18 14:44:19.183957656 -0800 172 | @@ -1642,9 +1642,6 @@ 173 | /* Define to 1 if you have the 'gnutls' library ('lgnutls') */ 174 | #undef HAVE_LIBGNUTLS 175 | 176 | -/* Define to 1 if you have the 'gnutls-extra' library ('lgnutls-extra') */ 177 | -#undef HAVE_LIBGNUTLS_EXTRA 178 | - 179 | /* Define to 1 if you have the 'gpg-error' library ('lgpg-error') */ 180 | #undef HAVE_LIBGPG_ERROR 181 | 182 | @@ -1696,8 +1693,8 @@ 183 | /* Define to 1 if you have the `lstat' function. */ 184 | #undef HAVE_LSTAT 185 | 186 | -/* Define to 1 if you have the header file. */ 187 | -#undef HAVE_LUSTRE_LIBLUSTREAPI_H 188 | +/* Define to 1 if you have the header file. */ 189 | +#undef HAVE_LUSTRE_LUSTREAPI_H 190 | 191 | /* Define to 1 if you have the `lutimes' function. */ 192 | #undef HAVE_LUTIMES 193 | diff -rupN old1/m4/gnulib-common.m4 new/m4/gnulib-common.m4 194 | --- old1/m4/gnulib-common.m4 2014-01-23 11:53:12.000000000 -0800 195 | +++ new/m4/gnulib-common.m4 2018-01-18 14:44:16.179876693 -0800 196 | @@ -13,7 +13,6 @@ AC_DEFUN([gl_COMMON], [ 197 | dnl PZK > 198 | AC_REQUIRE([mutil_LIBM]) 199 | AC_REQUIRE([mutil_LIBRT]) 200 | - AC_REQUIRE([mutil_LIBGNUTLS_EXTRA]) 201 | AC_REQUIRE([mutil_LIBGNUTLS]) 202 | AC_REQUIRE([mutil_LIBGCRYPT]) 203 | AC_REQUIRE([mutil_LIBLUSTREAPI]) 204 | diff -rupN old1/m4/mutil.m4 new/m4/mutil.m4 205 | --- old1/m4/mutil.m4 2014-01-24 14:43:52.000000000 -0800 206 | +++ new/m4/mutil.m4 2018-01-18 14:44:17.079900948 -0800 207 | @@ -15,25 +15,6 @@ AC_DEFUN([mutil_LIBRT], [ 208 | AC_CHECK_LIB([rt], [clock_gettime]) 209 | ]) 210 | 211 | -AC_DEFUN([mutil_LIBGNUTLS_EXTRA], [ 212 | - AC_REQUIRE([mutil_LIBGNUTLS]) 213 | - if test $MUTIL_STATIC_GCRYPT = yes; then 214 | - AC_CHECK_LIB([gnutls-extra], [gnutls_extra_check_version], [ 215 | - LIBS="$LIBS -Wl,-Bstatic -lgnutls-extra -Wl,-Bdynamic" 216 | - AC_DEFINE([HAVE_LIBGNUTLS_EXTRA], [1], [ 217 | - Define to 1 if you have the 'gnutls-extra' library ('lgnutls-extra') 218 | - ]) 219 | - ]) 220 | - else 221 | - AC_CHECK_LIB([gnutls-extra], [gnutls_extra_check_version], [ 222 | - LIBS="$LIBS -Wl,--as-needed -lgnutls-extra -Wl,--no-as-needed" 223 | - AC_DEFINE([HAVE_LIBGNUTLS_EXTRA], [1], [ 224 | - Define to 1 if you have the 'gnutls-extra' library ('lgnutls-extra') 225 | - ]) 226 | - ]) 227 | - fi 228 | -]) 229 | - 230 | AC_DEFUN([mutil_LIBGNUTLS], [ 231 | AC_REQUIRE([mutil_LIBGCRYPT]) 232 | AC_CHECK_HEADERS([gnutls/gnutls.h]) 233 | @@ -52,13 +33,13 @@ AC_DEFUN([mutil_LIBGNUTLS], [ 234 | ]) 235 | else 236 | AC_CHECK_LIB([gnutls], [gnutls_srp_verifier], [ 237 | - LIBS="$LIBS -Wl,--as-needed -lgnutls -Wl,--no-as-needed" 238 | + LIBS="$LIBS -lgnutls" 239 | AC_DEFINE([HAVE_LIBGNUTLS], [1], [ 240 | Define to 1 if you have the 'gnutls' library ('lgnutls') 241 | ]) 242 | ]) 243 | AC_CHECK_LIB([z], [zlibVersion], [ 244 | - LIBS="$LIBS -Wl,--as-needed -lz -Wl,--no-as-needed" 245 | + LIBS="$LIBS -lz" 246 | AC_DEFINE([HAVE_LIBZ], [1], [ 247 | Define to 1 if you have the 'z' library ('lz') 248 | ]) 249 | @@ -88,13 +69,13 @@ AC_DEFUN([mutil_LIBGCRYPT], [ 250 | ]) 251 | else 252 | AC_CHECK_LIB([gcrypt], [gcry_md_open], [ 253 | - LIBS="$LIBS -Wl,--as-needed -lgcrypt -Wl,--no-as-needed" 254 | + LIBS="$LIBS -lgcrypt" 255 | AC_DEFINE([HAVE_LIBGCRYPT], [1], [ 256 | Define to 1 if you have the 'gcrypt' library ('lgcrypt') 257 | ]) 258 | ]) 259 | AC_CHECK_LIB([gpg-error], [gpg_err_init], [ 260 | - LIBS="$LIBS -Wl,--as-needed -lgpg-error -Wl,--no-as-needed" 261 | + LIBS="$LIBS -lgpg-error" 262 | AC_DEFINE([HAVE_LIBGPG_ERROR], [1], [ 263 | Define to 1 if you have the 'gpg-error' library ('lgpg-error') 264 | ]) 265 | @@ -103,7 +84,7 @@ AC_DEFUN([mutil_LIBGCRYPT], [ 266 | ]) 267 | 268 | AC_DEFUN([mutil_LIBLUSTREAPI], [ 269 | - AC_CHECK_HEADERS([lustre/liblustreapi.h]) 270 | + AC_CHECK_HEADERS([lustre/lustreapi.h]) 271 | AC_CHECK_LIB([lustreapi], [llapi_file_get_stripe]) 272 | ]) 273 | 274 | diff -rupN old1/src/copy.c new/src/copy.c 275 | --- old1/src/copy.c 2015-01-08 12:06:32.000000000 -0800 276 | +++ new/src/copy.c 2018-01-18 14:44:17.935924020 -0800 277 | @@ -133,43 +133,44 @@ 278 | #endif 279 | 280 | // PZK > 281 | -#ifndef SYNC_FILE_RANGE_WRITE 282 | -# define SYNC_FILE_RANGE_WAIT_BEFORE 1 283 | -# define SYNC_FILE_RANGE_WRITE 2 284 | -# define SYNC_FILE_RANGE_WAIT_AFTER 4 285 | - 286 | -# ifdef __i386__ 287 | -# define NR_sync_file_range 314 288 | -# endif 289 | - 290 | -# ifdef __x86_64__ 291 | -# define NR_sync_file_range 277 292 | -# endif 293 | +#ifdef __linux__ 294 | +# include 295 | 296 | -# ifdef __ia64__ 297 | -# define NR_sync_file_range 1300 298 | -# endif 299 | +# ifndef SYNC_FILE_RANGE_WRITE 300 | +# define SYNC_FILE_RANGE_WAIT_BEFORE 1 301 | +# define SYNC_FILE_RANGE_WRITE 2 302 | +# define SYNC_FILE_RANGE_WAIT_AFTER 4 303 | + 304 | +# ifdef __i386__ 305 | +# define NR_sync_file_range 314 306 | +# endif 307 | + 308 | +# ifdef __x86_64__ 309 | +# define NR_sync_file_range 277 310 | +# endif 311 | + 312 | +# ifdef __ia64__ 313 | +# define NR_sync_file_range 1300 314 | +# endif 315 | 316 | -# include 317 | +# include 318 | static inline int sync_file_range( 319 | int fd, loff_t offset, loff_t nbytes, int flags) { 320 | return syscall(NR_sync_file_range, fd, offset, nbytes, flags); 321 | } 322 | - 323 | +# endif 324 | #endif 325 | 326 | #if HAVE_LIBLUSTREAPI 327 | # include 328 | -# include 329 | -# include 330 | +# include 331 | # include 332 | # define MAX_OSTS 1024 333 | # define LOV_EA_SIZE(lum, num) (sizeof(*lum) + num * sizeof(*lum->lmm_objects)) 334 | # define LOV_EA_MAX(lum) LOV_EA_SIZE(lum, MAX_OSTS) 335 | -//# ifndef LOV_MAX_STRIPE_COUNT 336 | //TODO: llapi is still messed up when max above 160 (could be our env 337 | // with mix of lustre versions) 338 | -# define LOV_MAX_STRIPE_COUNT 160 339 | +# define MUTIL_MAX_STRIPE_COUNT 160 340 | //# endif 341 | #endif 342 | 343 | @@ -180,10 +181,6 @@ static inline int sync_file_range( 344 | # include 345 | #endif 346 | 347 | -#ifdef __linux__ 348 | -# include 349 | -#endif 350 | - 351 | #ifndef DEFAULT_LUSTRE_STRIPES 352 | # define DEFAULT_LUSTRE_STRIPES 1 353 | #endif 354 | @@ -310,13 +307,33 @@ sparse_copy (copy_reg_t *crt, struct cp_ 355 | 356 | ssize_t n_read; 357 | if (raiol[0] != NULL) { 358 | - // this will be skipped during the first double buffer iteration 359 | - aio_suspend((const struct aiocb * const *) raiol, 1, NULL); 360 | - if (co->print_stats) clock_gettime(CLOCK_REALTIME, &rts[1]); 361 | + // this will be skipped during the first double buffer iteration 362 | + // wait for previous asynchronous read to complete 363 | + while (aio_suspend((const struct aiocb * const *) raiol, 1, NULL) && errno == EINTR); 364 | + if (co->print_stats) clock_gettime(0, &rts[1]); 365 | if (waiol[0] != NULL) { 366 | - aio_suspend((const struct aiocb * const *) waiol, 1, NULL); 367 | + while (1) { 368 | + // wait for previous asynchronous write to complete 369 | + while (aio_suspend((const struct aiocb * const *) waiol, 1, NULL) && errno == EINTR); 370 | + ssize_t n_write = aio_return(waiol[0]); 371 | + if (n_write < 0 && errno == EINTR || 372 | + n_write >= 0 && n_write < waiol[0]->aio_nbytes) { 373 | + // retry if write interrupted or short write 374 | + if (aio_write(waiol[0]) < 0) { 375 | + error (0, errno, _("failed to initiate aio_write: %s"), 376 | + quote (crt->dst_name)); 377 | + return false; 378 | + } 379 | + continue; 380 | + } else if (n_write < 0) { 381 | + // abort if write error 382 | + error (0, errno, _("writing %s"), quote (crt->dst_name)); 383 | + return false; 384 | + } 385 | + break; 386 | + } 387 | if (co->print_stats) { 388 | - clock_gettime(CLOCK_REALTIME, &wts[1]); 389 | + clock_gettime(0, &wts[1]); 390 | crt->write_time += (double) ( 391 | (double) wts[1].tv_sec + 392 | (double) wts[1].tv_nsec / (double) 1.0e9 - 393 | @@ -341,9 +358,9 @@ sparse_copy (copy_reg_t *crt, struct cp_ 394 | quote(crt->src_name)); 395 | } 396 | 397 | - if (co->print_stats) clock_gettime(CLOCK_REALTIME, &rts[0]); 398 | + if (co->print_stats) clock_gettime(0, &rts[0]); 399 | n_read = read (crt->src_fd, buf[aio_buf], to_read); 400 | - if (co->print_stats) clock_gettime(CLOCK_REALTIME, &rts[1]); 401 | + if (co->print_stats) clock_gettime(0, &rts[1]); 402 | 403 | if (co->read_mode && align_read != 0) { 404 | // turn direct i/o back on in case it was turned off 405 | @@ -407,15 +424,18 @@ sparse_copy (copy_reg_t *crt, struct cp_ 406 | quote(crt->src_name)); 407 | } 408 | 409 | - if (co->print_stats) clock_gettime(CLOCK_REALTIME, &rts[0]); 410 | + if (co->print_stats) clock_gettime(0, &rts[0]); 411 | memset(&raio, 0, sizeof(struct aiocb)); 412 | raio.aio_fildes = crt->src_fd; 413 | raio.aio_offset = start_offset + *total_n_read; 414 | raio.aio_buf = buf[!aio_buf]; 415 | raio.aio_nbytes = to_read; 416 | raiol[0] = &raio; 417 | - //TODO: error handling for bad aio_read 418 | - int rc = aio_read(&raio); 419 | + if (aio_read(&raio) < 0) { 420 | + error (0, errno, _("failed to initiate aio_read: %s"), 421 | + quote (crt->src_name)); 422 | + return false; 423 | + } 424 | } 425 | // < PZK 426 | 427 | @@ -461,7 +481,7 @@ sparse_copy (copy_reg_t *crt, struct cp_ 428 | error (0, errno, _("failed to turn off O_DIRECT: %s"), 429 | quote (crt->dst_name)); 430 | } 431 | - if (co->print_stats) clock_gettime(CLOCK_REALTIME, &wts[0]); 432 | + if (co->print_stats) clock_gettime(0, &wts[0]); 433 | ssize_t n_write; 434 | if (co->double_buffer) { 435 | memset(&waio, 0, sizeof(struct aiocb)); 436 | @@ -470,11 +490,15 @@ sparse_copy (copy_reg_t *crt, struct cp_ 437 | waio.aio_buf = buf[aio_buf]; 438 | waio.aio_nbytes = n; 439 | waiol[0] = &waio; 440 | - n_write = aio_write(&waio); 441 | + if (aio_write(&waio) < 0) { 442 | + error (0, errno, _("failed to initiate aio_write: %s"), 443 | + quote (crt->dst_name)); 444 | + return false; 445 | + } 446 | } else { 447 | n_write = full_write (crt->dst_fd, buf[aio_buf], n); 448 | if (co->print_stats) { 449 | - clock_gettime(CLOCK_REALTIME, &wts[1]); 450 | + clock_gettime(0, &wts[1]); 451 | crt->write_time += (double) ( 452 | (double) wts[1].tv_sec + 453 | (double) wts[1].tv_nsec / (double) 1.0e9 - 454 | @@ -483,7 +507,6 @@ sparse_copy (copy_reg_t *crt, struct cp_ 455 | } 456 | } 457 | 458 | - //TODO: check wrote n bytes in double buffer case? 459 | if (!co->double_buffer && n_write != n) 460 | { 461 | error (0, errno, _("writing %s"), quote (crt->dst_name)); 462 | @@ -509,16 +532,38 @@ sparse_copy (copy_reg_t *crt, struct cp_ 463 | if (co->double_buffer) aio_buf = !aio_buf; 464 | } 465 | 466 | - if (waiol[0] != NULL) 467 | - aio_suspend((const struct aiocb * const *) waiol, 1, NULL); 468 | + if (waiol[0] != NULL) { 469 | + while (1) { 470 | + // wait for final asynchronous write to complete 471 | + while (aio_suspend((const struct aiocb * const *) waiol, 1, NULL) && errno == EINTR); 472 | + ssize_t n_write = aio_return(waiol[0]); 473 | + if (n_write < 0 && errno == EINTR || 474 | + n_write >= 0 && n_write < waiol[0]->aio_nbytes) { 475 | + // retry if write interrupted or short write 476 | + if (aio_write(waiol[0]) < 0) { 477 | + error (0, errno, _("failed to initiate aio_write: %s"), 478 | + quote (crt->dst_name)); 479 | + return false; 480 | + } 481 | + continue; 482 | + } else if (n_write < 0) { 483 | + // abort if write error 484 | + error (0, errno, _("writing %s"), quote (crt->dst_name)); 485 | + return false; 486 | + } 487 | + break; 488 | + } 489 | #ifdef POSIX_FADV_DONTNEED 490 | - if (co->fadvise_write) { 491 | - sync_file_range(crt->dst_fd, waiol[0]->aio_offset, waiol[0]->aio_nbytes, 492 | - SYNC_FILE_RANGE_WRITE|SYNC_FILE_RANGE_WAIT_AFTER); 493 | - posix_fadvise(crt->dst_fd, waiol[0]->aio_offset, waiol[0]->aio_nbytes, 494 | - POSIX_FADV_DONTNEED); 495 | + if (co->fadvise_write) { 496 | +# ifdef __linux__ 497 | + sync_file_range(crt->dst_fd, waiol[0]->aio_offset, waiol[0]->aio_nbytes, 498 | + SYNC_FILE_RANGE_WRITE|SYNC_FILE_RANGE_WAIT_AFTER); 499 | +# endif 500 | + posix_fadvise(crt->dst_fd, waiol[0]->aio_offset, waiol[0]->aio_nbytes, 501 | + POSIX_FADV_DONTNEED); 502 | } 503 | #endif 504 | + } 505 | // < PZK 506 | 507 | return true; 508 | @@ -682,7 +727,8 @@ extent_copy (copy_reg_t *crt, struct cp_ 509 | || (!empty_extent && sparse_mode != SPARSE_NEVER)) 510 | { 511 | // PZK > 512 | - if (lseek (crt->dst_fd, ext_start, SEEK_SET) < 0) 513 | + if (lseek (crt->dst_fd, crt->dst_offset - crt->start_offset + 514 | + ext_start, SEEK_SET) < 0) 515 | { 516 | error (0, errno, _("cannot lseek %s"), quote (crt->dst_name)); 517 | // < PZK 518 | @@ -699,7 +745,13 @@ extent_copy (copy_reg_t *crt, struct cp_ 519 | if (empty_extent) 520 | // PZK > 521 | nzeros = MIN (crt->stop_offset - dest_pos, hole_size); 522 | - 523 | + // when double buffering, dst_fd may not even be set 524 | + if (co->double_buffer && lseek(crt->dst_fd, 525 | + crt->dst_offset - crt->start_offset + 526 | + crt->stop_offset - nzeros, SEEK_SET) < 0L) { 527 | + error (0, errno, _("cannot lseek %s"), quote (crt->dst_name)); 528 | + goto fail; 529 | + } 530 | if (! write_zeros (crt->dst_fd, nzeros)) 531 | { 532 | error (0, errno, _("%s: write failed"), quote (crt->dst_name)); 533 | @@ -790,25 +842,30 @@ extent_copy (copy_reg_t *crt, struct cp_ 534 | here in order to record the proper length in the destination. */ 535 | 536 | // PZK > 537 | - if (wrote_hole_at_eof && crt->dst_offset == 0 && 538 | - crt->stop_offset == src_total_size && 539 | - (sparse_mode != SPARSE_NEVER 540 | - ? ftruncate (crt->dst_fd, src_total_size) 541 | - : ! write_zeros (crt->dst_fd, src_total_size - dest_pos))) 542 | - { 543 | - error (0, errno, _("failed to extend %s"), quote (crt->dst_name)); 544 | - return false; 545 | - } 546 | - else if (wrote_hole_at_eof && crt->split + 1 == crt->nsplits && 547 | - (lseek (crt->dst_fd, (off_t) -1, SEEK_CUR) < 0L 548 | - || co->write_mode 549 | - && fcntl (crt->dst_fd, F_SETFL, 550 | - fcntl (crt->dst_fd, F_GETFL) & ~O_DIRECT) 551 | - || full_write (crt->dst_fd, "", 1) != 1)) 552 | - { 553 | - error (0, errno, _("writing %s"), quote (crt->dst_name)); 554 | - return false; 555 | + if (wrote_hole_at_eof || dest_pos < crt->stop_offset) { 556 | + if (sparse_mode == SPARSE_NEVER) { 557 | + if (lseek (crt->dst_fd, crt->dst_offset - crt->start_offset + 558 | + dest_pos, SEEK_SET) < 0L || 559 | + !write_zeros(crt->dst_fd, crt->stop_offset - dest_pos)) { 560 | + error (0, errno, _("%s: write failed"), quote (crt->dst_name)); 561 | + return false; 562 | + } 563 | + } else if (crt->dst_offset == 0 && crt->stop_offset == src_total_size) { 564 | + if (ftruncate(crt->dst_fd, src_total_size)) { 565 | + error (0, errno, _("failed to extend %s"), quote (crt->dst_name)); 566 | + return false; 567 | + } 568 | + } else if (crt->split + 1 == crt->nsplits) { 569 | + if (lseek (crt->dst_fd, crt->dst_offset - crt->start_offset + 570 | + crt->stop_offset - 1, SEEK_SET) < 0L || 571 | + co->write_mode && fcntl (crt->dst_fd, F_SETFL, 572 | + fcntl (crt->dst_fd, F_GETFL) & ~O_DIRECT) || 573 | + full_write (crt->dst_fd, "", 1) != 1) { 574 | + error (0, errno, _("%s: write failed"), quote (crt->dst_name)); 575 | + return false; 576 | + } 577 | } 578 | + } 579 | 580 | #if HAVE_LIBGCRYPT 581 | if (dest_pos < crt->stop_offset) { 582 | @@ -1395,27 +1452,36 @@ copy_reg_task (copy_reg_t *crt, struct c 583 | , &ctx, &htt 584 | #endif 585 | ); 586 | - if (copy_ok && wrote_hole_at_eof && crt->dst_offset == 0 && 587 | - crt->stop_offset == src_open_sb.st_size && 588 | - ftruncate (crt->dst_fd, src_open_sb.st_size) < 0) 589 | - { 590 | - error (0, errno, _("failed to extend %s"), quote (crt->dst_name)); 591 | - return_val = false; 592 | - goto task_close_src_and_dst_desc; 593 | - } 594 | - else if (copy_ok && wrote_hole_at_eof && crt->split + 1 == crt->nsplits && 595 | - (lseek (crt->dst_fd, (off_t) -1, SEEK_CUR) < 0L 596 | // PZK > 597 | - || co->write_mode 598 | - && fcntl (crt->dst_fd, F_SETFL, 599 | - fcntl (crt->dst_fd, F_GETFL) & ~O_DIRECT) 600 | + off_t dest_pos = crt->start_offset + n_read; 601 | + if (copy_ok && (wrote_hole_at_eof || dest_pos < crt->stop_offset)) { 602 | + if (co->sparse_mode == SPARSE_NEVER) { 603 | + if (lseek (crt->dst_fd, crt->dst_offset - crt->start_offset + 604 | + dest_pos, SEEK_SET) < 0L || 605 | + !write_zeros(crt->dst_fd, crt->stop_offset - dest_pos)) { 606 | + error (0, errno, _("%s: write failed"), quote (crt->dst_name)); 607 | + return_val = false; 608 | + goto task_close_src_and_dst_desc; 609 | + } 610 | + } else if (crt->dst_offset == 0 && crt->stop_offset == src_open_sb.st_size) { 611 | + if (ftruncate(crt->dst_fd, src_open_sb.st_size)) { 612 | + error (0, errno, _("failed to extend %s"), quote (crt->dst_name)); 613 | + return_val = false; 614 | + goto task_close_src_and_dst_desc; 615 | + } 616 | + } else if (crt->split + 1 == crt->nsplits) { 617 | + if (lseek (crt->dst_fd, crt->dst_offset - crt->start_offset + 618 | + crt->stop_offset - 1, SEEK_SET) < 0L || 619 | + co->write_mode && fcntl (crt->dst_fd, F_SETFL, 620 | + fcntl (crt->dst_fd, F_GETFL) & ~O_DIRECT) || 621 | + full_write (crt->dst_fd, "", 1) != 1) { 622 | + error (0, errno, _("%s: write failed"), quote (crt->dst_name)); 623 | + return_val = false; 624 | + goto task_close_src_and_dst_desc; 625 | + } 626 | + } 627 | + } 628 | // < PZK 629 | - || full_write (crt->dst_fd, "", 1) != 1)) 630 | - { 631 | - error (0, errno, _("writing %s"), quote (crt->dst_name)); 632 | - return_val = false; 633 | - goto task_close_src_and_dst_desc; 634 | - } 635 | 636 | task_preserve_metadata: 637 | if (co->preserve_timestamps) 638 | @@ -1650,20 +1716,16 @@ copy_reg (char const *src_name, char con 639 | scount = src_sb->st_size / 1000000000 * x->stripe_count + 1; 640 | } 641 | } 642 | - if (scount > LOV_MAX_STRIPE_COUNT) scount = LOV_MAX_STRIPE_COUNT; 643 | - if (!llapi_file_create(dst_name, ssize, -1, scount, 0)) { 644 | - dest_desc = open (dst_name, open_flags | O_LOV_DELAY_CREATE, 645 | - wdst_mode & ~omitted_permissions); 646 | - if (dest_desc && !llapi_file_get_stripe(dst_name, lum) && 647 | - lum->lmm_stripe_count != scount) { 648 | - //TODO: this probably shouldn't be printed for every 649 | - // file, especially when physical OST counts differ 650 | - // between file systems 651 | - error(0, 0, _("warning: allocated stripe count of %s does not match original stripe count of %s"), 652 | - quote_n(0, dst_name), quote_n(1, src_name)); 653 | - } 654 | - } else { 655 | - dest_desc = -1; 656 | + if (scount > MUTIL_MAX_STRIPE_COUNT) scount = MUTIL_MAX_STRIPE_COUNT; 657 | + dest_desc = llapi_file_open(dst_name, open_flags, 658 | + wdst_mode & ~omitted_permissions, ssize, -1, scount, 0); 659 | + if (dest_desc > 0 && !llapi_file_get_stripe(dst_name, lum) && 660 | + lum->lmm_stripe_count != scount) { 661 | + //TODO: this probably shouldn't be printed for every 662 | + // file, especially when physical OST counts differ 663 | + // between file systems 664 | + error(0, 0, _("warning: allocated stripe count of %s does not match original stripe count of %s"), 665 | + quote_n(0, dst_name), quote_n(1, src_name)); 666 | } 667 | free(lum); 668 | } else 669 | diff -rupN old1/src/cp.c new/src/cp.c 670 | --- old1/src/cp.c 2015-01-08 11:39:44.000000000 -0800 671 | +++ new/src/cp.c 2019-10-09 14:45:38.688430184 -0700 672 | @@ -106,7 +106,6 @@ GCRY_THREAD_OPTION_PTHREAD_IMPL; 673 | #if HAVE_LIBGNUTLS && defined(_OPENMP) 674 | # include 675 | # include 676 | -# include 677 | # include 678 | # include 679 | # include 680 | @@ -144,7 +143,7 @@ GCRY_THREAD_OPTION_PTHREAD_IMPL; 681 | 682 | /* The official name of this program (e.g., no 'g' prefix). */ 683 | // PZK > 684 | -#define PROGRAM_NAME "mcp 1.822.1" 685 | +#define PROGRAM_NAME "mcp 1.822.6" 686 | 687 | #define AUTHORS \ 688 | proper_name_utf8 ("Torbjorn Granlund", "Torbj\303\266rn Granlund"), \ 689 | @@ -1194,7 +1193,6 @@ do_copy (int n_files, char **file, const 690 | # if HAVE_LIBGNUTLS 691 | if (x->listen_port || x->mgr_port) { 692 | gnutls_global_init(); 693 | - gnutls_global_init_extra(); 694 | } 695 | # endif 696 | 697 | @@ -1212,7 +1210,7 @@ do_copy (int n_files, char **file, const 698 | fprintf(stderr, _(" size rd_mbs wt_mbs cp_mbs %s\n"), 699 | x->print_src ? "src" : "dst"); 700 | fprintf(stderr, _(" ---- ------ ------ ------ ---\n")); 701 | - clock_gettime(CLOCK_REALTIME, &tts[0]); 702 | + clock_gettime(0, &tts[0]); 703 | } 704 | off_t tsize = 0; 705 | int maxcrts = 128; 706 | @@ -1316,7 +1314,7 @@ do_copy (int n_files, char **file, const 707 | } 708 | } 709 | if (x->print_stats) { 710 | - clock_gettime(CLOCK_REALTIME, &tts[1]); 711 | + clock_gettime(0, &tts[1]); 712 | double tt = (double) ( 713 | (double) tts[1].tv_sec + (double) tts[1].tv_nsec / (double) 1.0e9 - 714 | (double) tts[0].tv_sec - (double) tts[0].tv_nsec / (double) 1.0e9); 715 | @@ -1370,7 +1368,8 @@ do_copy (int n_files, char **file, const 716 | gnutls_init(&tls_sess, GNUTLS_CLIENT); 717 | gnutls_priority_set_direct(tls_sess, "NORMAL:+SRP", NULL); 718 | gnutls_credentials_set(tls_sess, GNUTLS_CRD_SRP, srp_cred); 719 | - gnutls_transport_set_ptr(tls_sess, (gnutls_transport_ptr_t) sock); 720 | + gnutls_transport_set_ptr(tls_sess, 721 | + (gnutls_transport_ptr_t)(uintptr_t) sock); 722 | if (gnutls_handshake(tls_sess) < 0) { 723 | error(0, 0, _("unable to authenticate to server")); 724 | //TODO: can this cause deadlocK? 725 | @@ -1502,7 +1501,8 @@ do_copy (int n_files, char **file, const 726 | client_sock = 727 | accept(server_sock, (struct sockaddr *) &client_sa, &client_len); 728 | if (client_sock < 0) continue; 729 | - gnutls_transport_set_ptr(tls_sess, (gnutls_transport_ptr_t) client_sock); 730 | + gnutls_transport_set_ptr(tls_sess, 731 | + (gnutls_transport_ptr_t)(uintptr_t) client_sock); 732 | if (gnutls_handshake(tls_sess) < 0) { 733 | close(client_sock); 734 | gnutls_deinit(tls_sess); 735 | @@ -1874,10 +1874,10 @@ do_copy (int n_files, char **file, const 736 | // indicate that file has been opened 737 | sem_q_push(&open_q, NULL); 738 | struct timespec ts[2]; 739 | - if (x->print_stats) clock_gettime(CLOCK_REALTIME, &ts[0]); 740 | + if (x->print_stats) clock_gettime(0, &ts[0]); 741 | oks[tid] &= copy_reg_task(crt, x); 742 | if (x->print_stats) { 743 | - clock_gettime(CLOCK_REALTIME, &ts[1]); 744 | + clock_gettime(0, &ts[1]); 745 | crt->copy_time = (double) ( 746 | (double) ts[1].tv_sec + (double) ts[1].tv_nsec / (double) 1.0e9 - 747 | (double) ts[0].tv_sec - (double) ts[0].tv_nsec / (double) 1.0e9); 748 | @@ -1997,22 +1997,16 @@ do_copy (int n_files, char **file, const 749 | // PZK > 750 | else if (x->read_stdin) 751 | { 752 | - /* Start with a buffer larger than PATH_MAX, but beware of systems 753 | - on which PATH_MAX is very large -- e.g., INT_MAX. */ 754 | - size_t buf_max = MIN(2 * PATH_MAX, 32 * 1024); 755 | - char *buf = xmalloc(buf_max); 756 | + char *buf = NULL; 757 | + size_t buf_max = 0; 758 | 759 | char *new_dest; 760 | char *source; 761 | char *dest; 762 | bool unused; 763 | 764 | - while (fgets(buf, buf_max, stdin) != NULL) { 765 | + while (getline(&buf, &buf_max, stdin) > 0) { 766 | buf[strcspn(buf, "\n")] = '\0'; 767 | - if (buf[0] == '\0') { 768 | - //TODO: error handling if string too long 769 | - continue; 770 | - } 771 | size_t ifile2 = strcspn(buf, " "); 772 | if (buf[ifile2] == '\0') continue; 773 | buf[ifile2++] = '\0'; 774 | @@ -2123,6 +2117,7 @@ do_copy (int n_files, char **file, const 775 | free(source); 776 | free(dest); 777 | } 778 | + free(buf); 779 | } 780 | // < PZK 781 | else /* !target_directory */ 782 | @@ -2911,9 +2906,8 @@ main (int argc, char **argv) 783 | error(0, 0, _("note: hash leaf size has been adjusted to the split size")); 784 | x.hash_leaf_size = x.split_size; 785 | } 786 | - if (!x.hash_leaf_size) { 787 | - error(0, 0, _("note: hash leaf size has been adjusted to 1GiB")); 788 | - x.hash_leaf_size = 1024 * 1024 * 1024; 789 | + if (x.split_size > 0 && !x.hash_leaf_size) { 790 | + x.hash_leaf_size = x.split_size; 791 | } 792 | x.hash_size = gcry_md_get_algo_dlen(x.hash_type); 793 | #endif 794 | diff -rupN old1/src/md5sum.c new/src/md5sum.c 795 | --- old1/src/md5sum.c 2015-01-08 11:39:58.000000000 -0800 796 | +++ new/src/md5sum.c 2019-10-09 14:45:27.456116389 -0700 797 | @@ -128,7 +128,6 @@ GCRY_THREAD_OPTION_PTHREAD_IMPL; 798 | #if HAVE_LIBGNUTLS && defined(_OPENMP) 799 | # include 800 | # include 801 | -# include 802 | # include 803 | # include 804 | # include 805 | @@ -140,7 +139,7 @@ GCRY_THREAD_OPTION_PTHREAD_IMPL; 806 | /* The official name of this program (e.g., no 'g' prefix). */ 807 | #if HASH_ALGO_MD5 808 | // PZK > 809 | -# define PROGRAM_NAME "msum 1.822.1" 810 | +# define PROGRAM_NAME "msum 1.822.6" 811 | // < PZK 812 | # define DIGEST_TYPE_STRING "MD5" 813 | # define DIGEST_STREAM md5_stream 814 | @@ -492,7 +491,8 @@ sum_task(sum_task_t *stt, struct sum_opt 815 | ssize_t n_read; 816 | if (aiol[0] != NULL) { 817 | // this will be skipped during the first double buffer iteration 818 | - aio_suspend((const struct aiocb * const *) aiol, 1, NULL); 819 | + // wait for previous asynchronous read to complete 820 | + while (aio_suspend((const struct aiocb * const *) aiol, 1, NULL) && errno == EINTR); 821 | n_read = aio_return(aiol[0]); 822 | } else { 823 | off_t to_read = MIN(buf_size, 824 | @@ -510,7 +510,7 @@ sum_task(sum_task_t *stt, struct sum_opt 825 | quote (stt->src_name)); 826 | } 827 | 828 | - if (so->print_stats) clock_gettime(CLOCK_REALTIME, &rts[0]); 829 | + if (so->print_stats) clock_gettime(0, &rts[0]); 830 | n_read = read (src_fd, buf[aio_buf], to_read); 831 | 832 | if (so->read_mode && align_read != 0) { 833 | @@ -524,7 +524,7 @@ sum_task(sum_task_t *stt, struct sum_opt 834 | } 835 | 836 | if (so->print_stats) { 837 | - clock_gettime(CLOCK_REALTIME, &rts[1]); 838 | + clock_gettime(0, &rts[1]); 839 | stt->read_time += (double) ( 840 | (double) rts[1].tv_sec + (double) rts[1].tv_nsec / (double) 1.0e9 - 841 | (double) rts[0].tv_sec - (double) rts[0].tv_nsec / (double) 1.0e9); 842 | @@ -566,18 +566,22 @@ sum_task(sum_task_t *stt, struct sum_opt 843 | quote (stt->src_name)); 844 | } 845 | 846 | - if (so->print_stats) clock_gettime(CLOCK_REALTIME, &rts[0]); 847 | + if (so->print_stats) clock_gettime(0, &rts[0]); 848 | memset(&aio, 0, sizeof(struct aiocb)); 849 | aio.aio_fildes = src_fd; 850 | aio.aio_offset = stt->start_offset + total_n_read; 851 | aio.aio_buf = buf[!aio_buf]; 852 | aio.aio_nbytes = to_read; 853 | aiol[0] = &aio; 854 | - //TODO: error handling for bad aio_read 855 | - aio_read(&aio); 856 | + if (aio_read(&aio) < 0) { 857 | + error (0, errno, _("failed to initiate aio_read: %s"), 858 | + quote (stt->src_name)); 859 | + return_val = false; 860 | + goto task_close_src_and_dst_desc; 861 | + } 862 | } 863 | 864 | - if (so->print_stats) clock_gettime(CLOCK_REALTIME, &hts[0]); 865 | + if (so->print_stats) clock_gettime(0, &hts[0]); 866 | #if HAVE_LIBGCRYPT 867 | //TODO: is st_size right for partial files? 868 | if (stt->nsplits > 1) 869 | @@ -586,7 +590,7 @@ sum_task(sum_task_t *stt, struct sum_opt 870 | gcry_md_write(ctx, buf[aio_buf], n_read); 871 | #endif 872 | if (so->print_stats) { 873 | - clock_gettime(CLOCK_REALTIME, &hts[1]); 874 | + clock_gettime(0, &hts[1]); 875 | stt->hash_time += (double) ( 876 | (double) hts[1].tv_sec + (double) hts[1].tv_nsec / (double) 1.0e9 - 877 | (double) hts[0].tv_sec - (double) hts[0].tv_nsec / (double) 1.0e9); 878 | @@ -1057,7 +1061,7 @@ split_3 (char *s, size_t s_len, 879 | i += digest_hex_bytes; 880 | // PZK > 881 | //TODO: put this in for checktree 882 | - while (!ISWHITE (s[i])) 883 | + while (isxdigit(s[i])) 884 | i++; 885 | // < PZK 886 | if (!ISWHITE (s[i])) 887 | @@ -1303,9 +1307,11 @@ digest_check (struct sum_options *x, con 888 | if (line_length <= 0) 889 | break; 890 | 891 | - /* Ignore comment lines, which begin with a '#' character. */ 892 | +// PZK > 893 | + /* Ignore comment lines, which begin with a '#' character. 894 | if (line[0] == '#') 895 | - continue; 896 | + continue;*/ 897 | +// < PZK 898 | 899 | /* Remove any trailing newline. */ 900 | if (line[line_length - 1] == '\n') 901 | @@ -1830,10 +1836,8 @@ main (int argc, char **argv) 902 | if (x.split_size > 0 && x.split_size < x.hash_leaf_size) { 903 | error(0, 0, _("Note: hash leaf size has been adjusted to the split size")); 904 | x.hash_leaf_size = x.split_size; 905 | - } 906 | - if (!x.hash_leaf_size) { 907 | - error(0, 0, _("Note: hash leaf size has been adjusted to 1GiB")); 908 | - x.hash_leaf_size = 1024 * 1024 * 1024; 909 | + } else if (x.split_size > 0 && !x.hash_leaf_size) { 910 | + x.hash_leaf_size = x.split_size; 911 | } 912 | x.hash_size = gcry_md_get_algo_dlen(x.hash_type); 913 | min_digest_line_length = 2 * x.hash_size + 2 + 1; 914 | @@ -1921,7 +1925,6 @@ main (int argc, char **argv) 915 | # if HAVE_LIBGNUTLS 916 | if (x.listen_port || x.mgr_port) { 917 | gnutls_global_init(); 918 | - gnutls_global_init_extra(); 919 | } 920 | #endif 921 | 922 | @@ -1938,7 +1941,7 @@ main (int argc, char **argv) 923 | if (x.print_stats) { 924 | fprintf(stderr, _(" size rd_mbs hs_mbs sm_mbs file\n")); 925 | fprintf(stderr, _(" ---- ------ ------ ------ ----\n")); 926 | - clock_gettime(CLOCK_REALTIME, &tts[0]); 927 | + clock_gettime(0, &tts[0]); 928 | } 929 | off_t tsize = 0; 930 | int maxstts = 128; 931 | @@ -2047,7 +2050,7 @@ main (int argc, char **argv) 932 | } 933 | } 934 | if (x.print_stats) { 935 | - clock_gettime(CLOCK_REALTIME, &tts[1]); 936 | + clock_gettime(0, &tts[1]); 937 | double tt = (double) ( 938 | (double) tts[1].tv_sec + (double) tts[1].tv_nsec / (double) 1.0e9 - 939 | (double) tts[0].tv_sec - (double) tts[0].tv_nsec / (double) 1.0e9); 940 | @@ -2101,7 +2104,8 @@ main (int argc, char **argv) 941 | gnutls_init(&tls_sess, GNUTLS_CLIENT); 942 | gnutls_priority_set_direct(tls_sess, "NORMAL:+SRP", NULL); 943 | gnutls_credentials_set(tls_sess, GNUTLS_CRD_SRP, srp_cred); 944 | - gnutls_transport_set_ptr(tls_sess, (gnutls_transport_ptr_t) sock); 945 | + gnutls_transport_set_ptr(tls_sess, 946 | + (gnutls_transport_ptr_t)(uintptr_t) sock); 947 | if (gnutls_handshake(tls_sess) < 0) { 948 | error(0, 0, _("unable to authenticate to server")); 949 | //TODO: can this cause deadlocK? 950 | @@ -2233,7 +2237,8 @@ main (int argc, char **argv) 951 | client_sock = 952 | accept(server_sock, (struct sockaddr *) &client_sa, &client_len); 953 | if (client_sock < 0) continue; 954 | - gnutls_transport_set_ptr(tls_sess, (gnutls_transport_ptr_t) client_sock); 955 | + gnutls_transport_set_ptr(tls_sess, 956 | + (gnutls_transport_ptr_t)(uintptr_t) client_sock); 957 | if (gnutls_handshake(tls_sess) < 0) { 958 | error(0, 0, _("warning: failed authentication attempt from %s:%d"), 959 | inet_ntoa(client_sa.sin_addr), ntohs(client_sa.sin_port)); 960 | @@ -2555,10 +2560,10 @@ main (int argc, char **argv) 961 | sum_task_t *stt; 962 | while ((stt = sem_q_pop(&task_q)) != NULL) { 963 | struct timespec ts[2]; 964 | - if (x.print_stats) clock_gettime(CLOCK_REALTIME, &ts[0]); 965 | + if (x.print_stats) clock_gettime(0, &ts[0]); 966 | oks[tid] &= sum_task(stt, &x); 967 | if (x.print_stats) { 968 | - clock_gettime(CLOCK_REALTIME, &ts[1]); 969 | + clock_gettime(0, &ts[1]); 970 | stt->sum_time = (double) ( 971 | (double) ts[1].tv_sec + (double) ts[1].tv_nsec / (double) 1.0e9 - 972 | (double) ts[0].tv_sec - (double) ts[0].tv_nsec / (double) 1.0e9); 973 | @@ -2576,15 +2581,11 @@ main (int argc, char **argv) 974 | char *file = argv[optind]; 975 | // PZK > 976 | if (x.read_stdin) { 977 | - size_t buf_max = MIN(PATH_MAX, 32 * 1024); 978 | - char *buf = xmalloc(buf_max); 979 | + char *buf = NULL; 980 | + size_t buf_max = 0; 981 | 982 | - while (fgets(buf, buf_max, stdin) != NULL) { 983 | + while (getline(&buf, &buf_max, stdin) > 0) { 984 | buf[strcspn(buf, "\n")] = '\0'; 985 | - if (file[0] == '\0') { 986 | - //TODO: error handling if string too long 987 | - continue; 988 | - } 989 | size_t irange = strcspn(buf, " "); 990 | if (buf[irange] == '\0') irange = 0; 991 | else buf[irange++] = '\0'; 992 | @@ -2611,6 +2612,7 @@ main (int argc, char **argv) 993 | ok = false; 994 | } 995 | } 996 | + free(buf); 997 | break; 998 | } 999 | // < PZK 1000 | diff -rupN old1/src/mutil-q.h new/src/mutil-q.h 1001 | --- old1/src/mutil-q.h 2015-01-08 12:14:38.000000000 -0800 1002 | +++ new/src/mutil-q.h 2018-01-18 14:44:17.931923912 -0800 1003 | @@ -81,16 +81,16 @@ 1004 | #ifndef MUTIL_Q_H 1005 | # define MUTIL_Q_H 1006 | 1007 | -# include 1008 | +# include 1009 | +# include 1010 | +# include 1011 | 1012 | ///////////////////////// 1013 | //// Semaphore Queue //// 1014 | ///////////////////////// 1015 | 1016 | typedef struct { 1017 | - sem_t max_sem; 1018 | - sem_t min_sem; 1019 | - sem_t q_lock; 1020 | + int sem_id; 1021 | int size; 1022 | size_t ptr_size; 1023 | int i_read; 1024 | diff -rupN old1/src/mutil.c new/src/mutil.c 1025 | --- old1/src/mutil.c 2014-05-13 13:56:49.000000000 -0700 1026 | +++ new/src/mutil.c 2018-01-18 14:44:17.931923912 -0800 1027 | @@ -79,7 +79,17 @@ 1028 | */ 1029 | 1030 | #include "mutil.h" 1031 | -#include 1032 | + 1033 | +#ifndef CLOCK_REALTIME 1034 | +int clock_gettime(int clk_id, struct timespec* t) { 1035 | + struct timeval now; 1036 | + int rv = gettimeofday(&now, NULL); 1037 | + if (rv) return rv; 1038 | + t->tv_sec = now.tv_sec; 1039 | + t->tv_nsec = now.tv_usec * 1000; 1040 | + return 0; 1041 | +} 1042 | +#endif 1043 | 1044 | /////////////////// 1045 | //// Hash Tree //// 1046 | @@ -197,9 +207,17 @@ void hash_leaf(hash_tree_t *htt, copy_re 1047 | ///////////////////////// 1048 | 1049 | void sem_q_init(sem_q_t *q, int size, size_t ptr_size) { 1050 | - sem_init(&q->max_sem, 0, size); 1051 | - sem_init(&q->min_sem, 0, 0); 1052 | - sem_init(&q->q_lock, 0, 1); 1053 | + q->sem_id = semget(0, 3, IPC_PRIVATE | IPC_CREAT | 0600); 1054 | + 1055 | + // max_sem 1056 | + semctl(q->sem_id, 0, SETVAL, size); 1057 | + 1058 | + // min_sem 1059 | + semctl(q->sem_id, 1, SETVAL, 0); 1060 | + 1061 | + // q_lock 1062 | + semctl(q->sem_id, 2, SETVAL, 1); 1063 | + 1064 | q->i_read = 0; 1065 | q->i_write = 0; 1066 | q->size = size; 1067 | @@ -209,27 +227,58 @@ void sem_q_init(sem_q_t *q, int size, si 1068 | 1069 | void sem_q_destroy(sem_q_t *q) { 1070 | free(q->vals); 1071 | - sem_destroy(&q->q_lock); 1072 | - sem_destroy(&q->min_sem); 1073 | - sem_destroy(&q->max_sem); 1074 | + semctl(q->sem_id, 0, IPC_RMID); 1075 | } 1076 | 1077 | void sem_q_push(sem_q_t *q, void *val) { 1078 | - sem_wait(&q->max_sem); 1079 | - sem_wait(&q->q_lock); 1080 | + struct sembuf sb; 1081 | + sb.sem_flg = 0; 1082 | + 1083 | + // wait max_sem 1084 | + sb.sem_num = 0; 1085 | + sb.sem_op = -1; 1086 | + semop(q->sem_id, &sb, 1); 1087 | + 1088 | + // wait q_lock 1089 | + sb.sem_num = 2; 1090 | + semop(q->sem_id, &sb, 1); 1091 | + 1092 | q->vals[q->i_write] = val; 1093 | q->i_write = (q->i_write + 1) % q->size; 1094 | - sem_post(&q->q_lock); 1095 | - sem_post(&q->min_sem); 1096 | + 1097 | + // post q_lock 1098 | + sb.sem_op = 1; 1099 | + semop(q->sem_id, &sb, 1); 1100 | + 1101 | + // post min_sem 1102 | + sb.sem_num = 1; 1103 | + semop(q->sem_id, &sb, 1); 1104 | } 1105 | 1106 | void *sem_q_pop(sem_q_t *q) { 1107 | - sem_wait(&q->min_sem); 1108 | - sem_wait(&q->q_lock); 1109 | + struct sembuf sb; 1110 | + sb.sem_flg = 0; 1111 | + 1112 | + // wait min_sem 1113 | + sb.sem_num = 1; 1114 | + sb.sem_op = -1; 1115 | + semop(q->sem_id, &sb, 1); 1116 | + 1117 | + // wait q_lock 1118 | + sb.sem_num = 2; 1119 | + semop(q->sem_id, &sb, 1); 1120 | + 1121 | void *val = q->vals[q->i_read]; 1122 | q->i_read = (q->i_read + 1) % q->size; 1123 | - sem_post(&q->q_lock); 1124 | - sem_post(&q->max_sem); 1125 | + 1126 | + // post q_lock 1127 | + sb.sem_op = 1; 1128 | + semop(q->sem_id, &sb, 1); 1129 | + 1130 | + // post max_sem 1131 | + sb.sem_num = 0; 1132 | + semop(q->sem_id, &sb, 1); 1133 | + 1134 | return val; 1135 | } 1136 | 1137 | @@ -254,7 +303,6 @@ int sem_q_size(sem_q_t *q) { 1138 | # include 1139 | # include 1140 | # include 1141 | -# include 1142 | # include 1143 | 1144 | static int generate_create_conf(char *tpasswd_conf) { 1145 | diff -rupN old1/src/mutil.h new/src/mutil.h 1146 | --- old1/src/mutil.h 2014-05-13 13:56:49.000000000 -0700 1147 | +++ new/src/mutil.h 2018-01-18 14:44:17.927923805 -0800 1148 | @@ -90,6 +90,11 @@ 1149 | # include "copy.h" 1150 | # include "mutil-q.h" 1151 | 1152 | +#ifndef CLOCK_REALTIME 1153 | +# include 1154 | +int clock_gettime(int clk_id, struct timespec* t); 1155 | +#endif 1156 | + 1157 | /////////////////// 1158 | //// Hash Tree //// 1159 | /////////////////// 1160 | --------------------------------------------------------------------------------