* [PATCH 02/11] Make runtests.sh a wrapper for fileio tests
[not found] ` <20100129202842.GA25490-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
@ 2010-01-29 20:37 ` Sukadev Bhattiprolu
2010-01-29 20:38 ` [PATCH 03/11] Check for failure while waiting for checkpoint-ready Sukadev Bhattiprolu
` (8 subsequent siblings)
9 siblings, 0 replies; 12+ messages in thread
From: Sukadev Bhattiprolu @ 2010-01-29 20:37 UTC (permalink / raw)
To: serue-r/Jw6+rmf7HQT0dZR+AlfA; +Cc: Containers
From: Sukadev Bhattiprolu <sukadev-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
Date: Fri, 22 Jan 2010 11:55:45 -0800
Subject: [PATCH 02/11] Make runtests.sh a wrapper for fileio tests
Move runtests.sh to run-fileio1.sh and create a runtests.sh that
runs both run-fileio1.sh and run-filelock1.sh. It can later be
extended to run other, possibly all, fileio tests.
Signed-off-by: Sukadev Bhattiprolu <sukadev-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
---
fileio/run-fileio1.sh | 148 +++++++++++++++++++++++++++++++++++++++++++++++
fileio/runtests.sh | 153 +++----------------------------------------------
2 files changed, 156 insertions(+), 145 deletions(-)
create mode 100755 fileio/run-fileio1.sh
mode change 100644 => 100755 fileio/runtests.sh
diff --git a/fileio/run-fileio1.sh b/fileio/run-fileio1.sh
new file mode 100755
index 0000000..c7179ab
--- /dev/null
+++ b/fileio/run-fileio1.sh
@@ -0,0 +1,148 @@
+#!/bin/bash
+# Copyright 2009 IBM Corp.
+# Author: Sukadev Bhattiprolu <sukadev-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
+
+source ../common.sh
+
+# test_case could be a command-line-arg, but since only one test
+# uses this for now, hard code.
+test_case="fileio1"
+
+dir=`mktemp -p . -d -t cr_${test_case}_XXXXXXX` || (echo "mktemp failed"; exit 1)
+echo "Using output dir $dir"
+
+SLOW_DOWN="$dir/slow-down-fileio"
+CKPT_FILE="$dir/checkpoint-${test_case}"
+CKPT_READY="$dir/checkpoint.ready"
+COPY_DONE="$dir/copy.done"
+SRC_FILE="$dir/input-data.1";
+DEST_FILE="$dir/output-data.1";
+DEST_FILE_SNAP="$dir/output-data.1.snap";
+TEST_LOG="$dir/log.${test_case}"
+TEST_LOG_SNAP="$dir/log.${test_case}.snap"
+
+LOG_FILE="$dir/f1-loop.log"
+TEST_CMD="./$test_case"
+NS_EXEC="../ns_exec"
+
+# Make sure no stray TEST_CMD from another run is still going
+killall $TEST_CMD
+
+#echo > $LOG_FILE
+
+#Create the SRC_FILE
+$TEST_CMD -d $dir -C $SRC_FILE
+
+cnt=1
+sleep_time=3;
+
+NUMTESTS=5
+for testnum in `seq 1 $NUMTESTS`; do
+ echo "----- Iteration $cnt"
+
+ # Copy file slowly, so we can checkpoint
+ touch $SLOW_DOWN
+
+ # Remove CKPT_READY file, start the application and let app tell
+ # us when it is ready
+ rm -f $CKPT_READY;
+ $NS_EXEC -m $TEST_CMD -d $dir -c $SRC_FILE $DEST_FILE &
+ while [ ! -f $CKPT_READY ]; do
+ sleep 1;
+ done;
+
+ # Let it run for a while before checkpointing
+ echo "Created $TEST_CMD process, sleep $sleep_time"
+ sleep $sleep_time
+
+ pid=`pidof $TEST_CMD`
+ if [ "x$pid" == "x" ]; then
+ echo "$TEST_CMD is not running! pid is $pid. fail"
+ ps -ef |grep $TEST_CMD
+ exit 1
+ fi
+
+ freeze_pid $pid
+
+ # Checkpoint
+ echo $CHECKPOINT $pid > $CKPT_FILE
+ $CHECKPOINT $pid > $CKPT_FILE
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ echo "===== Checkpoint of $pid failed"
+ ps aux |grep $TEST_CMD
+ exit 1;
+ fi
+
+ # Snapshot the outfile and log file
+ cp $DEST_FILE $DEST_FILE_SNAP
+ cp $TEST_LOG $TEST_LOG_SNAP
+
+ ls -l $SRC_FILE $DEST_FILE
+
+ thaw $pid
+
+ kill -9 $pid
+
+ # Restore the snapshot after the main process has been killed
+ cp ${DEST_FILE}.snap $DEST_FILE
+
+ cp $TEST_LOG_SNAP $TEST_LOG
+
+ # Remove COPY_DONE file. We will wait below for application to
+ # finish copying and let us know.
+ rm -f $COPY_DONE;
+
+ # Restart.
+ $NS_EXEC -m rstrsh $CKPT_FILE &
+ ret=$?
+
+ if [ $ret -ne 0 ]; then
+ echo "===== Restart of $pid failed"
+ ps aux |grep $TEST_CMD
+ exit 1;
+ fi
+
+ # Find pid of restarted test cmd...
+
+ sleep 1;
+ pid=`pidof $TEST_CMD`
+ if [ "x$pid" == "x" ]; then
+ echo "Can't find pid of $TEST_CMD"
+ exit 1
+ fi
+
+ nspid=`pidof $NS_EXEC`
+ if [ "x$nspid" == "x" ]; then
+ echo "Can't find pid of $NS_EXEC"
+ exit 1
+ fi
+
+ # ...then zip through rest of copy.
+ rm $SLOW_DOWN
+
+ wait $nspid;
+ ret=$?
+
+ echo "$nspid exited, status $ret"
+
+ #ls -l $SRC_FILE $DEST_FILE $CKPT_FILE
+
+ /usr/bin/cmp $SRC_FILE $DEST_FILE
+ if [ $? -ne 0 ]; then
+ echo "file copy ($SRC_FILE -> $DEST_FILE) failed after restart"
+ exit 1;
+ fi
+
+ cnt=$((cnt+1))
+
+ # Change delay so next checkpoint happens at a different point
+ sleep_time=$((sleep_time+1))
+ if [ $sleep_time -gt 10 ]; then
+ sleep_time=2;
+ fi
+done
+
+echo PASS
+
+exit 0
diff --git a/fileio/runtests.sh b/fileio/runtests.sh
old mode 100644
new mode 100755
index 69758f0..3e3e495
--- a/fileio/runtests.sh
+++ b/fileio/runtests.sh
@@ -1,148 +1,11 @@
#!/bin/bash
-# Copyright 2009 IBM Corp.
-# Author: Sukadev Bhattiprolu <sukadev-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
-source ../common.sh
+echo
+echo "****** $0: Running test: fileio1"
+echo
+./run-fileio1.sh
-# test_case could be a command-line-arg, but since only one test
-# uses this for now, hard code.
-test_case="fileio1"
-
-dir=`mktemp -p . -d -t cr_${test_case}_XXXXXXX` || (echo "mktemp failed"; exit 1)
-echo "Using output dir $dir"
-
-SLOW_DOWN="$dir/slow-down-fileio"
-CKPT_FILE="$dir/checkpoint-${test_case}"
-CKPT_READY="$dir/checkpoint.ready"
-COPY_DONE="$dir/copy.done"
-SRC_FILE="$dir/input-data.1";
-DEST_FILE="$dir/output-data.1";
-DEST_FILE_SNAP="$dir/output-data.1.snap";
-TEST_LOG="$dir/log.${test_case}"
-TEST_LOG_SNAP="$dir/log.${test_case}.snap"
-
-LOG_FILE="$dir/f1-loop.log"
-TEST_CMD="./$test_case"
-NS_EXEC="../ns_exec"
-
-# Make sure no stray TEST_CMD from another run is still going
-killall $TEST_CMD
-
-#echo > $LOG_FILE
-
-#Create the SRC_FILE
-$TEST_CMD -d $dir -C $SRC_FILE
-
-cnt=1
-sleep_time=3;
-
-NUMTESTS=5
-for testnum in `seq 1 $NUMTESTS`; do
- echo "----- Iteration $cnt"
-
- # Copy file slowly, so we can checkpoint
- touch $SLOW_DOWN
-
- # Remove CKPT_READY file, start the application and let app tell
- # us when it is ready
- rm -f $CKPT_READY;
- $NS_EXEC -m $TEST_CMD -d $dir -c $SRC_FILE $DEST_FILE &
- while [ ! -f $CKPT_READY ]; do
- sleep 1;
- done;
-
- # Let it run for a while before checkpointing
- echo "Created $TEST_CMD process, sleep $sleep_time"
- sleep $sleep_time
-
- pid=`pidof $TEST_CMD`
- if [ "x$pid" == "x" ]; then
- echo "$TEST_CMD is not running! pid is $pid. fail"
- ps -ef |grep $TEST_CMD
- exit 1
- fi
-
- freeze_pid $pid
-
- # Checkpoint
- echo $CHECKPOINT $pid > $CKPT_FILE
- $CHECKPOINT $pid > $CKPT_FILE
- ret=$?
- if [ $ret -ne 0 ]; then
- echo "===== Checkpoint of $pid failed"
- ps aux |grep $TEST_CMD
- exit 1;
- fi
-
- # Snapshot the outfile and log file
- cp $DEST_FILE $DEST_FILE_SNAP
- cp $TEST_LOG $TEST_LOG_SNAP
-
- ls -l $SRC_FILE $DEST_FILE
-
- thaw $pid
-
- kill -9 $pid
-
- # Restore the snapshot after the main process has been killed
- cp ${DEST_FILE}.snap $DEST_FILE
-
- cp $TEST_LOG_SNAP $TEST_LOG
-
- # Remove COPY_DONE file. We will wait below for application to
- # finish copying and let us know.
- rm -f $COPY_DONE;
-
- # Restart.
- $NS_EXEC -m rstrsh $CKPT_FILE &
- ret=$?
-
- if [ $ret -ne 0 ]; then
- echo "===== Restart of $pid failed"
- ps aux |grep $TEST_CMD
- exit 1;
- fi
-
- # Find pid of restarted test cmd...
-
- sleep 1;
- pid=`pidof $TEST_CMD`
- if [ "x$pid" == "x" ]; then
- echo "Can't find pid of $TEST_CMD"
- exit 1
- fi
-
- nspid=`pidof $NS_EXEC`
- if [ "x$nspid" == "x" ]; then
- echo "Can't find pid of $NS_EXEC"
- exit 1
- fi
-
- # ...then zip through rest of copy.
- rm $SLOW_DOWN
-
- wait $nspid;
- ret=$?
-
- echo "$nspid exited, status $ret"
-
- #ls -l $SRC_FILE $DEST_FILE $CKPT_FILE
-
- /usr/bin/cmp $SRC_FILE $DEST_FILE
- if [ $? -ne 0 ]; then
- echo "file copy ($SRC_FILE -> $DEST_FILE) failed after restart"
- exit 1;
- fi
-
- cnt=$((cnt+1))
-
- # Change delay so next checkpoint happens at a different point
- sleep_time=$((sleep_time+1))
- if [ $sleep_time -gt 10 ]; then
- sleep_time=2;
- fi
-done
-
-echo PASS
-
-exit 0
+echo
+echo "****** $0: Running test: filelock1"
+echo
+./run-filelock1.sh
--
1.6.0.4
^ permalink raw reply related [flat|nested] 12+ messages in thread* [PATCH 03/11] Check for failure while waiting for checkpoint-ready
[not found] ` <20100129202842.GA25490-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
2010-01-29 20:37 ` [PATCH 02/11] Make runtests.sh a wrapper for fileio tests Sukadev Bhattiprolu
@ 2010-01-29 20:38 ` Sukadev Bhattiprolu
2010-01-29 20:42 ` [PATCH 04/11] Rename run-filelock1 to run-fcntltests.sh Sukadev Bhattiprolu
` (7 subsequent siblings)
9 siblings, 0 replies; 12+ messages in thread
From: Sukadev Bhattiprolu @ 2010-01-29 20:38 UTC (permalink / raw)
To: serue-r/Jw6+rmf7HQT0dZR+AlfA; +Cc: Containers
From: Sukadev Bhattiprolu <sukadev-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
Date: Mon, 25 Jan 2010 18:09:50 -0800
Subject: [PATCH 03/11] Check for failure while waiting for checkpoint-ready
It is possible that an application has encountered an error before creating
the checkpoint-ready file. So while polling for 'checkpoint-ready' to be true,
look for errors in the log file.
Also, ensure filelock temp files are cleaned up by 'make clean'.
Signed-off-by: Sukadev Bhattiprolu <sukadev-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
---
fileio/Makefile | 2 +-
fileio/run-filelock1.sh | 24 +++++++++++++++---------
2 files changed, 16 insertions(+), 10 deletions(-)
diff --git a/fileio/Makefile b/fileio/Makefile
index 40d19da..eb3887b 100644
--- a/fileio/Makefile
+++ b/fileio/Makefile
@@ -9,4 +9,4 @@ all: $(LIBCRTEST) $(targets)
clean:
rm -f $(targets)
- rm -rf cr_fileio*
+ rm -rf cr_fileio* cr_filelock1*
diff --git a/fileio/run-filelock1.sh b/fileio/run-filelock1.sh
index 0ba2d18..b4bbaec 100755
--- a/fileio/run-filelock1.sh
+++ b/fileio/run-filelock1.sh
@@ -45,11 +45,25 @@ checkpoint()
fi
}
+function check_for_failure()
+{
+ grep --binary-files=text FAIL $PWD/$TEST_LOG > /dev/null 2>&1
+ if [ $? -eq 0 ]; then
+ $ECHO "\t***** Application FAILED after restart" >> $SCRIPT_LOG
+ $ECHO "\t***** See $TEST_LOG for details" >> $SCRIPT_LOG
+
+ $ECHO "\t***** Application FAILED after restart"
+ $ECHO "\tSee $PWD/$TEST_LOG for details"
+ exit 1;
+ fi
+}
+
function wait_for_checkpoint_ready()
{
# Wait for test to finish setup
while [ ! -f $CHECKPOINT_READY ]; do
$ECHO "\t- Waiting for $CHECKPOINT_READY"
+ check_for_failure;
sleep 1;
done;
}
@@ -202,15 +216,7 @@ while [ $cnt -lt 20 ]; do
wait $nspid;
ret=$?
- grep --binary-files=text FAIL $PWD/$TEST_LOG > /dev/null 2>&1
- if [ $? -eq 0 ]; then
- $ECHO "\t***** Application FAILED after restart" >> $SCRIPT_LOG
- $ECHO "\t***** See $TEST_LOG for details" >> $SCRIPT_LOG
-
- $ECHO "\t***** Application FAILED after restart"
- $ECHO "\tSee $PWD/$TEST_LOG for details"
- exit 1;
- fi
+ check_for_failure;
$ECHO "\t- Container exited, status $ret"
--
1.6.0.4
^ permalink raw reply related [flat|nested] 12+ messages in thread* [PATCH 04/11] Rename run-filelock1 to run-fcntltests.sh
[not found] ` <20100129202842.GA25490-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
2010-01-29 20:37 ` [PATCH 02/11] Make runtests.sh a wrapper for fileio tests Sukadev Bhattiprolu
2010-01-29 20:38 ` [PATCH 03/11] Check for failure while waiting for checkpoint-ready Sukadev Bhattiprolu
@ 2010-01-29 20:42 ` Sukadev Bhattiprolu
2010-01-29 20:42 ` [PATCH 05/11] Move event-notifications to libcrtest/common.c Sukadev Bhattiprolu
` (6 subsequent siblings)
9 siblings, 0 replies; 12+ messages in thread
From: Sukadev Bhattiprolu @ 2010-01-29 20:42 UTC (permalink / raw)
To: serue-r/Jw6+rmf7HQT0dZR+AlfA; +Cc: Containers
From: Sukadev Bhattiprolu <sukadev-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
Date: Mon, 25 Jan 2010 18:26:57 -0800
Subject: [PATCH 04/11] Rename run-filelock1 to run-fcntltests.sh
run-filelock1 wrapper could share lot of code with other fcntl tests.
Remove hardcoded names, rename it run-fcntltests.sh and pass in
test_case name as an argument.
Signed-off-by: Sukadev Bhattiprolu <sukadev-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
---
fileio/run-fcntltests.sh | 236 ++++++++++++++++++++++++++++++++++++++++++++++
fileio/run-filelock1.sh | 223 +-------------------------------------------
fileio/runtests.sh | 2 +-
3 files changed, 238 insertions(+), 223 deletions(-)
create mode 100755 fileio/run-fcntltests.sh
diff --git a/fileio/run-fcntltests.sh b/fileio/run-fcntltests.sh
new file mode 100755
index 0000000..0b168e9
--- /dev/null
+++ b/fileio/run-fcntltests.sh
@@ -0,0 +1,236 @@
+#!/bin/bash
+
+source ../common.sh
+
+if [ $# -ne 1 ]; then
+ echo "Usage: $0 <test-case>";
+ exit 1;
+fi
+
+test_case=$1;
+
+if [ ! -x $test_case ]; then
+ echo "$0: Test case \'$test_case\' does not exist / not executable ?"
+ exit 1;
+fi
+
+dir=`mktemp -p . -d -t cr_${test_case}_XXXXXXX` || (echo "mktemp failed"; exit 1)
+
+# NOTE: As of ckpt-v15-dev, the --container option to 'ckpt' causes this
+# test to fail with "container not isolated" message due to the
+# log-file being shared between the application threads.
+#
+CHECKPOINT="`which checkpoint` --container"
+RESTART=`which restart`
+ECHO="/bin/echo -e"
+
+TEST_CMD="../$test_case"
+TEST_ARGS=""
+TEST_LOG="logs.d/log.${test_case}"
+SCRIPT_LOG="logs.d/log.run-${test_case}"
+TEST_PID_FILE="pid.${test_case}";
+
+SNAPSHOT_DIR="snap1.d"
+
+TEST_DONE="test-done"
+CHECKPOINT_FILE="checkpoint-${test_case}";
+CHECKPOINT_READY="checkpoint-ready"
+CHECKPOINT_DONE="checkpoint-done"
+
+LOGS_DIR="logs.d"
+DATA_DIR="data.d"
+
+NS_EXEC="../../ns_exec"
+NS_EXEC_ARGS="-cgpuimP $TEST_PID_FILE"
+
+checkpoint()
+{
+ local pid=$1
+
+ $ECHO "\t- Checkpoint: $CHECKPOINT $pid \> $CHECKPOINT_FILE"
+ $CHECKPOINT $pid > $CHECKPOINT_FILE
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ $ECHO "***** FAIL: Checkpoint of $pid failed"
+ ps -efL |grep $TEST_CMD >> $SCRIPT_LOG
+ exit 1;
+ fi
+}
+
+function check_for_failure()
+{
+ grep --binary-files=text FAIL $PWD/$TEST_LOG > /dev/null 2>&1
+ if [ $? -eq 0 ]; then
+ $ECHO "\t***** Application FAILED after restart" >> $SCRIPT_LOG
+ $ECHO "\t***** See $TEST_LOG for details" >> $SCRIPT_LOG
+
+ $ECHO "\t***** Application FAILED after restart"
+ $ECHO "\tSee $PWD/$TEST_LOG for details"
+ exit 1;
+ fi
+}
+
+function wait_for_checkpoint_ready()
+{
+ # Wait for test to finish setup
+ while [ ! -f $CHECKPOINT_READY ]; do
+ $ECHO "\t- Waiting for $CHECKPOINT_READY"
+ check_for_failure;
+ sleep 1;
+ done;
+}
+
+function create_container()
+{
+ local pid;
+
+ cmdline="$NS_EXEC $NS_EXEC_ARGS -- $TEST_CMD $TEST_ARGS"
+
+ $ECHO "\t- Creating container:"
+ $ECHO "\t- $cmdline"
+
+ $cmdline &
+
+ wait_for_checkpoint_ready;
+
+ # Find global pid of container-init
+ pid=`cat $TEST_PID_FILE`;
+ if [ "x$pid" == "x" ]; then
+ $ECHO "***** FAIL: Invalid container-init pid $pid"
+ ps -efL |grep $TEST_CMD >> $SCRIPT_LOG
+ exit 1
+ fi
+ $ECHO "Created container with pid $pid" >> $SCRIPT_LOG
+}
+
+function restart_container
+{
+ local ret;
+
+ cmdline="$RESTART --pids --pidns --wait"
+ $ECHO "\t- $cmdline"
+
+ sleep 1
+
+ $cmdline < $CHECKPOINT_FILE >> $SCRIPT_LOG 2>&1 &
+ ret=$?
+
+ if [ $ret -ne 0 ]; then
+ $ECHO "***** FAIL: Restart of $pid failed"
+ ps -efL |grep $TEST_CMD >> $SCRIPT_LOG
+ exit 1;
+ fi
+
+}
+
+function create_fs_snapshot()
+{
+ # Prepare for snapshot
+ if [ -d $SNAPSHOT_DIR ]; then
+ rm -rf ${SNAPSHOT_DIR}.prev
+ mv $SNAPSHOT_DIR ${SNAPSHOT_DIR}.prev
+ mkdir $SNAPSHOT_DIR
+ fi
+
+ # Snapshot the log files
+ cp ${LOGS_DIR}/* $SNAPSHOT_DIR
+}
+
+function restore_fs_snapshot()
+{
+ # Restore the snapshot after the main process has been killed
+ /bin/cp ${SNAPSHOT_DIR}/* $LOGS_DIR
+}
+
+cd $dir
+echo "Current directory: `pwd`"
+
+if [ ! -d $LOGS_DIR ]; then
+ mkdir $LOGS_DIR
+fi
+
+if [ ! -d $DATA_DIR ]; then
+ mkdir $DATA_DIR
+fi
+
+if [ ! -d $SNAPSHOT_DIR ]; then
+ mkdir $SNAPSHOT_DIR
+fi
+
+if [ ! -f $INPUT_DATA ]; then
+ $FILEIO -C $INPUT_DATA
+fi
+
+# Make sure no stray test-case process from another run is still going
+killall $TEST_CMD > $SCRIPT_LOG 2>&1
+
+> $SCRIPT_LOG;
+cnt=1
+while [ $cnt -lt 20 ]; do
+ $ECHO "===== Iteration $cnt"
+
+ # Remove any 'state' files, start the app and let it tell us
+ # when it is ready
+ rm -f $CHECKPOINT_READY $TEST_DONE $TEST_PID_FILE
+
+ create_container
+ wait_for_checkpoint_ready
+
+ pid=`cat $TEST_PID_FILE`
+
+ $ECHO "\t- Done creating container, cinit-pid $pid"
+
+ ps -efL |grep $TEST_CMD >> $SCRIPT_LOG
+
+ # override default freezerdir
+ if [ -d $freezerdir ]; then
+ rmdir $freezerdir
+ fi
+ freezerdir=$freezermountpoint/$pid
+ freeze_pid $pid
+
+ num_pids1=`ps -efL |grep $TEST_CMD | wc -l`
+
+ create_fs_snapshot
+
+ checkpoint $pid
+
+ touch $CHECKPOINT_DONE
+
+ killall -9 `basename $TEST_CMD`
+
+ thaw
+
+ sleep 3
+
+ restore_fs_snapshot
+
+ restart_container
+
+ sleep 3;
+
+ num_pids2=`ps -efL |grep $TEST_CMD | wc -l`
+ ps -efL |grep $TEST_CMD >> $SCRIPT_LOG
+ $ECHO "\t- num_pids1 $num_pids1, num_pids2 $num_pids2";
+
+ # ns_exec pid is parent-pid of restarted-container-init
+ nspid=`pidof restart`
+
+ if [ "x$nspid" == "x" ]; then
+ $ECHO "***** FAIL: Can't find pid of $RESTART"
+ exit 1;
+ fi
+
+ # End test gracefully
+ touch $TEST_DONE
+
+ $ECHO "\t- Waiting for restarted container to exit (gloabl-pid $nspid)"
+ wait $nspid;
+ ret=$?
+
+ check_for_failure;
+
+ $ECHO "\t- Container exited, status $ret"
+
+ cnt=$((cnt+1))
+done
diff --git a/fileio/run-filelock1.sh b/fileio/run-filelock1.sh
index b4bbaec..554c24a 100755
--- a/fileio/run-filelock1.sh
+++ b/fileio/run-filelock1.sh
@@ -1,224 +1,3 @@
#!/bin/bash
-source ../common.sh
-
-dir=`mktemp -p . -d -t cr_filelock1_XXXXXXX` || (echo "mktemp failed"; exit 1)
-
-# NOTE: As of ckpt-v15-dev, the --container option to 'ckpt' causes this
-# test to fail with "container not isolated" message due to the
-# log-file being shared between the application threads.
-#
-CHECKPOINT="`which checkpoint` --container"
-RESTART=`which restart`
-ECHO="/bin/echo -e"
-
-TEST_CMD="../filelock1"
-TEST_ARGS=""
-TEST_LOG="logs.d/log.filelock1"
-SCRIPT_LOG="logs.d/log.run-filelock1"
-TEST_PID_FILE="pid.filelock1";
-
-SNAPSHOT_DIR="snap1.d"
-
-TEST_DONE="test-done"
-CHECKPOINT_FILE="checkpoint-filelock1";
-CHECKPOINT_READY="checkpoint-ready"
-CHECKPOINT_DONE="checkpoint-done"
-
-LOGS_DIR="logs.d"
-DATA_DIR="data.d"
-
-NS_EXEC="../../ns_exec"
-NS_EXEC_ARGS="-cgpuimP $TEST_PID_FILE"
-
-checkpoint()
-{
- local pid=$1
-
- $ECHO "\t- Checkpoint: $CHECKPOINT $pid \> $CHECKPOINT_FILE"
- $CHECKPOINT $pid > $CHECKPOINT_FILE
- ret=$?
- if [ $ret -ne 0 ]; then
- $ECHO "***** FAIL: Checkpoint of $pid failed"
- ps -efL |grep $TEST_CMD >> $SCRIPT_LOG
- exit 1;
- fi
-}
-
-function check_for_failure()
-{
- grep --binary-files=text FAIL $PWD/$TEST_LOG > /dev/null 2>&1
- if [ $? -eq 0 ]; then
- $ECHO "\t***** Application FAILED after restart" >> $SCRIPT_LOG
- $ECHO "\t***** See $TEST_LOG for details" >> $SCRIPT_LOG
-
- $ECHO "\t***** Application FAILED after restart"
- $ECHO "\tSee $PWD/$TEST_LOG for details"
- exit 1;
- fi
-}
-
-function wait_for_checkpoint_ready()
-{
- # Wait for test to finish setup
- while [ ! -f $CHECKPOINT_READY ]; do
- $ECHO "\t- Waiting for $CHECKPOINT_READY"
- check_for_failure;
- sleep 1;
- done;
-}
-
-function create_container()
-{
- local pid;
-
- cmdline="$NS_EXEC $NS_EXEC_ARGS -- $TEST_CMD $TEST_ARGS"
-
- $ECHO "\t- Creating container:"
- $ECHO "\t- $cmdline"
-
- $cmdline &
-
- wait_for_checkpoint_ready;
-
- # Find global pid of container-init
- pid=`cat $TEST_PID_FILE`;
- if [ "x$pid" == "x" ]; then
- $ECHO "***** FAIL: Invalid container-init pid $pid"
- ps -efL |grep $TEST_CMD >> $SCRIPT_LOG
- exit 1
- fi
- $ECHO "Created container with pid $pid" >> $SCRIPT_LOG
-}
-
-function restart_container
-{
- local ret;
-
- cmdline="$RESTART --pids --pidns --wait"
- $ECHO "\t- $cmdline"
-
- sleep 1
-
- $cmdline < $CHECKPOINT_FILE >> $SCRIPT_LOG 2>&1 &
- ret=$?
-
- if [ $ret -ne 0 ]; then
- $ECHO "***** FAIL: Restart of $pid failed"
- ps -efL |grep $TEST_CMD >> $SCRIPT_LOG
- exit 1;
- fi
-
-}
-
-function create_fs_snapshot()
-{
- # Prepare for snapshot
- if [ -d $SNAPSHOT_DIR ]; then
- rm -rf ${SNAPSHOT_DIR}.prev
- mv $SNAPSHOT_DIR ${SNAPSHOT_DIR}.prev
- mkdir $SNAPSHOT_DIR
- fi
-
- # Snapshot the log files
- cp ${LOGS_DIR}/* $SNAPSHOT_DIR
-}
-
-function restore_fs_snapshot()
-{
- # Restore the snapshot after the main process has been killed
- /bin/cp ${SNAPSHOT_DIR}/* $LOGS_DIR
-}
-
-cd $dir
-echo "Current directory: `pwd`"
-
-if [ ! -d $LOGS_DIR ]; then
- mkdir $LOGS_DIR
-fi
-
-if [ ! -d $DATA_DIR ]; then
- mkdir $DATA_DIR
-fi
-
-if [ ! -d $SNAPSHOT_DIR ]; then
- mkdir $SNAPSHOT_DIR
-fi
-
-if [ ! -f $INPUT_DATA ]; then
- $FILEIO -C $INPUT_DATA
-fi
-
-# Make sure no stray filelock1 process from another run is still going
-killall $TEST_CMD > $SCRIPT_LOG 2>&1
-
-> $SCRIPT_LOG;
-cnt=1
-while [ $cnt -lt 20 ]; do
- $ECHO "===== Iteration $cnt"
-
- # Remove any 'state' files, start the app and let it tell us
- # when it is ready
- rm -f $CHECKPOINT_READY $TEST_DONE $TEST_PID_FILE
-
- create_container
- wait_for_checkpoint_ready
-
- pid=`cat $TEST_PID_FILE`
-
- $ECHO "\t- Done creating container, cinit-pid $pid"
-
- ps -efL |grep $TEST_CMD >> $SCRIPT_LOG
-
- # override default freezerdir
- if [ -d $freezerdir ]; then
- rmdir $freezerdir
- fi
- freezerdir=$freezermountpoint/$pid
- freeze_pid $pid
-
- num_pids1=`ps -efL |grep $TEST_CMD | wc -l`
-
- create_fs_snapshot
-
- checkpoint $pid
-
- touch $CHECKPOINT_DONE
-
- killall -9 `basename $TEST_CMD`
-
- thaw
-
- sleep 3
-
- restore_fs_snapshot
-
- restart_container
-
- sleep 3;
-
- num_pids2=`ps -efL |grep $TEST_CMD | wc -l`
- ps -efL |grep $TEST_CMD >> $SCRIPT_LOG
- $ECHO "\t- num_pids1 $num_pids1, num_pids2 $num_pids2";
-
- # ns_exec pid is parent-pid of restarted-container-init
- nspid=`pidof restart`
-
- if [ "x$nspid" == "x" ]; then
- $ECHO "***** FAIL: Can't find pid of $RESTART"
- exit 1;
- fi
-
- # End test gracefully
- touch $TEST_DONE
-
- $ECHO "\t- Waiting for restarted container to exit (gloabl-pid $nspid)"
- wait $nspid;
- ret=$?
-
- check_for_failure;
-
- $ECHO "\t- Container exited, status $ret"
-
- cnt=$((cnt+1))
-done
+./run-fcntltests.sh filelock1
diff --git a/fileio/runtests.sh b/fileio/runtests.sh
index 3e3e495..d674311 100755
--- a/fileio/runtests.sh
+++ b/fileio/runtests.sh
@@ -8,4 +8,4 @@ echo
echo
echo "****** $0: Running test: filelock1"
echo
-./run-filelock1.sh
+./run-fcntltests.sh filelock1
--
1.6.0.4
^ permalink raw reply related [flat|nested] 12+ messages in thread* [PATCH 05/11] Move event-notifications to libcrtest/common.c
[not found] ` <20100129202842.GA25490-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
` (2 preceding siblings ...)
2010-01-29 20:42 ` [PATCH 04/11] Rename run-filelock1 to run-fcntltests.sh Sukadev Bhattiprolu
@ 2010-01-29 20:42 ` Sukadev Bhattiprolu
[not found] ` <20100129204228.GD26721-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
2010-01-29 20:42 ` [PATCH 06/11] filelease1: Test restore of file leases Sukadev Bhattiprolu
` (5 subsequent siblings)
9 siblings, 1 reply; 12+ messages in thread
From: Sukadev Bhattiprolu @ 2010-01-29 20:42 UTC (permalink / raw)
To: serue-r/Jw6+rmf7HQT0dZR+AlfA; +Cc: Containers
From: Sukadev Bhattiprolu <sukadev-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
Date: Tue, 26 Jan 2010 16:46:09 -0800
Subject: [PATCH 05/11] Move event-notifications to libcrtest/common.c
The event notification functions using eventfd can be used by other
fcntl tests (and possibly other tests). Move them out of filelock1.c
and into libcrtest/common.c
Signed-off-by: Sukadev Bhattiprolu <sukadev-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
---
fileio/filelock1.c | 53 -------------------------------------------
libcrtest/common.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++++
libcrtest/libcrtest.h | 7 +++++
3 files changed, 67 insertions(+), 53 deletions(-)
diff --git a/fileio/filelock1.c b/fileio/filelock1.c
index 305cbeb..19f7e3b 100644
--- a/fileio/filelock1.c
+++ b/fileio/filelock1.c
@@ -9,8 +9,6 @@
#define TEST_FILE "data.d/data.filelock1"
#define LOG_FILE "logs.d/log.filelock1"
-typedef unsigned long long u64;
-
extern FILE *logfp;
int test_fd;
int event_fd1;
@@ -31,57 +29,6 @@ int event_fd2;
* held by the other process.
*/
-setup_notification()
-{
- int efd;
-
- efd = eventfd(0, 0);
- if (efd < 0) {
- fprintf(logfp, "ERROR: eventfd(): %s\n", strerror(errno));
- do_exit(1);
- }
- return efd;
-}
-
-wait_for_events(int efd, u64 total)
-{
- int n;
- u64 events;
- u64 count = (u64)0;
-
- do {
- fprintf(logfp, "%d: wait_for_events: fd %d, reading for %llu\n",
- getpid(), efd, total);
- fflush(logfp);
-
- n = read(efd, &events, sizeof(events));
- if (n != sizeof(events)) {
- fprintf(logfp, "ERROR: read(event_fd) %s\n",
- strerror(errno));
- do_exit(1);
- }
- fprintf(logfp, "%d: wait_for_events: fd %d read %llu\n",
- getpid(), efd, events);
-
- count += events;
- } while (count < total);
-}
-
-notify_one_event(int efd)
-{
- int n;
- u64 event = (u64)1;
-
- fprintf(logfp, "%d: Notifying one event on fd %d\n", getpid(), efd);
- fflush(logfp);
-
- n = write(efd, &event, sizeof(event));
- if (n != sizeof(event)) {
- fprintf(logfp, "ERROR: write(event_fd) %s\n", strerror(errno));
- do_exit(1);
- }
-}
-
struct test_arg {
int child_idx;
int type;
diff --git a/libcrtest/common.c b/libcrtest/common.c
index ca3d2d8..b29042a 100644
--- a/libcrtest/common.c
+++ b/libcrtest/common.c
@@ -335,3 +335,63 @@ int move_to_cgroup(char *subsys, char *grp, int pid)
fclose(fout);
return 1;
}
+
+/*
+ * Set up an eventfd for communication between parent/child processes
+ */
+int setup_notification(void)
+{
+ int efd;
+
+ efd = eventfd(0, 0);
+ if (efd < 0) {
+ fprintf(logfp, "ERROR: eventfd(): %s\n", strerror(errno));
+ do_exit(1);
+ }
+ return efd;
+}
+
+/*
+ * Wait on eventfd @efd till the total number of events equals @total.
+ */
+void wait_for_events(int efd, u64 total)
+{
+ int n;
+ u64 events;
+ u64 count = (u64)0;
+
+ do {
+ fprintf(logfp, "%d: wait_for_events: fd %d, reading for %llu\n",
+ getpid(), efd, total);
+ fflush(logfp);
+
+ n = read(efd, &events, sizeof(events));
+ if (n != sizeof(events)) {
+ fprintf(logfp, "ERROR: read(event_fd) %s\n",
+ strerror(errno));
+ do_exit(1);
+ }
+ fprintf(logfp, "%d: wait_for_events: fd %d read %llu\n",
+ getpid(), efd, events);
+
+ count += events;
+ } while (count < total);
+}
+
+/*
+ * Notify one event on the eventfd @efd.
+ */
+void notify_one_event(int efd)
+{
+ int n;
+ u64 event = (u64)1;
+
+ fprintf(logfp, "%d: Notifying one event on fd %d\n", getpid(), efd);
+ fflush(logfp);
+
+ n = write(efd, &event, sizeof(event));
+ if (n != sizeof(event)) {
+ fprintf(logfp, "ERROR: write(event_fd) %s\n", strerror(errno));
+ do_exit(1);
+ }
+}
diff --git a/libcrtest/libcrtest.h b/libcrtest/libcrtest.h
index a42c178..9a0a13e 100644
--- a/libcrtest/libcrtest.h
+++ b/libcrtest/libcrtest.h
@@ -12,6 +12,10 @@ struct record {
char data[256];
};
+#ifdef __i386__
+typedef unsigned long long u64;
+#endif
+
extern void do_exit(int status);
extern int test_done(void);
extern int test_checkpoint_done();
@@ -23,4 +27,7 @@ extern char *freezer_mountpoint(void);
/* right now, subsys must always be "freezer" */
extern int move_to_cgroup(char *subsys, char *grp, int pid);
+extern void notify_one_event(int efd);
+extern void wait_for_events(int efd, u64 total);
+extern int setup_notification();
#endif /* LIBCRTEST_H */
--
1.6.0.4
^ permalink raw reply related [flat|nested] 12+ messages in thread* [PATCH 06/11] filelease1: Test restore of file leases
[not found] ` <20100129202842.GA25490-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
` (3 preceding siblings ...)
2010-01-29 20:42 ` [PATCH 05/11] Move event-notifications to libcrtest/common.c Sukadev Bhattiprolu
@ 2010-01-29 20:42 ` Sukadev Bhattiprolu
2010-01-29 20:43 ` [PATCH 07/11] fsetown1: Test async I/O notification after restart Sukadev Bhattiprolu
` (4 subsequent siblings)
9 siblings, 0 replies; 12+ messages in thread
From: Sukadev Bhattiprolu @ 2010-01-29 20:42 UTC (permalink / raw)
To: serue-r/Jw6+rmf7HQT0dZR+AlfA; +Cc: Containers
From: Sukadev Bhattiprolu <sukadev-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
Date: Thu, 21 Jan 2010 12:36:24 -0800
Subject: [PATCH 06/11] filelease1: Test restore of file leases
Checkpoint an application that has F_RDLCK and F_WRLCK leases on files.
Restart the application and ensure that the leases are restored.
Signed-off-by: Sukadev Bhattiprolu <sukadev-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
---
fileio/Makefile | 4 +-
fileio/filelease1.c | 262 ++++++++++++++++++++++++++++++++++++++++++++++
fileio/run-filelease1.sh | 3 +
fileio/runtests.sh | 5 +
4 files changed, 272 insertions(+), 2 deletions(-)
create mode 100644 fileio/filelease1.c
create mode 100755 fileio/run-filelease1.sh
diff --git a/fileio/Makefile b/fileio/Makefile
index eb3887b..acc2df9 100644
--- a/fileio/Makefile
+++ b/fileio/Makefile
@@ -1,4 +1,4 @@
-targets = fileio1 filelock1
+targets = fileio1 filelock1 filelease1
INCLUDE = ../libcrtest
LIBCRTEST = ../libcrtest/common.o
@@ -9,4 +9,4 @@ all: $(LIBCRTEST) $(targets)
clean:
rm -f $(targets)
- rm -rf cr_fileio* cr_filelock1*
+ rm -rf cr_fileio* cr_filelock1* cr_filelease1*
diff --git a/fileio/filelease1.c b/fileio/filelease1.c
new file mode 100644
index 0000000..21494e9
--- /dev/null
+++ b/fileio/filelease1.c
@@ -0,0 +1,262 @@
+#include <stdio.h>
+#include <unistd.h>
+#define __USE_GNU
+#include <fcntl.h>
+#include <string.h>
+#include <signal.h>
+#include <errno.h>
+#include "libcrtest.h"
+
+#define TEST_FILE1 "data.d/data.filelease1"
+#define TEST_FILE2 "data.d/data.filelease2"
+#define LOG_FILE "logs.d/log.filelease1"
+
+extern FILE *logfp;
+int test_fd;
+int event_fd1;
+int event_fd2;
+
+/*
+ * Description:
+ * Ensure that F_RDLCK and F_WRLCK file leases held by a process at
+ * the time of checkpoint are properly restored when the process is
+ * restarted from the checkpoint.
+ *
+ * Implementation:
+ * Two processes, P0 and P1 acquire a F_RDLCK lease on file F1.
+ * Process P2 acquires a F_WRLCK lease on file F2. After acquiring
+ * leases the processes notify parent they are ready for checkpoint
+ * and wait for checkpoint to be done. When they are restarted
+ * (i.e when test_done() is TRUE), each process verifies that it has the
+ * lease it had at the time of checkpoint.
+ */
+
+void set_lease(int fd, int type)
+{
+ int rc;
+
+ fprintf(logfp, "%d: set_lease() called for fd %d, type %d\n",
+ getpid(), fd, type);
+
+ rc = fcntl(fd, F_SETLEASE, type);
+ if (rc < 0) {
+ fprintf(logfp, "%d: set_lease(type %d):, ERROR %s\n",
+ getpid(), type, strerror(errno));
+ if (errno == EINVAL)
+ fprintf(logfp, "%d: Maybe the fs does not support "
+ "F_SETLEASE (eg: NFS)\n", getpid());
+ fflush(logfp);
+ kill(getppid(), SIGUSR1);
+ do_exit(1);
+ }
+
+ fprintf(logfp, "%d: set_lease(%d): %s\n", getpid(), type,
+ rc < 0 ? strerror(errno) : "done");
+}
+
+char *get_lease_desc(int type)
+{
+ switch(type) {
+ case F_RDLCK: return "F_RDLCK";
+ case F_WRLCK: return "F_WRLCK";
+ case F_UNLCK: return "F_UNLCK";
+ default: return "Unknown !";
+ }
+}
+
+void test_lease(int fd, int exp_type)
+{
+ int rc;
+
+ rc = fcntl(fd, F_GETLEASE, 0);
+ if (rc < 0 || rc > 2) {
+ fprintf(logfp, "ERROR: fcntl(F_GETLEASE): expected %s, rc %d, "
+ "error %s\n", get_lease_desc(exp_type), rc,
+ strerror(errno));
+ do_exit(1);
+ }
+
+ if (rc != exp_type) {
+ fprintf(logfp, "%d: FAIL: Expected %s, actual %s\n", getpid(),
+ get_lease_desc(exp_type), get_lease_desc(rc));
+ do_exit(1);
+ }
+
+ fprintf(logfp, "%d: PASS: Expected %s, actual %s\n", getpid(),
+ get_lease_desc(exp_type), get_lease_desc(rc));
+ return;
+}
+
+struct test_arg {
+ int fd;
+ int type;
+ int pid;
+};
+
+struct test_arg test_data[3];
+
+int do_child(int idx)
+{
+ int type = test_data[idx].type;
+ int fd = test_data[idx].fd;
+
+ fprintf(logfp, "%d: Setting lease to type %s\n", getpid(),
+ get_lease_desc(type));
+
+ set_lease(fd, type);
+
+ /*
+ * Tell parent we are ready for checkpoint...
+ */
+ notify_one_event(event_fd1);
+
+ /*
+ * Wait for checkpoint/restart
+ */
+ fprintf(logfp, "%d: waiting for test-done\n", getpid());
+ while(!test_done()) {
+ sleep(1);
+ }
+ fprintf(logfp, "%d: Found test-done\n", getpid());
+
+ test_lease(fd, type);
+
+ do_exit(0);
+}
+
+/*
+ * Create two test files and populate test_data[] so that:
+ * - first two childrent get a F_RDLCK lease on file TEST_FILE1.
+ * - third child gets a F_WRLCK lease on file TEST_FILE2.
+ */
+void setup_test_data()
+{
+ int fd;
+ char buf[256];
+
+ /* Create TEST_FILE1 */
+ fd = open(TEST_FILE1, O_RDWR|O_CREAT|O_TRUNC, 0666);
+ if (fd < 0) {
+ fprintf(logfp, "ERROR: open(%s): %s\n", TEST_FILE1,
+ strerror(errno));
+ do_exit(1);
+ }
+
+ memset(buf, 0, sizeof(buf));
+ write(fd, buf, sizeof(buf));
+
+ /* Close TEST_FILE1 and open for read-only */
+ close(fd);
+
+ fd = open(TEST_FILE1, O_RDONLY);
+ if (fd < 0) {
+ fprintf(logfp, "ERROR: open(%s): %s\n", TEST_FILE1,
+ strerror(errno));
+ do_exit(1);
+ }
+
+ /*
+ * First two childrent get a F_RDLCK lease on file TEST_FILE1.
+ * Third child gets a F_WRLCK lease on file TEST_FILE2.
+ */
+ test_data[0].fd = test_data[1].fd = fd;
+ test_data[0].type = test_data[1].type = F_RDLCK;
+ fprintf(logfp, "fd0: %d, type %d\n",
+ test_data[0].fd, test_data[0].type);
+
+ /* Create TEST_FILE2 */
+ fd = open(TEST_FILE2, O_RDWR|O_CREAT|O_TRUNC, 0666);
+ if (fd < 0) {
+ fprintf(logfp, "ERROR: open(%s): %s\n", TEST_FILE2,
+ strerror(errno));
+ do_exit(1);
+ }
+ write(fd, buf, sizeof(buf));
+
+ test_data[2].fd = fd;
+ test_data[2].type = F_WRLCK;
+
+ return;
+}
+
+void child_handler(int sig)
+{
+ int i;
+ int num_children = 3;
+ /*
+ * Test failed or a child encountered an error.
+ * Kill (remaining) children, reap children and exit.
+ */
+ fprintf(logfp, "%d: Got signal %d\n", getpid(), sig);
+ for (i = 0; i < num_children; i++)
+ if (test_data[i].pid)
+ kill(test_data[i].pid, SIGKILL);
+
+ fprintf(logfp, "%d: Test case FAILED\n", getpid());
+ fflush(logfp);
+
+ do_wait(num_children);
+
+ do_exit(-1);
+}
+
+main(int argc, char *argv[])
+{
+ int i, status, rc;
+ int pid;
+
+ if (test_done()) {
+ printf("Remove %s before running test\n", TEST_DONE);
+ do_exit(1);
+ }
+
+ logfp = fopen(LOG_FILE, "w");
+ if (!logfp) {
+ perror("open() logfile");
+ do_exit(1);
+ }
+
+ printf("%s: Closing stdio fds and writing messages to %s\n",
+ argv[0], LOG_FILE);
+
+ for (i=0; i<100; i++) {
+ if (fileno(logfp) != i)
+ close(i);
+ }
+
+ setup_test_data();
+ event_fd1 = setup_notification();
+
+ /*
+ * Before waiting for events below, ensure we will be notified
+ * if a child encounters an error and/or exits prematurely.
+ */
+ signal(SIGUSR1, child_handler);
+ signal(SIGCHLD, child_handler);
+
+ /*
+ * Create the test processes and wait for them to be ready for
+ * checkpoint.
+ */
+ for (i = 0; i < 3; i ++) {
+ pid = fork();
+ if (pid == 0)
+ do_child(i);
+ test_data[i].pid = pid;
+ }
+
+ wait_for_events(event_fd1, 1);
+
+ /*
+ * Now that the test processes are ready, tell any wrapper scripts,
+ * we are ready for checkpoint
+ */
+ set_checkpoint_ready();
+
+ fprintf(logfp, "***** %d: Ready for checkpoint\n", getpid());
+ fflush(logfp);
+
+ do_wait(3);
+
+ do_exit(0);
+}
diff --git a/fileio/run-filelease1.sh b/fileio/run-filelease1.sh
new file mode 100755
index 0000000..41249a8
--- /dev/null
+++ b/fileio/run-filelease1.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+./run-fcntltests.sh filelease1
diff --git a/fileio/runtests.sh b/fileio/runtests.sh
index d674311..e83f9cc 100755
--- a/fileio/runtests.sh
+++ b/fileio/runtests.sh
@@ -9,3 +9,8 @@ echo
echo "****** $0: Running test: filelock1"
echo
./run-fcntltests.sh filelock1
+
+echo
+echo "****** $0: Running test: filelease1"
+echo
+./run-fcntltests.sh filelease1
--
1.6.0.4
^ permalink raw reply related [flat|nested] 12+ messages in thread* [PATCH 07/11] fsetown1: Test async I/O notification after restart
[not found] ` <20100129202842.GA25490-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
` (4 preceding siblings ...)
2010-01-29 20:42 ` [PATCH 06/11] filelease1: Test restore of file leases Sukadev Bhattiprolu
@ 2010-01-29 20:43 ` Sukadev Bhattiprolu
2010-01-29 20:43 ` [PATCH 08/11] filelock1: Extend for mandatory locks Sukadev Bhattiprolu
` (3 subsequent siblings)
9 siblings, 0 replies; 12+ messages in thread
From: Sukadev Bhattiprolu @ 2010-01-29 20:43 UTC (permalink / raw)
To: serue-r/Jw6+rmf7HQT0dZR+AlfA; +Cc: Containers
From: Sukadev Bhattiprolu <sukadev-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
Date: Thu, 21 Jan 2010 23:07:51 -0800
Subject: [PATCH 07/11] fsetown1: Test async I/O notification after restart
Checkpoint a process that is waiting for async notification of data
being available on a pipe. When the process is restarted, make data
available on the pipe and ensure that the process is notified.
Signed-off-by: Sukadev Bhattiprolu <sukadev-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
---
fileio/Makefile | 4 +-
fileio/fsetown1.c | 268 ++++++++++++++++++++++++++++++++++++++++++++++++
fileio/run-fsetown1.sh | 3 +
fileio/runtests.sh | 5 +
libcrtest/common.c | 2 +-
5 files changed, 279 insertions(+), 3 deletions(-)
create mode 100644 fileio/fsetown1.c
create mode 100755 fileio/run-fsetown1.sh
diff --git a/fileio/Makefile b/fileio/Makefile
index acc2df9..bd28561 100644
--- a/fileio/Makefile
+++ b/fileio/Makefile
@@ -1,4 +1,4 @@
-targets = fileio1 filelock1 filelease1
+targets = fileio1 filelock1 filelease1 fsetown1
INCLUDE = ../libcrtest
LIBCRTEST = ../libcrtest/common.o
@@ -9,4 +9,4 @@ all: $(LIBCRTEST) $(targets)
clean:
rm -f $(targets)
- rm -rf cr_fileio* cr_filelock1* cr_filelease1*
+ rm -rf cr_fileio* cr_filelock1* cr_filelease1* cr_fsetown1*
diff --git a/fileio/fsetown1.c b/fileio/fsetown1.c
new file mode 100644
index 0000000..c6c5734
--- /dev/null
+++ b/fileio/fsetown1.c
@@ -0,0 +1,268 @@
+#include <stdio.h>
+#include <unistd.h>
+#define __USE_GNU
+#include <fcntl.h>
+#include <string.h>
+#include <signal.h>
+#include <errno.h>
+#include <wait.h>
+#include "libcrtest.h"
+
+#define LOG_FILE "logs.d/log.fsetown1"
+
+int pipe_fds[2];
+int event_fd1;
+int got_sigio;
+
+/*
+ * Description:
+ * Checkpoint a process that is waiting for async notification of data
+ * being available on a pipe. When the process is restarted, make data
+ * available on the pipe and ensure that the process is notified.
+ *
+ * Implementation:
+ */
+void iohandler(int sig)
+{
+ int rc;
+ char buf[16];
+
+ fprintf(logfp, "%d: Got signal %d\n", getpid(), sig);
+ fflush(logfp);
+ got_sigio = 1;
+}
+
+static void wait_for_child()
+{
+ int rc;
+ int status;
+
+ rc = waitpid(-1, &status, 0);
+ if (rc < 0) {
+ fprintf(logfp, "%d: waitpid(): rc %d, error %s\n",
+ getpid(), rc, strerror(errno));
+ do_exit(1);
+ }
+
+ if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
+ fprintf(logfp, "%d: Test case PASSED\n", getpid());
+ rc = 0;
+ } else {
+ fprintf(logfp, "%d: Test case FAILED\n", getpid());
+ print_exit_status(rc, status);
+ rc = 1;
+ }
+ do_exit(rc);
+}
+
+void set_owner(int fd)
+{
+ int rc;
+ long flags;
+
+ fprintf(logfp, "%d: Setting owner to myself\n", getpid());
+
+ signal(SIGIO, iohandler);
+
+ flags = O_ASYNC;
+ rc = fcntl(fd, F_SETFL, flags);
+ if (rc < 0) {
+ fprintf(logfp, "%d: set_owner(): F_SETFL ERROR %s\n", getpid(),
+ strerror(errno));
+ goto error;
+ }
+
+ rc = fcntl(fd, F_SETOWN, getpid());
+ if (rc < 0) {
+ fprintf(logfp, "%d: set_owner():, ERROR %s\n", getpid(),
+ strerror(errno));
+ if (errno == EINVAL)
+ fprintf(logfp, "%d: Maybe the fs does not support "
+ "F_SETLEASE (eg: NFS)\n", getpid());
+ goto error;
+ }
+
+ fprintf(logfp, "%d: Set owner() done\n", getpid());
+ return;
+
+error:
+ /*
+ * Parent will be waiting for notification. Signal that we failed
+ * and are exiting
+ */
+ kill(getppid(), SIGUSR1);
+ do_exit(1);
+}
+
+/*
+ * Called by parent to see if child is still the owner
+ */
+void test_owner(int fd, int exp_owner)
+{
+ int rc;
+
+ rc = fcntl(fd, F_GETOWN, 0);
+ if (rc < 0) {
+ fprintf(logfp, "%d: ERROR: fcntl(F_GETOWN) error %s\n",
+ getpid(), strerror(errno));
+ do_exit(1);
+ }
+
+ if (rc != exp_owner) {
+ fprintf(logfp, "%d: FAILED: Expected owner %d, actual %d\n",
+ getpid(), exp_owner, rc);
+ /*
+ * Terminate the child since it will not be notified of I/O.
+ */
+ kill(exp_owner, SIGKILL);
+ wait_for_child();
+ do_exit(1);
+ }
+
+ fprintf(logfp, "%d: PASS: Owner is %d\n", getpid(), exp_owner);
+ return;
+}
+
+int do_child()
+{
+ int rc;
+ char buf[16];
+ int fd = pipe_fds[0];
+
+ set_owner(fd);
+
+ /*
+ * Tell parent we are ready for checkpoint...
+ */
+ notify_one_event(event_fd1);
+
+ /*
+ * Read data from the pipe. If this synchronous read finds data
+ * without a SIGIO signal, then we were not notified and the
+ * test fails.
+ */
+ fprintf(logfp, "%d: Waiting for data to be available\n", getpid());
+ fflush(logfp);
+
+ rc = read(fd, buf, 4);
+ if (rc <= 0) {
+ fprintf(logfp, "%d: ERROR: read(): rc %d, error %s\n",
+ getpid(), rc, strerror(errno));
+ do_exit(1);
+ } else if (!got_sigio) {
+ fprintf(logfp, "%d: FAILED: read() found data but did not"
+ "get SIGIO, rc %d buf %.4s\n", getpid(),
+ rc, buf);
+ do_exit(1);
+ } else {
+ fprintf(logfp, "%d: PASS: Got SIGIO, read data, rc %d, "
+ "buf '%.4s'\n", getpid(), rc, buf);
+ do_exit(0);
+ }
+}
+
+/*
+ * Create a pipe that the child will try to read from and parent will
+ * write to.
+ */
+void setup_test_data()
+{
+ int rc;
+
+ rc = pipe(pipe_fds);
+ if (rc < 0) {
+ fprintf(logfp, "%d: pipe() failed, rc %d, error %s\n",
+ getpid(), rc, strerror(errno));
+ do_exit(1);
+ }
+
+ return;
+}
+
+void usr1_handler(int sig)
+{
+ /*
+ * Test failed or a child encountered an error.
+ * Reap the child, report error and exit.
+ */
+ fprintf(logfp, "%d: Signal %d, Test case FAILED\n", getpid(), sig);
+ fflush(logfp);
+
+ wait_for_child();
+}
+
+main(int argc, char *argv[])
+{
+ int i, status, rc;
+ int pid;
+
+ if (test_done()) {
+ printf("Remove %s before running test\n", TEST_DONE);
+ do_exit(1);
+ }
+
+ logfp = fopen(LOG_FILE, "w");
+ if (!logfp) {
+ perror("open() logfile");
+ do_exit(1);
+ }
+
+ printf("%s: Closing stdio fds and writing messages to %s\n",
+ argv[0], LOG_FILE);
+
+ for (i=0; i<100; i++) {
+ if (fileno(logfp) != i)
+ close(i);
+ }
+
+ setup_test_data();
+ event_fd1 = setup_notification();
+
+ /*
+ * Before waiting for events below, ensure we will be notified
+ * if a child encounters an error.
+ */
+ signal(SIGUSR1, usr1_handler);
+
+ /*
+ * Create the child process and wait for it to be ready for checkpoint.
+ */
+ pid = fork();
+ if (pid == 0)
+ do_child(i);
+
+ if (pid < 0) {
+ fprintf(logfp, "%d: fork() failed, rc %d, error %s\n", getpid(),
+ rc, strerror(errno));
+ do_exit(1);
+ }
+
+ wait_for_events(event_fd1, 1);
+
+ /*
+ * Tell any wrapper scripts, we are ready for checkpoint
+ */
+ set_checkpoint_ready();
+
+ fprintf(logfp, "%d: ***** Ready for checkpoint\n", getpid());
+ fflush(logfp);
+
+ /* Wait for wrappers to complete checkpoint/restart */
+ while(!test_done())
+ sleep(1);
+
+ /* Ensure that child is still owner for the read side of pipe */
+ test_owner(pipe_fds[0], pid);
+
+ /* Make data available on the pipe for the child */
+ rc = write(pipe_fds[1], "done", 4);
+ if (rc < 0) {
+ fprintf(logfp, "%d: write() failed, rc %d, error %s\n",
+ getpid(), rc, strerror(errno));
+ kill(pid, SIGKILL);
+ do_exit(1);
+ }
+
+ fflush(logfp);
+ wait_for_child();
+}
diff --git a/fileio/run-fsetown1.sh b/fileio/run-fsetown1.sh
new file mode 100755
index 0000000..535c544
--- /dev/null
+++ b/fileio/run-fsetown1.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+./run-fcntltests.sh fsetown1
diff --git a/fileio/runtests.sh b/fileio/runtests.sh
index e83f9cc..b808927 100755
--- a/fileio/runtests.sh
+++ b/fileio/runtests.sh
@@ -14,3 +14,8 @@ echo
echo "****** $0: Running test: filelease1"
echo
./run-fcntltests.sh filelease1
+
+echo
+echo "****** $0: Running test: fsetown1"
+echo
+./run-fcntltests.sh fsetown1
diff --git a/libcrtest/common.c b/libcrtest/common.c
index b29042a..c20da5e 100644
--- a/libcrtest/common.c
+++ b/libcrtest/common.c
@@ -58,7 +58,7 @@ void set_checkpoint_ready()
close(fd);
}
-static void print_exit_status(int pid, int status)
+void print_exit_status(int pid, int status)
{
fprintf(logfp, "Pid %d unexpected exit - ", pid);
if (WIFEXITED(status)) {
--
1.6.0.4
^ permalink raw reply related [flat|nested] 12+ messages in thread* [PATCH 08/11] filelock1: Extend for mandatory locks
[not found] ` <20100129202842.GA25490-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
` (5 preceding siblings ...)
2010-01-29 20:43 ` [PATCH 07/11] fsetown1: Test async I/O notification after restart Sukadev Bhattiprolu
@ 2010-01-29 20:43 ` Sukadev Bhattiprolu
2010-01-29 20:43 ` [PATCH 09/11] pthread1: Don't close stderr() before opening log Sukadev Bhattiprolu
` (2 subsequent siblings)
9 siblings, 0 replies; 12+ messages in thread
From: Sukadev Bhattiprolu @ 2010-01-29 20:43 UTC (permalink / raw)
To: serue-r/Jw6+rmf7HQT0dZR+AlfA; +Cc: Containers
From: Sukadev Bhattiprolu <sukadev-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
Date: Tue, 26 Jan 2010 19:38:28 -0800
Subject: [PATCH 08/11] filelock1: Extend for mandatory locks
Extend filelock1 to test for mandatory locks, when filelock1 is run
with the -m option.
Signed-off-by: Sukadev Bhattiprolu <sukadev-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
---
fileio/filelock1.c | 67 +++++++++++++++++++++++++++++++++++++++------
fileio/run-fcntltests.sh | 5 ++-
fileio/run-filelock1.sh | 2 +
3 files changed, 63 insertions(+), 11 deletions(-)
diff --git a/fileio/filelock1.c b/fileio/filelock1.c
index 19f7e3b..34e9ad2 100644
--- a/fileio/filelock1.c
+++ b/fileio/filelock1.c
@@ -4,6 +4,7 @@
#include <string.h>
#include <signal.h>
#include <errno.h>
+#include <sys/stat.h>
#include "libcrtest.h"
#define TEST_FILE "data.d/data.filelock1"
@@ -13,6 +14,7 @@ extern FILE *logfp;
int test_fd;
int event_fd1;
int event_fd2;
+int mandatory_locks = 1;
/*
* Description:
@@ -60,6 +62,9 @@ void set_lock(int fd, struct test_arg *tlock)
fprintf(logfp, "%d: set_lock(): ERROR [%d, %llu, %llu]: %s\n",
getpid(), tlock->type, (u64)tlock->start,
(u64)tlock->len, strerror(errno));
+ if (mandatory_locks)
+ fprintf(logfp, "\n\t***** Is the FS mounted with "
+ "'-o mand' option ?\n\n");
fflush(logfp);
kill(getppid(), SIGUSR1);
do_exit(1);
@@ -108,6 +113,9 @@ void test_lock(int fd, int locked_by_me, struct test_arg *tlock)
} else if (rc < 0) {
fprintf(logfp, "ERROR: fcntl(F_SETLK): %s, error %s\n",
lock_info, strerror(errno));
+ if (mandatory_locks)
+ fprintf(logfp, "\n\t***** Is the FS mounted with "
+ "'-o mand' option ?\n\n");
goto error;
}
@@ -215,8 +223,12 @@ int do_child1(int idx)
void setup_test_file()
{
char buf[256];
+ int mode;
+ int rc;
+
+ mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH; /* 0666 */
- test_fd = open(TEST_FILE, O_RDWR|O_CREAT|O_TRUNC, 0666);
+ test_fd = open(TEST_FILE, O_RDWR|O_CREAT|O_TRUNC, mode);
if (test_fd < 0) {
fprintf(logfp, "ERROR: open(%s): %s\n", TEST_FILE,
strerror(errno));
@@ -225,6 +237,23 @@ void setup_test_file()
memset(buf, 0, sizeof(buf));
write(test_fd, buf, sizeof(buf));
+
+ if (!mandatory_locks)
+ return;
+
+ /* Enable mandatory file locks (setgid, clear group execute) */
+ mode |= S_ISGID;
+ mode &= ~S_IXGRP;
+
+ rc = fchmod(test_fd, mode);
+ if (rc < 0) {
+ fprintf(logfp, "ERROR: fchmod(%s): rc %d, error %s\n",
+ TEST_FILE, rc, strerror(errno));
+ fprintf(logfp, "Maybe '-o mand' mount option is not set ?\n");
+ do_exit(1);
+ }
+ fprintf(logfp, "Mandatory locking set on %s, mode 0%o\n", TEST_FILE,
+ mode);
}
int pid1, pid2;
@@ -238,25 +267,32 @@ void child_handler(int sig)
if (sig == SIGCHLD)
do_wait(1);
+
fprintf(logfp, "%d: Test case FAILED\n", getpid());
fflush(logfp);
/*
* Kill (remaining) children and exit.
*/
- kill(pid1, SIGKILL);
- kill(pid2, SIGKILL);
+ if (pid1)
+ kill(pid1, SIGKILL);
+ if (pid2)
+ kill(pid2, SIGKILL);
do_exit(-1);
}
-main(int argc, char *argv[])
+usage(char *argv[])
{
- int i, status, rc;
+ fprintf(logfp, "Usage: %s [-m]\n", argv[0]);
+ fprintf(logfp, "\tTest POSIX (advisory) file locks (without -m)\n");
+ fprintf(logfp, "\t-m: Test mandatory file locks\n");
+ fprintf(logfp, "Test FAILED\n");
+ do_exit(1);
+}
- if (test_done()) {
- printf("Remove %s before running test\n", TEST_DONE);
- do_exit(1);
- }
+main(int argc, char *argv[])
+{
+ int i, c, status, rc;
logfp = fopen(LOG_FILE, "w");
if (!logfp) {
@@ -264,6 +300,19 @@ main(int argc, char *argv[])
do_exit(1);
}
+ mandatory_locks = 0;
+ while((c = getopt(argc, argv, "m")) != EOF) {
+ switch (c) {
+ case 'm': mandatory_locks = 1; break;
+ default: usage(argv);
+ }
+ }
+
+ if (test_done()) {
+ printf("Remove %s before running test\n", TEST_DONE);
+ do_exit(1);
+ }
+
printf("%s: Closing stdio fds and writing messages to %s\n",
argv[0], LOG_FILE);
diff --git a/fileio/run-fcntltests.sh b/fileio/run-fcntltests.sh
index 0b168e9..f76c942 100755
--- a/fileio/run-fcntltests.sh
+++ b/fileio/run-fcntltests.sh
@@ -2,12 +2,13 @@
source ../common.sh
-if [ $# -ne 1 ]; then
+if [ $# -lt 1 ]; then
echo "Usage: $0 <test-case>";
exit 1;
fi
test_case=$1;
+shift
if [ ! -x $test_case ]; then
echo "$0: Test case \'$test_case\' does not exist / not executable ?"
@@ -25,7 +26,7 @@ RESTART=`which restart`
ECHO="/bin/echo -e"
TEST_CMD="../$test_case"
-TEST_ARGS=""
+TEST_ARGS=$*
TEST_LOG="logs.d/log.${test_case}"
SCRIPT_LOG="logs.d/log.run-${test_case}"
TEST_PID_FILE="pid.${test_case}";
diff --git a/fileio/run-filelock1.sh b/fileio/run-filelock1.sh
index 554c24a..b7d5cd6 100755
--- a/fileio/run-filelock1.sh
+++ b/fileio/run-filelock1.sh
@@ -1,3 +1,5 @@
#!/bin/bash
./run-fcntltests.sh filelock1
+
+./run-fcntltests.sh filelock1 -m
--
1.6.0.4
^ permalink raw reply related [flat|nested] 12+ messages in thread* [PATCH 09/11] pthread1: Don't close stderr() before opening log
[not found] ` <20100129202842.GA25490-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
` (6 preceding siblings ...)
2010-01-29 20:43 ` [PATCH 08/11] filelock1: Extend for mandatory locks Sukadev Bhattiprolu
@ 2010-01-29 20:43 ` Sukadev Bhattiprolu
2010-01-29 20:44 ` [PATCH 10/11] filelock2: Test restart of process in F_GETLK Sukadev Bhattiprolu
2010-01-29 20:44 ` [PATCH 11/11] filelease2: Test C/R during lease-break-interval Sukadev Bhattiprolu
9 siblings, 0 replies; 12+ messages in thread
From: Sukadev Bhattiprolu @ 2010-01-29 20:43 UTC (permalink / raw)
To: serue-r/Jw6+rmf7HQT0dZR+AlfA; +Cc: Containers
From: Sukadev Bhattiprolu <sukadev-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
Date: Tue, 26 Jan 2010 22:47:24 -0800
Subject: [PATCH 09/11] pthread1: Don't close stderr() before opening log
If we encounter an error while opening the log file, we write to stderr.
In which case, we need the 'stderr' to remain open at least till the log
file is open.
Signed-off-by: Sukadev Bhattiprolu <sukadev-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
---
process-tree/pthread1.c | 12 +++++++++++-
1 files changed, 11 insertions(+), 1 deletions(-)
diff --git a/process-tree/pthread1.c b/process-tree/pthread1.c
index fa45127..d1743de 100644
--- a/process-tree/pthread1.c
+++ b/process-tree/pthread1.c
@@ -9,6 +9,10 @@
int num_threads = 5;
FILE *logfp;
+/*
+ * Use LOG_PREFIX with thread index as suffix, if each thread needs a
+ * separate log file. For now, we use a single log
+ */
#define LOG_PREFIX "logs.d/pthread1"
static void usage(char *argv[])
@@ -137,7 +141,6 @@ main(int argc, char *argv[])
pthread_t *tid_list;
char log_file[256];
- for (i=0; i<100; i++) close(i);
sprintf(log_file, "%s.log", LOG_PREFIX);
logfp = fopen(log_file, "w");
@@ -148,6 +151,13 @@ main(int argc, char *argv[])
do_exit(1);
}
+ fprintf(stderr, "Redirecting output to logfile %s\n", log_file);
+
+ for (i=0; i<100; i++) {
+ if (i != fileno(logfp))
+ close(i);
+ }
+
if (test_done()) {
printf("Remove %s before running test\n", TEST_DONE);
do_exit(1);
--
1.6.0.4
^ permalink raw reply related [flat|nested] 12+ messages in thread* [PATCH 10/11] filelock2: Test restart of process in F_GETLK
[not found] ` <20100129202842.GA25490-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
` (7 preceding siblings ...)
2010-01-29 20:43 ` [PATCH 09/11] pthread1: Don't close stderr() before opening log Sukadev Bhattiprolu
@ 2010-01-29 20:44 ` Sukadev Bhattiprolu
2010-01-29 20:44 ` [PATCH 11/11] filelease2: Test C/R during lease-break-interval Sukadev Bhattiprolu
9 siblings, 0 replies; 12+ messages in thread
From: Sukadev Bhattiprolu @ 2010-01-29 20:44 UTC (permalink / raw)
To: serue-r/Jw6+rmf7HQT0dZR+AlfA; +Cc: Containers
From: Sukadev Bhattiprolu <sukadev-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
Date: Wed, 27 Jan 2010 19:31:22 -0800
Subject: [PATCH 10/11] filelock2: Test restart of process in F_GETLK
Checkpoint a process that is waiting on a record lock in fcntl(F_GETLK).
Upon restart, ensure that it remains in fcntl(F_GETLK) and when the record
is unlocked, ensure that the process correctly gets the record lock.
Signed-off-by: Sukadev Bhattiprolu <sukadev-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
---
fileio/filelock2.c | 421 +++++++++++++++++++++++++++++++++++++++++++++++
fileio/run-filelock2.sh | 5 +
2 files changed, 426 insertions(+), 0 deletions(-)
create mode 100644 fileio/filelock2.c
create mode 100755 fileio/run-filelock2.sh
diff --git a/fileio/filelock2.c b/fileio/filelock2.c
new file mode 100644
index 0000000..e24ce54
--- /dev/null
+++ b/fileio/filelock2.c
@@ -0,0 +1,421 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include "libcrtest.h"
+
+#define TEST_FILE "data.d/data.filelock2"
+#define LOG_FILE "logs.d/log.filelock2"
+
+extern FILE *logfp;
+int test_fd;
+int event_fd1;
+int event_fd2;
+int mandatory_locks = 1;
+
+/*
+ * Description:
+ * Ensure that a process waiting for a range lock on a file the time
+ * of checkpoint is properly notified after restart from the checkpoint.
+ *
+ * Implementation:
+ * Process P1 acquires a F_WRLCK on a range and waits for checkpoint.
+ * Process P2 waits in F_SETLKW. After the checkpoint, P1 confirms
+ * that it still has the lock and then unlocks the range. P2 must
+ * return succesfully from the fcntl() and must acquire the lock.
+ */
+struct test_record {
+ int start;
+ int len;
+};
+
+struct test_record test_record = { 0, 17 };
+
+void set_lock(int fd, int lock_type, struct test_record *rec)
+{
+ int rc;
+ struct flock lock;
+
+ lock.l_type = lock_type;
+ lock.l_whence = SEEK_SET;
+ lock.l_start = (off_t)rec->start;
+ lock.l_len = (off_t)rec->len;
+
+ rc = fcntl(fd, F_SETLKW, &lock);
+ if (rc < 0 && errno != EAGAIN) {
+ fprintf(logfp, "%d: set_lock(): ERROR [%d, %llu, %llu]: %s\n",
+ getpid(), lock_type, (u64)rec->start,
+ (u64)rec->len, strerror(errno));
+ if (mandatory_locks)
+ fprintf(logfp, "\n\t***** Is the FS mounted with "
+ "'-o mand' option ?\n\n");
+ fflush(logfp);
+ kill(getppid(), SIGUSR1);
+ do_exit(1);
+ }
+
+ fprintf(logfp, "%d: set_lock(): [%d, %llu, %llu] %s\n", getpid(),
+ lock_type, (u64)rec->start, (u64)rec->len,
+ rc < 0 ? strerror(errno) : "done");
+}
+/*
+ * If @set is TRUE, ensure that the given lock is set.
+ * If @set is FALSE, ensure that the given lock is NOT set.
+ */
+void test_lock(int fd, int lock_type, struct test_record *rec)
+{
+ int rc;
+ int conflict;
+ struct flock lock;
+ char lock_info[512];
+
+ lock.l_type = lock_type;
+ lock.l_whence = SEEK_SET;
+ lock.l_start = (off_t)rec->start;
+ lock.l_len = (off_t)rec->len;
+ lock.l_pid = 0;
+
+ sprintf(lock_info, "lock [%d, %llu, %llu] ", lock_type,
+ (u64)rec->start, (u64)rec->len);
+
+ conflict = 0;
+ rc = fcntl(fd, F_SETLK, &lock);
+ if (rc < 0 && (errno == EAGAIN || errno == EACCES)) {
+ rc = fcntl(fd, F_GETLK, &lock);
+ if (rc < 0) {
+ fprintf(logfp, "ERROR: fcntl(F_GETLK): %s, error %s\n",
+ lock_info, strerror(errno));
+ goto error;
+ }
+
+ if (lock.l_type == F_UNLCK || lock.l_pid == 0) {
+ fprintf(logfp, "%d: ERROR: %s F_SETLK / F_GETLK "
+ "mismatch !!!\n", getpid(), lock_info);
+ goto error;
+ }
+ conflict = 1;
+ } else if (rc < 0) {
+ fprintf(logfp, "ERROR: fcntl(F_SETLK): %s, error %s\n",
+ lock_info, strerror(errno));
+ if (mandatory_locks)
+ fprintf(logfp, "\n\t***** Is the FS mounted with "
+ "'-o mand' option ?\n\n");
+ goto error;
+ }
+
+ fprintf(logfp, "%d: %s, conflict %d\n", getpid(), lock_info, conflict);
+
+ if (conflict) {
+ fprintf(logfp, "%d: FAIL: %s is NOT set by me !!!\n", getpid(),
+ lock_info);
+ goto error;
+ } else {
+ fprintf(logfp, "%d: PASS: %s is set by me\n", getpid(),
+ lock_info);
+ return;
+ }
+
+error:
+ fflush(logfp);
+ kill(getppid(), SIGUSR1);
+ do_exit(1);
+}
+
+void handler(int sig)
+{
+ /*
+ * We completed the test and sibling completed its test. Safe to
+ * exit.
+ */
+ fprintf(logfp, "%d: Ok to exit...\n", getpid());
+ fflush(logfp);
+ do_exit(0);
+}
+
+/*
+ * Notify parent that we are done testing and wait for a SIGINT to
+ * exit cleanly. Parent will wait for sibling to also exit and then
+ * signal us. This orderly exit will help parent distinguish this
+ * exit from an unexpected exit by the children.
+ */
+exit_cleanly()
+{
+ notify_one_event(event_fd2);
+ pause();
+ do_exit(0);
+}
+
+int do_child1(int idx)
+{
+ int rc;
+ int i;
+ int num_locks;
+ int failed;
+
+ fprintf(logfp, "%d: Child %d starting up\n", getpid(), idx);
+ fflush(logfp);
+
+ signal(SIGINT, handler);
+
+ set_lock(test_fd, F_WRLCK, &test_record);
+
+ /*
+ * Tell parent we are ready for checkpoint...
+ */
+ notify_one_event(event_fd1);
+
+ /*
+ * Wait for checkpoint/restart
+ */
+ fprintf(logfp, "%d: waiting for test-done\n", getpid());
+ fflush(logfp);
+ while(!test_done()) {
+ sleep(1);
+ }
+ fprintf(logfp, "%d: Found test-done\n", getpid());
+ fflush(logfp);
+
+ test_lock(test_fd, F_WRLCK, &test_record);
+
+ /*
+ * Drop our lock and exit. Sibling can then acquire the lock.
+ */
+ set_lock(test_fd, F_UNLCK, &test_record);
+
+ exit_cleanly();
+}
+
+int do_child2(int idx)
+{
+ int rc;
+ int i;
+ int num_locks;
+ int failed;
+
+ fprintf(logfp, "%d: Child %d starting up\n", getpid(), idx);
+ fflush(logfp);
+
+ signal(SIGINT, handler);
+
+ /*
+ * Tell parent we are about to get the lock.
+ * NOTE: There is still a window between now and when we actually
+ * block in the F_SETLK. But the parent has to guess and sleep()
+ * before enabling checkpoint.
+ */
+ notify_one_event(event_fd1);
+
+ /* This should block, until checkpoint/restart is done */
+ set_lock(test_fd, F_WRLCK, &test_record);
+
+ /*
+ * We must got here after checkpoint/restart. If not, something is
+ * wrong ?
+ */
+ if (!test_checkpoint_done()) {
+ fprintf(logfp, "Child2: ERROR: expected C/R to be done "
+ "by now, but is not ?\n");
+ do_exit(1);
+ }
+
+ /*
+ * Since we get here after checkpoint/restart, ensure we have the lock.
+ */
+ test_lock(test_fd, F_WRLCK, &test_record);
+
+ exit_cleanly();
+}
+
+/*
+ * Populate the test file so the children can lock some portions of
+ * the file
+ */
+void setup_test_file()
+{
+ char buf[256];
+ int mode;
+ int rc;
+
+ mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH; /* 0666 */
+
+ test_fd = open(TEST_FILE, O_RDWR|O_CREAT|O_TRUNC, mode);
+ if (test_fd < 0) {
+ fprintf(logfp, "ERROR: open(%s): %s\n", TEST_FILE,
+ strerror(errno));
+ do_exit(1);
+ }
+
+ memset(buf, 0, sizeof(buf));
+ write(test_fd, buf, sizeof(buf));
+
+ if (!mandatory_locks)
+ return;
+
+ /* Enable mandatory file locks (setgid, clear group execute) */
+ mode |= S_ISGID;
+ mode &= ~S_IXGRP;
+
+ rc = fchmod(test_fd, mode);
+ if (rc < 0) {
+ fprintf(logfp, "ERROR: fchmod(%s): rc %d, error %s\n",
+ TEST_FILE, rc, strerror(errno));
+ fprintf(logfp, "Maybe '-o mand' mount option is not set ?\n");
+ do_exit(1);
+ }
+ fprintf(logfp, "Mandatory locking set on %s, mode 0%o\n", TEST_FILE,
+ mode);
+}
+
+int pid1, pid2;
+
+kill_children(int sig)
+{
+ signal(SIGCHLD, SIG_DFL);
+ if (pid1)
+ kill(pid1, sig);
+
+ if (pid2)
+ kill(pid2, sig);
+ do_wait(2);
+}
+
+/*
+ * We get a SIGCHLD if a child exited prematurely. SIGUSR1 if child
+ * exited due to an error.
+ */
+void child_handler(int sig)
+{
+ fprintf(logfp, "%d: Got signal %d. Test case FAILED\n", getpid(), sig);
+ fflush(logfp);
+
+ /*
+ * Kill (remaining) children and exit.
+ */
+ kill_children(SIGKILL);
+
+ do_exit(-1);
+}
+
+usage(char *argv[])
+{
+ fprintf(logfp, "Usage: %s [-m]\n", argv[0]);
+ fprintf(logfp, "\tTest POSIX (advisory) file locks (without -m)\n");
+ fprintf(logfp, "\t-m: Test mandatory file locks\n");
+ fprintf(logfp, "Test FAILED\n");
+ do_exit(1);
+}
+
+int create_child(int idx, int (*child_func)(int))
+{
+ int rc;
+
+ rc = fork();
+ if (rc == 0)
+ (*child_func)(idx);
+
+ if (rc < 0) {
+ fprintf(logfp, "%d: fork() failed, error %s\n", getpid(),
+ strerror(errno));
+ kill_children(SIGKILL);
+ }
+
+ wait_for_events(event_fd1, 1);
+
+ return rc;
+}
+
+main(int argc, char *argv[])
+{
+ int i, c, status, rc;
+
+ logfp = fopen(LOG_FILE, "w");
+ if (!logfp) {
+ perror("open() logfile");
+ do_exit(1);
+ }
+
+ fprintf(logfp, "%d: Parent starting up\n", getpid());
+ fflush(logfp);
+
+ mandatory_locks = 0;
+ while((c = getopt(argc, argv, "m")) != EOF) {
+ switch (c) {
+ case 'm': mandatory_locks = 1; break;
+ default: usage(argv);
+ }
+ }
+
+ if (test_done()) {
+ printf("Remove %s before running test\n", TEST_DONE);
+ do_exit(1);
+ }
+
+ printf("%s: Closing stdio fds and writing messages to %s\n",
+ argv[0], LOG_FILE);
+
+ for (i=0; i<100; i++) {
+ if (fileno(logfp) != i)
+ close(i);
+ }
+
+ setup_test_file();
+ event_fd1 = setup_notification();
+ event_fd2 = setup_notification();
+
+ /*
+ * Before waiting for events below, ensure we will be notified
+ * if a child encounters an error and/or exits prematurely.
+ */
+ signal(SIGCHLD, child_handler);
+ signal(SIGUSR1, child_handler);
+
+ /*
+ * Create the first child and wait for it take its record lock.
+ */
+ pid1 = create_child(0, do_child1);
+
+ /*
+ * Create the second child and wait for it to block on the
+ * record lock.
+ *
+ */
+ pid2 = create_child(1, do_child2);
+
+ /*
+ * NOTE: We have some guessing to do here. The notification from
+ * the second child (in create_child()) just tells us that
+ * the child is _about_ to attempt the lock. Give it extra
+ * time to actually block before enabling checkpoint.
+ */
+ sleep(10);
+
+ /*
+ * Now that the test processes are ready, tell any wrapper scripts,
+ * we are ready for checkpoint.
+ */
+ set_checkpoint_ready();
+
+ fprintf(logfp, "***** %d: Ready for checkpoint\n", getpid());
+ fflush(logfp);
+
+ /*
+ * Wait for tests to finish their testing.
+ */
+ wait_for_events(event_fd2, 2);
+
+ /*
+ * Now tell them that it is safe to exit.
+ *
+ * NOTE: This orderly exit is needed to:
+ *
+ * - ensure we don't get stuck waiting for events, and,
+ * - enable us to distinguish normal and unexpected exits so
+ * we can properly report test status to wrapper scripts.
+ */
+ kill_children(SIGINT);
+
+ do_exit(0);
+}
diff --git a/fileio/run-filelock2.sh b/fileio/run-filelock2.sh
new file mode 100755
index 0000000..33934cb
--- /dev/null
+++ b/fileio/run-filelock2.sh
@@ -0,0 +1,5 @@
+#!/bin/bash
+
+./run-fcntltests.sh filelock2
+
+./run-fcntltests.sh filelock2 -m
--
1.6.0.4
^ permalink raw reply related [flat|nested] 12+ messages in thread* [PATCH 11/11] filelease2: Test C/R during lease-break-interval
[not found] ` <20100129202842.GA25490-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
` (8 preceding siblings ...)
2010-01-29 20:44 ` [PATCH 10/11] filelock2: Test restart of process in F_GETLK Sukadev Bhattiprolu
@ 2010-01-29 20:44 ` Sukadev Bhattiprolu
9 siblings, 0 replies; 12+ messages in thread
From: Sukadev Bhattiprolu @ 2010-01-29 20:44 UTC (permalink / raw)
To: serue-r/Jw6+rmf7HQT0dZR+AlfA; +Cc: Containers
From: Sukadev Bhattiprolu <sukadev-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
Date: Thu, 28 Jan 2010 23:18:50 -0800
Subject: [PATCH 11/11] filelease2: Test C/R during lease-break-interval
When a process, P1 (lease-owner of a file) is notified of an impending
lease-break (due to a conflicting open of the file by process P2 (lease-
breaker), have P1 "flush" some data to the file. Checkpoint processes
P1 and P2 before the kernel forcibly revokes the lease (i.e checkpoint
within the lease-break-interval).
Upon restart, verify that the P2's open() of the file completes properly
and that the data flushed by P1 is visible to P2.
NOTE:
This test passes even with out support for checkpoint of file-locks.
The reason for this is that the kernel terminates the lease of P1
before notifying P1 about the lease-break. Since we checkpoint while
P1 is in signal handler, neither P1 nor P2 have a lease and so the
C/R passes. Hopefully the data-comparison checks will catch some
errors during development. If not, we may need to redesign the test
or drop it later.
Signed-off-by: Sukadev Bhattiprolu <sukadev-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
---
fileio/Makefile | 4 +-
fileio/filelease2.c | 400 ++++++++++++++++++++++++++++++++++++++++++++++
fileio/run-filelease2.sh | 3 +
3 files changed, 405 insertions(+), 2 deletions(-)
create mode 100644 fileio/filelease2.c
create mode 100755 fileio/run-filelease2.sh
diff --git a/fileio/Makefile b/fileio/Makefile
index bd28561..4cf401b 100644
--- a/fileio/Makefile
+++ b/fileio/Makefile
@@ -1,4 +1,4 @@
-targets = fileio1 filelock1 filelease1 fsetown1
+targets = fileio1 filelock1 fsetown1 filelease1 filelease2
INCLUDE = ../libcrtest
LIBCRTEST = ../libcrtest/common.o
@@ -9,4 +9,4 @@ all: $(LIBCRTEST) $(targets)
clean:
rm -f $(targets)
- rm -rf cr_fileio* cr_filelock1* cr_filelease1* cr_fsetown1*
+ rm -rf cr_fileio* cr_filelock1* cr_filelease[12]* cr_fsetown1*
diff --git a/fileio/filelease2.c b/fileio/filelease2.c
new file mode 100644
index 0000000..1a53617
--- /dev/null
+++ b/fileio/filelease2.c
@@ -0,0 +1,400 @@
+#include <stdio.h>
+#include <unistd.h>
+#define __USE_GNU
+#include <fcntl.h>
+#include <string.h>
+#include <signal.h>
+#include <errno.h>
+#include <wait.h>
+#include "libcrtest.h"
+
+#define TEST_FILE1 "data.d/data.filelease2"
+#define LOG_FILE "logs.d/log.filelease2"
+
+int event_fd1;
+
+static int test_fd;
+static int got_sigio;
+static int num_children;
+static int pid1, pid2;
+char test_data[256];
+
+/*
+ * Description:
+ * Ensure that processes checkpointed when they are in the middle
+ * of a lease-break, are restored correctly.
+ *
+ * Implementation:
+ * Process P1 takes F_WRLCK lease on a file.
+ * Process P2 attempts to set F_WRLCK lease on the file
+ * Process P1 gets a SIGIO signal about the pending lease-break.
+ * Initiate a checkpoint before the downgrade is complete.
+ * After checkpoint/restart, ensure Process P1 still has the lease
+ * and that it can be downgraded.
+ * Ensure Process P2 gets the F_RDLCK lease.
+ */
+
+char *get_lease_desc(int type)
+{
+ switch(type) {
+ case F_RDLCK: return "F_RDLCK";
+ case F_WRLCK: return "F_WRLCK";
+ case F_UNLCK: return "F_UNLCK";
+ default: return "Unknown !";
+ }
+}
+
+void set_lease(int fd, int type)
+{
+ int rc;
+
+ fprintf(logfp, "%d: set_lease() called for fd %d, type %s\n",
+ getpid(), fd, get_lease_desc(type));
+
+ rc = fcntl(fd, F_SETLEASE, type);
+ if (rc < 0) {
+ fprintf(logfp, "%d: set_lease(type %d):, ERROR %s\n",
+ getpid(), type, strerror(errno));
+ if (errno == EINVAL)
+ fprintf(logfp, "%d: Maybe the fs does not support "
+ "F_SETLEASE (eg: NFS)\n", getpid());
+ fflush(logfp);
+ kill(getppid(), SIGUSR1);
+ do_exit(1);
+ }
+}
+
+void test_lease(int fd, int exp_type)
+{
+ int rc;
+
+ rc = fcntl(fd, F_GETLEASE, 0);
+ if (rc < 0 || rc > 2) {
+ fprintf(logfp, "ERROR: fcntl(F_GETLEASE): expected %s, rc %d, "
+ "error %s\n", get_lease_desc(exp_type), rc,
+ strerror(errno));
+ do_exit(1);
+ }
+
+ if (rc != exp_type) {
+ fprintf(logfp, "%d: FAIL: Expected %s, actual %s\n", getpid(),
+ get_lease_desc(exp_type), get_lease_desc(rc));
+ do_exit(1);
+ }
+
+ fprintf(logfp, "%d: PASS: Expected %s, actual %s\n", getpid(),
+ get_lease_desc(exp_type), get_lease_desc(rc));
+ return;
+}
+
+set_signal_action(int sig, void(*action)(int, siginfo_t *, void *))
+{
+ int rc;
+ struct sigaction act;
+
+ act.sa_sigaction = action;
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = SA_SIGINFO;
+
+ rc = sigaction(sig, &act, NULL);
+ if (rc < 0) {
+ fprintf(logfp, "%d: sigaction() sig %d failed, error %s\n",
+ getpid(), sig, strerror(errno));
+ do_exit(1);
+ }
+}
+
+static void iohandler(int sig, siginfo_t *info, void *arg)
+{
+ int rc;
+
+ got_sigio++;
+ fprintf(logfp, "%d: Got signal %d\n", getpid(), sig);
+ fflush(logfp);
+
+ /*
+ * Before giving up the lease, write some data to the file
+ */
+ rc = write(test_fd, test_data, sizeof(test_data));
+ if (rc != sizeof(test_data)) {
+ fprintf(logfp, "%d: write() failed, n %d, error %s\n", getpid(),
+ rc, strerror(errno));
+ do_exit(1);
+ }
+
+ set_checkpoint_ready();
+ fprintf(logfp, "***** %d: Ready for checkpoint\n", getpid());
+ fflush(logfp);
+
+ /*
+ * Wait for checkpoint/restart
+ */
+ while(!test_done())
+ sleep(1);
+
+ fprintf(logfp, "%d: Test-done\n", getpid());
+ fflush(logfp);
+
+ /*
+ * Checkpoint/restart is done, ensure we still have the lease
+ * and then terminate the lease.
+ *
+ * TODO: Looks like the lease is revoked even before the handler
+ * returns and hence the following test_lease() fails. This
+ * behavior is not obvious from the description of F_SETLEASE
+ * in the man page. Disable the test-lease() test for now
+ * (it does not affect C/R).
+ */
+ /* test_lease(test_fd, F_WRLCK); */
+
+ set_lease(test_fd, F_UNLCK);
+
+ return;
+}
+
+/* Lease holder */
+int do_child1(int idx)
+{
+ int type = F_WRLCK;
+
+ fprintf(logfp, "%d: Setting lease to type %s\n", getpid(),
+ get_lease_desc(type));
+ fflush(logfp);
+
+ set_signal_action(SIGIO, iohandler);
+
+ test_fd = open(TEST_FILE1, O_RDWR);
+ if (test_fd < 0) {
+ fprintf(logfp, "%d: open(%s) failed, error %s\n", getpid(),
+ TEST_FILE1, strerror(errno));
+ do_exit(1);
+ }
+
+ set_lease(test_fd, type);
+
+ /*
+ * Tell parent we are ready for checkpoint.
+ */
+ notify_one_event(event_fd1);
+
+ while(!got_sigio)
+ sleep(1);
+
+ do_exit(0);
+}
+
+/* Lease breaker */
+int do_child2(int idx)
+{
+ int rc;
+ int fd;
+ int type = F_WRLCK;
+ char buf[256];
+
+ fprintf(logfp, "%d: Setting lease to type %s\n", getpid(),
+ get_lease_desc(type));
+ fflush(logfp);
+
+ /*
+ * Tell parent we are (almost) ready for checkpoint.
+ */
+ notify_one_event(event_fd1);
+
+ /*
+ * To break the lease, open the file for write. This should block
+ * until sibling drops the lease (after Checkpoint/restart is done).
+ */
+ fd = open(TEST_FILE1, O_RDWR);
+ if (fd < 0) {
+ fprintf(logfp, "%d: open(%s) failed, error %s\n", getpid(),
+ TEST_FILE1, strerror(errno));
+ do_exit(1);
+ }
+
+ /*
+ * If checkpoint is not done yet, then maybe the lease-break-interval
+ * was not long enough for the wrapper scripts to complete checkpoint.
+ * So fail the test.
+ */
+ if (!test_checkpoint_done()) {
+ fprintf(logfp, "%d: Checkpoint not done yet ?\n", getpid());
+ do_exit(1);
+ }
+
+ rc = read(fd, buf, sizeof(test_data));
+ if (rc != sizeof(test_data)) {
+ fprintf(logfp, "%d: read() failed, rc %d, error %s\n",
+ getpid(), rc, strerror(errno));
+ do_exit(1);
+ }
+
+ if (memcmp(test_data, buf, sizeof(test_data))) {
+ fprintf(logfp, "%d: FAILED: Data miscompare !!!\n", getpid());
+ do_exit(1);
+ }
+
+ do_exit(0);
+}
+
+void setup_test_data()
+{
+ int rc;
+ int fd;
+ char buf[256];
+
+ rc = unlink(TEST_FILE1);
+ if (rc < 0 && errno != ENOENT) {
+ fprintf(logfp, "ERROR: unlink(%s): %s\n", TEST_FILE1,
+ strerror(errno));
+ do_exit(1);
+ }
+
+ fd = open(TEST_FILE1, O_RDWR|O_CREAT|O_TRUNC, 0666);
+ if (fd < 0) {
+ fprintf(logfp, "ERROR: open(%s): %s\n", TEST_FILE1,
+ strerror(errno));
+ do_exit(1);
+ }
+
+ memset(buf, 0, sizeof(buf));
+ write(fd, buf, sizeof(buf));
+
+ memset(test_data, 1, sizeof(test_data));
+ close(fd);
+
+ return;
+}
+
+kill_children(int sig)
+{
+ if (pid1)
+ kill(pid1, sig);
+ if (pid2)
+ kill(pid2, sig);
+ do_wait(2);
+}
+
+int create_child(int idx, int (*child_func)(int))
+{
+ int rc;
+
+ rc = fork();
+ if (rc == 0)
+ (*child_func)(idx);
+
+ if (rc < 0) {
+ fprintf(logfp, "%d: fork() failed, error %s\n", getpid(),
+ strerror(errno));
+ kill_children(SIGKILL);
+ }
+
+ fprintf(logfp, "%d: Created child %d, pid %d\n", getpid(), idx, rc);
+ fflush(logfp);
+
+ num_children++;
+ wait_for_events(event_fd1, 1);
+
+ return rc;
+}
+
+void child_handler(int sig, siginfo_t *info, void *arg)
+{
+ int i;
+ int rc;
+ int status;
+
+ fprintf(logfp, "%d: Got signal %d\n", getpid(), sig);
+ fflush(logfp);
+
+ if (sig == SIGUSR1)
+ goto failed;
+
+ while(num_children) {
+ rc = waitpid(-1, &status, WNOHANG);
+ if (rc < 0) {
+ fprintf(logfp, "%d: waitpid(): failed, rc %d, "
+ "error %s\n", getpid(), rc,
+ strerror(errno));
+ goto failed;
+ }
+
+ if (!rc)
+ break;
+
+ if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
+ num_children--;
+ else {
+ print_exit_status(info->si_pid, status);
+ goto failed;
+ }
+ }
+
+ if (!num_children) {
+ fprintf(logfp, "Both children exited cleanly, test passed\n");
+ do_exit(0);
+ }
+ return;
+
+failed:
+ kill_children(SIGKILL);
+ fprintf(logfp, "Test FAILED\n");
+ do_exit(1);
+}
+
+main(int argc, char *argv[])
+{
+ int i, status, rc;
+ int pid;
+
+ if (test_done()) {
+ printf("Remove %s before running test\n", TEST_DONE);
+ do_exit(1);
+ }
+
+ logfp = fopen(LOG_FILE, "w");
+ if (!logfp) {
+ perror("open() logfile");
+ do_exit(1);
+ }
+
+ printf("%s: Closing stdio fds and writing messages to %s\n",
+ argv[0], LOG_FILE);
+
+ for (i=0; i<100; i++) {
+ if (fileno(logfp) != i)
+ close(i);
+ }
+
+ setup_test_data();
+ event_fd1 = setup_notification();
+
+ /*
+ * Before waiting for events below, ensure we will be notified
+ * if a child encounters an error and/or exits prematurely.
+ */
+ set_signal_action(SIGUSR1, child_handler);
+ set_signal_action(SIGCHLD, child_handler);
+
+ pid1 = create_child(0, do_child1);
+
+ pid2 = create_child(1, do_child2);
+
+ /*
+ * NOTE: We have some guessing to do here. The notification from
+ * the second child (in create_child()) just tells us that
+ * the child is _about_ to attempt the lease. Give it extra
+ * time to actually block before enabling checkpoint.
+ *
+ * And this extra time must be less than the lease-break-window
+ * (set by the test wrapper-script.
+ */
+ sleep(10);
+
+ /*
+ * Just wait for children to exit and exit from SIGCHLD handler.
+ */
+ while(num_children)
+ pause();
+
+ do_exit(9); /* should not get here */
+}
diff --git a/fileio/run-filelease2.sh b/fileio/run-filelease2.sh
new file mode 100755
index 0000000..67de611
--- /dev/null
+++ b/fileio/run-filelease2.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+./run-fcntltests.sh filelease2
--
1.6.0.4
^ permalink raw reply related [flat|nested] 12+ messages in thread