From 282c28f56396cf07f98cb1dac09cd7bc7831de3a Mon Sep 17 00:00:00 2001 From: phil Date: Thu, 14 Aug 2003 05:01:54 +0000 Subject: [PATCH] merge three weeks of b_devel fixes into b_filterio --- lustre/tests/iosanity.sh | 149 +++++++++++++++++++ lustre/tests/multiop.c | 76 +++++++--- lustre/tests/replay-dual.sh | 210 ++++++++++++++++++++++++--- lustre/tests/sleeptest.c | 115 +++++++++++++++ lustre/tests/write_append_truncate.c | 271 +++++++++++++++++++++++++++++++++++ 5 files changed, 775 insertions(+), 46 deletions(-) create mode 100644 lustre/tests/iosanity.sh create mode 100644 lustre/tests/sleeptest.c create mode 100644 lustre/tests/write_append_truncate.c diff --git a/lustre/tests/iosanity.sh b/lustre/tests/iosanity.sh new file mode 100644 index 0000000..8fc483e --- /dev/null +++ b/lustre/tests/iosanity.sh @@ -0,0 +1,149 @@ +#!/bin/bash +# +# Run select tests by setting ONLY, or as arguments to the script. +# Skip specific tests by setting EXCEPT. +# +# e.g. ONLY="22 23" or ONLY="`seq 32 39`" or EXCEPT="31" +set -e + +ONLY=${ONLY:-"$*"} +# bug number for skipped test: +ALWAYS_EXCEPT=${ALWAYS_EXCEPT:-""} + +SRCDIR=`dirname $0` +PATH=$PWD/$SRCDIR:$SRCDIR:$SRCDIR/../utils:$PATH + +CHECKSTAT=${CHECKSTAT:-"checkstat -v"} +CREATETEST=${CREATETEST:-createtest} +LFIND=${LFIND:-lfind} +LSTRIPE=${LSTRIPE:-lstripe} +LCTL=${LCTL:-lctl} +MCREATE=${MCREATE:-mcreate} +OPENFILE=${OPENFILE:-openfile} +OPENUNLINK=${OPENUNLINK:-openunlink} +TOEXCL=${TOEXCL:-toexcl} +TRUNCATE=${TRUNCATE:-truncate} +MUNLINK=${MUNLINK:-munlink} + +export NAME=${NAME:-local} + +SAVE_PWD=$PWD + +clean() { + echo -n "cln.." + sh llmountcleanup.sh > /dev/null || exit 20 +} +CLEAN=${CLEAN:-clean} + +start() { + echo -n "mnt.." + sh llrmount.sh > /dev/null || exit 10 + echo "done" +} +START=${START:-start} + +log() { + echo "$*" + lctl mark "$*" 2> /dev/null || true +} + +run_one() { + if ! mount | grep -q $DIR; then + $START + fi + log "== test $1: $2" + test_$1 || error "test_$1: $?" + pass + cd $SAVE_PWD + $CLEAN +} + +build_test_filter() { + for O in $ONLY; do + eval ONLY_${O}=true + done + for E in $EXCEPT $ALWAYS_EXCEPT; do + eval EXCEPT_${E}=true + done +} + +_basetest() { + echo $* +} + +basetest() { + IFS=abcdefghijklmnopqrstuvwxyz _basetest $1 +} + +run_test() { + base=`basetest $1` + if [ "$ONLY" ]; then + testname=ONLY_$1 + if [ ${!testname}x != x ]; then + run_one $1 "$2" + return $? + fi + testname=ONLY_$base + if [ ${!testname}x != x ]; then + run_one $1 "$2" + return $? + fi + echo -n "." + return 0 + fi + testname=EXCEPT_$1 + if [ ${!testname}x != x ]; then + echo "skipping excluded test $1" + return 0 + fi + testname=EXCEPT_$base + if [ ${!testname}x != x ]; then + echo "skipping excluded test $1 (base $base)" + return 0 + fi + run_one $1 "$2" + return $? +} + +error() { + log "FAIL: $@" + exit 1 +} + +pass() { + echo PASS +} + +MOUNT="`mount | awk '/^'$NAME' .* lustre_lite / { print $3 }'`" +if [ -z "$MOUNT" ]; then + sh llmount.sh + MOUNT="`mount | awk '/^'$NAME' .* lustre_lite / { print $3 }'`" + [ -z "$MOUNT" ] && error "NAME=$NAME not mounted" + I_MOUNTED=yes +fi + +[ `echo $MOUNT | wc -w` -gt 1 ] && error "NAME=$NAME mounted more than once" + +DIR=${DIR:-$MOUNT} +[ -z "`echo $DIR | grep $MOUNT`" ] && echo "$DIR not in $MOUNT" && exit 99 + +[ `ls -d /proc/fs/lustre/osc/OSC* 2> /dev/null | wc -l` -gt 1 ] && LOV=yes + +rm -rf $DIR/[df][1-9]* + +build_test_filter + +test_1() { + [ "$LOV" != "yes" ] && echo "skipping LOV-only test" && return + dd if=/dev/zero of=$DIR/f1 bs=4k count=1 seek=127 + dd if=$DIR/f1 bs=4k count=1 +} +run_test 0 "zero length read from a sparse stripe ==============" + +log "cleanup: ======================================================" +rm -rf $DIR/[df][1-9]* +if [ "$I_MOUNTED" = "yes" -a "`mount | grep ^$NAME`" ]; then + sh llmountcleanup.sh || error +fi + +echo '=========================== finished ===============================' diff --git a/lustre/tests/multiop.c b/lustre/tests/multiop.c index 1e69f0e..d8fec95 100755 --- a/lustre/tests/multiop.c +++ b/lustre/tests/multiop.c @@ -21,8 +21,12 @@ char usage[] = " m mknod\n" " c close\n" " _ wait for signal\n" +" r read\n" " s stat\n" -" S fstat\n"; +" S fstat\n" +" t fchmod\n" +" w write\n" +" z seek to zero\n"; void null_handler(int unused) { } @@ -30,7 +34,7 @@ int main(int argc, char **argv) { char *fname, *commands; struct stat st; - int fd; + int fd = -1; if (argc != 3) { fprintf(stderr, usage, argv[0]); @@ -43,19 +47,15 @@ int main(int argc, char **argv) for (commands = argv[2]; *commands; commands++) { switch (*commands) { - case 'o': - fd = open(fname, O_RDONLY); - if (fd == -1) { - perror("open(O_RDONLY)"); - exit(1); - } + case '_': + pause(); break; - case 'O': - fd = open(fname, O_CREAT|O_RDWR, 0644); - if (fd == -1) { - perror("open(O_RDWR|O_CREAT"); + case 'c': + if (close(fd) == -1) { + perror("close"); exit(1); } + fd = -1; break; case 'm': if (mknod(fname, S_IFREG | 0644, 0) == -1) { @@ -63,20 +63,32 @@ int main(int argc, char **argv) exit(1); } break; - case 'u': - if (unlink(fname) == -1) { - perror("unlink"); + case 'O': + fd = open(fname, O_CREAT|O_RDWR, 0644); + if (fd == -1) { + perror("open(O_RDWR|O_CREAT"); exit(1); } break; - case 'c': - if (close(fd) == -1) { - perror("close"); + case 'o': + fd = open(fname, O_RDONLY); + if (fd == -1) { + perror("open(O_RDONLY)"); exit(1); } break; - case '_': - pause(); + case 'r': { + char buf; + if (read(fd, &buf, 1) == -1) { + perror("read"); + exit(1); + } + } + case 'S': + if (fstat(fd, &st) == -1) { + perror("fstat"); + exit(1); + } break; case 's': if (stat(fname, &st) == -1) { @@ -84,12 +96,30 @@ int main(int argc, char **argv) exit(1); } break; - case 'S': - if (fstat(fd, &st) == -1) { - perror("fstat"); + case 't': + if (fchmod(fd, 0) == -1) { + perror("fchmod"); + exit(1); + } + break; + case 'u': + if (unlink(fname) == -1) { + perror("unlink"); exit(1); } break; + case 'w': + if (write(fd, "w", 1) == -1) { + perror("write"); + exit(1); + } + break; + case 'z': + if (lseek(fd, 0, SEEK_SET) == -1) { + perror("lseek"); + exit(1); + } + break; default: fprintf(stderr, "unknown command \"%c\"\n", *commands); fprintf(stderr, usage, argv[0]); diff --git a/lustre/tests/replay-dual.sh b/lustre/tests/replay-dual.sh index d6d4c5c..e0742f3 100755 --- a/lustre/tests/replay-dual.sh +++ b/lustre/tests/replay-dual.sh @@ -33,7 +33,7 @@ start() { stop() { facet=$1 shift - lconf --node ${facet}_facet $@ -d replay-dual.xml + lconf --node ${facet}_facet $@ --cleanup replay-dual.xml } replay_barrier() { @@ -41,11 +41,15 @@ replay_barrier() { sync lctl --device %${dev}1 readonly lctl --device %${dev}1 notransno + lctl mark "REPLAY BARRIER" } fail() { - stop mds - start mds + local facet=$1 + lctl mark "FAIL $facet" + stop $facet --force --failover --nomod + start $facet --nomod + lctl mark "RECOVER $facet" df $MOUNT1 | tail -1 df $MOUNT2 | tail -1 } @@ -70,35 +74,195 @@ gen_config() { do_lmc --add mds --node mds_facet --mds mds1 --dev $MDSDEV --size $MDSSIZE do_lmc --add ost --node ost_facet --ost ost1 --dev $OSTDEV --size $OSTSIZE do_lmc --add mtpt --node client1_facet --path $MOUNT1 --mds mds1 --ost ost1 - do_lmc --add mtpt --node client1_facet --path $MOUNT2 --mds mds1 --ost ost1 + do_lmc --add mtpt --node client2_facet --path $MOUNT2 --mds mds1 --ost ost1 +} +error() { + echo '**** FAIL:' $@ + exit 1 +} + +build_test_filter() { + for O in $ONLY; do + eval ONLY_${O}=true + done + for E in $EXCEPT $ALWAYS_EXCEPT; do + eval EXCEPT_${E}=true + done +} + +_basetest() { + echo $* } +basetest() { + IFS=abcdefghijklmnopqrstuvwxyz _basetest $1 +} + +run_test() { + base=`basetest $1` + if [ ! -z "$ONLY" ]; then + testname=ONLY_$1 + if [ ${!testname}x != x ]; then + run_one $1 "$2" + return $? + fi + testname=ONLY_$base + if [ ${!testname}x != x ]; then + run_one $1 "$2" + return $? + fi + echo -n "." + return 0 + fi + testname=EXCEPT_$1 + if [ ${!testname}x != x ]; then + echo "skipping excluded test $1" + return 0 + fi + testname=EXCEPT_$base + if [ ${!testname}x != x ]; then + echo "skipping excluded test $1 (base $base)" + return 0 + fi + run_one $1 "$2" + + return $? +} + +EQUALS="======================================================================" +equals_msg() { + msg="$@" + + local suffixlen=$((65 - ${#msg})) + printf '===== %s %.*s\n' "$msg" $suffixlen $EQUALS +} + +run_one() { + testnum=$1 + message=$2 + + # Pretty tests run faster. + equals_msg $testnum: $message + + test_${testnum} || error "test_$testnum failed with $?" +} + +build_test_filter + gen_config -start mds -start ost +start mds --reformat +start ost --reformat start client1 start client2 -touch $MOUNT1/lustre-works -replay_barrier mds -touch $MOUNT2/lustre-does-not-work +test_1() { + touch $MOUNT1/a + replay_barrier mds + touch $MOUNT2/b -stop client2 -stop client1 -stop ost -stop mds + fail mds + checkstat $MOUNT2/a || return 1 + checkstat $MOUNT1/b || return 2 + rm $MOUNT2/a $MOUNT1/b + checkstat $MOUNT1/a && return 3 + checkstat $MOUNT2/b && return 4 + return 0 +} -start mds -start ost -start client1 -start client2 +run_test 1 "|X| simple create" + + +test_2() { + replay_barrier mds + mkdir $MOUNT1/adir + + fail mds + checkstat $MOUNT2/adir || return 1 + rmdir $MOUNT2/adir + checkstat $MOUNT2/adir && return 2 + return 0 +} + +run_test 2 "|X| mkdir adir" + +test_3() { + replay_barrier mds + mkdir $MOUNT1/adir + mkdir $MOUNT2/adir/bdir + + fail mds + checkstat $MOUNT2/adir || return 1 + checkstat $MOUNT1/adir/bdir || return 2 + rmdir $MOUNT2/adir/bdir $MOUNT1/adir + checkstat $MOUNT1/adir && return 3 + checkstat $MOUNT2/adir/bdir && return 4 + return 0 +} + +run_test 3 "|X| mkdir adir, mkdir adir/bdir " + +test_4() { + mkdir $MOUNT1/adir + replay_barrier mds + mkdir $MOUNT1/adir && return 1 + mkdir $MOUNT2/adir/bdir + + fail mds + checkstat $MOUNT2/adir || return 2 + checkstat $MOUNT1/adir/bdir || return 3 + + rmdir $MOUNT2/adir/bdir $MOUNT1/adir + checkstat $MOUNT1/adir && return 4 + checkstat $MOUNT2/adir/bdir && return 5 + return 0 +} + +run_test 4 "|X| mkdir adir (-EEXIST), mkdir adir/bdir " + + +test_5() { + # multiclient version of replay_single.sh/test_8 + mcreate $MOUNT1/a + multiop $MOUNT2/a o_tSc & + pid=$! + # give multiop a chance to open + sleep 1 + rm -f $MOUNT1/a + replay_barrier mds + kill -USR1 $pid + wait $pid || return 1 + + fail mds + [ -e $MOUNT2/a ] && return 2 + return 0 +} +run_test 5 "open, unlink |X| close" + + +test_6() { + mcreate $MOUNT1/a + multiop $MOUNT2/a o_c & + pid1=$! + multiop $MOUNT1/a o_c & + pid2=$! + # give multiop a chance to open + sleep 1 + rm -f $MOUNT1/a + replay_barrier mds + kill -USR1 $pid1 + wait $pid1 || return 1 + + fail mds + kill -USR1 $pid2 + wait $pid2 || return 1 + [ -e $MOUNT2/a ] && return 2 + return 0 +} +run_test 6 "open1, open2, unlink |X| close1 [fail mds] close2" -if [ -e $MOUNT1/lustre-does-not-work ]; then - echo "$MOUNT1/lustre-does-not-work exists" - exit 1 -fi -stop client2 +equals_msg test complete, cleaning up +stop client2 --nomod stop client1 stop ost -stop mds +stop mds --dump cleanup-dual.log diff --git a/lustre/tests/sleeptest.c b/lustre/tests/sleeptest.c new file mode 100644 index 0000000..d8beceb --- /dev/null +++ b/lustre/tests/sleeptest.c @@ -0,0 +1,115 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#define BUFSIZE (4096) + +#define min(a,b) ((a) < (b) ? (a) : (b)) + +int main(int argc, char *argv[]) +{ + + FILE *w_str; + int read_fd; + int rc, iter; + int line, delta, next; + int sleeptime = 0; + char *now_time; + const char ok_chars[] = "MonTueWedThuFriSatSun" + "JanFebMarAprMayJunJulAugSepOctNovDec" + "Line 0123456789 of file, written at:\n"; + + char buf_r[BUFSIZE]; + + char pathname[256] = "/mnt/lustre/linetest_"; + char *host; + + if (argc > 1) { + strncpy(pathname, argv[1], 255); + pathname[255] = '\0'; + } + + host = getenv("HOSTNAME"); + if (host) + strcat(pathname, host); + + if (argc > 2) + sleeptime = strtoul(argv[2], NULL, 0); + + if (sleeptime == 0) + sleeptime = 30; + + printf("Test file used is: %s at %ds intervals\n", pathname, sleeptime); + + w_str = fopen(pathname, "wb"); + if (w_str == NULL) { + perror("fopen"); + exit(1); + } + read_fd = open(pathname, O_RDONLY); + if (read_fd < 0) { + perror("open"); + exit(1); + } + + next = 1; + delta = 17; + iter = 1; + while (1) { + time_t now; + struct tm *t; + long offset; + + now = time((time_t *)NULL); + t = localtime(&now); + now_time = asctime(t); + + printf("iter: %d\n", iter); + + for (line=next; line<(next+delta); line++) { + rc = fprintf(w_str, "Line %8d of file, written at: %s", + line, now_time); + /* \n comes from ctime() result */ + if (rc <= 0) { + perror("fprintf"); + exit(4); + } + rc = fflush(w_str); + if (rc != 0) { + perror("fflush"); + exit(5); + } + } + next += delta; + + /* Check for corruption */ + offset = ftell(w_str); + rc = lseek(read_fd, offset & ~4095, SEEK_SET); + if (rc != (offset & ~4095)) { + perror("lseek"); + exit(7); + } + + rc = read(read_fd, buf_r, min(100, offset & 4095)); + if (rc != min(100, offset & 4095)) { + printf("rc: %d, off %lu buf: '%s'\n", rc,offset,buf_r); + exit(8); + } + buf_r[rc] = 0; + /* Chars from "C" days/months, and above Line */ + if (strspn(buf_r, ok_chars) != rc) { + printf("Corruption detected at %lu on %s", + offset & ~4095, now_time); + exit(9); + } + + sleep(sleeptime); + iter++; + } + +} diff --git a/lustre/tests/write_append_truncate.c b/lustre/tests/write_append_truncate.c new file mode 100644 index 0000000..b0557bb --- /dev/null +++ b/lustre/tests/write_append_truncate.c @@ -0,0 +1,271 @@ +/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- + * vim:expandtab:shiftwidth=8:tabstop=8: + * + * Each loop does 3 things: + * - truncate file to zero (not via ftruncate though, to test O_APPEND) + * - append a "chunk" of data (should be at file offset 0 after truncate) + * - on each of two threads either append or truncate-up the file + * + * If the truncate happened first, we should have a hole in the file. + * If the append happened first, we should have truncated the file down. + * + * We pick the CHUNK_SIZE_MAX and APPEND_SIZE_MAX so that we cross a stripe. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "mpi.h" + + +#define CHUNK_SIZE_MAX 123456 +#define CHUNK_CHAR 'C' + +#define APPEND_SIZE_MAX 123456 +#define APPEND_CHAR 'A' + +#define TRUNC_SIZE_MAX (CHUNK_SIZE_MAX+APPEND_SIZE_MAX) + +#define HOSTNAME_SIZE 50 + +void usage(char *prog) +{ + printf("usage: %s [nloops]\n", prog); + printf("%s must be run on 2 nodes\n", prog); + + exit(1); +} + +/* Print process rank, loop count, message, and exit (i.e. a fatal error) */ +int rprintf(int rank, int loop, const char *fmt, ...) +{ + va_list ap; + + printf("rank %d, loop %d: ", rank, loop); + + va_start(ap, fmt); + + printf(fmt, ap); + + exit(1); +} + +int main(int argc, char *argv[]) +{ + int n, nloops = 0, fd; + int rank, ret; + int chunk_size, append_size, trunc_offset; + char append_buf[APPEND_SIZE_MAX]; + char chunk_buf[CHUNK_SIZE_MAX]; + char read_buf[TRUNC_SIZE_MAX+APPEND_SIZE_MAX]; + char trunc_buf[TRUNC_SIZE_MAX]; + int done; + int error; + char hostname[HOSTNAME_SIZE]; + char *fname, *prog; + + error = MPI_Init(&argc, &argv); + if (error != MPI_SUCCESS) + rprintf(-1, -1, "MPI_Init failed: %d\n", error); + + prog = strrchr(argv[0], '/'); + if (prog == NULL) + prog = argv[0]; + else + prog++; + + if (argc < 2 || argc > 3) + usage(prog); + + error = MPI_Comm_rank(MPI_COMM_WORLD, &rank); + if (error != MPI_SUCCESS) + rprintf(-1, -1, "MPI_Comm_rank failed: %d\n", error); + + error = MPI_Comm_size(MPI_COMM_WORLD, &n); + if (error != MPI_SUCCESS) + rprintf(rank, -1, "MPI_Comm_size failed: %d\n", error); + + if (n != 2) + rprintf(rank, -1, "%s: must run with 2 processes, not %d\n", + prog, n); + + memset(append_buf, APPEND_CHAR, APPEND_SIZE_MAX); + memset(chunk_buf, CHUNK_CHAR, CHUNK_SIZE_MAX); + memset(trunc_buf, 0, TRUNC_SIZE_MAX); + + if (gethostname(hostname, HOSTNAME_SIZE) < 0) + rprintf(rank, -1, "gethostname failed: %s\n", strerror(errno)); + + fname = argv[1]; + + if (argc == 3) + nloops = strtoul(argv[2], NULL, 0); + if (nloops == 0) + nloops = 100000; + + if (rank == 0) { + fd = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666); + if (fd <= 0) + rprintf(0, -1, "create %s failed: %s\n", fname, + strerror(errno)); + printf("using %s\n", fname); + } + error = MPI_Barrier(MPI_COMM_WORLD); + if (error != MPI_SUCCESS) + rprintf(rank, -1, "prep MPI_Barrier failed: %d\n", error); + + fd = open(fname, O_RDWR | O_APPEND); + if (fd <= 0) + rprintf(rank, -1, "open %s failed: %s\n",fname,strerror(errno)); + + for (n = 0; n < nloops; n++) { + /* reset the environment */ + chunk_size = (rand()%(CHUNK_SIZE_MAX-1))+1; + append_size = (rand()%(APPEND_SIZE_MAX-1))+1; + trunc_offset = chunk_size + rand()%append_size; + if (rank == 0) { + if (n % 1000 == 0) + printf("loop %5d: chunk %6d/%#06x, " + "append %6d/%#06x, trunc @ %6d/%#06x\n", + n, chunk_size, chunk_size, append_size, + append_size, trunc_offset, trunc_offset); + + ret = truncate(fname, (off_t)0); + if (ret < 0) + rprintf(0, n, "truncate @ 0: %s\n", + strerror(errno)); + done = 0; + do { + ret = write(fd, chunk_buf+done,chunk_size-done); + if (ret <= 0) { + rprintf(0, n, "chunk @ %d: %s\n", + done, strerror(errno)); + break; + } + done += ret; + } while (done != chunk_size); + } + + error = MPI_Barrier(MPI_COMM_WORLD); + if (error != MPI_SUCCESS) + rprintf(rank, n, "start MPI_Barrier: %d\n",error); + + /* Do the race */ + if (rank == n % 2) { + // + done = 0; + do { + ret = write(fd, append_buf + done, + append_size - done); + if (ret < 0) { + rprintf(rank, n, + "loop %d: append @ %u: %s\n", + done, strerror(errno)); + break; + } + done += ret; + } while (done != append_size); + } else if (rank == 1 - n % 2) { + ret = truncate(fname, (off_t)trunc_offset); + if (ret != 0) + rprintf(rank, n, "truncate @ %u: %s\n", + trunc_offset, strerror(errno) ); + } + + error = MPI_Barrier(MPI_COMM_WORLD); + if (error != MPI_SUCCESS) + rprintf(rank, n, "end MPI_Barrier: %d\n", error); + + error = 0; + + /* Check the result */ + if (rank == 0) { + struct stat st; + if (stat(fname, &st) < 0) + rprintf(0, n, "loop %d: stat %s: %s\n", + fname, strerror(errno)); + + if (lseek(fd, (off_t)0, SEEK_SET) != 0) + rprintf(0, n, "lseek fname 0: %s\n", fname, + strerror(errno)); + + done = 0; + do { + ret = read(fd, read_buf+done, st.st_size-done); + if (ret < 0) { + rprintf(0, n, "read @ %u: %s\n", + done, strerror(errno)); + } + done += ret; + } while (done != st.st_size); + + if (memcmp(read_buf, chunk_buf, chunk_size)) { + printf("loop %d: base chunk bad" + " [0-%d]/[0-%#x] != %c\n", n, + chunk_size - 1, chunk_size - 1, + CHUNK_CHAR); + error = 1; + } + + if (st.st_size == trunc_offset) { + /* Check case 1: first append then truncate */ + error = memcmp(read_buf+chunk_size, append_buf, + trunc_offset - chunk_size); + if (error) { + printf("loop %d: trunc-after-append bad" + " [%d-%d]/[%#x-%#x] != %c\n", + n, chunk_size, trunc_offset - 1, + chunk_size, trunc_offset - 1, + APPEND_CHAR); + } + } else { + /* Check case 2: first truncate then append */ + if (memcmp(read_buf+chunk_size, trunc_buf, + trunc_offset-chunk_size)) { + printf("loop %d: append-after-TRUNC" + " bad [%d-%d]/[%#x-%#x] != 0\n", + n, chunk_size, trunc_offset - 1, + chunk_size, trunc_offset - 1); + error = 1; + } else if (memcmp(read_buf+trunc_offset, + append_buf, append_size)) { + printf("loop %d: APPEND-after-trunc" + " bad [%d-%d]/[%#x-%#x] != %c\n", + n, trunc_offset, append_size - 1, + trunc_offset, append_size - 1, + APPEND_CHAR); + error = 1; + } + } + } + ret = MPI_Bcast(&error, 1, MPI_INT, 0, MPI_COMM_WORLD); + if (ret != MPI_SUCCESS) + rprintf(rank, n, "MPI_Bcast: %d\n"); + + if (error == 1) { + if (rank == 0) { + char command[4096]; + + printf("loop %5d: chunk %6d/%#06x, " + "append %6d/%#06x, trunc @ %6d/%#06x\n", + n, chunk_size, chunk_size, append_size, + append_size, trunc_offset, trunc_offset); + + sprintf(command, "od -Ax -a %s", fname); + system(command); + } + rprintf(rank, n, "on machine %s with pid %d\n", + hostname, (int)getpid()); + } + } + + printf("Finished after %d loops\n", n); + + MPI_Finalize(); + return 0; +} -- 1.8.3.1