diff options
Diffstat (limited to 'tests/basic')
288 files changed, 28914 insertions, 366 deletions
diff --git a/tests/basic/0symbol-check.t b/tests/basic/0symbol-check.t new file mode 100755 index 00000000000..69485a516af --- /dev/null +++ b/tests/basic/0symbol-check.t @@ -0,0 +1,46 @@ +#!/bin/bash +# + +. $(dirname $0)/../include.rc + +buildscratch="" + +case $OSTYPE in +Linux) + ;; +*) + echo "Skip Linux specific test" >&2 + SKIP_TESTS + exit 0 + ;; +esac + +# look in the usual places for the build tree +if [ -d /build/scratch ]; then + buildscratch="/build/scratch" +else + # might be in developer's tree + if [ -d ./libglusterfs/src/.libs ]; then + buildscratch="." + elif [ -d ../libglusterfs/src/.libs ]; then + buildscratch=".." + fi +fi + +if [ -z ${buildscratch} ]; then + echo "could find build tree in /build/scratch, . or .." >&2 + SKIP_TESTS + exit 0 +fi + +# check symbols + +rm -f ./.symbol-check-errors + +TEST find ${buildscratch} -name \*.o -exec ./tests/basic/symbol-check.sh {} \\\; + +TEST [ ! -e ./.symbol-check-errors ] + +rm -f ./.symbol-check-errors + +cleanup diff --git a/tests/basic/afr/add-brick-self-heal.t b/tests/basic/afr/add-brick-self-heal.t new file mode 100644 index 00000000000..c847e22977f --- /dev/null +++ b/tests/basic/afr/add-brick-self-heal.t @@ -0,0 +1,74 @@ +#!/bin/bash +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc +cleanup; + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 replica 2 $H0:$B0/${V0}{0,1} +EXPECT 'Created' volinfo_field $V0 'Status'; +TEST $CLI volume start $V0 +EXPECT 'Started' volinfo_field $V0 'Status'; +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}1 + +TEST $CLI volume set $V0 cluster.data-self-heal off +TEST $CLI volume set $V0 cluster.metadata-self-heal off +TEST $CLI volume set $V0 cluster.entry-self-heal off +TEST $CLI volume set $V0 cluster.heal-timeout 5 + +TEST $CLI volume set $V0 self-heal-daemon off +TEST $GFS --volfile-id=$V0 --volfile-server=$H0 $M0; + +# Create files +for i in {1..5} +do + echo $i > $M0/file$i.txt +done + +# Metadata changes +TEST setfattr -n user.test -v qwerty $M0/file5.txt + +# Add brick1 +TEST $CLI volume add-brick $V0 replica 3 $H0:$B0/${V0}2 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}2 + +# New-brick should accuse the old-bricks (Simulating case for data-loss) +TEST setfattr -n trusted.afr.$V0-client-0 -v 0x000000000000000000000001 $B0/${V0}2/ +TEST setfattr -n trusted.afr.$V0-client-1 -v 0x000000000000000000000001 $B0/${V0}2/ + +# Check if pending xattr and dirty-xattr are set for newly-added-brick +EXPECT "000000000000000100000001" get_hex_xattr trusted.afr.$V0-client-2 $B0/${V0}0 +EXPECT "000000000000000100000001" get_hex_xattr trusted.afr.$V0-client-2 $B0/${V0}1 +EXPECT "000000000000000000000001" get_hex_xattr trusted.afr.dirty $B0/${V0}2 + +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 2 + +TEST $CLI volume set $V0 self-heal-daemon on +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "Y" glustershd_up_status +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 1 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 2 +TEST $CLI volume heal $V0 + +# Wait for heal to complete +EXPECT_WITHIN $HEAL_TIMEOUT "^0$" get_pending_heal_count $V0 + +# Check if entry-heal has happened +TEST diff <(ls $B0/${V0}0 | sort) <(ls $B0/${V0}2 | sort) +TEST diff <(ls $B0/${V0}1 | sort) <(ls $B0/${V0}2 | sort) + +# Test if data was healed +TEST diff $B0/${V0}0/file1.txt $B0/${V0}2/file1.txt + +# Test if metadata was healed and exists on both the bricks +EXPECT "qwerty" get_text_xattr user.test $B0/${V0}2/file5.txt +EXPECT "qwerty" get_text_xattr user.test $B0/${V0}0/file5.txt + +EXPECT "000000000000000000000000" get_hex_xattr trusted.afr.$V0-client-2 $B0/${V0}0 +EXPECT "000000000000000000000000" get_hex_xattr trusted.afr.$V0-client-2 $B0/${V0}1 +EXPECT "000000000000000000000000" get_hex_xattr trusted.afr.dirty $B0/${V0}2 + +cleanup; diff --git a/tests/basic/afr/afr-anon-inode-no-quorum.t b/tests/basic/afr/afr-anon-inode-no-quorum.t new file mode 100644 index 00000000000..896ba0c9b2c --- /dev/null +++ b/tests/basic/afr/afr-anon-inode-no-quorum.t @@ -0,0 +1,63 @@ +#!/bin/bash + +#Test that anon-inode entry is not cleaned up as long as there exists at least +#one valid entry +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc +. $(dirname $0)/../../afr.rc + +cleanup; + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 replica 2 $H0:$B0/${V0}{0,1} +TEST $CLI volume heal $V0 disable +TEST $CLI volume set $V0 performance.write-behind off +TEST $CLI volume set $V0 performance.read-ahead off +TEST $CLI volume set $V0 performance.readdir-ahead off +TEST $CLI volume set $V0 performance.open-behind off +TEST $CLI volume set $V0 performance.stat-prefetch off +TEST $CLI volume set $V0 performance.io-cache off +TEST $CLI volume set $V0 performance.quick-read off +TEST $CLI volume set $V0 cluster.entry-self-heal off +TEST $CLI volume start $V0 + +TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0 + +TEST touch $M0/a $M0/b + +gfid_a=$(gf_gfid_xattr_to_str $(gf_get_gfid_xattr $B0/${V0}0/a)) +gfid_b=$(gf_gfid_xattr_to_str $(gf_get_gfid_xattr $B0/${V0}0/b)) +TEST kill_brick $V0 $H0 $B0/${V0}0 +TEST mv $M0/a $M0/a-new +TEST mv $M0/b $M0/b-new + +TEST $CLI volume start $V0 force +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status $V0 0 +TEST ! ls $M0/a +TEST ! ls $M0/b +anon_inode_name=$(ls -a $B0/${V0}0 | grep glusterfs-anonymous-inode) +TEST stat $B0/${V0}0/$anon_inode_name/$gfid_a +TEST stat $B0/${V0}0/$anon_inode_name/$gfid_b +#Make sure index heal doesn't happen after enabling heal +TEST setfattr -x trusted.afr.$V0-client-0 $B0/${V0}1 +TEST rm -f $B0/${V0}1/.glusterfs/indices/xattrop/* +TEST $CLI volume heal $V0 enable +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "Y" glustershd_up_status +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 1 +TEST $CLI volume heal $V0 +#Allow time for a scan +sleep 5 +TEST stat $B0/${V0}0/$anon_inode_name/$gfid_a +TEST stat $B0/${V0}0/$anon_inode_name/$gfid_b +inum_b=$(STAT_INO $B0/${V0}0/$anon_inode_name/$gfid_b) +TEST rm -f $M0/a-new +TEST stat $M0/b-new + +TEST $CLI volume heal $V0 +EXPECT_WITHIN $HEAL_TIMEOUT "^0$" afr_anon_entry_count $B0/${V0}0 +EXPECT_WITHIN $HEAL_TIMEOUT "^0$" afr_anon_entry_count $B0/${V0}1 +EXPECT "$inum_b" STAT_INO $B0/${V0}0/b-new + +cleanup diff --git a/tests/basic/afr/afr-anon-inode.t b/tests/basic/afr/afr-anon-inode.t new file mode 100644 index 00000000000..f4cf37a2fa0 --- /dev/null +++ b/tests/basic/afr/afr-anon-inode.t @@ -0,0 +1,114 @@ +#!/bin/bash +#Tests that afr-anon-inode test cases work fine as expected +#These are cases where in entry-heal/name-heal we dont know entry for an inode +#so these inodes are kept in a special directory + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc +. $(dirname $0)/../../afr.rc + +cleanup; + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 replica 3 $H0:$B0/${V0}{0..2} +TEST $CLI volume set $V0 performance.quick-read off +TEST $CLI volume set $V0 performance.io-cache off +TEST $CLI volume set $V0 performance.write-behind off +TEST $CLI volume set $V0 performance.stat-prefetch off +TEST $CLI volume set $V0 performance.read-ahead off +TEST $CLI volume set $V0 performance.open-behind off +TEST $CLI volume start $V0 +TEST $GFS --volfile-id=$V0 --volfile-server=$H0 $M0; +EXPECT "^1$" afr_private_key_value $V0 $M0 0 "use-anonymous-inode" +TEST $CLI volume set $V0 cluster.use-anonymous-inode no +EXPECT_WITHIN $CONFIG_UPDATE_TIMEOUT "^0$" afr_private_key_value $V0 $M0 0 "use-anonymous-inode" +TEST $CLI volume set $V0 cluster.use-anonymous-inode yes +EXPECT_WITHIN $CONFIG_UPDATE_TIMEOUT "^1$" afr_private_key_value $V0 $M0 0 "use-anonymous-inode" +TEST mkdir -p $M0/d1/b $M0/d2/a +TEST kill_brick $V0 $H0 $B0/${V0}0 +TEST mv $M0/d2/a $M0/d1 +TEST mv $M0/d1/b $M0/d2 +TEST $CLI volume start $V0 force +EXPECT_WITHIN $HEAL_TIMEOUT "^0$" get_pending_heal_count $V0 +anon_inode_name=$(ls -a $B0/${V0}0 | grep glusterfs-anonymous-inode) +TEST [[ -d $B0/${V0}1/$anon_inode_name ]] +TEST [[ -d $B0/${V0}2/$anon_inode_name ]] +anon_gfid=$(gf_get_gfid_xattr $B0/${V0}0/$anon_inode_name) +EXPECT "$anon_gfid" gf_get_gfid_xattr $B0/${V0}1/$anon_inode_name +EXPECT "$anon_gfid" gf_get_gfid_xattr $B0/${V0}2/$anon_inode_name + +TEST ! ls $M0/$anon_inode_name +EXPECT "^4$" echo $(ls -a $M0 | wc -l) + +#Test purging code path by shd +TEST $CLI volume heal $V0 disable +TEST mkdir $M0/l0 $M0/l1 $M0/l2 +TEST touch $M0/del-file $M0/del-file-nolink $M0/l0/file +TEST ln $M0/del-file $M0/del-file-link +TEST ln $M0/l0/file $M0/l1/file-link1 +TEST ln $M0/l0/file $M0/l2/file-link2 +TEST mkdir -p $M0/del-recursive-dir/d1 + +TEST kill_brick $V0 $H0 $B0/${V0}0 +TEST rm -f $M0/del-file $M0/del-file-nolink +TEST rm -rf $M0/del-recursive-dir +TEST mv $M0/d1/a $M0/d2 +TEST mv $M0/l0/file $M0/l0/renamed-file +TEST $CLI volume start $V0 force +EXPECT_WITHIN $CHILD_UP_TIMEOUT "^1$" afr_child_up_status $V0 0 + +nolink_gfid=$(gf_gfid_xattr_to_str $(gf_get_gfid_xattr $B0/${V0}0/del-file-nolink)) +link_gfid=$(gf_gfid_xattr_to_str $(gf_get_gfid_xattr $B0/${V0}0/del-file)) +dir_gfid=$(gf_gfid_xattr_to_str $(gf_get_gfid_xattr $B0/${V0}0/del-recursive-dir)) +rename_dir_gfid=$(gf_gfid_xattr_to_str $(gf_get_gfid_xattr $B0/${V0}0/d1/a)) +rename_file_gfid=$(gf_gfid_xattr_to_str $(gf_get_gfid_xattr $B0/${V0}0/l0/file)) +TEST ! stat $M0/del-file +TEST stat $B0/${V0}0/$anon_inode_name/$link_gfid +TEST ! stat $M0/del-file-nolink +TEST ! stat $B0/${V0}0/$anon_inode_name/$nolink_gfid +TEST ! stat $M0/del-recursive-dir +TEST stat $B0/${V0}0/$anon_inode_name/$dir_gfid +TEST ! stat $M0/d1/a +TEST stat $B0/${V0}0/$anon_inode_name/$rename_dir_gfid +TEST ! stat $M0/l0/file +TEST stat $B0/${V0}0/$anon_inode_name/$rename_file_gfid + +TEST kill_brick $V0 $H0 $B0/${V0}1 +TEST mv $M0/l1/file-link1 $M0/l1/renamed-file-link1 +TEST $CLI volume start $V0 force +EXPECT_WITHIN $CHILD_UP_TIMEOUT "^1$" afr_child_up_status $V0 1 +TEST ! stat $M0/l1/file-link1 +TEST stat $B0/${V0}1/$anon_inode_name/$rename_file_gfid + +TEST kill_brick $V0 $H0 $B0/${V0}2 +TEST mv $M0/l2/file-link2 $M0/l2/renamed-file-link2 +TEST $CLI volume start $V0 force +EXPECT_WITHIN $CHILD_UP_TIMEOUT "^1$" afr_child_up_status $V0 2 +TEST ! stat $M0/l2/file-link2 +TEST stat $B0/${V0}2/$anon_inode_name/$rename_file_gfid + +#Simulate only anon-inodes present in all bricks +TEST rm -f $M0/l0/renamed-file $M0/l1/renamed-file-link1 $M0/l2/renamed-file-link2 + +#Test that shd doesn't cleanup anon-inodes when some bricks are down +TEST kill_brick $V0 $H0 $B0/${V0}1 +TEST $CLI volume heal $V0 enable +$CLI volume heal $V0 +sleep 5 #Allow time for completion of one scan +TEST stat $B0/${V0}0/$anon_inode_name/$link_gfid +TEST stat $B0/${V0}0/$anon_inode_name/$rename_dir_gfid +TEST stat $B0/${V0}0/$anon_inode_name/$dir_gfid +rename_dir_inum=$(STAT_INO $B0/${V0}0/$anon_inode_name/$rename_dir_gfid) + +TEST $CLI volume start $V0 force +EXPECT_WITHIN $CHILD_UP_TIMEOUT "^1$" afr_child_up_status $V0 1 +EXPECT_WITHIN $HEAL_TIMEOUT "^0$" get_pending_heal_count $V0 +EXPECT_WITHIN $HEAL_TIMEOUT "^0$" afr_anon_entry_count $B0/${V0}0 +EXPECT_WITHIN $HEAL_TIMEOUT "^0$" afr_anon_entry_count $B0/${V0}1 +EXPECT_WITHIN $HEAL_TIMEOUT "^0$" afr_anon_entry_count $B0/${V0}2 + +#Test that rename indeed happened instead of rmdir/mkdir +renamed_dir_inum=$(STAT_INO $B0/${V0}0/d2/a) +EXPECT "$rename_dir_inum" echo $renamed_dir_inum +cleanup; diff --git a/tests/basic/afr/afr-no-fsync.t b/tests/basic/afr/afr-no-fsync.t new file mode 100644 index 00000000000..0966d9b0a11 --- /dev/null +++ b/tests/basic/afr/afr-no-fsync.t @@ -0,0 +1,20 @@ +#!/bin/bash +#Tests that sequential write workload doesn't lead to FSYNCs + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +cleanup; + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 replica 3 $H0:$B0/brick{0,1,3} +TEST $CLI volume set $V0 features.shard on +TEST $CLI volume set $V0 performance.flush-behind off +TEST $CLI volume start $V0 +TEST $CLI volume profile $V0 start +TEST $GFS --volfile-id=$V0 --volfile-server=$H0 $M0; +TEST dd if=/dev/zero of=$M0/a bs=1M count=500 +TEST ! "$CLI volume profile $V0 info incremental | grep FSYNC" + +cleanup; diff --git a/tests/basic/afr/afr-read-hash-mode.t b/tests/basic/afr/afr-read-hash-mode.t new file mode 100644 index 00000000000..eeff10d8ebd --- /dev/null +++ b/tests/basic/afr/afr-read-hash-mode.t @@ -0,0 +1,56 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +cleanup + +function reads_brick_count { + $CLI volume profile $V0 info incremental | grep -w READ | wc -l +} + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 replica 3 arbiter 1 $H0:$B0/${V0}{0..2} + +TEST $CLI volume set $V0 cluster.choose-local off +TEST $CLI volume set $V0 performance.quick-read off +TEST $CLI volume set $V0 performance.io-cache off +TEST $CLI volume set $V0 performance.write-behind off +TEST $CLI volume set $V0 performance.stat-prefetch off +TEST $CLI volume set $V0 performance.read-ahead off +TEST $CLI volume start $V0 + +# Disable all caching +TEST glusterfs --entry-timeout=0 --attribute-timeout=0 -s $H0 --volfile-id $V0 $M0 +TEST dd if=/dev/urandom of=$M0/FILE bs=1M count=8 +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 + +# TEST if the option gives the intended behavior. The way we perform this test +# is by performing reads from the mount and write to /dev/null. If the +# read-hash-mode is 3, then for a given file, more than 1 brick should serve the +# read-fops where as with the default read-hash-mode (i.e. 1), only 1 brick will. + +# read-hash-mode=1 +TEST glusterfs --entry-timeout=0 --attribute-timeout=0 -s $H0 --volfile-id $V0 $M0 +EXPECT "1" mount_get_option_value $M0 $V0-replicate-0 read-hash-mode +TEST $CLI volume profile $V0 start +TEST dd if=$M0/FILE of=/dev/null bs=1M +count=`reads_brick_count` +TEST [ $count -eq 1 ] +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 + +# read-hash-mode=3 +TEST glusterfs --entry-timeout=0 --attribute-timeout=0 -s $H0 --volfile-id $V0 $M0 +TEST $CLI volume set $V0 cluster.read-hash-mode 3 +EXPECT_WITHIN $CONFIG_UPDATE_TIMEOUT "3" mount_get_option_value $M0 $V0-replicate-0 read-hash-mode +TEST $CLI volume profile $V0 info clear +TEST dd if=$M0/FILE of=/dev/null bs=1M +count=`reads_brick_count` +TEST [ $count -eq 2 ] + +# Check that the arbiter did not serve any reads +arbiter_reads=$($CLI volume top $V0 read brick $H0:$B0/${V0}2|grep FILE|awk '{print $1}') +TEST [ -z $arbiter_reads ] + +cleanup; diff --git a/tests/basic/afr/afr-seek.t b/tests/basic/afr/afr-seek.t new file mode 100644 index 00000000000..c12ee011660 --- /dev/null +++ b/tests/basic/afr/afr-seek.t @@ -0,0 +1,55 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +cleanup + +SEEK=$(dirname $0)/seek +build_tester $(dirname $0)/../seek.c -o ${SEEK} + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume info + +TEST mkdir -p $B0/${V0}{0..2} +TEST $CLI volume create $V0 replica 3 $H0:$B0/${V0}{0..2} + +TEST $CLI volume start $V0 + +TEST $GFS -s $H0 --volfile-id $V0 $M0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 2 + +TEST ${SEEK} create ${M0}/test 0 1 1048576 1 +# Determine underlying filesystem allocation block size +BSIZE="$(($(${SEEK} scan ${M0}/test hole 0) * 2))" + +TEST ${SEEK} create ${M0}/test 0 ${BSIZE} $((${BSIZE} * 4 + 512)) ${BSIZE} + +EXPECT "^0$" ${SEEK} scan ${M0}/test data 0 +EXPECT "^$((${BSIZE} / 2))$" ${SEEK} scan ${M0}/test data $((${BSIZE} / 2)) +EXPECT "^$((${BSIZE} - 1))$" ${SEEK} scan ${M0}/test data $((${BSIZE} - 1)) +EXPECT "^$((${BSIZE} * 4))$" ${SEEK} scan ${M0}/test data ${BSIZE} +EXPECT "^$((${BSIZE} * 4))$" ${SEEK} scan ${M0}/test data $((${BSIZE} * 4)) +EXPECT "^$((${BSIZE} * 5))$" ${SEEK} scan ${M0}/test data $((${BSIZE} * 5)) +EXPECT "^$((${BSIZE} * 5 + 511))$" ${SEEK} scan ${M0}/test data $((${BSIZE} * 5 + 511)) +EXPECT "^ENXIO$" ${SEEK} scan ${M0}/test data $((${BSIZE} * 5 + 512)) +EXPECT "^ENXIO$" ${SEEK} scan ${M0}/test data $((${BSIZE} * 6)) + +EXPECT "^${BSIZE}$" ${SEEK} scan ${M0}/test hole 0 +EXPECT "^${BSIZE}$" ${SEEK} scan ${M0}/test hole $((${BSIZE} / 2)) +EXPECT "^${BSIZE}$" ${SEEK} scan ${M0}/test hole $((${BSIZE} - 1)) +EXPECT "^${BSIZE}$" ${SEEK} scan ${M0}/test hole ${BSIZE} +EXPECT "^$((${BSIZE} * 5 + 512))$" ${SEEK} scan ${M0}/test hole $((${BSIZE} * 4)) +EXPECT "^$((${BSIZE} * 5 + 512))$" ${SEEK} scan ${M0}/test hole $((${BSIZE} * 5)) +EXPECT "^$((${BSIZE} * 5 + 512))$" ${SEEK} scan ${M0}/test hole $((${BSIZE} * 5 + 511)) +EXPECT "^ENXIO$" ${SEEK} scan ${M0}/test hole $((${BSIZE} * 5 + 512)) +EXPECT "^ENXIO$" ${SEEK} scan ${M0}/test hole $((${BSIZE} * 6)) + +rm -f ${SEEK} +cleanup + +# Centos6 regression slaves seem to not support SEEK_DATA/SEEK_HOLE +#G_TESTDEF_TEST_STATUS_CENTOS6=BAD_TEST,BUG=000000 diff --git a/tests/basic/afr/afr-up.t b/tests/basic/afr/afr-up.t new file mode 100644 index 00000000000..428aac875e0 --- /dev/null +++ b/tests/basic/afr/afr-up.t @@ -0,0 +1,28 @@ +#!/bin/bash +#Tests that afr up/down works as expected + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc +. $(dirname $0)/../../afr.rc + +cleanup; + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 replica 3 $H0:$B0/${V0}{0,1,3,4,5,6} +TEST $CLI volume start $V0 +TEST $GFS --volfile-id=$V0 --volfile-server=$H0 $M0; +EXPECT "1" afr_up_status $V0 $M0 0 +EXPECT "1" afr_up_status $V0 $M0 1 + +#kill two bricks in first replica and check that afr_up_status is 0 for it +TEST kill_brick $V0 $H0 $B0/${V0}0 +TEST kill_brick $V0 $H0 $B0/${V0}1 + +EXPECT_WITHIN $PROCESS_DOWN_TIMEOUT "0" afr_up_status $V0 $M0 0 +EXPECT "1" afr_up_status $V0 $M0 1 + +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_up_status $V0 $M0 0 +EXPECT "1" afr_up_status $V0 $M0 1 +cleanup; diff --git a/tests/basic/afr/arbiter-add-brick.t b/tests/basic/afr/arbiter-add-brick.t new file mode 100644 index 00000000000..77b93d9a210 --- /dev/null +++ b/tests/basic/afr/arbiter-add-brick.t @@ -0,0 +1,86 @@ +#!/bin/bash +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc +cleanup; + +TEST glusterd +TEST pidof glusterd + +#Create replica 2 volume and create file/dir. +TEST $CLI volume create $V0 replica 2 $H0:$B0/${V0}{0,1} +TEST $CLI volume set $V0 performance.stat-prefetch off +TEST $CLI volume start $V0 +TEST $CLI volume set $V0 self-heal-daemon off +TEST $GFS --volfile-id=$V0 --volfile-server=$H0 $M0; +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 1 +TEST mkdir $M0/dir1 +TEST dd if=/dev/urandom of=$M0/file1 bs=1024 count=1 + +#Kill second brick and perform I/O to have pending heals. +TEST kill_brick $V0 $H0 $B0/${V0}1 +TEST mkdir $M0/dir2 +TEST dd if=/dev/urandom of=$M0/file1 bs=1024 count=1024 + + +#convert replica 2 to arbiter volume +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 1 + +#syntax check for add-brick. +TEST ! $CLI volume add-brick $V0 replica 2 arbiter 1 $H0:$B0/${V0}2 +TEST ! $CLI volume add-brick $V0 replica 3 arbiter 2 $H0:$B0/${V0}2 + +TEST $CLI volume add-brick $V0 replica 3 arbiter 1 $H0:$B0/${V0}2 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}2 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 2 + +#Trigger name heals from client. If we just rely on index heal, the first index +#crawl on B0 fails for /, dir2 and /file either due to lock collision or files +#not being present on the other 2 bricks yet. It is getting healed only in the +#next crawl after priv->shd.timeout (600 seconds) or by manually launching +#index heal again. +TEST $CLI volume set $V0 data-self-heal off +TEST $CLI volume set $V0 metadata-self-heal off +TEST $CLI volume set $V0 entry-self-heal off +TEST stat $M0/dir1 +TEST stat $M0/dir2 +TEST stat $M0/file1 + +#Heal files +TEST $CLI volume set $V0 self-heal-daemon on +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "Y" glustershd_up_status +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 1 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 2 +TEST $CLI volume heal $V0 +EXPECT_WITHIN $HEAL_TIMEOUT "0" get_pending_heal_count $V0 + +#Perform I/O after add-brick +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 2 +TEST mkdir $M0/dir3 +TEST dd if=/dev/urandom of=$M0/file2 bs=1024 count=1024 + +# File hierarchy must be same in all 3 bricks. +TEST diff <(ls $B0/${V0}0 | sort) <(ls $B0/${V0}2 | sort) +TEST diff <(ls $B0/${V0}1 | sort) <(ls $B0/${V0}2 | sort) + +#Mount serves the correct file size +EXPECT "1048576" stat -c %s $M0/file1 +EXPECT "1048576" stat -c %s $M0/file2 + +#Check file size in arbiter brick +EXPECT "0" stat -c %s $B0/${V0}2/file1 +EXPECT "0" stat -c %s $B0/${V0}2/file2 + +#Increasing replica count of arbiter volumes must not be allowed. +TEST ! $CLI volume add-brick $V0 replica 4 $H0:$B0/${V0}3 +TEST ! $CLI volume add-brick $V0 replica 4 arbiter 1 $H0:$B0/${V0}3 + +#Adding another distribute leg should succeed. +TEST $CLI volume add-brick $V0 replica 3 arbiter 1 $H0:$B0/${V0}{3..5} +TEST force_umount $M0 +cleanup; diff --git a/tests/basic/afr/arbiter-cli.t b/tests/basic/afr/arbiter-cli.t new file mode 100644 index 00000000000..ad79de79d02 --- /dev/null +++ b/tests/basic/afr/arbiter-cli.t @@ -0,0 +1,30 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc +. $(dirname $0)/../../afr.rc +cleanup; + +# Negative test cases for arbiter volume creation should not crash. + +TEST glusterd; +TEST pidof glusterd + +# No replica count. +TEST ! $CLI volume create $V0 arbiter 3 $H0:$B0/${V0}{0,1,2} + +# replica count given after arbiter count. +TEST ! $CLI volume create $V0 arbiter 1 replica 3 $H0:$B0/${V0}{0,1,2} + +# Incorrect values for replica and arbiter count. +TEST ! $CLI volume create $V0 replica 3 arbiter 2 $H0:$B0/${V0}{0,1,2} + +# Correct setup +# Only documented value is replica=2 and arbiter=1. +TEST $CLI volume create $V0 replica 2 arbiter 1 $H0:$B0/${V0}{0,1,2} + +# Earlier documents mentioned 'replica 3 arbiter 1' as the valid option +# Preserve backward compatibility till Oct, 2019. +TEST $CLI volume create ${V0}-old replica 3 arbiter 1 $H0:$B0/${V0}-old{0,1,2} + +cleanup diff --git a/tests/basic/afr/arbiter-mount.t b/tests/basic/afr/arbiter-mount.t new file mode 100644 index 00000000000..404d334d2f9 --- /dev/null +++ b/tests/basic/afr/arbiter-mount.t @@ -0,0 +1,48 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc +. $(dirname $0)/../../afr.rc +. $(dirname $0)/../../nfs.rc + +#G_TESTDEF_TEST_STATUS_CENTOS6=NFS_TEST + +cleanup; + +#Check that mounting fails when only arbiter brick is up. + +TEST glusterd; +TEST pidof glusterd + +TEST $CLI volume create $V0 replica 3 arbiter 1 $H0:$B0/${V0}{0,1,2} +TEST $CLI volume set $V0 nfs.disable false +TEST $CLI volume start $V0 +EXPECT 'Started' volinfo_field $V0 'Status' +EXPECT_WITHIN $NFS_EXPORT_TIMEOUT "1" is_nfs_export_available; + +TEST kill_brick $V0 $H0 $B0/${V0}0 +TEST kill_brick $V0 $H0 $B0/${V0}1 + +# Doing `mount -t glusterfs $H0:$V0 $M0` fails right away but doesn't work on NetBSD +# So check that stat <mount> fails instead. +TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0 +TEST ! stat $M0 +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 + +mount_nfs $H0:/$V0 $N0 +TEST [ $? -ne 0 ] + +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}1 +EXPECT_WITHIN $NFS_EXPORT_TIMEOUT "1" is_nfs_export_available; + +TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0 +TEST stat $M0 +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 + +mount_nfs $H0:/$V0 $N0 +TEST [ $? -eq 0 ] +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $N0 + +cleanup diff --git a/tests/basic/afr/arbiter-remove-brick.t b/tests/basic/afr/arbiter-remove-brick.t new file mode 100644 index 00000000000..ec93c8758e4 --- /dev/null +++ b/tests/basic/afr/arbiter-remove-brick.t @@ -0,0 +1,36 @@ +#!/bin/bash +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc +cleanup; + +TEST glusterd +TEST pidof glusterd + +#Create arbiter volume. +TEST $CLI volume create $V0 replica 3 arbiter 1 $H0:$B0/${V0}{0,1,2} +EXPECT "1 x \(2 \+ 1\) = 3" volinfo_field $V0 "Number of Bricks" +TEST $CLI volume set $V0 performance.stat-prefetch off +TEST $CLI volume start $V0 +TEST $GFS --volfile-id=$V0 --volfile-server=$H0 $M0; + +#syntax check for remove-brick. +TEST ! $CLI volume remove-brick $V0 replica 2 $H0:$B0/${V0}0 force +TEST ! $CLI volume remove-brick $V0 replica 2 $H0:$B0/${V0}1 force + +#convert to replica 2 volume +TEST $CLI volume remove-brick $V0 replica 2 $H0:$B0/${V0}2 force +EXPECT "1 x 2 = 2" volinfo_field $V0 "Number of Bricks" + +TEST mkdir $M0/dir +TEST dd if=/dev/urandom of=$M0/file bs=1024 count=1024 +TEST diff <(ls $B0/${V0}0 | sort) <(ls $B0/${V0}1 | sort) + +#Mount serves the correct file size +EXPECT "1048576" stat -c %s $M0/file + +#Check file size in bricks +EXPECT "1048576" stat -c %s $B0/${V0}0/file +EXPECT "1048576" stat -c %s $B0/${V0}1/file + +TEST force_umount $M0 +cleanup; diff --git a/tests/basic/afr/arbiter-statfs.t b/tests/basic/afr/arbiter-statfs.t new file mode 100644 index 00000000000..61cb9e1d04f --- /dev/null +++ b/tests/basic/afr/arbiter-statfs.t @@ -0,0 +1,41 @@ +#!/bin/bash +#Test that statfs is not served from the arbiter brick. + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +cleanup; +EXIT_EARLY=1 +TEST glusterd + +#Create brick partitions +TEST truncate -s 1G $B0/brick1 +TEST truncate -s 1G $B0/brick2 +#Arbiter brick is of a lesser size. +TEST truncate -s 90M $B0/brick3 +LO1=`SETUP_LOOP $B0/brick1` +TEST [ $? -eq 0 ] +TEST MKFS_LOOP $LO1 +LO2=`SETUP_LOOP $B0/brick2` +TEST [ $? -eq 0 ] +TEST MKFS_LOOP $LO2 +LO3=`SETUP_LOOP $B0/brick3` +TEST [ $? -eq 0 ] +TEST MKFS_LOOP $LO3 +TEST mkdir -p $B0/${V0}1 $B0/${V0}2 $B0/${V0}3 +TEST MOUNT_LOOP $LO1 $B0/${V0}1 +TEST MOUNT_LOOP $LO2 $B0/${V0}2 +TEST MOUNT_LOOP $LO3 $B0/${V0}3 + +TEST $CLI volume create $V0 replica 3 arbiter 1 $H0:$B0/${V0}{1,2,3}; +TEST $CLI volume start $V0 +TEST $GFS --volfile-server=$H0 --volfile-id=$V0 $M0 +free_space=$(df -P $M0 | tail -1 | awk '{ print $4}') +TEST [ $free_space -gt 100000 ] +TEST force_umount $M0 +TEST $CLI volume stop $V0 +EXPECT 'Stopped' volinfo_field $V0 'Status'; +TEST $CLI volume delete $V0; +UMOUNT_LOOP ${B0}/${V0}{1,2,3} +rm -f ${B0}/brick{1,2,3} +cleanup; diff --git a/tests/basic/afr/arbiter.t b/tests/basic/afr/arbiter.t new file mode 100644 index 00000000000..7c92a9fe6c9 --- /dev/null +++ b/tests/basic/afr/arbiter.t @@ -0,0 +1,92 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc +. $(dirname $0)/../../afr.rc +cleanup; + +TEST glusterd; +TEST pidof glusterd + +# Non arbiter replica 3 volumes should not have arbiter-count option enabled. +TEST mkdir -p $B0/${V0}{0,1,2} +TEST $CLI volume create $V0 replica 3 $H0:$B0/${V0}{0,1,2} +TEST $CLI volume start $V0 +EXPECT 'Started' volinfo_field $V0 'Status' +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}2 +TEST $GFS --volfile-id=$V0 --volfile-server=$H0 $M0; +TEST ! stat $M0/.meta/graphs/active/$V0-replicate-0/options/arbiter-count +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 +TEST $CLI volume stop $V0 +TEST $CLI volume delete $V0 + +# Make sure we clean up *all the way* so we don't get "brick X is already part +# of a volume" errors. +cleanup; +TEST glusterd; +TEST pidof glusterd + +# Create and mount a replica 3 arbiter volume. +TEST mkdir -p $B0/${V0}{0,1,2} +TEST $CLI volume create $V0 replica 3 arbiter 1 $H0:$B0/${V0}{0,1,2} +TEST $CLI volume set $V0 performance.write-behind off +TEST $CLI volume set $V0 performance.stat-prefetch off +TEST $CLI volume set $V0 cluster.self-heal-daemon off +TEST $CLI volume set $V0 cluster.metadata-self-heal off +TEST $CLI volume set $V0 cluster.data-self-heal off +TEST $CLI volume set $V0 cluster.entry-self-heal off +TEST $CLI volume start $V0 +EXPECT 'Started' volinfo_field $V0 'Status' +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}2 +TEST $GFS --volfile-id=$V0 --volfile-server=$H0 $M0; +TEST stat $M0/.meta/graphs/active/$V0-replicate-0/options/arbiter-count +EXPECT "1" cat $M0/.meta/graphs/active/$V0-replicate-0/options/arbiter-count + +# Write data and metadata +TEST `echo hello >> $M0/file` +TEST setfattr -n user.name -v value1 $M0/file + +# Data I/O will fail if arbiter is the only source. +TEST kill_brick $V0 $H0 $B0/${V0}0 +TEST `echo "B0 is down, B1 and B2 are sources" >> $M0/file` +TEST setfattr -n user.name -v value2 $M0/file +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0 +TEST kill_brick $V0 $H0 $B0/${V0}1 +echo "B2 is down, B3 is the only source, writes will fail" >> $M0/file +EXPECT_NOT "0" echo $? +TEST ! cat $M0/file +# Though metadata IO could have been served from arbiter, we do not allow it +# anymore as FOPS like getfattr could be overloaded to return iatt buffers for +# use by other translators. +TEST ! getfattr -n user.name $M0/file +TEST ! setfattr -n user.name -v value3 $M0/file + +#shd should not data self-heal from arbiter to the sinks. +TEST $CLI volume set $V0 cluster.self-heal-daemon on +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "Y" glustershd_up_status +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 2 +$CLI volume heal $V0 +EXPECT_WITHIN $HEAL_TIMEOUT '1' echo $(count_sh_entries $B0/$V0"1") +EXPECT_WITHIN $HEAL_TIMEOUT '1' echo $(count_sh_entries $B0/$V0"2") + +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "Y" glustershd_up_status +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 1 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 2 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 1 +TEST $CLI volume heal $V0 +EXPECT 0 get_pending_heal_count $V0 + +# I/O can resume again. +TEST cat $M0/file +TEST getfattr -n user.name $M0/file +TEST `echo append>> $M0/file` +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 +cleanup diff --git a/tests/basic/afr/client-side-heal.t b/tests/basic/afr/client-side-heal.t new file mode 100755 index 00000000000..1e9336184b5 --- /dev/null +++ b/tests/basic/afr/client-side-heal.t @@ -0,0 +1,95 @@ +#!/bin/bash +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +cleanup; + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 replica 2 $H0:$B0/${V0}{0,1} +TEST $CLI volume set $V0 cluster.self-heal-daemon off +TEST $CLI volume set $V0 cluster.entry-self-heal off +TEST $CLI volume set $V0 cluster.data-self-heal off +TEST $CLI volume set $V0 cluster.metadata-self-heal off + +TEST $CLI volume start $V0 +TEST $GFS --volfile-id=$V0 --volfile-server=$H0 $M0; +echo "some data" > $M0/datafile +EXPECT 0 echo $? +TEST touch $M0/mdatafile +TEST touch $M0/mdatafile-backend-direct-modify +TEST mkdir $M0/dir + +#Kill a brick and perform I/O to have pending heals. +TEST kill_brick $V0 $H0 $B0/${V0}0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "0" afr_child_up_status $V0 0 + +#pending data heal +echo "some more data" >> $M0/datafile +EXPECT 0 echo $? + +#pending metadata heal +TEST chmod +x $M0/mdatafile +TEST chmod +x $B0/${V0}0/mdatafile-backend-direct-modify + +#pending entry heal. Also causes pending metadata/data heals on file{1..5} +TEST touch $M0/dir/file{1..5} + +EXPECT 8 get_pending_heal_count $V0 + +#After brick comes back up, access from client should not trigger heals +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0 + +#Medatada heal via explicit lookup must not happen +TEST getfattr -d -m. -e hex $M0/mdatafile +TEST ls $M0/mdatafile-backend-direct-modify + +TEST [[ "$(stat -c %A $B0/${V0}0/mdatafile-backend-direct-modify)" != "$(stat -c %A $B0/${V0}1/mdatafile-backend-direct-modify)" ]] + +#Inode refresh must not trigger data metadata and entry heals. +#To trigger inode refresh for sure, the volume is unmounted and mounted each time. +#Check that data heal does not happen. +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 +TEST $GFS --volfile-id=$V0 --volfile-server=$H0 $M0; +TEST cat $M0/datafile +#Check that entry heal does not happen. +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 +TEST $GFS --volfile-id=$V0 --volfile-server=$H0 $M0; +TEST ls $M0/dir +#No heal must have happened +EXPECT 8 get_pending_heal_count $V0 + +#Enable heal client side heal options and trigger heals +TEST $CLI volume set $V0 cluster.data-self-heal on +TEST $CLI volume set $V0 cluster.metadata-self-heal on +TEST $CLI volume set $V0 cluster.entry-self-heal on + +#Inode refresh must trigger data metadata and entry heals. +#To trigger inode refresh for sure, the volume is unmounted and mounted each time. +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 +TEST $GFS --volfile-id=$V0 --volfile-server=$H0 $M0; +TEST ls $M0/mdatafile-backend-direct-modify + +TEST [[ "$(stat -c %A $B0/${V0}0/mdatafile-backend-direct-modify)" == "$(stat -c %A $B0/${V0}1/mdatafile-backend-direct-modify)" ]] + + +TEST getfattr -d -m. -e hex $M0/mdatafile +EXPECT_WITHIN $HEAL_TIMEOUT 7 get_pending_heal_count $V0 + +TEST cat $M0/datafile +EXPECT_WITHIN $HEAL_TIMEOUT 6 get_pending_heal_count $V0 + +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 +TEST $GFS --volfile-id=$V0 --volfile-server=$H0 $M0; +TEST ls $M0/dir +EXPECT_WITHIN $HEAL_TIMEOUT 5 get_pending_heal_count $V0 + +TEST cat $M0/dir/file1 +TEST cat $M0/dir/file2 +TEST cat $M0/dir/file3 +TEST cat $M0/dir/file4 +TEST cat $M0/dir/file5 + +EXPECT_WITHIN $HEAL_TIMEOUT 0 get_pending_heal_count $V0 +cleanup; diff --git a/tests/basic/afr/data-self-heal.t b/tests/basic/afr/data-self-heal.t new file mode 100644 index 00000000000..0f417b4a0ba --- /dev/null +++ b/tests/basic/afr/data-self-heal.t @@ -0,0 +1,209 @@ +#!/bin/bash +#Self-heal tests + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc +. $(dirname $0)/../../afr.rc +cleanup; + +function create_xattrop_entry { + local xattrop_dir0=$(afr_get_index_path $B0/brick0) + local xattrop_dir1=$(afr_get_index_path $B0/brick1) + local base_entry_b0=`ls $xattrop_dir0` + local base_entry_b1=`ls $xattrop_dir1` + local gfid_str + + for file in "$@" + do + gfid_str=$(gf_gfid_xattr_to_str $(gf_get_gfid_xattr $B0/brick0/$file)) + ln $xattrop_dir0/$base_entry_b0 $xattrop_dir0/$gfid_str + ln $xattrop_dir1/$base_entry_b1 $xattrop_dir1/$gfid_str + done +} + +function is_heal_done { + local f1_path="${1}/${3}" + local f2_path="${2}/${3}" + local zero_xattr="000000000000000000000000" + local size1=$(stat -c "%s" $f1_path) + local size2=$(stat -c "%s" $f2_path) + local diff=$((size1-size2)) + local xattr11=$(get_hex_xattr trusted.afr.$V0-client-0 $f1_path) + local xattr12=$(get_hex_xattr trusted.afr.$V0-client-1 $f1_path) + local xattr21=$(get_hex_xattr trusted.afr.$V0-client-0 $f2_path) + local xattr22=$(get_hex_xattr trusted.afr.$V0-client-1 $f2_path) + local dirty1=$(get_hex_xattr trusted.afr.dirty $f1_path) + local dirty2=$(get_hex_xattr trusted.afr.dirty $f2_path) + if [ -z $xattr11 ]; then xattr11="000000000000000000000000"; fi + if [ -z $xattr12 ]; then xattr12="000000000000000000000000"; fi + if [ -z $xattr21 ]; then xattr21="000000000000000000000000"; fi + if [ -z $xattr22 ]; then xattr22="000000000000000000000000"; fi + if [ -z $dirty1 ]; then dirty1="000000000000000000000000"; fi + if [ -z $dirty2 ]; then dirty2="000000000000000000000000"; fi + if [ "${diff}${xattr11}${xattr12}${xattr21}${xattr22}${dirty1}${dirty2}" == "0${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}" ]; + then + echo "Y" + else + echo "N" + fi +} + +function print_pending_heals { + local result=":" + for i in "$@"; + do + if [ "N" == $(is_heal_done $B0/brick0 $B0/brick1 $i) ]; + then + result="$result:$i" + fi + done +#To prevent any match for EXPECT_WITHIN, print a char non-existent in file-names + if [ $result == ":" ]; then result="~"; fi + echo $result +} + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 replica 2 $H0:$B0/brick{0,1} +TEST $CLI volume set $V0 cluster.background-self-heal-count 0 +TEST $CLI volume set $V0 performance.write-behind off +TEST $CLI volume set $V0 performance.read-ahead off +TEST $CLI volume set $V0 performance.io-cache off +TEST $CLI volume set $V0 performance.stat-prefetch off +TEST $CLI volume set $V0 performance.quick-read off +TEST $CLI volume set $V0 performance.open-behind off + +TEST $CLI volume start $V0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "Y" glustershd_up_status +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 1 +TEST $GFS --volfile-id=$V0 --volfile-server=$H0 $M0; +cd $M0 +TEST touch pending-changelog biggest-file-source.txt biggest-file-more-prio-than-changelog.txt same-size-more-prio-to-changelog.txt size-and-witness-same.txt self-accusing-vs-source.txt self-accusing-both.txt self-accusing-vs-innocent.txt self-accusing-bigger-exists.txt size-more-prio-than-self-accused.txt v1-dirty.txt split-brain.txt split-brain-all-dirty.txt split-brain-with-dirty.txt + +TEST setfattr -n trusted.afr.$V0-client-1 -v 0x000000010000000000000000 $B0/brick0/pending-changelog +TEST "echo abc > $B0/brick1/pending-changelog" + +TEST "echo abc > $B0/brick0/biggest-file-source.txt" +TEST "echo abcd > $B0/brick1/biggest-file-source.txt" + +TEST "echo abc > $B0/brick0/biggest-file-more-prio-than-changelog.txt" +TEST "echo abcd > $B0/brick1/biggest-file-more-prio-than-changelog.txt" +TEST setfattr -n trusted.afr.dirty -v 0x000000200000000000000000 $B0/brick0/biggest-file-more-prio-than-changelog.txt + +TEST "echo abc > $B0/brick0/same-size-more-prio-to-changelog.txt" +TEST "echo def > $B0/brick1/same-size-more-prio-to-changelog.txt" +TEST setfattr -n trusted.afr.dirty -v 0x000000200000000000000000 $B0/brick0/same-size-more-prio-to-changelog.txt + +TEST "echo abc > $B0/brick0/size-and-witness-same.txt" +TEST "echo def > $B0/brick1/size-and-witness-same.txt" +TEST setfattr -n trusted.afr.dirty -v 0x000000200000000000000000 $B0/brick0/size-and-witness-same.txt +TEST setfattr -n trusted.afr.dirty -v 0x000000200000000000000000 $B0/brick1/size-and-witness-same.txt + +TEST "echo abc > $B0/brick0/split-brain.txt" +TEST "echo def > $B0/brick1/split-brain.txt" +TEST setfattr -n trusted.afr.$V0-client-1 -v 0x000000200000000000000000 $B0/brick0/split-brain.txt +TEST setfattr -n trusted.afr.$V0-client-0 -v 0x000000200000000000000000 $B0/brick1/split-brain.txt + +TEST "echo abc > $B0/brick0/split-brain-all-dirty.txt" +TEST "echo def > $B0/brick1/split-brain-all-dirty.txt" +TEST setfattr -n trusted.afr.$V0-client-1 -v 0x000000200000000000000000 $B0/brick0/split-brain-all-dirty.txt +TEST setfattr -n trusted.afr.$V0-client-0 -v 0x000000200000000000000000 $B0/brick1/split-brain-all-dirty.txt +TEST setfattr -n trusted.afr.dirty -v 0x000000200000000000000000 $B0/brick0/split-brain-all-dirty.txt +TEST setfattr -n trusted.afr.dirty -v 0x000000200000000000000000 $B0/brick1/split-brain-all-dirty.txt + +TEST "echo abc > $B0/brick0/split-brain-with-dirty.txt" +TEST "echo def > $B0/brick1/split-brain-with-dirty.txt" +TEST setfattr -n trusted.afr.$V0-client-1 -v 0x000000200000000000000000 $B0/brick0/split-brain-with-dirty.txt +TEST setfattr -n trusted.afr.$V0-client-0 -v 0x000000200000000000000000 $B0/brick1/split-brain-with-dirty.txt +TEST setfattr -n trusted.afr.dirty -v 0x000000200000000000000000 $B0/brick1/split-brain-with-dirty.txt + +TEST "echo def > $B0/brick1/self-accusing-vs-source.txt" +TEST "echo abc > $B0/brick0/self-accusing-vs-source.txt" +TEST setfattr -n trusted.afr.$V0-client-0 -v 0x000000200000000000000000 $B0/brick1/self-accusing-vs-source.txt +TEST setfattr -n trusted.afr.$V0-client-1 -v 0x000000200000000000000000 $B0/brick1/self-accusing-vs-source.txt +TEST setfattr -n trusted.afr.$V0-client-1 -v 0x000000200000000000000000 $B0/brick0/self-accusing-vs-source.txt + +TEST "echo abc > $B0/brick0/self-accusing-both.txt" +TEST "echo def > $B0/brick1/self-accusing-both.txt" +TEST setfattr -n trusted.afr.$V0-client-0 -v 0x000000200000000000000000 $B0/brick0/self-accusing-both.txt +TEST setfattr -n trusted.afr.$V0-client-1 -v 0x000000200000000000000000 $B0/brick0/self-accusing-both.txt +TEST setfattr -n trusted.afr.$V0-client-0 -v 0x000000200000000000000000 $B0/brick1/self-accusing-both.txt +TEST setfattr -n trusted.afr.$V0-client-1 -v 0x000000200000000000000000 $B0/brick1/self-accusing-both.txt + +TEST "echo abc > $B0/brick0/self-accusing-vs-innocent.txt" +TEST "echo def > $B0/brick1/self-accusing-vs-innocent.txt" +TEST setfattr -n trusted.afr.$V0-client-1 -v 0x000000200000000000000000 $B0/brick1/self-accusing-vs-innocent.txt + +TEST "echo abc > $B0/brick0/self-accusing-bigger-exists.txt" +TEST "echo def > $B0/brick1/self-accusing-bigger-exists.txt" +TEST setfattr -n trusted.afr.$V0-client-0 -v 0x000000200000000000000000 $B0/brick0/self-accusing-bigger-exists.txt +TEST setfattr -n trusted.afr.$V0-client-1 -v 0x000000300000000000000000 $B0/brick0/self-accusing-bigger-exists.txt +TEST setfattr -n trusted.afr.$V0-client-0 -v 0x000000200000000000000000 $B0/brick1/self-accusing-bigger-exists.txt +TEST setfattr -n trusted.afr.$V0-client-1 -v 0x000000200000000000000000 $B0/brick1/self-accusing-bigger-exists.txt + +TEST "echo abc > $B0/brick0/size-more-prio-than-self-accused.txt" +TEST "echo defg > $B0/brick1/size-more-prio-than-self-accused.txt" +TEST setfattr -n trusted.afr.$V0-client-0 -v 0x000000200000000000000000 $B0/brick0/size-more-prio-than-self-accused.txt +TEST setfattr -n trusted.afr.$V0-client-1 -v 0x000000300000000000000000 $B0/brick0/size-more-prio-than-self-accused.txt +TEST setfattr -n trusted.afr.$V0-client-0 -v 0x000000200000000000000000 $B0/brick1/size-more-prio-than-self-accused.txt +TEST setfattr -n trusted.afr.$V0-client-1 -v 0x000000200000000000000000 $B0/brick1/size-more-prio-than-self-accused.txt + +TEST "echo abc > $B0/brick0/v1-dirty.txt" +TEST "echo def > $B0/brick1/v1-dirty.txt" +TEST setfattr -n trusted.afr.$V0-client-0 -v 0x000000200000000000000000 $B0/brick0/v1-dirty.txt +TEST setfattr -n trusted.afr.$V0-client-1 -v 0x000000100000000000000000 $B0/brick1/v1-dirty.txt + +#Create base entry in indices/xattrop +echo "Data" > $M0/FILE +rm -f $M0/FILE +EXPECT "1" count_index_entries $B0/brick0 +EXPECT "1" count_index_entries $B0/brick1 +cd - + +#Create gfid hard links for all files before triggering index heals. +create_xattrop_entry pending-changelog biggest-file-source.txt biggest-file-more-prio-than-changelog.txt same-size-more-prio-to-changelog.txt size-and-witness-same.txt self-accusing-vs-source.txt self-accusing-both.txt self-accusing-vs-innocent.txt self-accusing-bigger-exists.txt size-more-prio-than-self-accused.txt v1-dirty.txt + +TEST $CLI volume heal $V0 +EXPECT_WITHIN $HEAL_TIMEOUT "~" print_pending_heals pending-changelog biggest-file-source.txt biggest-file-more-prio-than-changelog.txt same-size-more-prio-to-changelog.txt size-and-witness-same.txt self-accusing-vs-source.txt self-accusing-both.txt self-accusing-vs-innocent.txt self-accusing-bigger-exists.txt size-more-prio-than-self-accused.txt v1-dirty.txt +EXPECT "N" is_heal_done $B0/brick0 $B0/brick1 split-brain.txt +EXPECT "N" is_heal_done $B0/brick0 $B0/brick1 split-brain-all-dirty.txt +EXPECT "N" is_heal_done $B0/brick0 $B0/brick1 split-brain-with-dirty.txt + +EXPECT "0" stat -c "%s" $M0/pending-changelog +TEST cmp $B0/brick0/pending-changelog $B0/brick1/pending-changelog + +EXPECT "abcd" cat $M0/biggest-file-source.txt +TEST cmp $B0/brick0/biggest-file-source.txt $B0/brick1/biggest-file-source.txt + +EXPECT "abcd" cat $M0/biggest-file-more-prio-than-changelog.txt +TEST cmp $B0/brick0/biggest-file-more-prio-than-changelog.txt $B0/brick1/biggest-file-more-prio-than-changelog.txt + +EXPECT "abc" cat $M0/same-size-more-prio-to-changelog.txt +TEST cmp $B0/brick0/same-size-more-prio-to-changelog.txt $B0/brick1/same-size-more-prio-to-changelog.txt + +EXPECT "(abc|def)" cat $M0/size-and-witness-same.txt +TEST cmp $B0/brick0/size-and-witness-same.txt $B0/brick1/size-and-witness-same.txt + +TEST ! cat $M0/split-brain.txt +TEST ! cat $M0/split-brain-all-dirty.txt +TEST ! cat $M0/split-brain-with-dirty.txt + +EXPECT "abc" cat $M0/self-accusing-vs-source.txt +TEST cmp $B0/brick0/self-accusing-vs-source.txt $B0/brick1/self-accusing-vs-source.txt + +EXPECT "(abc|def)" cat $M0/self-accusing-both.txt +TEST cmp $B0/brick0/self-accusing-both.txt $B0/brick1/self-accusing-both.txt + +EXPECT "def" cat $M0/self-accusing-vs-innocent.txt +TEST cmp $B0/brick0/self-accusing-vs-innocent.txt $B0/brick1/self-accusing-vs-innocent.txt + +EXPECT "abc" cat $M0/self-accusing-bigger-exists.txt +TEST cmp $B0/brick0/self-accusing-bigger-exists.txt $B0/brick1/self-accusing-bigger-exists.txt + +EXPECT "defg" cat $M0/size-more-prio-than-self-accused.txt +TEST cmp $B0/brick0/size-more-prio-than-self-accused.txt $B0/brick1/size-more-prio-than-self-accused.txt + +EXPECT "abc" cat $M0/v1-dirty.txt +TEST cmp $B0/brick0/v1-dirty.txt $B0/brick1/v1-dirty.txt +cleanup; diff --git a/tests/basic/afr/durability-off.t b/tests/basic/afr/durability-off.t new file mode 100644 index 00000000000..6e0f18b88f8 --- /dev/null +++ b/tests/basic/afr/durability-off.t @@ -0,0 +1,46 @@ +#!/bin/bash +#This test tests that self-heals don't perform fsync when durability is turned +#off + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +cleanup; + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 replica 2 $H0:$B0/brick{0,1} +TEST $CLI volume start $V0 +TEST $CLI volume profile $V0 start +TEST $CLI volume set $V0 cluster.ensure-durability off +TEST $GFS --volfile-id=$V0 --volfile-server=$H0 $M0; +TEST kill_brick $V0 $H0 $B0/brick0 +TEST dd of=$M0/a.txt if=/dev/zero bs=1024k count=1 +#NetBSD sends FSYNC so the counts go for a toss. Stop and start the volume. +TEST $CLI volume stop $V0 +TEST $CLI volume start $V0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "Y" glustershd_up_status +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 1 +TEST $CLI volume heal $V0 +EXPECT_WITHIN $HEAL_TIMEOUT "0" get_pending_heal_count $V0 +EXPECT "^0$" echo $($CLI volume profile $V0 info | grep -w FSYNC | wc -l) + +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status $V0 0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status $V0 1 +#Test that fsyncs happen when durability is on +TEST $CLI volume set $V0 cluster.ensure-durability on +TEST $CLI volume set $V0 performance.strict-write-ordering on +TEST kill_brick $V0 $H0 $B0/brick0 +TEST dd of=$M0/a.txt if=/dev/zero bs=1024k count=1 +#NetBSD sends FSYNC so the counts go for a toss. Stop and start the volume. +TEST $CLI volume stop $V0 +TEST $CLI volume start $V0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "Y" glustershd_up_status +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 1 +TEST $CLI volume heal $V0 +EXPECT_WITHIN $HEAL_TIMEOUT "0" get_pending_heal_count $V0 +EXPECT "^2$" echo $($CLI volume profile $V0 info | grep -w FSYNC | wc -l) + +cleanup; diff --git a/tests/basic/afr/entry-self-heal-anon-dir-off.t b/tests/basic/afr/entry-self-heal-anon-dir-off.t new file mode 100644 index 00000000000..7bb6ee14193 --- /dev/null +++ b/tests/basic/afr/entry-self-heal-anon-dir-off.t @@ -0,0 +1,459 @@ +#!/bin/bash + +#This file checks if missing entry self-heal and entry self-heal are working +#as expected. +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc +. $(dirname $0)/../../afr.rc + +cleanup; + +function get_file_type { + stat -c "%a:%F:%g:%t:%T:%u" $1 +} + +function diff_dirs { + diff <(ls $1 | sort) <(ls $2 | sort) +} + +function heal_status { + local f1_path="${1}/${3}" + local f2_path="${2}/${3}" + local insync="" + diff_dirs $f1_path $f2_path + if [ $? -eq 0 ]; + then + insync="Y" + else + insync="N" + fi + local xattr11=$(get_hex_xattr trusted.afr.$V0-client-0 $f1_path) + local xattr12=$(get_hex_xattr trusted.afr.$V0-client-1 $f1_path) + local xattr21=$(get_hex_xattr trusted.afr.$V0-client-0 $f2_path) + local xattr22=$(get_hex_xattr trusted.afr.$V0-client-1 $f2_path) + local dirty1=$(get_hex_xattr trusted.afr.dirty $f1_path) + local dirty2=$(get_hex_xattr trusted.afr.dirty $f2_path) + if [ -z $xattr11 ]; then xattr11="000000000000000000000000"; fi + if [ -z $xattr12 ]; then xattr12="000000000000000000000000"; fi + if [ -z $xattr21 ]; then xattr21="000000000000000000000000"; fi + if [ -z $xattr22 ]; then xattr22="000000000000000000000000"; fi + if [ -z $dirty1 ]; then dirty1="000000000000000000000000"; fi + if [ -z $dirty2 ]; then dirty2="000000000000000000000000"; fi + echo ${insync}${xattr11}${xattr12}${xattr21}${xattr22}${dirty1}${dirty2} +} + +function is_heal_done { + local zero_xattr="000000000000000000000000" + if [ "$(heal_status $@)" == "Y${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}" ]; + then + echo "Y" + else + echo "N" + fi +} + +function print_pending_heals { + local result=":" + for i in "$@"; + do + if [ "N" == $(is_heal_done $B0/${V0}0 $B0/${V0}1 $i) ]; + then + result="$result:$i" + fi + done +#To prevent any match for EXPECT_WITHIN, print a char non-existent in file-names + if [ $result == ":" ]; then result="~"; fi + echo $result +} + +zero_xattr="000000000000000000000000" +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 replica 2 $H0:$B0/${V0}{0,1} +TEST $CLI volume heal $V0 disable +TEST $CLI volume set $V0 cluster.use-anonymous-inode off +TEST $CLI volume set $V0 performance.write-behind off +TEST $CLI volume set $V0 performance.read-ahead off +TEST $CLI volume set $V0 performance.readdir-ahead off +TEST $CLI volume set $V0 performance.open-behind off +TEST $CLI volume set $V0 performance.stat-prefetch off +TEST $CLI volume set $V0 performance.io-cache off +TEST $CLI volume set $V0 performance.quick-read off +TEST $CLI volume set $V0 cluster.data-self-heal on +TEST $CLI volume set $V0 cluster.metadata-self-heal on +TEST $CLI volume set $V0 cluster.entry-self-heal on +TEST $CLI volume start $V0 + +TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 --use-readdirp=no $M0 +cd $M0 +#_me_ is dir on which missing entry self-heal happens, _heal is where dir self-heal happens +#spb is split-brain, fool is all fool + +#source_self_accusing means there exists source and a sink which self-accuses. +#This simulates failures where fops failed on the bricks without it going down. +#Something like EACCESS/EDQUOT etc + +TEST mkdir spb_heal spb spb_me_heal spb_me fool_heal fool_me v1_fool_heal v1_fool_me source_creations_heal source_deletions_heal source_creations_me source_deletions_me v1_dirty_me v1_dirty_heal source_self_accusing +TEST mkfifo source_deletions_heal/fifo +TEST mknod source_deletions_heal/block b 4 5 +TEST mknod source_deletions_heal/char c 1 5 +TEST touch source_deletions_heal/file +TEST ln -s source_deletions_heal/file source_deletions_heal/slink +TEST mkdir source_deletions_heal/dir1 +TEST mkdir source_deletions_heal/dir1/dir2 + +TEST mkfifo source_deletions_me/fifo +TEST mknod source_deletions_me/block b 4 5 +TEST mknod source_deletions_me/char c 1 5 +TEST touch source_deletions_me/file +TEST ln -s source_deletions_me/file source_deletions_me/slink +TEST mkdir source_deletions_me/dir1 +TEST mkdir source_deletions_me/dir1/dir2 + +TEST mkfifo source_self_accusing/fifo +TEST mknod source_self_accusing/block b 4 5 +TEST mknod source_self_accusing/char c 1 5 +TEST touch source_self_accusing/file +TEST ln -s source_self_accusing/file source_self_accusing/slink +TEST mkdir source_self_accusing/dir1 +TEST mkdir source_self_accusing/dir1/dir2 + +TEST kill_brick $V0 $H0 $B0/${V0}0 + +TEST touch spb_heal/0 spb/0 spb_me_heal/0 spb_me/0 fool_heal/0 fool_me/0 v1_fool_heal/0 v1_fool_me/0 v1_dirty_heal/0 v1_dirty_me/0 +TEST rm -rf source_deletions_heal/fifo source_deletions_heal/block source_deletions_heal/char source_deletions_heal/file source_deletions_heal/slink source_deletions_heal/dir1 +TEST rm -rf source_deletions_me/fifo source_deletions_me/block source_deletions_me/char source_deletions_me/file source_deletions_me/slink source_deletions_me/dir1 +TEST rm -rf source_self_accusing/fifo source_self_accusing/block source_self_accusing/char source_self_accusing/file source_self_accusing/slink source_self_accusing/dir1 + +#Test that the files are deleted +TEST ! stat $B0/${V0}1/source_deletions_heal/fifo +TEST ! stat $B0/${V0}1/source_deletions_heal/block +TEST ! stat $B0/${V0}1/source_deletions_heal/char +TEST ! stat $B0/${V0}1/source_deletions_heal/file +TEST ! stat $B0/${V0}1/source_deletions_heal/slink +TEST ! stat $B0/${V0}1/source_deletions_heal/dir1 +TEST ! stat $B0/${V0}1/source_deletions_me/fifo +TEST ! stat $B0/${V0}1/source_deletions_me/block +TEST ! stat $B0/${V0}1/source_deletions_me/char +TEST ! stat $B0/${V0}1/source_deletions_me/file +TEST ! stat $B0/${V0}1/source_deletions_me/slink +TEST ! stat $B0/${V0}1/source_deletions_me/dir1 +TEST ! stat $B0/${V0}1/source_self_accusing/fifo +TEST ! stat $B0/${V0}1/source_self_accusing/block +TEST ! stat $B0/${V0}1/source_self_accusing/char +TEST ! stat $B0/${V0}1/source_self_accusing/file +TEST ! stat $B0/${V0}1/source_self_accusing/slink +TEST ! stat $B0/${V0}1/source_self_accusing/dir1 + + +TEST mkfifo source_creations_heal/fifo +TEST mknod source_creations_heal/block b 4 5 +TEST mknod source_creations_heal/char c 1 5 +TEST touch source_creations_heal/file +TEST ln -s source_creations_heal/file source_creations_heal/slink +TEST mkdir source_creations_heal/dir1 +TEST mkdir source_creations_heal/dir1/dir2 + +TEST mkfifo source_creations_me/fifo +TEST mknod source_creations_me/block b 4 5 +TEST mknod source_creations_me/char c 1 5 +TEST touch source_creations_me/file +TEST ln -s source_creations_me/file source_creations_me/slink +TEST mkdir source_creations_me/dir1 +TEST mkdir source_creations_me/dir1/dir2 + +$CLI volume stop $V0 + +#simulate fool fool scenario for fool_* dirs +setfattr -x trusted.afr.$V0-client-0 $B0/${V0}1/{fool_heal,fool_me} +setfattr -n trusted.afr.dirty -v 0x000000000000000000000001 $B0/${V0}1/{fool_heal,fool_me} +setfattr -n trusted.afr.$V0-client-1 -v 0x000000000000000000000001 $B0/${V0}1/{v1_fool_heal,v1_fool_me} + +#Simulate v1-dirty(self-accusing but no pending ops on others) scenario for v1-dirty +setfattr -x trusted.afr.$V0-client-0 $B0/${V0}1/v1_dirty_{heal,me} +setfattr -n trusted.afr.$V0-client-1 -v 0x000000000000000000000001 $B0/${V0}1/v1_dirty_{heal,me} + +$CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 1 +TEST kill_brick $V0 $H0 $B0/${V0}1 + +TEST touch spb_heal/1 spb/0 spb_me_heal/1 spb_me/0 fool_heal/1 fool_me/1 v1_fool_heal/1 v1_fool_me/1 + +$CLI volume stop $V0 + +#simulate fool fool scenario for fool_* dirs +setfattr -x trusted.afr.$V0-client-1 $B0/${V0}0/{fool_heal,fool_me} +setfattr -n trusted.afr.dirty -v 0x000000000000000000000001 $B0/${V0}1/{fool_heal,fool_me} +setfattr -n trusted.afr.$V0-client-0 -v 0x000000000000000000000001 $B0/${V0}1/{v1_fool_heal,v1_fool_me} + +#simulate self-accusing for source_self_accusing +TEST setfattr -n trusted.afr.$V0-client-0 -v 0x000000000000000000000006 $B0/${V0}0/source_self_accusing + +$CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0 + +# Check if conservative merges happened correctly on _me_ dirs +TEST stat spb_me_heal/1 +TEST stat $B0/${V0}0/spb_me_heal/1 +TEST stat $B0/${V0}1/spb_me_heal/1 + +TEST stat spb_me_heal/0 +TEST stat $B0/${V0}0/spb_me_heal/0 +TEST stat $B0/${V0}1/spb_me_heal/0 + +TEST stat fool_me/1 +TEST stat $B0/${V0}0/fool_me/1 +TEST stat $B0/${V0}1/fool_me/1 + +TEST stat fool_me/0 +TEST stat $B0/${V0}0/fool_me/0 +TEST stat $B0/${V0}1/fool_me/0 + +TEST stat v1_fool_me/0 +TEST stat $B0/${V0}0/v1_fool_me/0 +TEST stat $B0/${V0}1/v1_fool_me/0 + +TEST stat v1_fool_me/1 +TEST stat $B0/${V0}0/v1_fool_me/1 +TEST stat $B0/${V0}1/v1_fool_me/1 + +TEST stat v1_dirty_me/0 +TEST stat $B0/${V0}0/v1_dirty_me/0 +TEST stat $B0/${V0}1/v1_dirty_me/0 + +#Check if files that have gfid-mismatches in _me_ are giving EIO +TEST ! stat spb_me/0 + +#Check if stale files are deleted on access +TEST ! stat source_deletions_me/fifo +TEST ! stat $B0/${V0}0/source_deletions_me/fifo +TEST ! stat $B0/${V0}1/source_deletions_me/fifo +TEST ! stat source_deletions_me/block +TEST ! stat $B0/${V0}0/source_deletions_me/block +TEST ! stat $B0/${V0}1/source_deletions_me/block +TEST ! stat source_deletions_me/char +TEST ! stat $B0/${V0}0/source_deletions_me/char +TEST ! stat $B0/${V0}1/source_deletions_me/char +TEST ! stat source_deletions_me/file +TEST ! stat $B0/${V0}0/source_deletions_me/file +TEST ! stat $B0/${V0}1/source_deletions_me/file +TEST ! stat source_deletions_me/file +TEST ! stat $B0/${V0}0/source_deletions_me/file +TEST ! stat $B0/${V0}1/source_deletions_me/file +TEST ! stat source_deletions_me/dir1/dir2 +TEST ! stat $B0/${V0}0/source_deletions_me/dir1/dir2 +TEST ! stat $B0/${V0}1/source_deletions_me/dir1/dir2 +TEST ! stat source_deletions_me/dir1 +TEST ! stat $B0/${V0}0/source_deletions_me/dir1 +TEST ! stat $B0/${V0}1/source_deletions_me/dir1 + +#Test if the files created as part of access are healed correctly +r=$(get_file_type source_creations_me/fifo) +EXPECT "$r" get_file_type $B0/${V0}0/source_creations_me/fifo +EXPECT "$r" get_file_type $B0/${V0}1/source_creations_me/fifo +TEST [ -p source_creations_me/fifo ] + +r=$(get_file_type source_creations_me/block) +EXPECT "$r" get_file_type $B0/${V0}0/source_creations_me/block +EXPECT "$r" get_file_type $B0/${V0}1/source_creations_me/block +EXPECT "^4 5$" stat -c "%t %T" $B0/${V0}1/source_creations_me/block +EXPECT "^4 5$" stat -c "%t %T" $B0/${V0}0/source_creations_me/block +TEST [ -b source_creations_me/block ] + +r=$(get_file_type source_creations_me/char) +EXPECT "$r" get_file_type $B0/${V0}0/source_creations_me/char +EXPECT "$r" get_file_type $B0/${V0}1/source_creations_me/char +EXPECT "^1 5$" stat -c "%t %T" $B0/${V0}1/source_creations_me/char +EXPECT "^1 5$" stat -c "%t %T" $B0/${V0}0/source_creations_me/char +TEST [ -c source_creations_me/char ] + +r=$(get_file_type source_creations_me/file) +EXPECT "$r" get_file_type $B0/${V0}0/source_creations_me/file +EXPECT "$r" get_file_type $B0/${V0}1/source_creations_me/file +TEST [ -f source_creations_me/file ] + +r=$(get_file_type source_creations_me/slink) +EXPECT "$r" get_file_type $B0/${V0}0/source_creations_me/slink +EXPECT "$r" get_file_type $B0/${V0}1/source_creations_me/slink +TEST [ -h source_creations_me/slink ] + +r=$(get_file_type source_creations_me/dir1/dir2) +EXPECT "$r" get_file_type $B0/${V0}0/source_creations_me/dir1/dir2 +EXPECT "$r" get_file_type $B0/${V0}1/source_creations_me/dir1/dir2 +TEST [ -d source_creations_me/dir1/dir2 ] + +r=$(get_file_type source_creations_me/dir1) +EXPECT "$r" get_file_type $B0/${V0}0/source_creations_me/dir1 +EXPECT "$r" get_file_type $B0/${V0}1/source_creations_me/dir1 +TEST [ -d source_creations_me/dir1 ] + +#Trigger heal and check _heal dirs are healed properly +#Trigger change in event generation number. That way inodes would get refreshed during lookup +TEST kill_brick $V0 $H0 $B0/${V0}1 +$CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0 + +TEST stat spb_heal +TEST stat spb_me_heal +TEST stat fool_heal +TEST stat fool_me +TEST stat v1_fool_heal +TEST stat v1_fool_me +TEST stat source_deletions_heal +TEST stat source_deletions_me +TEST stat source_self_accusing +TEST stat source_creations_heal +TEST stat source_creations_me +TEST stat v1_dirty_heal +TEST stat v1_dirty_me +TEST $CLI volume stop $V0 +TEST rm -rf $B0/${V0}{0,1}/.glusterfs/indices/xattrop/* + +$CLI volume start $V0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0 + +#Create base entry in indices/xattrop +echo "Data" > $M0/FILE +rm -f $M0/FILE +EXPECT "1" count_index_entries $B0/${V0}0 +EXPECT "1" count_index_entries $B0/${V0}1 + +TEST $CLI volume stop $V0; + +#Create entries for fool_heal and fool_me to ensure they are fully healed and dirty xattrs erased, before triggering index heal +create_brick_xattrop_entry $B0/${V0}0 fool_heal fool_me source_creations_heal/dir1 + +$CLI volume start $V0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0 + +$CLI volume heal $V0 enable +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "Y" glustershd_up_status +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 1 + +TEST $CLI volume heal $V0; +EXPECT_WITHIN $HEAL_TIMEOUT "~" print_pending_heals spb_heal spb_me_heal fool_heal fool_me v1_fool_heal v1_fool_me source_deletions_heal source_deletions_me source_creations_heal source_creations_me v1_dirty_heal v1_dirty_me source_self_accusing + +EXPECT "Y${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}" heal_status $B0/${V0}0 $B0/${V0}1 spb_heal +EXPECT "Y${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}" heal_status $B0/${V0}0 $B0/${V0}1 spb_me_heal +EXPECT "Y${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}" heal_status $B0/${V0}0 $B0/${V0}1 fool_heal +EXPECT "Y${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}" heal_status $B0/${V0}0 $B0/${V0}1 fool_me +EXPECT "Y${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}" heal_status $B0/${V0}0 $B0/${V0}1 v1_fool_heal +EXPECT "Y${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}" heal_status $B0/${V0}0 $B0/${V0}1 v1_fool_me +EXPECT "Y${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}" heal_status $B0/${V0}0 $B0/${V0}1 source_deletions_heal +EXPECT "Y${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}" heal_status $B0/${V0}0 $B0/${V0}1 source_deletions_me +EXPECT "Y${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}" heal_status $B0/${V0}0 $B0/${V0}1 source_self_accusing +EXPECT "Y${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}" heal_status $B0/${V0}0 $B0/${V0}1 source_creations_heal +EXPECT "Y${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}" heal_status $B0/${V0}0 $B0/${V0}1 source_creations_me +EXPECT "Y${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}" heal_status $B0/${V0}0 $B0/${V0}1 v1_dirty_heal +EXPECT "Y${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}" heal_status $B0/${V0}0 $B0/${V0}1 v1_dirty_me + +#Don't access the files/dirs from mount point as that may cause self-heals +# Check if conservative merges happened correctly on heal dirs +TEST stat $B0/${V0}0/spb_heal/1 +TEST stat $B0/${V0}1/spb_heal/1 + +TEST stat $B0/${V0}0/spb_heal/0 +TEST stat $B0/${V0}1/spb_heal/0 + +TEST stat $B0/${V0}0/fool_heal/1 +TEST stat $B0/${V0}1/fool_heal/1 + +TEST stat $B0/${V0}0/fool_heal/0 +TEST stat $B0/${V0}1/fool_heal/0 + +TEST stat $B0/${V0}0/v1_fool_heal/0 +TEST stat $B0/${V0}1/v1_fool_heal/0 + +TEST stat $B0/${V0}0/v1_fool_heal/1 +TEST stat $B0/${V0}1/v1_fool_heal/1 + +TEST stat $B0/${V0}0/v1_dirty_heal/0 +TEST stat $B0/${V0}1/v1_dirty_heal/0 + +#Check if files that have gfid-mismatches in spb are giving EIO +TEST ! stat spb/0 + +#Check if stale files are deleted on access +TEST ! stat $B0/${V0}0/source_deletions_heal/fifo +TEST ! stat $B0/${V0}1/source_deletions_heal/fifo +TEST ! stat $B0/${V0}0/source_deletions_heal/block +TEST ! stat $B0/${V0}1/source_deletions_heal/block +TEST ! stat $B0/${V0}0/source_deletions_heal/char +TEST ! stat $B0/${V0}1/source_deletions_heal/char +TEST ! stat $B0/${V0}0/source_deletions_heal/file +TEST ! stat $B0/${V0}1/source_deletions_heal/file +TEST ! stat $B0/${V0}0/source_deletions_heal/file +TEST ! stat $B0/${V0}1/source_deletions_heal/file +TEST ! stat $B0/${V0}0/source_deletions_heal/dir1/dir2 +TEST ! stat $B0/${V0}1/source_deletions_heal/dir1/dir2 +TEST ! stat $B0/${V0}0/source_deletions_heal/dir1 +TEST ! stat $B0/${V0}1/source_deletions_heal/dir1 + +#Check if stale files are deleted on access +TEST ! stat $B0/${V0}0/source_self_accusing/fifo +TEST ! stat $B0/${V0}1/source_self_accusing/fifo +TEST ! stat $B0/${V0}0/source_self_accusing/block +TEST ! stat $B0/${V0}1/source_self_accusing/block +TEST ! stat $B0/${V0}0/source_self_accusing/char +TEST ! stat $B0/${V0}1/source_self_accusing/char +TEST ! stat $B0/${V0}0/source_self_accusing/file +TEST ! stat $B0/${V0}1/source_self_accusing/file +TEST ! stat $B0/${V0}0/source_self_accusing/file +TEST ! stat $B0/${V0}1/source_self_accusing/file +TEST ! stat $B0/${V0}0/source_self_accusing/dir1/dir2 +TEST ! stat $B0/${V0}1/source_self_accusing/dir1/dir2 +TEST ! stat $B0/${V0}0/source_self_accusing/dir1 +TEST ! stat $B0/${V0}1/source_self_accusing/dir1 + +#Test if the files created as part of full self-heal correctly +r=$(get_file_type $B0/${V0}0/source_creations_heal/fifo) +EXPECT "$r" get_file_type $B0/${V0}1/source_creations_heal/fifo +TEST [ -p $B0/${V0}0/source_creations_heal/fifo ] +EXPECT "^4 5$" stat -c "%t %T" $B0/${V0}1/source_creations_heal/block +EXPECT "^4 5$" stat -c "%t %T" $B0/${V0}0/source_creations_heal/block + +r=$(get_file_type $B0/${V0}0/source_creations_heal/block) +EXPECT "$r" get_file_type $B0/${V0}1/source_creations_heal/block + +r=$(get_file_type $B0/${V0}0/source_creations_heal/char) +EXPECT "$r" get_file_type $B0/${V0}1/source_creations_heal/char +EXPECT "^1 5$" stat -c "%t %T" $B0/${V0}1/source_creations_heal/char +EXPECT "^1 5$" stat -c "%t %T" $B0/${V0}0/source_creations_heal/char + +r=$(get_file_type $B0/${V0}0/source_creations_heal/file) +EXPECT "$r" get_file_type $B0/${V0}1/source_creations_heal/file +TEST [ -f $B0/${V0}0/source_creations_heal/file ] + +r=$(get_file_type source_creations_heal/file $B0/${V0}0/slink) +EXPECT "$r" get_file_type $B0/${V0}1/source_creations_heal/file slink +TEST [ -h $B0/${V0}0/source_creations_heal/slink ] + +r=$(get_file_type $B0/${V0}0/source_creations_heal/dir1/dir2) +EXPECT "$r" get_file_type $B0/${V0}1/source_creations_heal/dir1/dir2 +TEST [ -d $B0/${V0}0/source_creations_heal/dir1/dir2 ] + +r=$(get_file_type $B0/${V0}0/source_creations_heal/dir1) +EXPECT "$r" get_file_type $B0/${V0}1/source_creations_heal/dir1 +TEST [ -d $B0/${V0}0/source_creations_heal/dir1 ] + +cd - + +#Anonymous directory shouldn't be created +TEST mkdir $M0/rename-dir +before_rename=$(STAT_INO $B0/${V0}1/rename-dir) +TEST kill_brick $V0 $H0 $B0/${V0}1 +TEST mv $M0/rename-dir $M0/new-name +TEST $CLI volume start $V0 force +#'spb' is in split-brain so pending-heal-count will be 2 +EXPECT_WITHIN $HEAL_TIMEOUT "^2$" get_pending_heal_count $V0 +after_rename=$(STAT_INO $B0/${V0}1/new-name) +EXPECT "0" echo $(ls -a $B0/${V0}0/ | grep anonymous-inode | wc -l) +EXPECT "0" echo $(ls -a $B0/${V0}1/ | grep anonymous-inode | wc -l) +EXPECT_NOT "$before_rename" echo $after_rename +cleanup diff --git a/tests/basic/afr/entry-self-heal.t b/tests/basic/afr/entry-self-heal.t new file mode 100644 index 00000000000..0c1da7d211e --- /dev/null +++ b/tests/basic/afr/entry-self-heal.t @@ -0,0 +1,447 @@ +#!/bin/bash + +#This file checks if missing entry self-heal and entry self-heal are working +#as expected. +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc +. $(dirname $0)/../../afr.rc + +cleanup; + +function get_file_type { + stat -c "%a:%F:%g:%t:%T:%u" $1 +} + +function diff_dirs { + diff <(ls $1 | sort) <(ls $2 | sort) +} + +function heal_status { + local f1_path="${1}/${3}" + local f2_path="${2}/${3}" + local zero_xattr="000000000000000000000000" + local insync="" + diff_dirs $f1_path $f2_path + if [ $? -eq 0 ]; + then + insync="Y" + else + insync="N" + fi + local xattr11=$(get_hex_xattr trusted.afr.$V0-client-0 $f1_path) + local xattr12=$(get_hex_xattr trusted.afr.$V0-client-1 $f1_path) + local xattr21=$(get_hex_xattr trusted.afr.$V0-client-0 $f2_path) + local xattr22=$(get_hex_xattr trusted.afr.$V0-client-1 $f2_path) + local dirty1=$(get_hex_xattr trusted.afr.dirty $f1_path) + local dirty2=$(get_hex_xattr trusted.afr.dirty $f2_path) + if [ -z $xattr11 ]; then xattr11="000000000000000000000000"; fi + if [ -z $xattr12 ]; then xattr12="000000000000000000000000"; fi + if [ -z $xattr21 ]; then xattr21="000000000000000000000000"; fi + if [ -z $xattr22 ]; then xattr22="000000000000000000000000"; fi + if [ -z $dirty1 ]; then dirty1="000000000000000000000000"; fi + if [ -z $dirty2 ]; then dirty2="000000000000000000000000"; fi + echo ${insync}${xattr11}${xattr12}${xattr21}${xattr22}${dirty1}${dirty2} +} + +function is_heal_done { + local zero_xattr="000000000000000000000000" + if [ "$(heal_status $@)" == "Y${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}" ]; + then + echo "Y" + else + echo "N" + fi +} + +function print_pending_heals { + local result=":" + for i in "$@"; + do + if [ "N" == $(is_heal_done $B0/${V0}0 $B0/${V0}1 $i) ]; + then + result="$result:$i" + fi + done +#To prevent any match for EXPECT_WITHIN, print a char non-existent in file-names + if [ $result == ":" ]; then result="~"; fi + echo $result +} + +zero_xattr="000000000000000000000000" +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 replica 2 $H0:$B0/${V0}{0,1} +TEST $CLI volume set $V0 self-heal-daemon off +TEST $CLI volume set $V0 performance.write-behind off +TEST $CLI volume set $V0 performance.read-ahead off +TEST $CLI volume set $V0 performance.readdir-ahead off +TEST $CLI volume set $V0 performance.open-behind off +TEST $CLI volume set $V0 performance.stat-prefetch off +TEST $CLI volume set $V0 performance.io-cache off +TEST $CLI volume set $V0 performance.quick-read off +TEST $CLI volume set $V0 cluster.data-self-heal on +TEST $CLI volume set $V0 cluster.metadata-self-heal on +TEST $CLI volume set $V0 cluster.entry-self-heal on +TEST $CLI volume start $V0 + +TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 --use-readdirp=no $M0 +cd $M0 +#_me_ is dir on which missing entry self-heal happens, _heal is where dir self-heal happens +#spb is split-brain, fool is all fool + +#source_self_accusing means there exists source and a sink which self-accuses. +#This simulates failures where fops failed on the bricks without it going down. +#Something like EACCESS/EDQUOT etc + +TEST mkdir spb_heal spb spb_me_heal spb_me fool_heal fool_me v1_fool_heal v1_fool_me source_creations_heal source_deletions_heal source_creations_me source_deletions_me v1_dirty_me v1_dirty_heal source_self_accusing +TEST mkfifo source_deletions_heal/fifo +TEST mknod source_deletions_heal/block b 4 5 +TEST mknod source_deletions_heal/char c 1 5 +TEST touch source_deletions_heal/file +TEST ln -s source_deletions_heal/file source_deletions_heal/slink +TEST mkdir source_deletions_heal/dir1 +TEST mkdir source_deletions_heal/dir1/dir2 + +TEST mkfifo source_deletions_me/fifo +TEST mknod source_deletions_me/block b 4 5 +TEST mknod source_deletions_me/char c 1 5 +TEST touch source_deletions_me/file +TEST ln -s source_deletions_me/file source_deletions_me/slink +TEST mkdir source_deletions_me/dir1 +TEST mkdir source_deletions_me/dir1/dir2 + +TEST mkfifo source_self_accusing/fifo +TEST mknod source_self_accusing/block b 4 5 +TEST mknod source_self_accusing/char c 1 5 +TEST touch source_self_accusing/file +TEST ln -s source_self_accusing/file source_self_accusing/slink +TEST mkdir source_self_accusing/dir1 +TEST mkdir source_self_accusing/dir1/dir2 + +TEST kill_brick $V0 $H0 $B0/${V0}0 + +TEST touch spb_heal/0 spb/0 spb_me_heal/0 spb_me/0 fool_heal/0 fool_me/0 v1_fool_heal/0 v1_fool_me/0 v1_dirty_heal/0 v1_dirty_me/0 +TEST rm -rf source_deletions_heal/fifo source_deletions_heal/block source_deletions_heal/char source_deletions_heal/file source_deletions_heal/slink source_deletions_heal/dir1 +TEST rm -rf source_deletions_me/fifo source_deletions_me/block source_deletions_me/char source_deletions_me/file source_deletions_me/slink source_deletions_me/dir1 +TEST rm -rf source_self_accusing/fifo source_self_accusing/block source_self_accusing/char source_self_accusing/file source_self_accusing/slink source_self_accusing/dir1 + +#Test that the files are deleted +TEST ! stat $B0/${V0}1/source_deletions_heal/fifo +TEST ! stat $B0/${V0}1/source_deletions_heal/block +TEST ! stat $B0/${V0}1/source_deletions_heal/char +TEST ! stat $B0/${V0}1/source_deletions_heal/file +TEST ! stat $B0/${V0}1/source_deletions_heal/slink +TEST ! stat $B0/${V0}1/source_deletions_heal/dir1 +TEST ! stat $B0/${V0}1/source_deletions_me/fifo +TEST ! stat $B0/${V0}1/source_deletions_me/block +TEST ! stat $B0/${V0}1/source_deletions_me/char +TEST ! stat $B0/${V0}1/source_deletions_me/file +TEST ! stat $B0/${V0}1/source_deletions_me/slink +TEST ! stat $B0/${V0}1/source_deletions_me/dir1 +TEST ! stat $B0/${V0}1/source_self_accusing/fifo +TEST ! stat $B0/${V0}1/source_self_accusing/block +TEST ! stat $B0/${V0}1/source_self_accusing/char +TEST ! stat $B0/${V0}1/source_self_accusing/file +TEST ! stat $B0/${V0}1/source_self_accusing/slink +TEST ! stat $B0/${V0}1/source_self_accusing/dir1 + + +TEST mkfifo source_creations_heal/fifo +TEST mknod source_creations_heal/block b 4 5 +TEST mknod source_creations_heal/char c 1 5 +TEST touch source_creations_heal/file +TEST ln -s source_creations_heal/file source_creations_heal/slink +TEST mkdir source_creations_heal/dir1 +TEST mkdir source_creations_heal/dir1/dir2 + +TEST mkfifo source_creations_me/fifo +TEST mknod source_creations_me/block b 4 5 +TEST mknod source_creations_me/char c 1 5 +TEST touch source_creations_me/file +TEST ln -s source_creations_me/file source_creations_me/slink +TEST mkdir source_creations_me/dir1 +TEST mkdir source_creations_me/dir1/dir2 + +$CLI volume stop $V0 + +#simulate fool fool scenario for fool_* dirs +setfattr -x trusted.afr.$V0-client-0 $B0/${V0}1/{fool_heal,fool_me} +setfattr -n trusted.afr.dirty -v 0x000000000000000000000001 $B0/${V0}1/{fool_heal,fool_me} +setfattr -n trusted.afr.$V0-client-1 -v 0x000000000000000000000001 $B0/${V0}1/{v1_fool_heal,v1_fool_me} + +#Simulate v1-dirty(self-accusing but no pending ops on others) scenario for v1-dirty +setfattr -x trusted.afr.$V0-client-0 $B0/${V0}1/v1_dirty_{heal,me} +setfattr -n trusted.afr.$V0-client-1 -v 0x000000000000000000000001 $B0/${V0}1/v1_dirty_{heal,me} + +$CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 1 +TEST kill_brick $V0 $H0 $B0/${V0}1 + +TEST touch spb_heal/1 spb/0 spb_me_heal/1 spb_me/0 fool_heal/1 fool_me/1 v1_fool_heal/1 v1_fool_me/1 + +$CLI volume stop $V0 + +#simulate fool fool scenario for fool_* dirs +setfattr -x trusted.afr.$V0-client-1 $B0/${V0}0/{fool_heal,fool_me} +setfattr -n trusted.afr.dirty -v 0x000000000000000000000001 $B0/${V0}1/{fool_heal,fool_me} +setfattr -n trusted.afr.$V0-client-0 -v 0x000000000000000000000001 $B0/${V0}1/{v1_fool_heal,v1_fool_me} + +#simulate self-accusing for source_self_accusing +TEST setfattr -n trusted.afr.$V0-client-0 -v 0x000000000000000000000006 $B0/${V0}0/source_self_accusing + +$CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0 + +# Check if conservative merges happened correctly on _me_ dirs +TEST stat spb_me_heal/1 +TEST stat $B0/${V0}0/spb_me_heal/1 +TEST stat $B0/${V0}1/spb_me_heal/1 + +TEST stat spb_me_heal/0 +TEST stat $B0/${V0}0/spb_me_heal/0 +TEST stat $B0/${V0}1/spb_me_heal/0 + +TEST stat fool_me/1 +TEST stat $B0/${V0}0/fool_me/1 +TEST stat $B0/${V0}1/fool_me/1 + +TEST stat fool_me/0 +TEST stat $B0/${V0}0/fool_me/0 +TEST stat $B0/${V0}1/fool_me/0 + +TEST stat v1_fool_me/0 +TEST stat $B0/${V0}0/v1_fool_me/0 +TEST stat $B0/${V0}1/v1_fool_me/0 + +TEST stat v1_fool_me/1 +TEST stat $B0/${V0}0/v1_fool_me/1 +TEST stat $B0/${V0}1/v1_fool_me/1 + +TEST stat v1_dirty_me/0 +TEST stat $B0/${V0}0/v1_dirty_me/0 +TEST stat $B0/${V0}1/v1_dirty_me/0 + +#Check if files that have gfid-mismatches in _me_ are giving EIO +TEST ! stat spb_me/0 + +#Check if stale files are deleted on access +TEST ! stat source_deletions_me/fifo +TEST ! stat $B0/${V0}0/source_deletions_me/fifo +TEST ! stat $B0/${V0}1/source_deletions_me/fifo +TEST ! stat source_deletions_me/block +TEST ! stat $B0/${V0}0/source_deletions_me/block +TEST ! stat $B0/${V0}1/source_deletions_me/block +TEST ! stat source_deletions_me/char +TEST ! stat $B0/${V0}0/source_deletions_me/char +TEST ! stat $B0/${V0}1/source_deletions_me/char +TEST ! stat source_deletions_me/file +TEST ! stat $B0/${V0}0/source_deletions_me/file +TEST ! stat $B0/${V0}1/source_deletions_me/file +TEST ! stat source_deletions_me/file +TEST ! stat $B0/${V0}0/source_deletions_me/file +TEST ! stat $B0/${V0}1/source_deletions_me/file +TEST ! stat source_deletions_me/dir1/dir2 +TEST ! stat $B0/${V0}0/source_deletions_me/dir1/dir2 +TEST ! stat $B0/${V0}1/source_deletions_me/dir1/dir2 +TEST ! stat source_deletions_me/dir1 +TEST ! stat $B0/${V0}0/source_deletions_me/dir1 +TEST ! stat $B0/${V0}1/source_deletions_me/dir1 + +#Test if the files created as part of access are healed correctly +r=$(get_file_type source_creations_me/fifo) +EXPECT "$r" get_file_type $B0/${V0}0/source_creations_me/fifo +EXPECT "$r" get_file_type $B0/${V0}1/source_creations_me/fifo +TEST [ -p source_creations_me/fifo ] + +r=$(get_file_type source_creations_me/block) +EXPECT "$r" get_file_type $B0/${V0}0/source_creations_me/block +EXPECT "$r" get_file_type $B0/${V0}1/source_creations_me/block +EXPECT "^4 5$" stat -c "%t %T" $B0/${V0}1/source_creations_me/block +EXPECT "^4 5$" stat -c "%t %T" $B0/${V0}0/source_creations_me/block +TEST [ -b source_creations_me/block ] + +r=$(get_file_type source_creations_me/char) +EXPECT "$r" get_file_type $B0/${V0}0/source_creations_me/char +EXPECT "$r" get_file_type $B0/${V0}1/source_creations_me/char +EXPECT "^1 5$" stat -c "%t %T" $B0/${V0}1/source_creations_me/char +EXPECT "^1 5$" stat -c "%t %T" $B0/${V0}0/source_creations_me/char +TEST [ -c source_creations_me/char ] + +r=$(get_file_type source_creations_me/file) +EXPECT "$r" get_file_type $B0/${V0}0/source_creations_me/file +EXPECT "$r" get_file_type $B0/${V0}1/source_creations_me/file +TEST [ -f source_creations_me/file ] + +r=$(get_file_type source_creations_me/slink) +EXPECT "$r" get_file_type $B0/${V0}0/source_creations_me/slink +EXPECT "$r" get_file_type $B0/${V0}1/source_creations_me/slink +TEST [ -h source_creations_me/slink ] + +r=$(get_file_type source_creations_me/dir1/dir2) +EXPECT "$r" get_file_type $B0/${V0}0/source_creations_me/dir1/dir2 +EXPECT "$r" get_file_type $B0/${V0}1/source_creations_me/dir1/dir2 +TEST [ -d source_creations_me/dir1/dir2 ] + +r=$(get_file_type source_creations_me/dir1) +EXPECT "$r" get_file_type $B0/${V0}0/source_creations_me/dir1 +EXPECT "$r" get_file_type $B0/${V0}1/source_creations_me/dir1 +TEST [ -d source_creations_me/dir1 ] + +#Trigger heal and check _heal dirs are healed properly +#Trigger change in event generation number. That way inodes would get refreshed during lookup +TEST kill_brick $V0 $H0 $B0/${V0}1 +$CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0 + +TEST stat spb_heal +TEST stat spb_me_heal +TEST stat fool_heal +TEST stat fool_me +TEST stat v1_fool_heal +TEST stat v1_fool_me +TEST stat source_deletions_heal +TEST stat source_deletions_me +TEST stat source_self_accusing +TEST stat source_creations_heal +TEST stat source_creations_me +TEST stat v1_dirty_heal +TEST stat v1_dirty_me +TEST $CLI volume stop $V0 +TEST rm -rf $B0/${V0}{0,1}/.glusterfs/indices/xattrop/* + +$CLI volume start $V0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0 + +#Create base entry in indices/xattrop +echo "Data" > $M0/FILE +rm -f $M0/FILE +EXPECT "1" count_index_entries $B0/${V0}0 +EXPECT "1" count_index_entries $B0/${V0}1 + +TEST $CLI volume stop $V0; + +#Create entries for fool_heal and fool_me to ensure they are fully healed and dirty xattrs erased, before triggering index heal +create_brick_xattrop_entry $B0/${V0}0 fool_heal fool_me source_creations_heal/dir1 + +$CLI volume start $V0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0 + +$CLI volume set $V0 self-heal-daemon on +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "Y" glustershd_up_status +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 1 + +TEST $CLI volume heal $V0; +EXPECT_WITHIN $HEAL_TIMEOUT "~" print_pending_heals spb_heal spb_me_heal fool_heal fool_me v1_fool_heal v1_fool_me source_deletions_heal source_deletions_me source_creations_heal source_creations_me v1_dirty_heal v1_dirty_me source_self_accusing + +EXPECT "Y${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}" heal_status $B0/${V0}0 $B0/${V0}1 spb_heal +EXPECT "Y${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}" heal_status $B0/${V0}0 $B0/${V0}1 spb_me_heal +EXPECT "Y${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}" heal_status $B0/${V0}0 $B0/${V0}1 fool_heal +EXPECT "Y${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}" heal_status $B0/${V0}0 $B0/${V0}1 fool_me +EXPECT "Y${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}" heal_status $B0/${V0}0 $B0/${V0}1 v1_fool_heal +EXPECT "Y${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}" heal_status $B0/${V0}0 $B0/${V0}1 v1_fool_me +EXPECT "Y${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}" heal_status $B0/${V0}0 $B0/${V0}1 source_deletions_heal +EXPECT "Y${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}" heal_status $B0/${V0}0 $B0/${V0}1 source_deletions_me +EXPECT "Y${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}" heal_status $B0/${V0}0 $B0/${V0}1 source_self_accusing +EXPECT "Y${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}" heal_status $B0/${V0}0 $B0/${V0}1 source_creations_heal +EXPECT "Y${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}" heal_status $B0/${V0}0 $B0/${V0}1 source_creations_me +EXPECT "Y${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}" heal_status $B0/${V0}0 $B0/${V0}1 v1_dirty_heal +EXPECT "Y${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}" heal_status $B0/${V0}0 $B0/${V0}1 v1_dirty_me + +#Don't access the files/dirs from mount point as that may cause self-heals +# Check if conservative merges happened correctly on heal dirs +TEST stat $B0/${V0}0/spb_heal/1 +TEST stat $B0/${V0}1/spb_heal/1 + +TEST stat $B0/${V0}0/spb_heal/0 +TEST stat $B0/${V0}1/spb_heal/0 + +TEST stat $B0/${V0}0/fool_heal/1 +TEST stat $B0/${V0}1/fool_heal/1 + +TEST stat $B0/${V0}0/fool_heal/0 +TEST stat $B0/${V0}1/fool_heal/0 + +TEST stat $B0/${V0}0/v1_fool_heal/0 +TEST stat $B0/${V0}1/v1_fool_heal/0 + +TEST stat $B0/${V0}0/v1_fool_heal/1 +TEST stat $B0/${V0}1/v1_fool_heal/1 + +TEST stat $B0/${V0}0/v1_dirty_heal/0 +TEST stat $B0/${V0}1/v1_dirty_heal/0 + +#Check if files that have gfid-mismatches in spb are giving EIO +TEST ! stat spb/0 + +#Check if stale files are deleted on access +TEST ! stat $B0/${V0}0/source_deletions_heal/fifo +TEST ! stat $B0/${V0}1/source_deletions_heal/fifo +TEST ! stat $B0/${V0}0/source_deletions_heal/block +TEST ! stat $B0/${V0}1/source_deletions_heal/block +TEST ! stat $B0/${V0}0/source_deletions_heal/char +TEST ! stat $B0/${V0}1/source_deletions_heal/char +TEST ! stat $B0/${V0}0/source_deletions_heal/file +TEST ! stat $B0/${V0}1/source_deletions_heal/file +TEST ! stat $B0/${V0}0/source_deletions_heal/file +TEST ! stat $B0/${V0}1/source_deletions_heal/file +TEST ! stat $B0/${V0}0/source_deletions_heal/dir1/dir2 +TEST ! stat $B0/${V0}1/source_deletions_heal/dir1/dir2 +TEST ! stat $B0/${V0}0/source_deletions_heal/dir1 +TEST ! stat $B0/${V0}1/source_deletions_heal/dir1 + +#Check if stale files are deleted on access +TEST ! stat $B0/${V0}0/source_self_accusing/fifo +TEST ! stat $B0/${V0}1/source_self_accusing/fifo +TEST ! stat $B0/${V0}0/source_self_accusing/block +TEST ! stat $B0/${V0}1/source_self_accusing/block +TEST ! stat $B0/${V0}0/source_self_accusing/char +TEST ! stat $B0/${V0}1/source_self_accusing/char +TEST ! stat $B0/${V0}0/source_self_accusing/file +TEST ! stat $B0/${V0}1/source_self_accusing/file +TEST ! stat $B0/${V0}0/source_self_accusing/file +TEST ! stat $B0/${V0}1/source_self_accusing/file +TEST ! stat $B0/${V0}0/source_self_accusing/dir1/dir2 +TEST ! stat $B0/${V0}1/source_self_accusing/dir1/dir2 +TEST ! stat $B0/${V0}0/source_self_accusing/dir1 +TEST ! stat $B0/${V0}1/source_self_accusing/dir1 + +#Test if the files created as part of full self-heal correctly +r=$(get_file_type $B0/${V0}0/source_creations_heal/fifo) +EXPECT "$r" get_file_type $B0/${V0}1/source_creations_heal/fifo +TEST [ -p $B0/${V0}0/source_creations_heal/fifo ] +EXPECT "^4 5$" stat -c "%t %T" $B0/${V0}1/source_creations_heal/block +EXPECT "^4 5$" stat -c "%t %T" $B0/${V0}0/source_creations_heal/block + +r=$(get_file_type $B0/${V0}0/source_creations_heal/block) +EXPECT "$r" get_file_type $B0/${V0}1/source_creations_heal/block + +r=$(get_file_type $B0/${V0}0/source_creations_heal/char) +EXPECT "$r" get_file_type $B0/${V0}1/source_creations_heal/char +EXPECT "^1 5$" stat -c "%t %T" $B0/${V0}1/source_creations_heal/char +EXPECT "^1 5$" stat -c "%t %T" $B0/${V0}0/source_creations_heal/char + +r=$(get_file_type $B0/${V0}0/source_creations_heal/file) +EXPECT "$r" get_file_type $B0/${V0}1/source_creations_heal/file +TEST [ -f $B0/${V0}0/source_creations_heal/file ] + +r=$(get_file_type source_creations_heal/file $B0/${V0}0/slink) +EXPECT "$r" get_file_type $B0/${V0}1/source_creations_heal/file slink +TEST [ -h $B0/${V0}0/source_creations_heal/slink ] + +r=$(get_file_type $B0/${V0}0/source_creations_heal/dir1/dir2) +EXPECT "$r" get_file_type $B0/${V0}1/source_creations_heal/dir1/dir2 +TEST [ -d $B0/${V0}0/source_creations_heal/dir1/dir2 ] + +r=$(get_file_type $B0/${V0}0/source_creations_heal/dir1) +EXPECT "$r" get_file_type $B0/${V0}1/source_creations_heal/dir1 +TEST [ -d $B0/${V0}0/source_creations_heal/dir1 ] + +cd - + +cleanup diff --git a/tests/basic/afr/gfid-heal.t b/tests/basic/afr/gfid-heal.t new file mode 100644 index 00000000000..5e26e3307eb --- /dev/null +++ b/tests/basic/afr/gfid-heal.t @@ -0,0 +1,33 @@ +#!/bin/bash +#gfid self-heal test on distributed replica. Make sure all the gfids are same +#and the gfid exists on all the bricks + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +cleanup; + +function get_gfid_count { + getfattr -d -m. -e hex $B0/brick{0,1,2,3,4,5}/$1 2>&1 | grep trusted.gfid | grep -v gfid2path | wc -l +} + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 replica 2 $H0:$B0/brick{0,1,2,3,4,5} +TEST $CLI volume start $V0 +TEST $GFS --volfile-id=$V0 --volfile-server=$H0 $M0; + +TEST mkdir $B0/brick{0,1,2,3}/{0..9} +sleep 2 #to prevent is_fresh_file code path +TEST stat $M0/{0..9} +EXPECT 6 get_gfid_count 0 +EXPECT 6 get_gfid_count 1 +EXPECT 6 get_gfid_count 2 +EXPECT 6 get_gfid_count 3 +EXPECT 6 get_gfid_count 4 +EXPECT 6 get_gfid_count 5 +EXPECT 6 get_gfid_count 6 +EXPECT 6 get_gfid_count 7 +EXPECT 6 get_gfid_count 8 +EXPECT 6 get_gfid_count 9 +cleanup; diff --git a/tests/basic/afr/gfid-mismatch-resolution-with-cli.t b/tests/basic/afr/gfid-mismatch-resolution-with-cli.t new file mode 100644 index 00000000000..b739ddc49cc --- /dev/null +++ b/tests/basic/afr/gfid-mismatch-resolution-with-cli.t @@ -0,0 +1,168 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +cleanup; + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 replica 2 $H0:$B0/${V0}{0,1} +TEST $CLI volume start $V0 +TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0 +TEST $CLI volume set $V0 self-heal-daemon off +TEST $CLI volume set $V0 cluster.entry-self-heal off +TEST $CLI volume set $V0 cluster.metadata-self-heal off +TEST $CLI volume set $V0 cluster.data-self-heal off +cd $M0 + +##### Healing from latest mtime ###### + +TEST kill_brick $V0 $H0 $B0/${V0}0 +echo "Sink based on mtime" > f1 +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status $V0 0 +TEST kill_brick $V0 $H0 $B0/${V0}1 +echo "Source based on mtime" > f1 + +gfid_0=$(gf_get_gfid_xattr $B0/${V0}0/f1) +gfid_1=$(gf_get_gfid_xattr $B0/${V0}1/f1) +TEST [ "$gfid_0" != "$gfid_1" ] + +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}1 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status $V0 1 + +#We know that first brick has the latest mtime +LATEST_MTIME_MD5=$(md5sum $B0/${V0}0/f1 | awk '{print $1}') + +TEST $CLI volume heal $V0 split-brain latest-mtime /f1 + +#gfid split-brain should be resolved +gfid_1=$(gf_get_gfid_xattr $B0/${V0}1/f1) +TEST [ "$gfid_0" == "$gfid_1" ] + +#Heal the data and check the md5sum +TEST $CLI volume set $V0 self-heal-daemon on +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "Y" glustershd_up_status +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 1 +TEST $CLI volume heal $V0 +EXPECT_WITHIN $HEAL_TIMEOUT "^0$" get_pending_heal_count $V0 +HEALED_MD5=$(md5sum $B0/${V0}1/f1 | awk '{print $1}') +TEST [ "$LATEST_MTIME_MD5" == "$HEALED_MD5" ] + + +##### Healing from bigger file ###### + +TEST mkdir test +TEST $CLI volume set $V0 self-heal-daemon off +TEST kill_brick $V0 $H0 $B0/${V0}0 +echo "Bigger file" > test/f2 +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status $V0 0 +TEST kill_brick $V0 $H0 $B0/${V0}1 +echo "Small file" > test/f2 + +gfid_0=$(gf_get_gfid_xattr $B0/${V0}0/test/f2) +gfid_1=$(gf_get_gfid_xattr $B0/${V0}1/test/f2) +TEST [ "$gfid_0" != "$gfid_1" ] + +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}1 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status $V0 1 + +#We know that second brick has the bigger file +BIGGER_FILE_MD5=$(md5sum $B0/${V0}1/test/f2 | awk '{print $1}') + +TEST $CLI volume heal $V0 split-brain bigger-file /test/f2 + +#gfid split-brain should be resolved +gfid_0=$(gf_get_gfid_xattr $B0/${V0}0/test/f2) +TEST [ "$gfid_0" == "$gfid_1" ] + +#Heal the data and check the md5sum +TEST $CLI volume set $V0 self-heal-daemon on +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "Y" glustershd_up_status +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 1 +TEST $CLI volume heal $V0 +EXPECT_WITHIN $HEAL_TIMEOUT "^0$" get_pending_heal_count $V0 +HEALED_MD5=$(md5sum $B0/${V0}0/test/f2 | awk '{print $1}') +TEST [ "$BIGGER_FILE_MD5" == "$HEALED_MD5" ] + + +#Add one more brick, and heal. +TEST $CLI volume add-brick $V0 replica 3 $H0:$B0/${V0}2 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "Y" glustershd_up_status +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}2 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status $V0 0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status $V0 1 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status $V0 2 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 1 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 2 + +TEST $CLI volume heal $V0 +EXPECT_WITHIN $HEAL_TIMEOUT "^0$" get_pending_heal_count $V0 + + +##### Healing from source brick ###### + +TEST $CLI volume set $V0 self-heal-daemon off +TEST $CLI volume set $V0 cluster.quorum-type none +TEST kill_brick $V0 $H0 $B0/${V0}0 +echo "We will consider these as sinks" > test/f3 +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status $V0 0 +TEST kill_brick $V0 $H0 $B0/${V0}1 +TEST kill_brick $V0 $H0 $B0/${V0}2 +echo "We will take this as source" > test/f3 + +gfid_0=$(gf_get_gfid_xattr $B0/${V0}0/test/f3) +gfid_1=$(gf_get_gfid_xattr $B0/${V0}1/test/f3) +gfid_2=$(gf_get_gfid_xattr $B0/${V0}2/test/f3) +TEST [ "$gfid_0" != "$gfid_1" ] +TEST [ "$gfid_1" == "$gfid_2" ] + +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}2 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status $V0 1 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status $V0 2 + +#We will try to heal the split-brain with bigger file option. +#It should fail, since we have same file size in bricks 1 & 2. +EXPECT "No bigger file for file /test/f3" $CLI volume heal $V0 split-brain bigger-file /test/f3 + +#Now heal from taking the brick 0 as the source +SOURCE_MD5=$(md5sum $B0/${V0}0/test/f3 | awk '{print $1}') + +TEST $CLI volume heal $V0 split-brain source-brick $H0:$B0/${V0}0 /test/f3 + +#gfid split-brain should be resolved +gfid_1=$(gf_get_gfid_xattr $B0/${V0}1/test/f3) +gfid_2=$(gf_get_gfid_xattr $B0/${V0}2/test/f3) +TEST [ "$gfid_0" == "$gfid_1" ] +TEST [ "$gfid_0" == "$gfid_2" ] + +#Heal the data and check the md5sum +TEST $CLI volume set $V0 self-heal-daemon on +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "Y" glustershd_up_status +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 1 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 2 +TEST $CLI volume heal $V0 +EXPECT_WITHIN $HEAL_TIMEOUT "^0$" get_pending_heal_count $V0 +HEALED_MD5_1=$(md5sum $B0/${V0}1/test/f3 | awk '{print $1}') +HEALED_MD5_2=$(md5sum $B0/${V0}2/test/f3 | awk '{print $1}') +TEST [ "$SOURCE_MD5" == "$HEALED_MD5_1" ] +TEST [ "$SOURCE_MD5" == "$HEALED_MD5_2" ] + +cd - +cleanup; diff --git a/tests/basic/afr/gfid-mismatch-resolution-with-fav-child-policy.t b/tests/basic/afr/gfid-mismatch-resolution-with-fav-child-policy.t new file mode 100644 index 00000000000..35e295dc170 --- /dev/null +++ b/tests/basic/afr/gfid-mismatch-resolution-with-fav-child-policy.t @@ -0,0 +1,229 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +cleanup; + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 replica 2 $H0:$B0/${V0}{0,1} +TEST $CLI volume start $V0 +TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0 +TEST $CLI volume set $V0 cluster.heal-timeout 5 +TEST $CLI volume set $V0 self-heal-daemon off +TEST $CLI volume set $V0 cluster.data-self-heal off +TEST $CLI volume set $V0 cluster.metadata-self-heal off +TEST $CLI volume set $V0 cluster.entry-self-heal off + +##### Healing with favorite-child-policy = mtime ###### +##### and self-heal-daemon ###### + +TEST $CLI volume set $V0 favorite-child-policy mtime +TEST kill_brick $V0 $H0 $B0/${V0}0 +echo "Sink based on mtime" > $M0/f1 +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status $V0 0 +TEST kill_brick $V0 $H0 $B0/${V0}1 +echo "Source based on mtime" > $M0/f1 + +#Gfids of file f1 on bricks 0 & 1 should differ +gfid_0=$(gf_get_gfid_xattr $B0/${V0}0/f1) +gfid_1=$(gf_get_gfid_xattr $B0/${V0}1/f1) +TEST [ "$gfid_0" != "$gfid_1" ] + +TEST $CLI volume set $V0 self-heal-daemon on +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "Y" glustershd_up_status +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}1 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status $V0 1 + +#We know that first brick has the latest mtime +LATEST_MTIME_MD5=$(md5sum $B0/${V0}0/f1 | cut -d\ -f1) + +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 1 +TEST $CLI volume heal $V0 +EXPECT_WITHIN $HEAL_TIMEOUT "^0$" get_pending_heal_count $V0 + +#gfid split-brain should be resolved +gfid_1=$(gf_get_gfid_xattr $B0/${V0}1/f1) +TEST [ "$gfid_0" == "$gfid_1" ] + +HEALED_MD5=$(md5sum $B0/${V0}1/f1 | cut -d\ -f1) +TEST [ "$LATEST_MTIME_MD5" == "$HEALED_MD5" ] + +TEST $CLI volume set $V0 self-heal-daemon off + + +##### Healing with favorite-child-policy = ctime ###### +##### and self-heal-daemon ###### + +#gfid split-brain resolution should work even when the granular-enrty-heal is +#enabled +TEST $CLI volume heal $V0 granular-entry-heal enable + +TEST $CLI volume set $V0 favorite-child-policy ctime +TEST kill_brick $V0 $H0 $B0/${V0}1 +echo "Sink based on ctime" > $M0/f2 +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}1 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status $V0 1 +TEST kill_brick $V0 $H0 $B0/${V0}0 +echo "Source based on ctime" > $M0/f2 + +#Gfids of file f2 on bricks 0 & 1 should differ +gfid_0=$(gf_get_gfid_xattr $B0/${V0}0/f2) +gfid_1=$(gf_get_gfid_xattr $B0/${V0}1/f2) +TEST [ "$gfid_0" != "$gfid_1" ] + +TEST $CLI volume set $V0 self-heal-daemon on +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "Y" glustershd_up_status +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status $V0 0 + +#We know that second brick has the latest ctime +LATEST_CTIME_MD5=$(md5sum $B0/${V0}1/f2 | cut -d\ -f1) + +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 1 +TEST $CLI volume heal $V0 +EXPECT_WITHIN $HEAL_TIMEOUT "^0$" get_pending_heal_count $V0 + +#gfid split-brain should be resolved +gfid_0=$(gf_get_gfid_xattr $B0/${V0}0/f2) +TEST [ "$gfid_0" == "$gfid_1" ] + +HEALED_MD5=$(md5sum $B0/${V0}0/f2 | cut -d\ -f1) +TEST [ "$LATEST_CTIME_MD5" == "$HEALED_MD5" ] + + +#Add one more brick, and heal. +TEST $CLI volume add-brick $V0 replica 3 $H0:$B0/${V0}2 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "Y" glustershd_up_status +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}2 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status $V0 0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status $V0 1 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status $V0 2 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 1 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 2 + +TEST $CLI volume heal $V0 +EXPECT_WITHIN $HEAL_TIMEOUT "^0$" get_pending_heal_count $V0 + +TEST $CLI volume set $V0 self-heal-daemon off + + +##### Healing using favorite-child-policy = size ##### +##### and client side heal ##### + +TEST $CLI volume set $V0 cluster.data-self-heal on +TEST $CLI volume set $V0 cluster.metadata-self-heal on +TEST $CLI volume set $V0 cluster.entry-self-heal on + +#Set the quorum-type to none, and create a gfid split brain +TEST $CLI volume set $V0 cluster.quorum-type none +TEST kill_brick $V0 $H0 $B0/${V0}0 +TEST kill_brick $V0 $H0 $B0/${V0}1 +echo "Smallest file" > $M0/f3 + +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status $V0 0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}1 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status $V0 1 +TEST kill_brick $V0 $H0 $B0/${V0}1 +TEST kill_brick $V0 $H0 $B0/${V0}2 +echo "Second smallest file" > $M0/f3 + +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}1 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status $V0 1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}2 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status $V0 2 +TEST kill_brick $V0 $H0 $B0/${V0}0 +TEST kill_brick $V0 $H0 $B0/${V0}2 +echo "Biggest among the three files" > $M0/f3 + +#Bring back the down bricks. +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status $V0 0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}2 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status $V0 2 + +#Gfids of file f3 on all the bricks should differ +gfid_0=$(gf_get_gfid_xattr $B0/${V0}0/f3) +gfid_1=$(gf_get_gfid_xattr $B0/${V0}1/f3) +gfid_2=$(gf_get_gfid_xattr $B0/${V0}2/f3) +TEST [ "$gfid_0" != "$gfid_1" ] +TEST [ "$gfid_0" != "$gfid_2" ] +TEST [ "$gfid_1" != "$gfid_2" ] + +#We know that second brick has the bigger size file +BIGGER_FILE_MD5=$(md5sum $B0/${V0}1/f3 | cut -d\ -f1) + +TEST ls $M0 #Trigger entry heal via readdir inode refresh +TEST cat $M0/f3 #Trigger data heal via readv inode refresh +EXPECT_WITHIN $HEAL_TIMEOUT "^0$" get_pending_heal_count $V0 + +#gfid split-brain should be resolved +gfid_0=$(gf_get_gfid_xattr $B0/${V0}0/f3) +gfid_2=$(gf_get_gfid_xattr $B0/${V0}2/f3) +TEST [ "$gfid_0" == "$gfid_1" ] +TEST [ "$gfid_2" == "$gfid_1" ] + +HEALED_MD5_1=$(md5sum $B0/${V0}0/f3 | cut -d\ -f1) +HEALED_MD5_2=$(md5sum $B0/${V0}2/f3 | cut -d\ -f1) +TEST [ "$BIGGER_FILE_MD5" == "$HEALED_MD5_1" ] +TEST [ "$BIGGER_FILE_MD5" == "$HEALED_MD5_2" ] + + +##### Healing using favorite-child-policy = majority ##### +##### and client side heal ##### + +TEST kill_brick $V0 $H0 $B0/${V0}0 +TEST kill_brick $V0 $H0 $B0/${V0}1 +echo "Does not agree with bricks 0 & 1" > $M0/f4 + +TEST $CLI v start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status $V0 0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}1 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status $V0 1 +TEST kill_brick $V0 $H0 $B0/${V0}2 +echo "Agree on bricks 0 & 1" > $M0/f4 + +#Gfids of file f4 on bricks 0 & 1 should be same and bricks 0 & 2 should differ +gfid_0=$(gf_get_gfid_xattr $B0/${V0}0/f4) +gfid_1=$(gf_get_gfid_xattr $B0/${V0}1/f4) +gfid_2=$(gf_get_gfid_xattr $B0/${V0}2/f4) +TEST [ "$gfid_0" == "$gfid_1" ] +TEST [ "$gfid_0" != "$gfid_2" ] + +#We know that first and second bricks agree with each other. Pick any one of +#them as source +MAJORITY_MD5=$(md5sum $B0/${V0}0/f4 | cut -d\ -f1) + +#Bring back the down brick and heal. +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}2 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status $V0 2 + +TEST ls $M0 #Trigger entry heal via readdir inode refresh +TEST cat $M0/f4 #Trigger data heal via readv inode refresh +EXPECT_WITHIN $HEAL_TIMEOUT "^0$" get_pending_heal_count $V0 + +#gfid split-brain should be resolved +gfid_2=$(gf_get_gfid_xattr $B0/${V0}2/f4) +TEST [ "$gfid_0" == "$gfid_2" ] + +HEALED_MD5=$(md5sum $B0/${V0}2/f4 | cut -d\ -f1) +TEST [ "$MAJORITY_MD5" == "$HEALED_MD5" ] + +cleanup; diff --git a/tests/basic/afr/gfid-mismatch.t b/tests/basic/afr/gfid-mismatch.t new file mode 100644 index 00000000000..fc15793cf5a --- /dev/null +++ b/tests/basic/afr/gfid-mismatch.t @@ -0,0 +1,32 @@ +#!/bin/bash +#Test that GFID mismatches result in EIO + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc +cleanup; + +#Init +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 replica 2 $H0:$B0/brick{0,1} +TEST $CLI volume set $V0 self-heal-daemon off +TEST $CLI volume set $V0 stat-prefetch off +TEST $CLI volume start $V0 +TEST $CLI volume set $V0 cluster.background-self-heal-count 0 +# We can't count on brick0 getting a copy of the file immediately without this, +# because (especially with multiplexing) it might not have *come up* +# immediately. +TEST $CLI volume set $V0 cluster.quorum-type auto +TEST $GFS --volfile-id=$V0 -s $H0 $M0; + +#Test +TEST touch $M0/file +TEST setfattr -n trusted.gfid -v 0sBfz5vAdHTEK1GZ99qjqTIg== $B0/brick0/file +TEST ! "find $M0/file" +TEST ! "stat $M0/file" + +#Cleanup +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 +TEST $CLI volume stop $V0 +TEST $CLI volume delete $V0 +TEST rm -rf $B0/* diff --git a/tests/basic/afr/gfid-self-heal.t b/tests/basic/afr/gfid-self-heal.t new file mode 100644 index 00000000000..5a530681186 --- /dev/null +++ b/tests/basic/afr/gfid-self-heal.t @@ -0,0 +1,145 @@ +#!/bin/bash + +#Tests for files without gfids + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +cleanup; + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 replica 2 $H0:$B0/${V0}{0,1} +TEST $CLI volume set $V0 self-heal-daemon off +TEST $CLI volume set $V0 nfs.disable on +TEST touch $B0/${V0}{0,1}/{1,2,3,4} +TEST $CLI volume start $V0 + +TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0 +#Test that readdir returns entries even when no gfids are present +EXPECT 4 echo $(ls $M0 | grep -v '^\.' | wc -l) +sleep 2; +#stat the files and check that the files have same gfids on the bricks now +TEST stat $M0/1 +gfid_0=$(gf_get_gfid_xattr $B0/${V0}0/1) +gfid_1=$(gf_get_gfid_xattr $B0/${V0}1/1) +TEST "[[ ! -z $gfid_0 ]]" +EXPECT $gfid_0 echo $gfid_1 + +TEST stat $M0/2 +gfid_0=$(gf_get_gfid_xattr $B0/${V0}0/2) +gfid_1=$(gf_get_gfid_xattr $B0/${V0}1/2) +TEST "[[ ! -z $gfid_0 ]]" +EXPECT $gfid_0 echo $gfid_1 + +TEST stat $M0/3 +gfid_0=$(gf_get_gfid_xattr $B0/${V0}0/3) +gfid_1=$(gf_get_gfid_xattr $B0/${V0}1/3) +TEST "[[ ! -z $gfid_0 ]]" +EXPECT $gfid_0 echo $gfid_1 + +TEST stat $M0/4 +gfid_0=$(gf_get_gfid_xattr $B0/${V0}0/4) +gfid_1=$(gf_get_gfid_xattr $B0/${V0}1/4) +TEST "[[ ! -z $gfid_0 ]]" +EXPECT $gfid_0 echo $gfid_1 + +#Check gfid self-heal happens from one brick to other when a file has missing +#gfid +TEST kill_brick $V0 $H0 $B0/${V0}0 +TEST touch $M0/a +gfid_1=$(gf_get_gfid_xattr $B0/${V0}1/a) +TEST touch $B0/${V0}0/a +# storage/posix considers that a file without gfid changed less than a second +# before doesn't exist, so we need to wait for a second to force posix to +# consider that this is a valid file but without gfid. +sleep 1 +$CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0 +TEST stat $M0/a +gfid_0=$(gf_get_gfid_xattr $B0/${V0}0/a) +EXPECT $gfid_1 echo $gfid_0 + +#Check gfid self-heal doesn't happen from one brick to other when type mismatch +#is present for a name, without any xattrs +TEST kill_brick $V0 $H0 $B0/${V0}0 +TEST touch $M0/b +TEST mkdir $B0/${V0}0/b +TEST setfattr -x trusted.afr.$V0-client-0 $B0/${V0}1 +# storage/posix considers that a file without gfid changed less than a second +# before doesn't exist, so we need to wait for a second to force posix to +# consider that this is a valid file but without gfid. +sleep 1 +$CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0 +TEST ! stat $M0/b +gfid_0=$(gf_get_gfid_xattr $B0/${V0}0/b) +TEST "[[ -z \"$gfid_0\" ]]" + +#Check gfid assigning doesn't happen when there is type mismatch +TEST touch $B0/${V0}1/c +TEST mkdir $B0/${V0}0/c +# storage/posix considers that a file without gfid changed less than a second +# before doesn't exist, so we need to wait for a second to force posix to +# consider that this is a valid file but without gfid. +sleep 1 +TEST ! stat $M0/c +gfid_1=$(gf_get_gfid_xattr $B0/${V0}1/c) +gfid_0=$(gf_get_gfid_xattr $B0/${V0}0/c) +TEST "[[ -z \"$gfid_1\" ]]" +TEST "[[ -z \"$gfid_0\" ]]" + +#Check gfid assigning doesn't happen only when even one brick is down to prevent +# gfid split-brain +TEST kill_brick $V0 $H0 $B0/${V0}0 +TEST touch $B0/${V0}1/d +# storage/posix considers that a file without gfid changed less than a second +# before doesn't exist, so we need to wait for a second to force posix to +# consider that this is a valid file but without gfid. +sleep 1 +TEST ! stat $M0/d +gfid_1=$(gf_get_gfid_xattr $B0/${V0}1/d) +TEST "[[ -z \"$gfid_1\" ]]" +TEST $CLI volume start $V0 force; +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 1 + +#Check gfid self-heal doesn't happen from one brick to other when type mismatch +#is present for a name without any pending xattrs +#TEST kill_brick $V0 $H0 $B0/${V0}0 +#TEST touch $M0/e +#TEST $CLI volume start $V0 force; +#EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0 +#TEST kill_brick $V0 $H0 $B0/${V0}1 +#TEST mkdir $M0/e +#TEST $CLI volume stop $V0 force; +#TEST setfattr -x trusted.gfid $B0/${V0}1/e +#TEST setfattr -x trusted.gfid $B0/${V0}0/e +#TEST $CLI volume set $V0 cluster.entry-self-heal off +#$CLI volume start $V0 force +#EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0 +#EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 1 +#TEST ! stat $M0/e +#gfid_1=$(gf_get_gfid_xattr $B0/${V0}1/e) +#gfid_0=$(gf_get_gfid_xattr $B0/${V0}0/e) +#TEST "[[ -z \"$gfid_1\" ]]" +#TEST "[[ -z \"$gfid_0\" ]]" + +#Check if lookup fails with gfid-mismatch of a file +#is present for a name without any pending xattrs +#TEST kill_brick $V0 $H0 $B0/${V0}0 +#TEST touch $M0/f +#$CLI volume start $V0 force +#EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0 +#TEST kill_brick $V0 $H0 $B0/${V0}1 +#TEST touch $M0/f +#simulate no pending changelog +#$CLI volume stop $V0 force +#TEST setfattr -x trusted.afr.$V0-client-0 $B0/${V0}1 +#TEST setfattr -x trusted.afr.$V0-client-1 $B0/${V0}0 +#$CLI volume start $V0 force +#EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0 +#EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 1 +#TEST ! stat $M0/f + +cleanup diff --git a/tests/basic/afr/granular-esh/add-brick.t b/tests/basic/afr/granular-esh/add-brick.t new file mode 100644 index 00000000000..270cf1d32a6 --- /dev/null +++ b/tests/basic/afr/granular-esh/add-brick.t @@ -0,0 +1,80 @@ +#!/bin/bash + +. $(dirname $0)/../../../include.rc +. $(dirname $0)/../../../volume.rc +. $(dirname $0)/../../../afr.rc + +cleanup + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 replica 2 $H0:$B0/${V0}{0,1} +TEST $CLI volume start $V0 +TEST $CLI volume set $V0 cluster.data-self-heal off +TEST $CLI volume set $V0 cluster.metadata-self-heal off +TEST $CLI volume set $V0 cluster.entry-self-heal off +TEST $CLI volume set $V0 self-heal-daemon off +TEST $CLI volume heal $V0 granular-entry-heal enable + +TEST glusterfs --volfile-id=$V0 --volfile-server=$H0 $M0 + +# Create files +for i in {1..5} +do + echo $i > $M0/file$i.txt +done + +# Metadata changes +TEST setfattr -n user.test -v qwerty $M0/file5.txt + +# Add brick1 +TEST $CLI volume add-brick $V0 replica 3 $H0:$B0/${V0}2 + +# New-brick should accuse the old-bricks (Simulating case for data-loss) +TEST setfattr -n trusted.afr.$V0-client-0 -v 0x000000000000000000000001 $B0/${V0}2/ +TEST setfattr -n trusted.afr.$V0-client-1 -v 0x000000000000000000000001 $B0/${V0}2/ + +# Check if pending data, metadata and entry xattrs are set for newly-added-brick +EXPECT "000000010000000100000001" get_hex_xattr trusted.afr.$V0-client-2 $B0/${V0}0 +EXPECT "000000010000000100000001" get_hex_xattr trusted.afr.$V0-client-2 $B0/${V0}1 + +# Also ensure we are not mistakenly tampering with the new-brick's changelog xattrs +EXPECT "000000000000000000000001" get_hex_xattr trusted.afr.$V0-client-0 $B0/${V0}2 +EXPECT "000000000000000000000001" get_hex_xattr trusted.afr.$V0-client-1 $B0/${V0}2 + +# Check if dirty xattr is set for newly-added-brick +EXPECT "000000000000000000000001" get_hex_xattr trusted.afr.dirty $B0/${V0}2 + +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 2 + +TEST $CLI volume set $V0 self-heal-daemon on +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "Y" glustershd_up_status +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 1 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 2 +TEST $CLI volume heal $V0 + +# Wait for heal to complete +EXPECT_WITHIN $HEAL_TIMEOUT "^0$" get_pending_heal_count $V0 + +# Check if entry-heal has happened +TEST diff <(ls $B0/${V0}0 | sort) <(ls $B0/${V0}2 | sort) +TEST diff <(ls $B0/${V0}1 | sort) <(ls $B0/${V0}2 | sort) + +# Test if data was healed +TEST diff $B0/${V0}0/file1.txt $B0/${V0}2/file1.txt + +# Test if metadata was healed and exists on both the bricks +EXPECT "qwerty" get_text_xattr user.test $B0/${V0}2/file5.txt +EXPECT "qwerty" get_text_xattr user.test $B0/${V0}0/file5.txt + +# Ensure all changelog xattrs are now back to zero. +EXPECT "000000000000000000000000" get_hex_xattr trusted.afr.$V0-client-2 $B0/${V0}0 +EXPECT "000000000000000000000000" get_hex_xattr trusted.afr.$V0-client-2 $B0/${V0}1 +EXPECT "000000000000000000000000" get_hex_xattr trusted.afr.dirty $B0/${V0}2 +EXPECT "000000000000000000000000" get_hex_xattr trusted.afr.$V0-client-0 $B0/${V0}2 +EXPECT "000000000000000000000000" get_hex_xattr trusted.afr.$V0-client-1 $B0/${V0}2 + +cleanup diff --git a/tests/basic/afr/granular-esh/cli.t b/tests/basic/afr/granular-esh/cli.t new file mode 100644 index 00000000000..10b6c6398da --- /dev/null +++ b/tests/basic/afr/granular-esh/cli.t @@ -0,0 +1,114 @@ +#!/bin/bash + +. $(dirname $0)/../../../include.rc +. $(dirname $0)/../../../volume.rc +. $(dirname $0)/../../../afr.rc + +cleanup + +TESTS_EXPECTED_IN_LOOP=4 + +TEST glusterd +TEST pidof glusterd + +TEST $CLI volume create $V0 replica 3 $H0:$B0/${V0}{0,1,2} +# Test that enabling the option should work on a newly created volume +TEST $CLI volume set $V0 cluster.granular-entry-heal on +TEST $CLI volume set $V0 cluster.granular-entry-heal off + +######################### +##### DISPERSE TEST ##### +######################### +# Execute the same command on a disperse volume and make sure it fails. +TEST $CLI volume create $V1 disperse 3 redundancy 1 $H0:$B0/${V1}{0,1,2} +TEST $CLI volume start $V1 +TEST ! $CLI volume heal $V1 granular-entry-heal enable +TEST ! $CLI volume heal $V1 granular-entry-heal disable + +###################### +### REPLICATE TEST ### +###################### +TEST $CLI volume start $V0 +TEST $CLI volume set $V0 cluster.data-self-heal off +TEST $CLI volume set $V0 cluster.metadata-self-heal off +TEST $CLI volume set $V0 cluster.entry-self-heal off +TEST $CLI volume set $V0 self-heal-daemon off +# Test that the volume-set way of enabling the option is disallowed +TEST ! $CLI volume set $V0 granular-entry-heal on +# Test that the volume-heal way of enabling the option is allowed +TEST $CLI volume heal $V0 granular-entry-heal enable +# Volume-reset of the option should be allowed +TEST $CLI volume reset $V0 granular-entry-heal +TEST $CLI volume heal $V0 granular-entry-heal enable + +EXPECT "enable" volume_option $V0 cluster.granular-entry-heal + +TEST glusterfs --volfile-id=$V0 --volfile-server=$H0 $M0 + +# Kill brick-0. +TEST kill_brick $V0 $H0 $B0/${V0}0 + +# Disabling the option should work even when one or more bricks are down +TEST $CLI volume heal $V0 granular-entry-heal disable +# When a brick is down, 'enable' attempt should be failed +TEST ! $CLI volume heal $V0 granular-entry-heal enable + +# Restart the killed brick +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 1 + +# When all bricks are up, it should be possible to enable the option +TEST $CLI volume heal $V0 granular-entry-heal enable + +# Kill brick-0 again +TEST kill_brick $V0 $H0 $B0/${V0}0 + +# Create files under root +for i in {1..2} +do + echo $i > $M0/f$i +done + +# Test that the index associated with '/' is created on B1. +TEST stat $B0/${V0}1/.glusterfs/indices/entry-changes/$ROOT_GFID + +# Check for successful creation of granular entry indices +for i in {1..2} +do + TEST_IN_LOOP stat $B0/${V0}1/.glusterfs/indices/entry-changes/$ROOT_GFID/f$i +done + +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 1 + +TEST gluster volume set $V0 cluster.self-heal-daemon on +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "Y" glustershd_up_status +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 1 + +TEST $CLI volume heal $V0 + +# Wait for heal to complete +EXPECT_WITHIN $HEAL_TIMEOUT "^0$" get_pending_heal_count $V0 + +# Test if data was healed +for i in {1..2} +do + TEST_IN_LOOP diff $B0/${V0}0/f$i $B0/${V0}1/f$i +done + +# Now verify that there are no name indices left after self-heal +TEST ! stat $B0/${V0}1/.glusterfs/indices/entry-changes/$ROOT_GFID/f1 +TEST ! stat $B0/${V0}1/.glusterfs/indices/entry-changes/$ROOT_GFID/f2 +TEST ! stat $B0/${V0}1/.glusterfs/indices/entry-changes/$ROOT_GFID + +# Perform a volume-reset-all-options operation +TEST $CLI volume reset $V0 +# Ensure that granular entry heal is also disabled +EXPECT "no" volume_get_field $V0 cluster.granular-entry-heal +EXPECT "off" volume_get_field $V0 cluster.entry-self-heal + +cleanup +#G_TESTDEF_TEST_STATUS_NETBSD7=BAD_TEST,BUG=1399038 diff --git a/tests/basic/afr/granular-esh/conservative-merge.t b/tests/basic/afr/granular-esh/conservative-merge.t new file mode 100644 index 00000000000..b170e47e0cb --- /dev/null +++ b/tests/basic/afr/granular-esh/conservative-merge.t @@ -0,0 +1,138 @@ +#!/bin/bash + +. $(dirname $0)/../../../include.rc +. $(dirname $0)/../../../volume.rc +. $(dirname $0)/../../../afr.rc + +cleanup + +TESTS_EXPECTED_IN_LOOP=4 + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 replica 2 $H0:$B0/${V0}{0,1} +TEST $CLI volume start $V0 +TEST $CLI volume set $V0 self-heal-daemon off +TEST $CLI volume set $V0 data-self-heal off +TEST $CLI volume set $V0 metadata-self-heal off +TEST $CLI volume set $V0 entry-self-heal off +TEST $CLI volume heal $V0 granular-entry-heal enable + +TEST $GFS --volfile-id=$V0 -s $H0 $M0 + +TEST mkdir $M0/dir +gfid_dir=$(get_gfid_string $M0/dir) + +echo "1" > $M0/f1 +echo "2" > $M0/f2 + +TEST kill_brick $V0 $H0 $B0/${V0}0 + +TEST mkdir $M0/dir2 +gfid_dir2=$(get_gfid_string $M0/dir2) +TEST unlink $M0/f1 +echo "3" > $M0/f3 +TEST mkdir $M0/dir/subdir +gfid_subdir=$(get_gfid_string $M0/dir/subdir) +echo "dir2-1" > $M0/dir2/f1 +echo "subdir-1" > $M0/dir/subdir/f1 + +TEST stat $B0/${V0}1/.glusterfs/indices/entry-changes/$ROOT_GFID +TEST stat $B0/${V0}1/.glusterfs/indices/entry-changes/$ROOT_GFID/dir2 +TEST stat $B0/${V0}1/.glusterfs/indices/entry-changes/$ROOT_GFID/f1 +TEST stat $B0/${V0}1/.glusterfs/indices/entry-changes/$ROOT_GFID/f3 +TEST stat $B0/${V0}1/.glusterfs/indices/entry-changes/$gfid_dir2 +TEST stat $B0/${V0}1/.glusterfs/indices/entry-changes/$gfid_dir2/f1 +TEST stat $B0/${V0}1/.glusterfs/indices/entry-changes/$gfid_dir +TEST stat $B0/${V0}1/.glusterfs/indices/entry-changes/$gfid_dir/subdir +TEST stat $B0/${V0}1/.glusterfs/indices/entry-changes/$gfid_subdir +TEST stat $B0/${V0}1/.glusterfs/indices/entry-changes/$gfid_subdir/f1 + +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 1 +TEST kill_brick $V0 $H0 $B0/${V0}1 + +TEST mkdir $M0/dir3 +gfid_dir3=$(get_gfid_string $M0/dir3) +# Root is now in split-brain. +TEST mkdir $M0/dir/subdir2 +gfid_subdir2=$(get_gfid_string $M0/dir/subdir2) +# /dir is now in split-brain. +echo "4" > $M0/f4 +TEST unlink $M0/f2 +echo "dir3-1" > $M0/dir3/f1 +echo "subdir2-1" > $M0/dir/subdir2/f1 + +TEST stat $B0/${V0}0/.glusterfs/indices/entry-changes/$ROOT_GFID +TEST stat $B0/${V0}0/.glusterfs/indices/entry-changes/$ROOT_GFID/dir3 +TEST stat $B0/${V0}0/.glusterfs/indices/entry-changes/$ROOT_GFID/f2 +TEST stat $B0/${V0}0/.glusterfs/indices/entry-changes/$ROOT_GFID/f4 +TEST stat $B0/${V0}0/.glusterfs/indices/entry-changes/$gfid_dir +TEST stat $B0/${V0}0/.glusterfs/indices/entry-changes/$gfid_dir/subdir2 +TEST stat $B0/${V0}0/.glusterfs/indices/entry-changes/$gfid_dir3 +TEST stat $B0/${V0}0/.glusterfs/indices/entry-changes/$gfid_dir3/f1 +TEST stat $B0/${V0}0/.glusterfs/indices/entry-changes/$gfid_subdir2 +TEST stat $B0/${V0}0/.glusterfs/indices/entry-changes/$gfid_subdir2/f1 + +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 1 + +TEST $CLI volume set $V0 self-heal-daemon on +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "Y" glustershd_up_status +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 1 + +TEST $CLI volume heal $V0 + +# Wait for heal to complete +EXPECT_WITHIN $HEAL_TIMEOUT "^0$" get_pending_heal_count $V0 + +# Make sure entry self-heal did the right thing in terms of impunging deleted +# files in the event of a split-brain. +TEST stat $M0/f1 +TEST stat $M0/f2 + +# Test if data was healed +for i in {1..4} +do + TEST_IN_LOOP diff $B0/${V0}0/f$i $B0/${V0}1/f$i +done + +TEST diff $B0/${V0}0/dir2/f1 $B0/${V0}1/dir2/f1 +EXPECT "dir2-1" cat $M0/dir2/f1 + +TEST diff $B0/${V0}0/dir/subdir/f1 $B0/${V0}1/dir/subdir/f1 +EXPECT "subdir-1" cat $M0/dir/subdir/f1 + +TEST diff $B0/${V0}0/dir3/f1 $B0/${V0}1/dir3/f1 +EXPECT "dir3-1" cat $M0/dir3/f1 + +TEST diff $B0/${V0}0/dir/subdir2/f1 $B0/${V0}1/dir/subdir2/f1 +EXPECT "subdir2-1" cat $M0/dir/subdir2/f1 + +# Verify that all name indices have been removed after a successful heal. +TEST ! stat $B0/${V0}1/.glusterfs/indices/entry-changes/$ROOT_GFID/dir2 +TEST ! stat $B0/${V0}0/.glusterfs/indices/entry-changes/$ROOT_GFID/dir3 +TEST ! stat $B0/${V0}1/.glusterfs/indices/entry-changes/$ROOT_GFID/f1 +TEST ! stat $B0/${V0}0/.glusterfs/indices/entry-changes/$ROOT_GFID/f2 +TEST ! stat $B0/${V0}1/.glusterfs/indices/entry-changes/$ROOT_GFID/f3 +TEST ! stat $B0/${V0}0/.glusterfs/indices/entry-changes/$ROOT_GFID/f4 +TEST ! stat $B0/${V0}1/.glusterfs/indices/entry-changes/$gfid_dir2/f1 +TEST ! stat $B0/${V0}1/.glusterfs/indices/entry-changes/$gfid_dir/subdir +TEST ! stat $B0/${V0}0/.glusterfs/indices/entry-changes/$gfid_dir/subdir2 +TEST ! stat $B0/${V0}1/.glusterfs/indices/entry-changes/$gfid_subdir/f1 +TEST ! stat $B0/${V0}1/.glusterfs/indices/entry-changes/$gfid_dir3/f1 +TEST ! stat $B0/${V0}1/.glusterfs/indices/entry-changes/$gfid_subdir2/f1 + +TEST ! stat $B0/${V0}1/.glusterfs/indices/entry-changes/$ROOT_GFID +TEST ! stat $B0/${V0}0/.glusterfs/indices/entry-changes/$ROOT_GFID +TEST ! stat $B0/${V0}1/.glusterfs/indices/entry-changes/$gfid_dir +TEST ! stat $B0/${V0}0/.glusterfs/indices/entry-changes/$gfid_dir +TEST ! stat $B0/${V0}1/.glusterfs/indices/entry-changes/$gfid_dir2 +TEST ! stat $B0/${V0}1/.glusterfs/indices/entry-changes/$gfid_subdir +TEST ! stat $B0/${V0}1/.glusterfs/indices/entry-changes/$gfid_dir3 +TEST ! stat $B0/${V0}1/.glusterfs/indices/entry-changes/$gfid_subdir2 + +cleanup diff --git a/tests/basic/afr/granular-esh/granular-esh.t b/tests/basic/afr/granular-esh/granular-esh.t new file mode 100644 index 00000000000..de0e8f4290b --- /dev/null +++ b/tests/basic/afr/granular-esh/granular-esh.t @@ -0,0 +1,168 @@ +#!/bin/bash + +. $(dirname $0)/../../../include.rc +. $(dirname $0)/../../../volume.rc +. $(dirname $0)/../../../afr.rc + +cleanup + +TESTS_EXPECTED_IN_LOOP=12 + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 replica 2 $H0:$B0/${V0}{0,1} +TEST $CLI volume start $V0 +TEST $CLI volume set $V0 cluster.data-self-heal off +TEST $CLI volume set $V0 cluster.metadata-self-heal off +TEST $CLI volume set $V0 cluster.entry-self-heal off +TEST $CLI volume set $V0 self-heal-daemon off +TEST $CLI volume heal $V0 granular-entry-heal enable + +TEST glusterfs --volfile-id=$V0 --volfile-server=$H0 $M0 + +# Create files under root +for i in {1..4} +do + echo $i > $M0/f$i +done + +# Create a directory and few files under it +TEST mkdir $M0/dir +gfid_dir=$(get_gfid_string $M0/dir) + +for i in {1..3} +do + echo $i > $M0/dir/f$i +done + +# Kill brick-0. +TEST kill_brick $V0 $H0 $B0/${V0}0 + +# Create more files +for i in {5..6} +do + echo $i > $M0/f$i +done + +# Test that the index associated with '/' is created on B1. +TEST stat $B0/${V0}1/.glusterfs/indices/entry-changes/$ROOT_GFID + +# Check for successful creation of granular entry indices +for i in {5..6} +do + TEST_IN_LOOP stat $B0/${V0}1/.glusterfs/indices/entry-changes/$ROOT_GFID/f$i +done + +# Delete an existing file +TEST unlink $M0/f1 + +# Rename an existing file +TEST mv $M0/f2 $M0/f2_renamed + +# Create a hard link on f3 +TEST ln $M0/f3 $M0/link + +# Create a symlink on f4 +TEST ln -s $M0/f4 $M0/symlink + +# Check for successful creation of granular entry indices +for i in {1..2} +do + TEST_IN_LOOP stat $B0/${V0}1/.glusterfs/indices/entry-changes/$ROOT_GFID/f$i +done + +TEST stat $B0/${V0}1/.glusterfs/indices/entry-changes/$ROOT_GFID/f2_renamed +TEST stat $B0/${V0}1/.glusterfs/indices/entry-changes/$ROOT_GFID/link +TEST stat $B0/${V0}1/.glusterfs/indices/entry-changes/$ROOT_GFID/symlink + +# Create a file and also delete it. This is to test deletion of stale indices during heal. +TEST touch $M0/file_stale +TEST unlink $M0/file_stale +TEST stat $B0/${V0}1/.glusterfs/indices/entry-changes/$ROOT_GFID/file_stale + +# Create a directory and create its subdirs and files while a brick is down +TEST mkdir -p $M0/newdir/newsubdir + +for i in {1..3} +do + echo $i > $M0/newdir/f$i + echo $i > $M0/newdir/newsubdir/f$i +done + +TEST stat $B0/${V0}1/.glusterfs/indices/entry-changes/$ROOT_GFID/newdir +gfid_newdir=$(get_gfid_string $M0/newdir) +gfid_newsubdir=$(get_gfid_string $M0/newdir/newsubdir) +TEST stat $B0/${V0}1/.glusterfs/indices/entry-changes/$gfid_newdir/newsubdir +# Check if 'data' segment of the changelog is set for the newly created directories 'newdir' and 'newsubdir' +EXPECT "00000001" afr_get_specific_changelog_xattr $B0/${V0}1/newdir trusted.afr.$V0-client-0 data +EXPECT "00000001" afr_get_specific_changelog_xattr $B0/${V0}1/newdir/newsubdir trusted.afr.$V0-client-0 data + +# Test that removal of an entire sub-tree in the hierarchy works. +TEST rm -rf $M0/dir + +TEST stat $B0/${V0}1/.glusterfs/indices/entry-changes/$ROOT_GFID/dir +TEST stat $B0/${V0}1/.glusterfs/indices/entry-changes/$gfid_dir/f1 +TEST stat $B0/${V0}1/.glusterfs/indices/entry-changes/$gfid_dir/f2 +TEST stat $B0/${V0}1/.glusterfs/indices/entry-changes/$gfid_dir/f3 + +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 1 + +TEST gluster volume set $V0 cluster.self-heal-daemon on +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "Y" glustershd_up_status +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 1 +TEST $CLI volume heal $V0 + +# Wait for heal to complete +EXPECT_WITHIN $HEAL_TIMEOUT "^0$" get_pending_heal_count $V0 + +# Test if data was healed +for i in {5..6} +do + TEST_IN_LOOP diff $B0/${V0}0/f$i $B0/${V0}1/f$i +done + +for i in {1..3} +do + TEST_IN_LOOP diff $B0/${V0}0/newdir/f$i $B0/${V0}1/newdir/f$i + TEST_IN_LOOP diff $B0/${V0}0/newdir/newsubdir/f$i $B0/${V0}1/newdir/newsubdir/f$i +done + +# Verify that all the deleted names have been removed on the sink brick too by self-heal. +TEST ! stat $B0/${V0}0/f1 +TEST ! stat $B0/${V0}0/f2 +TEST stat $B0/${V0}0/f2_renamed +TEST stat $B0/${V0}0/symlink +EXPECT "3" get_hard_link_count $B0/${V0}0/f3 +EXPECT "f4" readlink $B0/${V0}0/symlink +TEST ! stat $B0/${V0}0/dir + +# Now verify that there are no name indices left after self-heal +TEST ! stat $B0/${V0}1/.glusterfs/indices/entry-changes/$ROOT_GFID/f1 +TEST ! stat $B0/${V0}1/.glusterfs/indices/entry-changes/$ROOT_GFID/f2 +TEST ! stat $B0/${V0}1/.glusterfs/indices/entry-changes/$ROOT_GFID/f2_renamed +TEST ! stat $B0/${V0}1/.glusterfs/indices/entry-changes/$ROOT_GFID/link +TEST ! stat $B0/${V0}1/.glusterfs/indices/entry-changes/$ROOT_GFID/symlink +TEST ! stat $B0/${V0}1/.glusterfs/indices/entry-changes/$ROOT_GFID/dir +TEST ! stat $B0/${V0}1/.glusterfs/indices/entry-changes/$ROOT_GFID/newdir +TEST ! stat $B0/${V0}1/.glusterfs/indices/entry-changes/$ROOT_GFID/file_stale + +TEST ! stat $B0/${V0}1/.glusterfs/indices/entry-changes/$gfid_dir/f1 +TEST ! stat $B0/${V0}1/.glusterfs/indices/entry-changes/$gfid_dir/f2 +TEST ! stat $B0/${V0}1/.glusterfs/indices/entry-changes/$gfid_dir/f3 + +TEST ! stat $B0/${V0}1/.glusterfs/indices/entry-changes/$gfid_newdir/f1 +TEST ! stat $B0/${V0}1/.glusterfs/indices/entry-changes/$gfid_newdir/f2 +TEST ! stat $B0/${V0}1/.glusterfs/indices/entry-changes/$gfid_newdir/f3 +TEST ! stat $B0/${V0}1/.glusterfs/indices/entry-changes/$gfid_newsubdir/f1 +TEST ! stat $B0/${V0}1/.glusterfs/indices/entry-changes/$gfid_newsubdir/f2 +TEST ! stat $B0/${V0}1/.glusterfs/indices/entry-changes/$gfid_newsubdir/f3 + +TEST ! stat $B0/${V0}1/.glusterfs/indices/entry-changes/$ROOT_GFID +TEST ! stat $B0/${V0}1/.glusterfs/indices/entry-changes/$gfid_newdir +TEST ! stat $B0/${V0}1/.glusterfs/indices/entry-changes/$gfid_newsubdir +TEST ! stat $B0/${V0}1/.glusterfs/indices/entry-changes/$gfid_dir + +cleanup diff --git a/tests/basic/afr/granular-esh/granular-indices-but-non-granular-heal.t b/tests/basic/afr/granular-esh/granular-indices-but-non-granular-heal.t new file mode 100644 index 00000000000..1b5421bf4b6 --- /dev/null +++ b/tests/basic/afr/granular-esh/granular-indices-but-non-granular-heal.t @@ -0,0 +1,76 @@ +#!/bin/bash + +. $(dirname $0)/../../../include.rc +. $(dirname $0)/../../../volume.rc +. $(dirname $0)/../../../afr.rc + +cleanup + +TESTS_EXPECTED_IN_LOOP=4 + +TEST glusterd +TEST pidof glusterd + +TEST $CLI volume create $V0 replica 2 $H0:$B0/${V0}{0,1} +TEST $CLI volume start $V0 +TEST $CLI volume set $V0 cluster.data-self-heal off +TEST $CLI volume set $V0 cluster.metadata-self-heal off +TEST $CLI volume set $V0 cluster.entry-self-heal off +TEST $CLI volume set $V0 self-heal-daemon off +TEST $CLI volume heal $V0 granular-entry-heal enable + +TEST glusterfs --volfile-id=$V0 --volfile-server=$H0 $M0 + +# Kill brick-0. +TEST kill_brick $V0 $H0 $B0/${V0}0 + +# Create files under root +for i in {1..2} +do + echo $i > $M0/f$i +done + +# Test that the index associated with '/' is created on B1. +TEST stat $B0/${V0}1/.glusterfs/indices/entry-changes/$ROOT_GFID + +# Check for successful creation of granular entry indices +for i in {1..2} +do + TEST_IN_LOOP stat $B0/${V0}1/.glusterfs/indices/entry-changes/$ROOT_GFID/f$i +done + +# Now disable granular-entry-heal +TEST $CLI volume heal $V0 granular-entry-heal disable + +# Start the brick that was down +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 1 + +# Enable shd +TEST gluster volume set $V0 cluster.self-heal-daemon on +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "Y" glustershd_up_status +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 1 + +# Now the indices created are granular but the heal is going to be of the +# normal kind. We test to make sure that heal still completes fine and that +# the stale granular indices are going to be deleted + +TEST $CLI volume heal $V0 + +# Wait for heal to complete +EXPECT_WITHIN $HEAL_TIMEOUT "^0$" get_pending_heal_count $V0 + +# Test if data was healed +for i in {1..2} +do + TEST_IN_LOOP diff $B0/${V0}0/f$i $B0/${V0}1/f$i +done + +# Now verify that there are no name indices left after self-heal +TEST ! stat $B0/${V0}1/.glusterfs/indices/entry-changes/$ROOT_GFID/f1 +TEST ! stat $B0/${V0}1/.glusterfs/indices/entry-changes/$ROOT_GFID/f2 +TEST ! stat $B0/${V0}1/.glusterfs/indices/entry-changes/$ROOT_GFID + +cleanup diff --git a/tests/basic/afr/granular-esh/replace-brick.t b/tests/basic/afr/granular-esh/replace-brick.t new file mode 100644 index 00000000000..5fc7811a8d8 --- /dev/null +++ b/tests/basic/afr/granular-esh/replace-brick.t @@ -0,0 +1,76 @@ +#!/bin/bash +. $(dirname $0)/../../../include.rc +. $(dirname $0)/../../../volume.rc + +cleanup + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 replica 2 $H0:$B0/${V0}{0,1} +TEST $CLI volume start $V0 +TEST $CLI volume set $V0 cluster.data-self-heal off +TEST $CLI volume set $V0 cluster.metadata-self-heal off +TEST $CLI volume set $V0 cluster.entry-self-heal off +TEST $CLI volume set $V0 self-heal-daemon off +TEST $CLI volume set $V0 cluster.heal-timeout 5 +TEST $CLI volume heal $V0 granular-entry-heal enable + +TEST glusterfs --volfile-id=$V0 --volfile-server=$H0 $M0; + +# Create files +for i in {1..5} +do + echo $i > $M0/file$i.txt +done + +# Metadata changes +TEST setfattr -n user.test -v qwerty $M0/file5.txt + +# Replace brick1 +TEST $CLI volume replace-brick $V0 $H0:$B0/${V0}1 $H0:$B0/${V0}1_new commit force + +# Replaced-brick should accuse the non-replaced-brick (Simulating case for data-loss) +TEST setfattr -n trusted.afr.$V0-client-0 -v 0x000000000000000000000001 $B0/${V0}1_new/ + +# Check if data, metadata and entry segments of changelog are set for replaced-brick +EXPECT "000000010000000100000001" get_hex_xattr trusted.afr.$V0-client-1 $B0/${V0}0 + +# Also ensure we don't mistakenly tamper with the new brick's changelog xattrs +EXPECT "000000000000000000000001" get_hex_xattr trusted.afr.$V0-client-0 $B0/${V0}1_new + +# Ensure the dirty xattr is set on the new brick. +EXPECT "000000000000000000000001" get_hex_xattr trusted.afr.dirty $B0/${V0}1_new + +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 1 + +TEST $CLI volume set $V0 self-heal-daemon on +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "Y" glustershd_up_status +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 1 +TEST $CLI volume heal $V0 + +# Wait for heal to complete +EXPECT_WITHIN $HEAL_TIMEOUT "0" get_pending_heal_count $V0 + +# Check if entry-heal has happened +TEST diff <(ls $B0/${V0}0 | sort) <(ls $B0/${V0}1_new | sort) + +# To make sure that files were not lost from brick0 +TEST diff <(ls $B0/${V0}0 | sort) <(ls $B0/${V0}1 | sort) +EXPECT "000000000000000000000000" get_hex_xattr trusted.afr.$V0-client-1 $B0/${V0}0 + +# Test if data was healed +TEST diff $B0/${V0}0/file1.txt $B0/${V0}1_new/file1.txt +# To make sure that data was not lost from brick0 +TEST diff $B0/${V0}0/file1.txt $B0/${V0}1/file1.txt + +# Test if metadata was healed and exists on both the bricks +EXPECT "qwerty" get_text_xattr user.test $B0/${V0}1_new/file5.txt +EXPECT "qwerty" get_text_xattr user.test $B0/${V0}0/file5.txt + +EXPECT "000000000000000000000000" get_hex_xattr trusted.afr.$V0-client-1 $B0/${V0}0 +EXPECT "000000000000000000000000" get_hex_xattr trusted.afr.$V0-client-0 $B0/${V0}1_new +EXPECT "000000000000000000000000" get_hex_xattr trusted.afr.dirty $B0/${V0}1_new + +cleanup diff --git a/tests/basic/afr/halo.t b/tests/basic/afr/halo.t new file mode 100644 index 00000000000..3f61f5a0402 --- /dev/null +++ b/tests/basic/afr/halo.t @@ -0,0 +1,61 @@ +#!/bin/bash +#Tests that halo basic functionality works as expected + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc +. $(dirname $0)/../../afr.rc + +cleanup; + +function get_up_child() +{ + if [ "1" == $(afr_private_key_value $V0 $M0 0 "child_up\[0\]") ]; + then + echo 0 + elif [ "1" == $(afr_private_key_value $V0 $M0 0 "child_up\[1\]") ] + then + echo 1 + fi +} + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 replica 2 $H0:$B0/${V0}{0,1} +TEST $CLI volume set $V0 cluster.halo-enabled yes +TEST $CLI volume set $V0 cluster.halo-max-replicas 1 +TEST $CLI volume start $V0 +TEST $GFS --volfile-id=$V0 --volfile-server=$H0 $M0; +EXPECT "^1$" afr_private_key_value $V0 $M0 0 "halo_child_up\[0\]" +EXPECT "^1$" afr_private_key_value $V0 $M0 0 "halo_child_up\[1\]" +EXPECT_NOT "^-1$" afr_private_key_value $V0 $M0 0 "child_latency\[0\]" +EXPECT_NOT "^-1$" afr_private_key_value $V0 $M0 0 "child_latency\[1\]" + +up_id=$(get_up_child) +TEST [[ ! -z "$up_id" ]] + +down_id=$((1-up_id)) + +TEST kill_brick $V0 $H0 $B0/${V0}${up_id} +#As max-replicas is configured to be 1, down_child should be up now +EXPECT_WITHIN $PROCESS_DOWN_TIMEOUT "^1$" afr_private_key_value $V0 $M0 0 "halo_child_up\[${down_id}\]" +EXPECT_WITHIN $PROCESS_DOWN_TIMEOUT "^1$" afr_private_key_value $V0 $M0 0 "child_up\[${down_id}\]" +EXPECT_WITHIN $PROCESS_DOWN_TIMEOUT "^0$" afr_private_key_value $V0 $M0 0 "halo_child_up\[${up_id}\]" +EXPECT_WITHIN $PROCESS_DOWN_TIMEOUT "^0$" afr_private_key_value $V0 $M0 0 "child_up\[${up_id}\]" +EXPECT "^-1$" afr_private_key_value $V0 $M0 0 "child_latency\[${up_id}\]" +EXPECT_NOT "^-1$" afr_private_key_value $V0 $M0 0 "child_latency\[${down_id}\]" + +#Bring the brick back up and the state should be restored +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "^1$" afr_private_key_value $V0 $M0 0 "halo_child_up\[${up_id}\]" + +up_id=$(get_up_child) +TEST [[ ! -z "$up_id" ]] +down_id=$((1-up_id)) +EXPECT_WITHIN $PROCESS_DOWN_TIMEOUT "^1$" afr_private_key_value $V0 $M0 0 "halo_child_up\[${down_id}\]" +EXPECT_WITHIN $PROCESS_DOWN_TIMEOUT "^0$" afr_private_key_value $V0 $M0 0 "child_up\[${down_id}\]" +EXPECT_WITHIN $PROCESS_DOWN_TIMEOUT "^1$" afr_private_key_value $V0 $M0 0 "halo_child_up\[${up_id}\]" +EXPECT_WITHIN $PROCESS_DOWN_TIMEOUT "^1$" afr_private_key_value $V0 $M0 0 "child_up\[${up_id}\]" +EXPECT_NOT "^-1$" afr_private_key_value $V0 $M0 0 "child_latency\[0\]" +EXPECT_NOT "^-1$" afr_private_key_value $V0 $M0 0 "child_latency\[1\]" + +cleanup; diff --git a/tests/basic/afr/heal-info.t b/tests/basic/afr/heal-info.t new file mode 100644 index 00000000000..46d65007c88 --- /dev/null +++ b/tests/basic/afr/heal-info.t @@ -0,0 +1,36 @@ +#!/bin/bash +#Test that parallel heal-info command execution doesn't result in spurious +#entries with locking-scheme granular + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +cleanup; + +function heal_info_to_file { + while [ -f $M0/b.txt ]; do + $CLI volume heal $V0 info | grep -i number | grep -v 0 >> $1 + done +} + +function write_and_del_file { + dd of=$M0/a.txt if=/dev/zero bs=1024k count=100 + rm -f $M0/b.txt +} + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 replica 2 $H0:$B0/brick{0,1} +TEST $CLI volume set $V0 locking-scheme granular +TEST $CLI volume start $V0 +TEST $GFS --volfile-id=$V0 --volfile-server=$H0 $M0; +TEST touch $M0/a.txt $M0/b.txt +write_and_del_file & +touch $B0/f1 $B0/f2 +heal_info_to_file $B0/f1 & +heal_info_to_file $B0/f2 & +wait +EXPECT "^$" cat $B0/f1 +EXPECT "^$" cat $B0/f2 + +cleanup; diff --git a/tests/basic/afr/heal-quota.t b/tests/basic/afr/heal-quota.t new file mode 100644 index 00000000000..96e23363da8 --- /dev/null +++ b/tests/basic/afr/heal-quota.t @@ -0,0 +1,35 @@ +#!/bin/bash + +#This file tests that heal succeeds even when quota is exceeded + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +cleanup; + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 replica 2 $H0:$B0/${V0}{0,1} +TEST $CLI volume set $V0 cluster.self-heal-daemon off +TEST $CLI volume start $V0 + +TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0; +TEST $CLI volume quota $V0 enable +TEST $CLI volume quota $V0 limit-usage / 10MB +TEST $CLI volume quota $V0 soft-timeout 0 +TEST $CLI volume quota $V0 hard-timeout 0 + +TEST touch $M0/a $M0/b +dd if=/dev/zero of=$M0/b bs=1M count=7 +TEST kill_brick $V0 $H0 $B0/${V0}0 +dd if=/dev/zero of=$M0/a bs=1M count=12 #This shall fail +TEST $CLI volume start $V0 force +TEST $CLI volume set $V0 cluster.self-heal-daemon on +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "Y" glustershd_up_status +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 1 + +TEST $CLI volume heal $V0 +EXPECT_WITHIN $HEAL_TIMEOUT "0" get_pending_heal_count $V0 + +cleanup diff --git a/tests/basic/afr/inodelk.t b/tests/basic/afr/inodelk.t new file mode 100644 index 00000000000..a32aa8531b5 --- /dev/null +++ b/tests/basic/afr/inodelk.t @@ -0,0 +1,87 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc +cleanup; + +#This test tests that inodelk fails when quorum is not met. Also tests the +#success case where inodelk is obtained and unlocks are done correctly. + +TEST glusterd; +TEST pidof glusterd + +TEST $CLI volume create $V0 replica 3 arbiter 1 $H0:$B0/${V0}{0..5} +TEST $CLI volume start $V0 +TEST $GFS -s $H0 --volfile-id=$V0 $M0 + +#Test success case +TEST mkdir $M0/dir1 +TEST mv $M0/dir1 $M0/dir2 + +#If there is a problem with inodelk unlocking the following would hang. +TEST mv $M0/dir2 $M0/dir1 + +#Test failure case by bringing two of the bricks down +#Test that the directory is not moved partially on some bricks but successful +#on other subvol where quorum meets. Do that for both set of bricks + +TEST kill_brick $V0 $H0 $B0/${V0}0 +TEST kill_brick $V0 $H0 $B0/${V0}1 +TEST ! mv $M0/dir1 $M0/dir2 + +TEST stat $B0/${V0}0/dir1 +TEST stat $B0/${V0}1/dir1 +TEST stat $B0/${V0}2/dir1 +TEST stat $B0/${V0}3/dir1 +TEST stat $B0/${V0}4/dir1 +TEST stat $B0/${V0}5/dir1 +TEST ! stat $B0/${V0}0/dir2 +TEST ! stat $B0/${V0}1/dir2 +TEST ! stat $B0/${V0}2/dir2 +TEST ! stat $B0/${V0}3/dir2 +TEST ! stat $B0/${V0}4/dir2 +TEST ! stat $B0/${V0}5/dir2 + +TEST $CLI volume start $V0 force +TEST kill_brick $V0 $H0 $B0/${V0}3 +TEST kill_brick $V0 $H0 $B0/${V0}4 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 1 +TEST ! mv $M0/dir1 $M0/dir2 +TEST stat $B0/${V0}0/dir1 +TEST stat $B0/${V0}1/dir1 +TEST stat $B0/${V0}2/dir1 +TEST stat $B0/${V0}3/dir1 +TEST stat $B0/${V0}4/dir1 +TEST stat $B0/${V0}5/dir1 +TEST ! stat $B0/${V0}0/dir2 +TEST ! stat $B0/${V0}1/dir2 +TEST ! stat $B0/${V0}2/dir2 +TEST ! stat $B0/${V0}3/dir2 +TEST ! stat $B0/${V0}4/dir2 +TEST ! stat $B0/${V0}5/dir2 + +#Bring the bricks back up and try mv once more, it should succeed. +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 3 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 4 +TEST mv $M0/dir1 $M0/dir2 +cleanup; +#Do similar tests on replica 2 +TEST glusterd; +TEST pidof glusterd +TEST $CLI volume create $V0 replica 2 $H0:$B0/${V0}{0..3} +TEST $CLI volume start $V0 +TEST $GFS -s $H0 --volfile-id=$V0 $M0 +TEST mkdir $M0/dir1 +TEST mv $M0/dir1 $M0/dir2 +#Because we don't know hashed subvol, do the same test twice bringing 1 brick +#from each down, quorum calculation should allow it. +TEST kill_brick $V0 $H0 $B0/${V0}0 +TEST mv $M0/dir2 $M0/dir1 +TEST $CLI volume start $V0 force +TEST kill_brick $V0 $H0 $B0/${V0}2 +TEST mv $M0/dir1 $M0/dir2 +TEST kill_brick $V0 $H0 $B0/${V0}0 +TEST mv $M0/dir2 $M0/dir1 +cleanup diff --git a/tests/basic/afr/lk-quorum.t b/tests/basic/afr/lk-quorum.t new file mode 100644 index 00000000000..3364d8a6a1b --- /dev/null +++ b/tests/basic/afr/lk-quorum.t @@ -0,0 +1,257 @@ +#!/bin/bash + +SCRIPT_TIMEOUT=300 + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc +. $(dirname $0)/../../fileio.rc +cleanup; + +TEST glusterd; +TEST pidof glusterd + +#Tests for quorum-type option for replica 2 +TEST $CLI volume create $V0 replica 2 $H0:$B0/${V0}{0,1}; +TEST $CLI volume set $V0 performance.quick-read off +TEST $CLI volume set $V0 performance.io-cache off +TEST $CLI volume set $V0 performance.write-behind off +TEST $CLI volume set $V0 performance.open-behind off +TEST $CLI volume set $V0 performance.stat-prefetch off +TEST $CLI volume set $V0 performance.read-ahead off +TEST $CLI volume start $V0 +TEST $GFS -s $H0 --volfile-id=$V0 --direct-io-mode=enable $M0; + +TEST touch $M0/a + +#When all bricks are up, lock and unlock should succeed +TEST fd1=`fd_available` +TEST fd_open $fd1 'w' $M0/a +TEST flock -x $fd1 +TEST fd_close $fd1 + +#When all bricks are down, lock/unlock should fail +TEST fd1=`fd_available` +TEST fd_open $fd1 'w' $M0/a +TEST $CLI volume stop $V0 +TEST ! flock -x $fd1 +TEST $CLI volume start $V0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 1 +TEST fd_close $fd1 + +#Check locking behavior with quorum 'fixed' and quorum-count 2 +TEST $CLI volume set $V0 cluster.quorum-type fixed +TEST $CLI volume set $V0 cluster.quorum-count 2 +EXPECT_WITHIN $CONFIG_UPDATE_TIMEOUT "^fixed$" mount_get_option_value $M0 $V0-replicate-0 quorum-type +EXPECT_WITHIN $CONFIG_UPDATE_TIMEOUT "^2$" mount_get_option_value $M0 $V0-replicate-0 quorum-count + +#When all bricks are up, lock and unlock should succeed +TEST fd1=`fd_available` +TEST fd_open $fd1 'w' $M0/a +TEST flock -x $fd1 +TEST fd_close $fd1 + +#When all bricks are down, lock/unlock should fail +TEST fd1=`fd_available` +TEST fd_open $fd1 'w' $M0/a +TEST $CLI volume stop $V0 +TEST ! flock -x $fd1 +TEST $CLI volume start $V0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 1 +TEST fd_close $fd1 + +#When any of the bricks is down lock/unlock should fail +#kill first brick +TEST fd1=`fd_available` +TEST fd_open $fd1 'w' $M0/a +TEST kill_brick $V0 $H0 $B0/${V0}0 +TEST ! flock -x $fd1 +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0 +TEST fd_close $fd1 + +#kill 2nd brick +TEST fd1=`fd_available` +TEST fd_open $fd1 'w' $M0/a +TEST kill_brick $V0 $H0 $B0/${V0}1 +TEST ! flock -x $fd1 +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 1 +TEST fd_close $fd1 + +#Check locking behavior with quorum 'fixed' and quorum-count 1 +TEST $CLI volume set $V0 cluster.quorum-count 1 +EXPECT_WITHIN $CONFIG_UPDATE_TIMEOUT "^1$" mount_get_option_value $M0 $V0-replicate-0 quorum-count + +#When all bricks are up, lock and unlock should succeed +TEST fd1=`fd_available` +TEST fd_open $fd1 'w' $M0/a +TEST flock -x $fd1 +TEST fd_close $fd1 + +#When all bricks are down, lock/unlock should fail +TEST fd1=`fd_available` +TEST fd_open $fd1 'w' $M0/a +TEST $CLI volume stop $V0 +TEST ! flock -x $fd1 +TEST $CLI volume start $V0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 1 +TEST fd_close $fd1 + +#When any of the bricks is down lock/unlock should succeed +#kill first brick +TEST fd1=`fd_available` +TEST fd_open $fd1 'w' $M0/a +TEST kill_brick $V0 $H0 $B0/${V0}0 +TEST flock -x $fd1 +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0 +TEST fd_close $fd1 + +#kill 2nd brick +TEST fd1=`fd_available` +TEST fd_open $fd1 'w' $M0/a +TEST kill_brick $V0 $H0 $B0/${V0}1 +TEST flock -x $fd1 +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 1 +TEST fd_close $fd1 + +#Check locking behavior with quorum 'auto' +TEST $CLI volume set $V0 cluster.quorum-type auto +EXPECT_WITHIN $CONFIG_UPDATE_TIMEOUT "^auto$" mount_get_option_value $M0 $V0-replicate-0 quorum-type + +#When all bricks are up, lock and unlock should succeed +TEST fd1=`fd_available` +TEST fd_open $fd1 'w' $M0/a +TEST flock -x $fd1 +TEST fd_close $fd1 + +#When all bricks are down, lock/unlock should fail +TEST fd1=`fd_available` +TEST fd_open $fd1 'w' $M0/a +TEST $CLI volume stop $V0 +TEST ! flock -x $fd1 +TEST $CLI volume start $V0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 1 +TEST fd_close $fd1 + +#When first brick is down lock/unlock should fail +#kill first brick +TEST fd1=`fd_available` +TEST fd_open $fd1 'w' $M0/a +TEST kill_brick $V0 $H0 $B0/${V0}0 +TEST ! flock -x $fd1 +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0 +TEST fd_close $fd1 + +#When second brick is down lock/unlock should succeed +TEST fd1=`fd_available` +TEST fd_open $fd1 'w' $M0/a +TEST kill_brick $V0 $H0 $B0/${V0}1 +TEST flock -x $fd1 +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 1 +TEST fd_close $fd1 + +cleanup; +TEST glusterd; +TEST pidof glusterd + +#Tests for replica 3 +TEST $CLI volume create $V0 replica 3 $H0:$B0/${V0}{0,1,2}; +TEST $CLI volume set $V0 performance.quick-read off +TEST $CLI volume set $V0 performance.io-cache off +TEST $CLI volume set $V0 performance.write-behind off +TEST $CLI volume set $V0 performance.open-behind off +TEST $CLI volume set $V0 performance.stat-prefetch off +TEST $CLI volume set $V0 performance.read-ahead off +TEST $CLI volume start $V0 +TEST $GFS -s $H0 --volfile-id=$V0 --direct-io-mode=enable $M0; + +TEST touch $M0/a + +#When all bricks are up, lock and unlock should succeed +TEST fd1=`fd_available` +TEST fd_open $fd1 'w' $M0/a +TEST flock -x $fd1 +TEST fd_close $fd1 + +#When all bricks are down, lock/unlock should fail +TEST fd1=`fd_available` +TEST fd_open $fd1 'w' $M0/a +TEST $CLI volume stop $V0 +TEST ! flock -x $fd1 +TEST $CLI volume start $V0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 2 +TEST fd_close $fd1 + +#When any of the bricks is down lock/unlock should succeed +#kill first brick +TEST fd1=`fd_available` +TEST fd_open $fd1 'w' $M0/a +TEST kill_brick $V0 $H0 $B0/${V0}0 +TEST flock -x $fd1 +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0 +TEST fd_close $fd1 + +#kill 2nd brick +TEST fd1=`fd_available` +TEST fd_open $fd1 'w' $M0/a +TEST kill_brick $V0 $H0 $B0/${V0}1 +TEST flock -x $fd1 +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 1 +TEST fd_close $fd1 + +#kill 3rd brick +TEST fd1=`fd_available` +TEST fd_open $fd1 'w' $M0/a +TEST kill_brick $V0 $H0 $B0/${V0}2 +TEST flock -x $fd1 +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 2 +TEST fd_close $fd1 + +#When any two of the bricks are down lock/unlock should fail +#kill first,second bricks +TEST fd1=`fd_available` +TEST fd_open $fd1 'w' $M0/a +TEST kill_brick $V0 $H0 $B0/${V0}0 +TEST kill_brick $V0 $H0 $B0/${V0}1 +TEST ! flock -x $fd1 +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 1 +TEST fd_close $fd1 + +#kill 2nd,3rd bricks +TEST fd1=`fd_available` +TEST fd_open $fd1 'w' $M0/a +TEST kill_brick $V0 $H0 $B0/${V0}1 +TEST kill_brick $V0 $H0 $B0/${V0}2 +TEST ! flock -x $fd1 +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 2 +TEST fd_close $fd1 + +#kill 1st,3rd brick +TEST fd1=`fd_available` +TEST fd_open $fd1 'w' $M0/a +TEST kill_brick $V0 $H0 $B0/${V0}0 +TEST kill_brick $V0 $H0 $B0/${V0}2 +TEST ! flock -x $fd1 +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 2 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0 +TEST fd_close $fd1 + +cleanup diff --git a/tests/basic/afr/metadata-self-heal.t b/tests/basic/afr/metadata-self-heal.t new file mode 100644 index 00000000000..275aecd2175 --- /dev/null +++ b/tests/basic/afr/metadata-self-heal.t @@ -0,0 +1,133 @@ +#!/bin/bash +#Self-heal tests + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc +cleanup; + +function is_heal_done { + local f1_path="${1}/${3}" + local f2_path="${2}/${3}" + local zero_xattr="000000000000000000000000" + local iatt1=$(stat -c "%g:%u:%A" $f1_path) + local iatt2=$(stat -c "%g:%u:%A" $f2_path) + local diff="1" + if [ "$iatt1" == "$iatt2" ]; then diff=0; fi + local xattr11=$(get_hex_xattr trusted.afr.$V0-client-0 $f1_path) + local xattr12=$(get_hex_xattr trusted.afr.$V0-client-1 $f1_path) + local xattr21=$(get_hex_xattr trusted.afr.$V0-client-0 $f2_path) + local xattr22=$(get_hex_xattr trusted.afr.$V0-client-1 $f2_path) + local dirty1=$(get_hex_xattr trusted.afr.dirty $f1_path) + local dirty2=$(get_hex_xattr trusted.afr.dirty $f2_path) + if [ -z $xattr11 ]; then xattr11="000000000000000000000000"; fi + if [ -z $xattr12 ]; then xattr12="000000000000000000000000"; fi + if [ -z $xattr21 ]; then xattr21="000000000000000000000000"; fi + if [ -z $xattr22 ]; then xattr22="000000000000000000000000"; fi + if [ -z $dirty1 ]; then dirty1="000000000000000000000000"; fi + if [ -z $dirty2 ]; then dirty2="000000000000000000000000"; fi + if [ "${diff}${xattr11}${xattr12}${xattr21}${xattr22}${dirty1}${dirty2}" == "0${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}${zero_xattr}" ]; + then + echo "Y" + else + echo "N" + fi +} + +function print_pending_heals { + local result=":" + for i in "$@"; + do + if [ "N" == $(is_heal_done $B0/brick0 $B0/brick1 $i) ]; + then + result="$result:$i" + fi + done +#To prevent any match for EXPECT_WITHIN, print a char non-existent in file-names + if [ $result == ":" ]; then result="~"; fi + echo $result +} + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 replica 2 $H0:$B0/brick{0,1} +TEST $CLI volume start $V0 +TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0 +cd $M0 + +TEST touch a + +#Test heal with pending xattrs +TEST kill_brick $V0 $H0 $B0/brick0 +TEST chmod 777 a +TEST chown 100:100 a +TEST setfattr -n trusted.abc -v 0x616263 a +TEST setfattr -n trusted.def -v 0x646566 a +permissions=$(stat -c "%A" a) +TEST $CLI volume start $V0 force +EXPECT_WITHIN $HEAL_TIMEOUT "~" print_pending_heals a +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0 + +EXPECT $permissions stat -c "%A" a +EXPECT $permissions stat -c "%A" $B0/brick0/a +EXPECT $permissions stat -c "%A" $B0/brick1/a + +EXPECT 100 stat -c "%g" a +EXPECT 100 stat -c "%g" $B0/brick0/a +EXPECT 100 stat -c "%g" $B0/brick1/a + +EXPECT 100 stat -c "%u" a +EXPECT 100 stat -c "%u" $B0/brick0/a +EXPECT 100 stat -c "%u" $B0/brick1/a + +EXPECT 616263 get_hex_xattr trusted.abc a +EXPECT 616263 get_hex_xattr trusted.abc $B0/brick0/a +EXPECT 616263 get_hex_xattr trusted.abc $B0/brick1/a + +EXPECT 646566 get_hex_xattr trusted.def a +EXPECT 646566 get_hex_xattr trusted.def $B0/brick0/a +EXPECT 646566 get_hex_xattr trusted.def $B0/brick1/a + +TEST kill_brick $V0 $H0 $B0/brick1 +TEST setfattr -n trusted.abc -v 0x646566 a +TEST setfattr -x trusted.def a + +TEST $CLI volume start $V0 force +EXPECT_WITHIN $HEAL_TIMEOUT "~" print_pending_heals a +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 1 + +EXPECT 646566 get_hex_xattr trusted.abc a +EXPECT 646566 get_hex_xattr trusted.abc $B0/brick0/a +EXPECT 646566 get_hex_xattr trusted.abc $B0/brick1/a + +TEST ! getfattr -n trusted.def a +TEST ! getfattr -n trusted.def $B0/brick0/a +TEST ! getfattr -n trusted.def $B0/brick1/a + +#Test split-brain && iatt mismatch without any xattrs (this will be simulated) +TEST $CLI volume set $V0 cluster.self-heal-daemon off +TEST touch b +TEST touch c +TEST kill_brick $V0 $H0 $B0/brick0 +TEST chmod 777 b +TEST chmod 777 c +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0 +TEST kill_brick $V0 $H0 $B0/brick1 +TEST chown 100:100 b +TEST chown 100:100 c +TEST $CLI volume stop $V0 +TEST setfattr -x trusted.afr.$V0-client-0 $B0/brick1/c +TEST setfattr -x trusted.afr.$V0-client-1 $B0/brick0/c +TEST $CLI volume set $V0 cluster.self-heal-daemon on +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "Y" glustershd_up_status +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 1 +TEST $CLI volume heal $V0 full +EXPECT_WITHIN $HEAL_TIMEOUT "~" print_pending_heals c +EXPECT "N" is_heal_done $B0/brick0 $B0/brick1 b + +cd - +cleanup; diff --git a/tests/basic/afr/name-self-heal.t b/tests/basic/afr/name-self-heal.t new file mode 100644 index 00000000000..50fc2ecc6c2 --- /dev/null +++ b/tests/basic/afr/name-self-heal.t @@ -0,0 +1,112 @@ +#!/bin/bash +#Self-heal tests + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc +. $(dirname $0)/../../afr.rc +cleanup; + +#Check that when quorum is not enabled name-heal happens correctly +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 replica 2 $H0:$B0/brick{0,1} +TEST $CLI volume set $V0 performance.stat-prefetch off +TEST $CLI volume start $V0 +TEST $CLI volume heal $V0 disable +TEST $CLI volume set $V0 cluster.entry-self-heal off +TEST $GFS --volfile-id=$V0 --volfile-server=$H0 $M0; + +TEST touch $M0/a +TEST touch $M0/c +TEST kill_brick $V0 $H0 $B0/brick0 +TEST touch $M0/b +TEST rm -f $M0/a +TEST rm -f $M0/c +TEST touch $M0/c #gfid mismatch case +c_gfid=$(gf_get_gfid_xattr $B0/brick1/c) +TEST $CLI volume start $V0 force +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status $V0 0 +TEST ! stat $M0/a +TEST ! stat $B0/brick0/a +TEST ! stat $B0/brick1/a + +TEST stat $M0/b +TEST stat $B0/brick0/b +TEST stat $B0/brick1/b +TEST [[ "$(gf_get_gfid_xattr $B0/brick0/b)" == "$(gf_get_gfid_xattr $B0/brick1/b)" ]] + +TEST stat $M0/c +TEST stat $B0/brick0/c +TEST stat $B0/brick1/c +TEST [[ "$(gf_get_gfid_xattr $B0/brick0/c)" == "$c_gfid" ]] + +cleanup; + +#Check that when quorum is enabled name-heal happens as expected +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 replica 3 $H0:$B0/brick{0,1,2} +TEST $CLI volume set $V0 performance.stat-prefetch off +TEST $CLI volume start $V0 +TEST $CLI volume heal $V0 disable +TEST $CLI volume set $V0 cluster.entry-self-heal off +TEST $GFS --volfile-id=$V0 --volfile-server=$H0 $M0; + +TEST touch $M0/a +TEST touch $M0/c +TEST kill_brick $V0 $H0 $B0/brick0 +TEST touch $M0/b +TEST rm -f $M0/a +TEST rm -f $M0/c +TEST touch $M0/c #gfid mismatch case +c_gfid=$(gf_get_gfid_xattr $B0/brick1/c) +TEST $CLI volume start $V0 force +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status $V0 0 +TEST ! stat $M0/a +TEST ! stat $B0/brick0/a +TEST ! stat $B0/brick1/a +TEST ! stat $B0/brick2/a + +TEST stat $M0/b +TEST ! stat $B0/brick0/b #Name heal shouldn't be triggered +TEST stat $B0/brick1/b +TEST stat $B0/brick2/b + +TEST stat $M0/c +TEST stat $B0/brick0/c +TEST stat $B0/brick1/c +TEST stat $B0/brick2/c +TEST [[ "$(gf_get_gfid_xattr $B0/brick0/c)" == "$c_gfid" ]] + +TEST $CLI volume set $V0 cluster.quorum-type none +EXPECT_WITHIN $CONFIG_UPDATE_TIMEOUT "none" get_quorum_type $M0 $V0 0 +TEST stat $M0/b +TEST stat $B0/brick0/b #Name heal should be triggered +TEST stat $B0/brick1/b +TEST stat $B0/brick2/b +TEST [[ "$(gf_get_gfid_xattr $B0/brick0/b)" == "$(gf_get_gfid_xattr $B0/brick1/b)" ]] +TEST $CLI volume set $V0 cluster.quorum-type auto +EXPECT_WITHIN $CONFIG_UPDATE_TIMEOUT "auto" get_quorum_type $M0 $V0 0 + +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 + +#Missing parent xattrs cases +TEST $CLI volume heal $V0 enable +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "Y" glustershd_up_status +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 1 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 2 +TEST $CLI volume heal $V0 +EXPECT_WITHIN $HEAL_TIMEOUT "0" get_pending_heal_count $V0 + +TEST $GFS --volfile-id=$V0 --volfile-server=$H0 $M0; +TEST $CLI volume heal $V0 disable +#In cases where a good parent doesn't have pending xattrs and a file, +#name-heal will be triggered +TEST gf_rm_file_and_gfid_link $B0/brick1 c +TEST stat $M0/c +TEST stat $B0/brick0/c +TEST stat $B0/brick1/c +TEST stat $B0/brick2/c +TEST [[ "$(gf_get_gfid_xattr $B0/brick0/c)" == "$c_gfid" ]] +cleanup diff --git a/tests/basic/afr/quorum.t b/tests/basic/afr/quorum.t new file mode 100644 index 00000000000..58116ba49f5 --- /dev/null +++ b/tests/basic/afr/quorum.t @@ -0,0 +1,97 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc +cleanup; + +TEST glusterd; +TEST pidof glusterd + +function test_write { + dd of=$M0/a if=/dev/urandom bs=1k count=1 2>&1 > /dev/null +} + +#Tests for quorum-type option for replica 2 +TEST $CLI volume create $V0 replica 2 $H0:$B0/${V0}{1,2}; +TEST $CLI volume set $V0 performance.quick-read off +TEST $CLI volume set $V0 performance.io-cache off +TEST $CLI volume set $V0 performance.write-behind off +TEST $CLI volume set $V0 performance.stat-prefetch off +TEST $CLI volume set $V0 performance.read-ahead off +TEST $CLI volume start $V0 +TEST $GFS -s $H0 --volfile-id=$V0 --direct-io-mode=enable $M0; + +touch $M0/a +echo abc > $M0/b + +TEST ! $CLI volume set $V0 cluster.quorum-type "" +TEST $CLI volume set $V0 cluster.quorum-type fixed +EXPECT fixed volume_option $V0 cluster.quorum-type +TEST $CLI volume set $V0 cluster.quorum-count 2 +TEST test_write +TEST kill_brick $V0 $H0 $B0/${V0}1 +TEST ! test_write +TEST ! cat $M0/b + +TEST $CLI volume set $V0 cluster.quorum-type auto +EXPECT auto volume_option $V0 cluster.quorum-type +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0 +TEST test_write +TEST kill_brick $V0 $H0 $B0/${V0}1 +TEST ! test_write +TEST ! cat $M0/b + +TEST $CLI volume set $V0 cluster.quorum-type none +EXPECT none volume_option $V0 cluster.quorum-type +TEST test_write +#Default is 'none' for even number of bricks in replication +TEST $CLI volume reset $V0 cluster.quorum-type +TEST test_write +EXPECT "abc" cat $M0/b + +cleanup; +TEST glusterd; +TEST pidof glusterd + +#Tests for quorum-type option for replica 3 +TEST $CLI volume create $V0 replica 3 $H0:$B0/${V0}{1,2,3}; +TEST $CLI volume set $V0 performance.quick-read off +TEST $CLI volume set $V0 performance.io-cache off +TEST $CLI volume set $V0 performance.write-behind off +TEST $CLI volume set $V0 performance.stat-prefetch off +TEST $CLI volume set $V0 performance.read-ahead off +TEST $CLI volume start $V0 +TEST $GFS -s $H0 --volfile-id=$V0 --direct-io-mode=enable $M0; + +touch $M0/a +echo abc > $M0/b + +TEST $CLI volume set $V0 cluster.quorum-type fixed +EXPECT fixed volume_option $V0 cluster.quorum-type +TEST $CLI volume set $V0 cluster.quorum-count 3 +TEST test_write +TEST kill_brick $V0 $H0 $B0/${V0}1 +TEST ! test_write +TEST ! cat $M0/b + +TEST $CLI volume set $V0 cluster.quorum-type auto +EXPECT auto volume_option $V0 cluster.quorum-type +TEST test_write +TEST kill_brick $V0 $H0 $B0/${V0}3 +TEST ! test_write +TEST ! cat $M0/b + +TEST $CLI volume set $V0 cluster.quorum-type none +EXPECT none volume_option $V0 cluster.quorum-type +TEST test_write +#Default is 'auto' for odd number of bricks in replication +TEST $CLI volume reset $V0 cluster.quorum-type +EXPECT "^$" volume_option $V0 cluster.quorum-type +TEST ! test_write +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 2 +TEST kill_brick $V0 $H0 $B0/${V0}3 +TEST test_write +cleanup; diff --git a/tests/basic/afr/read-subvol-data.t b/tests/basic/afr/read-subvol-data.t new file mode 100644 index 00000000000..39f43a15028 --- /dev/null +++ b/tests/basic/afr/read-subvol-data.t @@ -0,0 +1,33 @@ +#!/bin/bash +#Test if the source is selected based on data transaction for a regular file. + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc +cleanup; + +#Init +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 replica 2 $H0:$B0/brick{0,1} +TEST $CLI volume set $V0 self-heal-daemon off +TEST $CLI volume set $V0 stat-prefetch off +TEST $CLI volume start $V0 +TEST $CLI volume set $V0 cluster.background-self-heal-count 0 +TEST $GFS --volfile-id=$V0 --volfile-server=$H0 $M0; + +#Test +TEST $CLI volume set $V0 cluster.read-subvolume $V0-client-1 +TEST $CLI volume set $V0 cluster.data-self-heal off +TEST $CLI volume set $V0 cluster.metadata-self-heal off +TEST $CLI volume set $V0 cluster.entry-self-heal off +TEST dd if=/dev/urandom of=$M0/afr_success_5.txt bs=1024k count=1 +TEST kill_brick $V0 $H0 $B0/brick0 +TEST dd if=/dev/urandom of=$M0/afr_success_5.txt bs=1024k count=10 +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "10485760" echo `ls -l $M0/afr_success_5.txt | awk '{ print $5}'` + +#Cleanup +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 +TEST $CLI volume stop $V0 +TEST $CLI volume delete $V0 +TEST rm -rf $B0/* diff --git a/tests/basic/afr/read-subvol-entry.t b/tests/basic/afr/read-subvol-entry.t new file mode 100644 index 00000000000..76b2dcf85b0 --- /dev/null +++ b/tests/basic/afr/read-subvol-entry.t @@ -0,0 +1,35 @@ +#!/bin/bash +#Test if the read child is selected based on entry transaction for directory + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc +cleanup; + +#Init +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 replica 2 $H0:$B0/brick{0,1} +TEST $CLI volume set $V0 self-heal-daemon off +TEST $CLI volume set $V0 stat-prefetch off +TEST $CLI volume start $V0 +TEST $CLI volume set $V0 cluster.background-self-heal-count 0 +TEST $GFS --volfile-id=$V0 --volfile-server=$H0 $M0; + +#Test +TEST mkdir -p $M0/abc/def + +TEST $CLI volume set $V0 cluster.data-self-heal off +TEST $CLI volume set $V0 cluster.metadata-self-heal off +TEST $CLI volume set $V0 cluster.entry-self-heal off + +TEST kill_brick $V0 $H0 $B0/brick0 + +TEST touch $M0/abc/def/ghi +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "ghi" echo `ls $M0/abc/def/` + +#Cleanup +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 +TEST $CLI volume stop $V0 +TEST $CLI volume delete $V0 +TEST rm -rf $B0/* diff --git a/tests/basic/afr/rename-data-loss.t b/tests/basic/afr/rename-data-loss.t new file mode 100644 index 00000000000..256ee2aafce --- /dev/null +++ b/tests/basic/afr/rename-data-loss.t @@ -0,0 +1,72 @@ +#!/bin/bash +#Self-heal tests +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc +. $(dirname $0)/../../afr.rc + +cleanup; + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 replica 2 $H0:$B0/brick{0,1} +TEST $CLI volume set $V0 write-behind off +TEST $CLI volume set $V0 self-heal-daemon off +TEST $CLI volume set $V0 data-self-heal off +TEST $CLI volume set $V0 metadata-self-heal off +TEST $CLI volume set $V0 entry-self-heal off +TEST $CLI volume start $V0 +EXPECT 'Started' volinfo_field $V0 'Status' +TEST glusterfs --volfile-id=$V0 --volfile-server=$H0 $M0; + +cd $M0 +TEST `echo "line1" >> file1` +TEST mkdir dir1 +TEST mkdir dir2 +TEST mkdir -p dir1/dira/dirb +TEST `echo "line1">>dir1/dira/dirb/file1` +TEST mkdir delete_me +TEST `echo "line1" >> delete_me/file1` + +#brick0 has witnessed the second write while brick1 is down. +TEST kill_brick $V0 $H0 $B0/brick1 +TEST `echo "line2" >> file1` +TEST `echo "line2" >> dir1/dira/dirb/file1` +TEST `echo "line2" >> delete_me/file1` + +#Toggle the bricks that are up/down. +TEST $CLI volume start $V0 force +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status $V0 1 +TEST kill_brick $V0 $H0 $B0/brick0 + +#Rename when the 'source' brick0 for data-selfheals is down. +mv file1 file2 +mv dir1/dira dir2 + +#Delete a dir when brick0 is down. +rm -rf delete_me +cd - + +#Bring everything up and trigger heal +TEST $CLI volume set $V0 self-heal-daemon on +TEST $CLI volume start $V0 force +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status $V0 0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "Y" glustershd_up_status +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 1 +TEST $CLI volume heal $V0 +EXPECT_WITHIN $HEAL_TIMEOUT "^0$" get_pending_heal_count $V0 +EXPECT_WITHIN $HEAL_TIMEOUT "^0$" afr_anon_entry_count $B0/brick0 +EXPECT_WITHIN $HEAL_TIMEOUT "^0$" afr_anon_entry_count $B0/brick1 + +#Remount to avoid reading from caches +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 +TEST glusterfs --volfile-id=$V0 --volfile-server=$H0 $M0; +EXPECT "line2" tail -1 $M0/file2 +EXPECT "line2" tail -1 $M0/dir2/dira/dirb/file1 +TEST ! stat $M0/delete_me/file1 +TEST ! stat $M0/delete_me + +anon_inode_name=$(ls -a $B0/brick0 | grep glusterfs-anonymous-inode) +TEST [[ -d $B0/brick0/$anon_inode_name ]] +TEST [[ -d $B0/brick1/$anon_inode_name ]] +cleanup diff --git a/tests/basic/afr/replace-brick-self-heal.t b/tests/basic/afr/replace-brick-self-heal.t new file mode 100644 index 00000000000..0360db71a2f --- /dev/null +++ b/tests/basic/afr/replace-brick-self-heal.t @@ -0,0 +1,64 @@ +#!/bin/bash +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc +cleanup; + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 replica 2 $H0:$B0/${V0}{0,1} +TEST $CLI volume start $V0 +TEST $CLI volume set $V0 cluster.data-self-heal off +TEST $CLI volume set $V0 cluster.metadata-self-heal off +TEST $CLI volume set $V0 cluster.entry-self-heal off +TEST $CLI volume set $V0 cluster.heal-timeout 5 +TEST $CLI volume set $V0 self-heal-daemon off +TEST $GFS --volfile-id=$V0 --volfile-server=$H0 $M0; + +# Create files +for i in {1..5} +do + echo $i > $M0/file$i.txt +done + +# Metadata changes +TEST setfattr -n user.test -v qwerty $M0/file5.txt + +# Replace brick1 +TEST $CLI volume replace-brick $V0 $H0:$B0/${V0}1 $H0:$B0/${V0}1_new commit force + +# Replaced-brick should accuse the non-replaced-brick (Simulating case for data-loss) +TEST setfattr -n trusted.afr.$V0-client-0 -v 0x000000000000000000000001 $B0/${V0}1_new/ + +# Check if pending xattr and dirty-xattr are set for replaced-brick +EXPECT "000000000000000100000001" get_hex_xattr trusted.afr.$V0-client-1 $B0/${V0}0 +EXPECT "000000000000000000000001" get_hex_xattr trusted.afr.dirty $B0/${V0}1_new + +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 1 + +TEST $CLI volume set $V0 self-heal-daemon on +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "Y" glustershd_up_status +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 1 +TEST $CLI volume heal $V0 + +# Wait for heal to complete +EXPECT_WITHIN $HEAL_TIMEOUT "0" get_pending_heal_count $V0 + +# Check if entry-heal has happened +TEST diff <(ls $B0/${V0}0 | sort) <(ls $B0/${V0}1_new | sort) + +# To make sure that files were not lost from brick0 +TEST diff <(ls $B0/${V0}0 | sort) <(ls $B0/${V0}1 | sort) +EXPECT "000000000000000000000000" get_hex_xattr trusted.afr.$V0-client-1 $B0/${V0}0 + +# Test if data was healed +TEST diff $B0/${V0}0/file1.txt $B0/${V0}1_new/file1.txt +# To make sure that data was not lost from brick0 +TEST diff $B0/${V0}0/file1.txt $B0/${V0}1/file1.txt + +# Test if metadata was healed and exists on both the bricks +EXPECT "qwerty" get_text_xattr user.test $B0/${V0}1_new/file5.txt +EXPECT "qwerty" get_text_xattr user.test $B0/${V0}0/file5.txt + +cleanup; diff --git a/tests/basic/afr/resolve.t b/tests/basic/afr/resolve.t new file mode 100644 index 00000000000..a741eee6e5e --- /dev/null +++ b/tests/basic/afr/resolve.t @@ -0,0 +1,55 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +#Check that operations succeed after changing the disk of the brick while +#a brick is down +cleanup; + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 replica 2 $H0:$B0/${V0}{0,1} +TEST $CLI volume set $V0 cluster.self-heal-daemon off +TEST $CLI volume start $V0 +TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0; +TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M1; +TEST cd $M0 +TEST mkdir -p a/b/c/d/e +TEST cd a/b/c/d/e +echo abc > g + +#Simulate disk replacement +TEST kill_brick $V0 $H0 $B0/${V0}0 +rm -rf $B0/${V0}0/.glusterfs $B0/${V0}0/a + +#Ideally, disk replacement is done using reset-brick or replace-brick gluster CLI +#which will create .glusterfs folder. +mkdir $B0/${V0}0/.glusterfs && chmod 600 $B0/${V0}0/.glusterfs + +TEST $CLI volume start $V0 force +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_meta $M0 $V0-replicate-0 0 +#Test that the lookup returns ENOENT instead of ESTALE +#If lookup returns ESTALE this command will fail with ESTALE +TEST touch f + +#Test that ESTALE is ignored when there is a good copy +EXPECT abc cat g + +#Simulate file changing only one mount +#create the file on first mount +echo ghi > $M0/b + +#re-create the file on other mount while one of the bricks is down. +TEST kill_brick $V0 $H0 $B0/${V0}0 +TEST rm -f $M1/b +echo jkl > $M1/b +#Clear the extended attributes on the directory to create a scenario where +#gfid-mismatch happened. This should result in EIO +TEST setfattr -x trusted.afr.$V0-client-0 $B0/${V0}1 +TEST $CLI volume start $V0 force +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_meta $M0 $V0-replicate-0 0 +# The kernel knows nothing about the tricks done to the volume, and the file +# may still be in page cache. Wait for timeout. +EXPECT_WITHIN 10 "^$" cat $M0/b +cleanup diff --git a/tests/basic/afr/root-squash-self-heal.t b/tests/basic/afr/root-squash-self-heal.t new file mode 100644 index 00000000000..6e12098465a --- /dev/null +++ b/tests/basic/afr/root-squash-self-heal.t @@ -0,0 +1,27 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +cleanup; + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 replica 2 $H0:$B0/${V0}{0,1} +TEST $CLI volume set $V0 performance.stat-prefetch off +TEST $CLI volume set $V0 self-heal-daemon off +TEST $CLI volume set $V0 server.root-squash on +TEST $CLI volume set $V0 cluster.data-self-heal on +TEST $CLI volume set $V0 cluster.metadata-self-heal on +TEST $CLI volume set $V0 cluster.entry-self-heal on +TEST $CLI volume start $V0 +TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 --no-root-squash=yes --use-readdirp=no $M0 +TEST kill_brick $V0 $H0 $B0/${V0}0 +echo abc > $M0/a + +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0 +find $M0 | xargs stat > /dev/null +EXPECT_WITHIN $HEAL_TIMEOUT "0" get_pending_heal_count $V0 + +cleanup diff --git a/tests/basic/afr/self-heal.t b/tests/basic/afr/self-heal.t new file mode 100644 index 00000000000..10fb152d046 --- /dev/null +++ b/tests/basic/afr/self-heal.t @@ -0,0 +1,244 @@ +#!/bin/bash +#Self-heal tests + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc +cleanup; + +#Init +AREQUAL_PATH=$(dirname $0)/../../utils +AREQUAL_BIN=$AREQUAL_PATH/arequal-checksum +CFLAGS="" +test "`uname -s`" != "Linux" && { + CFLAGS="$CFLAGS -lintl"; +} +build_tester $AREQUAL_PATH/arequal-checksum.c $CFLAGS +TEST [ -e $AREQUAL_BIN ] + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 replica 2 $H0:$B0/brick{0,1} +TEST $CLI volume set $V0 stat-prefetch off +TEST $CLI volume start $V0 +TEST $CLI volume set $V0 cluster.background-self-heal-count 0 +TEST $GFS --volfile-id=$V0 --volfile-server=$H0 $M0; + +############################################################################### +#1.Test successful data, metadata and entry self-heal + +#Test +TEST mkdir -p $M0/abc/def $M0/abc/ghi +TEST dd if=/dev/urandom of=$M0/abc/file_abc.txt bs=1024k count=2 2>/dev/null +TEST dd if=/dev/urandom of=$M0/abc/def/file_abc_def_1.txt bs=1024k count=2 2>/dev/null +TEST dd if=/dev/urandom of=$M0/abc/def/file_abc_def_2.txt bs=1024k count=3 2>/dev/null +TEST dd if=/dev/urandom of=$M0/abc/ghi/file_abc_ghi.txt bs=1024k count=4 2>/dev/null + +TEST kill_brick $V0 $H0 $B0/brick0 +TEST truncate -s 0 $M0/abc/def/file_abc_def_1.txt +NEW_UID=36 +NEW_GID=36 +TEST chown $NEW_UID:$NEW_GID $M0/abc/def/file_abc_def_2.txt +TEST rm -rf $M0/abc/ghi +TEST mkdir -p $M0/def/ghi $M0/jkl/mno +TEST dd if=/dev/urandom of=$M0/def/ghi/file1.txt bs=1024k count=2 2>/dev/null +TEST dd if=/dev/urandom of=$M0/def/ghi/file2.txt bs=1024k count=3 2>/dev/null +TEST dd if=/dev/urandom of=$M0/jkl/mno/file.txt bs=1024k count=4 2>/dev/null +TEST chown $NEW_UID:$NEW_GID $M0/def/ghi/file2.txt + +TEST $CLI volume start $V0 force +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status $V0 0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "Y" glustershd_up_status +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 1 +TEST $CLI volume heal $V0 +EXPECT_WITHIN $HEAL_TIMEOUT "0" get_pending_heal_count $V0 + +#check all files created/deleted on brick1 are also replicated on brick 0 +#(i.e. no reverse heal has happened) +TEST ls $B0/brick0/def/ghi/file1.txt +TEST ls $B0/brick0/def/ghi/file2.txt +TEST ls $B0/brick0/jkl/mno/file.txt +TEST ! ls $B0/brick0/abc/ghi +EXPECT "$NEW_UID$NEW_GID" stat -c %u%g $B0/brick0/abc/def/file_abc_def_2.txt +TEST diff <($AREQUAL_BIN -p $B0/brick0 -i .glusterfs) <($AREQUAL_BIN -p $B0/brick1 -i .glusterfs) + +#Cleanup +TEST rm -rf $M0/* +############################################################################### + +#2.Test successful self-heal of different file types. + +#Test +TEST touch $M0/file +TEST kill_brick $V0 $H0 $B0/brick0 +TEST rm -f $M0/file +TEST mkdir $M0/file + +TEST $CLI volume start $V0 force +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status $V0 0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "Y" glustershd_up_status +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 1 +TEST $CLI volume heal $V0 +EXPECT_WITHIN $HEAL_TIMEOUT "0" get_pending_heal_count $V0 + +#check heal has happened in the correct direction +TEST test -d $B0/brick0/file +TEST diff <($AREQUAL_BIN -p $B0/brick0 -i .glusterfs) <($AREQUAL_BIN -p $B0/brick1 -i .glusterfs) + +#Cleanup +TEST rm -rf $M0/* +############################################################################### + +#3.Test successful self-heal of file permissions. + +#Test +TEST touch $M0/file +TEST chmod 666 $M0/file +TEST kill_brick $V0 $H0 $B0/brick0 +TEST chmod 777 $M0/file +TEST $CLI volume start $V0 force +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status $V0 0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "Y" glustershd_up_status +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 1 +TEST $CLI volume heal $V0 +EXPECT_WITHIN $HEAL_TIMEOUT "0" get_pending_heal_count $V0 + +#check heal has happened in the correct direction +EXPECT "777" stat -c %a $B0/brick0/file +TEST diff <($AREQUAL_BIN -p $B0/brick0 -i .glusterfs) <($AREQUAL_BIN -p $B0/brick1 -i .glusterfs) + +#Cleanup +TEST rm -rf $M0/* +############################################################################### + +#4.Test successful self-heal of file ownership + +#Test +TEST touch $M0/file +TEST kill_brick $V0 $H0 $B0/brick0 +NEW_UID=36 +NEW_GID=36 +TEST chown $NEW_UID:$NEW_GID $M0/file +TEST $CLI volume start $V0 force +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status $V0 0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "Y" glustershd_up_status +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 1 +TEST $CLI volume heal $V0 +EXPECT_WITHIN $HEAL_TIMEOUT "0" get_pending_heal_count $V0 + +#check heal has happened in the correct direction +EXPECT "$NEW_UID$NEW_GID" stat -c %u%g $B0/brick0/file +TEST diff <($AREQUAL_BIN -p $B0/brick0 -i .glusterfs) <($AREQUAL_BIN -p $B0/brick1 -i .glusterfs) + +#Cleanup +TEST rm -rf $M0/* +############################################################################### + +#5.File size test + +#Test +TEST touch $M0/file +TEST `echo "write1">$M0/file` +TEST kill_brick $V0 $H0 $B0/brick0 +TEST `echo "write2">>$M0/file` +TEST $CLI volume start $V0 force +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status $V0 0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "Y" glustershd_up_status +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 1 +TEST $CLI volume heal $V0 +TEST kill_brick $V0 $H0 $B0/brick1 +TEST truncate -s 0 $M0/file +TEST $CLI volume start $V0 force +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status $V0 1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "Y" glustershd_up_status +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 1 +TEST $CLI volume heal $V0 +EXPECT_WITHIN $HEAL_TIMEOUT "0" get_pending_heal_count $V0 + +#check heal has happened in the correct direction +EXPECT 0 stat -c %s $B0/brick1/file +TEST diff <($AREQUAL_BIN -p $B0/brick0 -i .glusterfs) <($AREQUAL_BIN -p $B0/brick1 -i .glusterfs) + +#Cleanup +TEST rm -rf $M0/* +############################################################################### + +#6.GFID heal + +#Test +TEST touch $M0/file +TEST kill_brick $V0 $H0 $B0/brick0 +TEST rm -f $M0/file +TEST touch $M0/file +GFID=$(gf_get_gfid_xattr $B0/brick1/file) +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "Y" glustershd_up_status +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 1 +TEST $CLI volume heal $V0 +EXPECT_WITHIN $HEAL_TIMEOUT "0" get_pending_heal_count $V0 + +#check heal has happened in the correct direction +EXPECT "$GFID" gf_get_gfid_xattr $B0/brick0/file + +#Cleanup +TEST rm -rf $M0/* +############################################################################### + +#7. Link/symlink heal + +#Test +TEST touch $M0/file +TEST ln $M0/file $M0/link_to_file +TEST kill_brick $V0 $H0 $B0/brick0 +TEST rm -f $M0/link_to_file +TEST ln -s $M0/file $M0/link_to_file +TEST ln $M0/file $M0/hard_link_to_file +TEST $CLI volume start $V0 force +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status $V0 0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "Y" glustershd_up_status +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 1 +TEST $CLI volume heal $V0 +EXPECT_WITHIN $HEAL_TIMEOUT "0" get_pending_heal_count $V0 + +#check heal has happened in the correct direction +TEST test -f $B0/brick0/hard_link_to_file +TEST test -h $B0/brick0/link_to_file +TEST diff <($AREQUAL_BIN -p $B0/brick0 -i .glusterfs) <($AREQUAL_BIN -p $B0/brick1 -i .glusterfs) + +#Cleanup +TEST rm -rf $M0/* +############################################################################### + +#8. Heal xattrs set by application + +#Test +TEST touch $M0/file +TEST setfattr -n user.myattr_1 -v My_attribute_1 $M0/file +TEST setfattr -n user.myattr_2 -v "My_attribute_2" $M0/file +TEST kill_brick $V0 $H0 $B0/brick0 +TEST setfattr -n user.myattr_1 -v "My_attribute_1_modified" $M0/file +TEST setfattr -n user.myattr_3 -v "My_attribute_3" $M0/file +TEST $CLI volume start $V0 force +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status $V0 0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "Y" glustershd_up_status +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 1 +TEST $CLI volume heal $V0 +EXPECT_WITHIN $HEAL_TIMEOUT "0" get_pending_heal_count $V0 + +TEST diff <(echo "user.myattr_1=\"My_attribute_1_modified\"") <(getfattr -n user.myattr_1 $B0/brick1/file|grep user.myattr_1) +TEST diff <(echo "user.myattr_3=\"My_attribute_3\"") <(getfattr -n user.myattr_3 $B0/brick1/file|grep user.myattr_3) + +#Cleanup +TEST rm -rf $M0/* +############################################################################### + +TEST rm -rf $AREQUAL_BIN +cleanup; diff --git a/tests/basic/afr/self-heald.t b/tests/basic/afr/self-heald.t new file mode 100644 index 00000000000..24c82777921 --- /dev/null +++ b/tests/basic/afr/self-heald.t @@ -0,0 +1,193 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +cleanup; +START_TIMESTAMP=`date +%s` + +function kill_multiple_bricks { + local vol=$1 + local host=$2 + local brickpath=$3 + + if [ $decide_kill == 0 ] + then + for ((i=0; i<=4; i=i+2)) do + TEST kill_brick $vol $host $brickpath/${vol}$i + done + else + for ((i=1; i<=5; i=i+2)) do + TEST kill_brick $vol $host $brickpath/${vol}$i + done + fi +} +function check_bricks_up { + local vol=$1 + if [ $decide_kill == 0 ] + then + for ((i=0; i<=4; i=i+2)) do + EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status_in_shd $vol $i + done + else + for ((i=1; i<=5; i=i+2)) do + EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status_in_shd $vol $i + done + fi +} + +function disconnected_brick_count { + local vol=$1 + $CLI volume heal $vol info | \ + egrep -i '(transport|Socket is not connected)' | wc -l +} + +TESTS_EXPECTED_IN_LOOP=20 +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 replica 2 $H0:$B0/${V0}{0,1,2,3,4,5} +TEST $CLI volume set $V0 cluster.background-self-heal-count 0 +TEST $CLI volume set $V0 cluster.eager-lock off +TEST $CLI volume set $V0 performance.flush-behind off +TEST $CLI volume start $V0 +TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0 + +decide_kill=$((`date +"%j"|sed 's/^0*//'` % 2 )) + +kill_multiple_bricks $V0 $H0 $B0 +cd $M0 +HEAL_FILES=0 +for i in {1..10} +do + dd if=/dev/urandom of=f bs=1024k count=10 + HEAL_FILES=$(($HEAL_FILES+1)) #+1 for data/metadata self-heal of 'f' + mkdir a; cd a; + #+3 for metadata self-heal of 'a' one per subvolume of DHT + HEAL_FILES=$(($HEAL_FILES+3)) +done +#+3 represents entry sh on "/", one per subvolume of DHT? +HEAL_FILES=$(($HEAL_FILES + 3)) + +cd ~ +EXPECT "$HEAL_FILES" get_pending_heal_count $V0 + +#When bricks are down, it says Transport End point Not connected for them +EXPECT "3" disconnected_brick_count $V0 + +#Create some stale indices and verify that they are not counted in heal info +#TO create stale index create and delete files when one brick is down in +#replica pair. +for i in {11..20}; do echo abc > $M0/$i; done +HEAL_FILES=$(($HEAL_FILES + 10)) #count extra 10 files +EXPECT "$HEAL_FILES" get_pending_heal_count $V0 +#delete the files now, so that stale indices will remain. +for i in {11..20}; do rm -f $M0/$i; done +#After deleting files they should not appear in heal info +HEAL_FILES=$(($HEAL_FILES - 10)) +EXPECT "$HEAL_FILES" get_pending_heal_count $V0 + + +TEST ! $CLI volume heal $V0 +TEST $CLI volume set $V0 cluster.self-heal-daemon off +TEST ! $CLI volume heal $V0 +TEST ! $CLI volume heal $V0 full +TEST $CLI volume start $V0 force +TEST $CLI volume set $V0 cluster.self-heal-daemon on +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "Y" glustershd_up_status + +check_bricks_up $V0 + +TEST $CLI volume heal $V0 +sleep 5 #Until the heal-statistics command implementation +#check that this heals the contents partially +TEST [ $HEAL_FILES -gt $(get_pending_heal_count $V0) ] + +TEST $CLI volume heal $V0 full +EXPECT_WITHIN $HEAL_TIMEOUT "^0$" get_pending_heal_count $V0 + +#Test that ongoing IO is not considered as Pending heal +(dd if=/dev/zero of=$M0/file1 bs=1k 2>/dev/null 1>/dev/null)& +back_pid1=$!; +(dd if=/dev/zero of=$M0/file2 bs=1k 2>/dev/null 1>/dev/null)& +back_pid2=$!; +(dd if=/dev/zero of=$M0/file3 bs=1k 2>/dev/null 1>/dev/null)& +back_pid3=$!; +(dd if=/dev/zero of=$M0/file4 bs=1k 2>/dev/null 1>/dev/null)& +back_pid4=$!; +(dd if=/dev/zero of=$M0/file5 bs=1k 2>/dev/null 1>/dev/null)& +back_pid5=$!; +EXPECT 0 get_pending_heal_count $V0 +kill -SIGTERM $back_pid1; +kill -SIGTERM $back_pid2; +kill -SIGTERM $back_pid3; +kill -SIGTERM $back_pid4; +kill -SIGTERM $back_pid5; +wait >/dev/null 2>&1; + +#Test that volume heal info reports files even when self-heal +#options are disabled +TEST touch $M0/f +TEST mkdir $M0/d +#DATA +TEST $CLI volume set $V0 cluster.data-self-heal off +EXPECT "off" volume_option $V0 cluster.data-self-heal +kill_multiple_bricks $V0 $H0 $B0 +echo abc > $M0/f +EXPECT 1 get_pending_heal_count $V0 +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "Y" glustershd_up_status +check_bricks_up $V0 + +TEST $CLI volume heal $V0 +EXPECT_WITHIN $HEAL_TIMEOUT "^0$" get_pending_heal_count $V0 +TEST $CLI volume set $V0 cluster.data-self-heal on + +#METADATA +TEST $CLI volume set $V0 cluster.metadata-self-heal off +EXPECT "off" volume_option $V0 cluster.metadata-self-heal +kill_multiple_bricks $V0 $H0 $B0 + +TEST chmod 777 $M0/f +EXPECT 1 get_pending_heal_count $V0 +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "Y" glustershd_up_status +check_bricks_up $V0 + +TEST $CLI volume heal $V0 +EXPECT_WITHIN $HEAL_TIMEOUT "^0$" get_pending_heal_count $V0 +TEST $CLI volume set $V0 cluster.metadata-self-heal on + +#ENTRY +TEST $CLI volume set $V0 cluster.entry-self-heal off +EXPECT "off" volume_option $V0 cluster.entry-self-heal +kill_multiple_bricks $V0 $H0 $B0 +TEST touch $M0/d/a +# 4 if mtime/ctime is modified for d in bricks without a +# 2 otherwise +PENDING=$( get_pending_heal_count $V0 ) +TEST test $PENDING -eq 2 -o $PENDING -eq 4 +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "Y" glustershd_up_status +check_bricks_up $V0 +TEST $CLI volume heal $V0 +EXPECT_WITHIN $HEAL_TIMEOUT "^0$" get_pending_heal_count $V0 +TEST $CLI volume set $V0 cluster.entry-self-heal on + +#Negative test cases +#Fail volume does not exist case +TEST ! $CLI volume heal fail info + +#Fail volume stopped case +TEST $CLI volume stop $V0 +TEST ! $CLI volume heal $V0 info + +#Fail non-replicate volume info +TEST $CLI volume delete $V0 +TEST $CLI volume create $V0 $H0:$B0/${V0}{6} +TEST $CLI volume start $V0 +TEST ! $CLI volume heal $V0 info + +# Check for non Linux systems that we did not mess with directory offsets +TEST ! log_newer $START_TIMESTAMP "offset reused from another DIR" + +cleanup diff --git a/tests/basic/afr/sparse-file-self-heal.t b/tests/basic/afr/sparse-file-self-heal.t new file mode 100644 index 00000000000..04b77c41de1 --- /dev/null +++ b/tests/basic/afr/sparse-file-self-heal.t @@ -0,0 +1,181 @@ +#!/bin/bash + +#This file checks if self-heal of files with holes is working properly or not +#bigger is 2M, big is 1M, small is anything less +#Also tests if non-sparse files with zeroes in it are healed correctly w.r.t +#disk usage. +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +cleanup; + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 replica 2 $H0:$B0/${V0}{0,1} +TEST $CLI volume set $V0 data-self-heal-algorithm full +TEST $CLI volume start $V0 + +TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0; +TEST dd if=/dev/urandom of=$M0/small count=1 bs=1024k +TEST dd if=/dev/urandom of=$M0/bigger2big count=1 bs=2048k +TEST dd if=/dev/urandom of=$M0/big2bigger count=1 bs=1024k +TEST truncate -s 1G $M0/FILE + +TEST kill_brick $V0 $H0 $B0/${V0}0 + +#File with >128k size hole +TEST truncate -s 1M $M0/big +big_md5sum=$(md5sum $M0/big | awk '{print $1}') + +#File with <128k hole +TEST truncate -s 0 $M0/small +TEST truncate -s 64k $M0/small +small_md5sum=$(md5sum $M0/small | awk '{print $1}') + +#Bigger file truncated to big size hole. +TEST truncate -s 0 $M0/bigger2big +TEST truncate -s 1M $M0/bigger2big +bigger2big_md5sum=$(md5sum $M0/bigger2big | awk '{print $1}') + +#Big file truncated to Bigger size hole +TEST truncate -s 2M $M0/big2bigger +big2bigger_md5sum=$(md5sum $M0/big2bigger | awk '{print $1}') + +#Write data to file and restore its sparseness +TEST dd if=/dev/urandom of=$M0/FILE count=1 bs=131072 +TEST truncate -s 1G $M0/FILE + +#Create a non-sparse file containing zeroes. +TEST dd if=/dev/zero of=$M0/zeroedfile bs=1024 count=1024 + +$CLI volume start $V0 force +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status $V0 0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "Y" glustershd_up_status +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 1 +TEST gluster volume heal $V0 full +EXPECT_WITHIN $HEAL_TIMEOUT "0" get_pending_heal_count $V0 + +#If the file system of bricks is XFS and speculative preallocation is on, +#dropping cahce should be done to free speculatively pre-allocated blocks +#by XFS. +drop_cache $M0 + +big_md5sum_0=$(md5sum $B0/${V0}0/big | awk '{print $1}') +small_md5sum_0=$(md5sum $B0/${V0}0/small | awk '{print $1}') +bigger2big_md5sum_0=$(md5sum $B0/${V0}0/bigger2big | awk '{print $1}') +big2bigger_md5sum_0=$(md5sum $B0/${V0}0/big2bigger | awk '{print $1}') + +EXPECT $big_md5sum echo $big_md5sum_0 +EXPECT $small_md5sum echo $small_md5sum_0 +EXPECT $big2bigger_md5sum echo $big2bigger_md5sum_0 +EXPECT $bigger2big_md5sum echo $bigger2big_md5sum_0 + + +EXPECT "1" has_holes $B0/${V0}0/big +#Because self-heal writes the final chunk hole should not be there for +#files < 128K +EXPECT "0" has_holes $B0/${V0}0/small +# Since source is smaller than sink, self-heal does blind copy so no holes will +# be present +EXPECT "0" has_holes $B0/${V0}0/bigger2big +EXPECT "1" has_holes $B0/${V0}0/big2bigger + +#Check that self-heal has not written 0s to sink and made it non-sparse. +USED_KB=`du -s $B0/${V0}0/FILE|cut -f1` +TEST [ $USED_KB -lt 1000000 ] + +#Check that the non-sparse file has the same file size on both bricks and that +#the disk usage is greater than or equal to the file size. We could have checked +#that the disk usage is just equal to the file size but XFS does speculative +#preallocation due to which disk usage can be more than the file size. +STAT_SIZE1=$(stat -c "%s" $B0/${V0}0/zeroedfile) +STAT_SIZE2=$(stat -c "%s" $B0/${V0}1/zeroedfile) +TEST [ $STAT_SIZE1 -eq $STAT_SIZE2 ] +USED_KB1="$((`stat -c %b $B0/${V0}0/zeroedfile` * `stat -c %B $B0/${V0}0/zeroedfile`))" +TEST [ $USED_KB1 -ge $STAT_SIZE1 ] +USED_KB2="$((`stat -c %b $B0/${V0}1/zeroedfile` * `stat -c %B $B0/${V0}1/zeroedfile`))" +TEST [ $USED_KB2 -ge $STAT_SIZE2 ] + +TEST rm -f $M0/* + +#check the same tests with diff self-heal +TEST $CLI volume set $V0 data-self-heal-algorithm diff + +TEST dd if=/dev/urandom of=$M0/small count=1 bs=1024k +TEST dd if=/dev/urandom of=$M0/big2bigger count=1 bs=1024k +TEST dd if=/dev/urandom of=$M0/bigger2big count=1 bs=2048k +TEST truncate -s 1G $M0/FILE + +TEST kill_brick $V0 $H0 $B0/${V0}0 + +#File with >128k size hole +TEST truncate -s 1M $M0/big +big_md5sum=$(md5sum $M0/big | awk '{print $1}') + +#File with <128k hole +TEST truncate -s 0 $M0/small +TEST truncate -s 64k $M0/small +small_md5sum=$(md5sum $M0/small | awk '{print $1}') + +#Bigger file truncated to big size hole +TEST truncate -s 0 $M0/bigger2big +TEST truncate -s 1M $M0/bigger2big +bigger2big_md5sum=$(md5sum $M0/bigger2big | awk '{print $1}') + +#Big file truncated to Bigger size hole +TEST truncate -s 2M $M0/big2bigger +big2bigger_md5sum=$(md5sum $M0/big2bigger | awk '{print $1}') + +#Write data to file and restore its sparseness +TEST dd if=/dev/urandom of=$M0/FILE count=1 bs=131072 +TEST truncate -s 1G $M0/FILE + +#Create a non-sparse file containing zeroes. +TEST dd if=/dev/zero of=$M0/zeroedfile bs=1024 count=1024 + +$CLI volume start $V0 force +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status $V0 0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "Y" glustershd_up_status +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 1 +TEST gluster volume heal $V0 full +EXPECT_WITHIN $HEAL_TIMEOUT "0" get_pending_heal_count $V0 + +#If the file system of bricks is XFS and speculative preallocation is on, +#dropping cahce should be done to free speculatively pre-allocated blocks +#by XFS. +drop_cache $M0 + +big_md5sum_0=$(md5sum $B0/${V0}0/big | awk '{print $1}') +small_md5sum_0=$(md5sum $B0/${V0}0/small | awk '{print $1}') +bigger2big_md5sum_0=$(md5sum $B0/${V0}0/bigger2big | awk '{print $1}') +big2bigger_md5sum_0=$(md5sum $B0/${V0}0/big2bigger | awk '{print $1}') + +EXPECT $big_md5sum echo $big_md5sum_0 +EXPECT $small_md5sum echo $small_md5sum_0 +EXPECT $big2bigger_md5sum echo $big2bigger_md5sum_0 +EXPECT $bigger2big_md5sum echo $bigger2big_md5sum_0 + +EXPECT "1" has_holes $B0/${V0}0/big +EXPECT "1" has_holes $B0/${V0}0/big2bigger +EXPECT "0" has_holes $B0/${V0}0/bigger2big +EXPECT "0" has_holes $B0/${V0}0/small + +#Check that self-heal has not written 0s to sink and made it non-sparse. +USED_KB=`du -s $B0/${V0}0/FILE|cut -f1` +TEST [ $USED_KB -lt 1000000 ] + +#Check that the non-sparse file has the same file size on both bricks and that +#the disk usage is greater than or equal to the file size. We could have checked +#that the disk usage is just equal to the file size but XFS does speculative +#preallocation due to which disk usage can be more than the file size. +STAT_SIZE1=$(stat -c "%s" $B0/${V0}0/zeroedfile) +STAT_SIZE2=$(stat -c "%s" $B0/${V0}1/zeroedfile) +TEST [ $STAT_SIZE1 -eq $STAT_SIZE2 ] +USED_KB1="$((`stat -c %b $B0/${V0}0/zeroedfile` * `stat -c %B $B0/${V0}0/zeroedfile`))" +TEST [ $USED_KB1 -ge $STAT_SIZE1 ] +USED_KB2="$((`stat -c %b $B0/${V0}1/zeroedfile` * `stat -c %B $B0/${V0}1/zeroedfile`))" +TEST [ $USED_KB2 -ge $STAT_SIZE2 ] + +cleanup diff --git a/tests/basic/afr/split-brain-favorite-child-policy-client-side-healing.t b/tests/basic/afr/split-brain-favorite-child-policy-client-side-healing.t new file mode 100644 index 00000000000..7c249c4bcbd --- /dev/null +++ b/tests/basic/afr/split-brain-favorite-child-policy-client-side-healing.t @@ -0,0 +1,124 @@ +#!/bin/bash + +#Test the client side split-brain resolution +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +cleanup; + +GET_MDATA_PATH=$(dirname $0)/../../utils +build_tester $GET_MDATA_PATH/get-mdata-xattr.c + +TEST glusterd +TEST pidof glusterd + +count_files () { + ls $1 | wc -l +} + +#Create replica 2 volume +TEST $CLI volume create $V0 replica 2 $H0:$B0/${V0}{0,1} +TEST $CLI volume set $V0 performance.write-behind off +TEST $CLI volume heal $V0 disable +TEST $CLI volume set $V0 cluster.quorum-type fixed +TEST $CLI volume set $V0 cluster.quorum-count 1 +TEST $CLI volume set $V0 cluster.metadata-self-heal on +TEST $CLI volume set $V0 cluster.data-self-heal on +TEST $CLI volume set $V0 cluster.entry-self-heal on + +TEST $CLI volume start $V0 +TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status $V0 0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status $V0 1 + +TEST mkdir $M0/data +TEST touch $M0/data/file + + +############ Client side healing using favorite-child-policy = mtime ################# +TEST kill_brick $V0 $H0 $B0/${V0}0 +TEST dd if=/dev/urandom of=$M0/data/file bs=1024 count=1024 +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0 +TEST kill_brick $V0 $H0 $B0/${V0}1 +TEST dd if=/dev/urandom of=$M0/data/file bs=1024 count=1024 + +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 1 + +mtime1=$(get_mtime $B0/${V0}0/data/file) +mtime2=$(get_mtime $B0/${V0}1/data/file) +if (( $(echo "$mtime1 > $mtime2" | bc -l) )); then + LATEST_MTIME_MD5=$(md5sum $B0/${V0}0/data/file | cut -d\ -f1) +else + LATEST_MTIME_MD5=$(md5sum $B0/${V0}1/data/file | cut -d\ -f1) +fi + +#file will be in split-brain +cat $M0/data/file > /dev/null +EXPECT "1" echo $? + +TEST $CLI volume set $V0 cluster.favorite-child-policy mtime +TEST $CLI volume start $V0 force + +EXPECT_WITHIN $HEAL_TIMEOUT "^2$" afr_get_split_brain_count $V0 +cat $M0/data/file > /dev/null +EXPECT "0" echo $? +M0_MD5=$(md5sum $M0/data/file | cut -d\ -f1) +EXPECT_WITHIN $HEAL_TIMEOUT "^0$" afr_get_split_brain_count $V0 +TEST [ "$LATEST_MTIME_MD5" == "$M0_MD5" ] + +EXPECT_WITHIN $HEAL_TIMEOUT "^0$" get_pending_heal_count $V0 + +B0_MD5=$(md5sum $B0/${V0}0/data/file | cut -d\ -f1) +B1_MD5=$(md5sum $B0/${V0}1/data/file | cut -d\ -f1) +TEST [ "$LATEST_MTIME_MD5" == "$B0_MD5" ] +TEST [ "$LATEST_MTIME_MD5" == "$B1_MD5" ] + +############ Client side directory conservative merge ################# +TEST $CLI volume reset $V0 cluster.favorite-child-policy +TEST kill_brick $V0 $H0 $B0/${V0}0 +TEST touch $M0/data/test +files=$(count_files $M0/data) +EXPECT "2" echo $files +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0 +TEST kill_brick $V0 $H0 $B0/${V0}1 +TEST touch $M0/data/test1 +files=$(count_files $M0/data) +EXPECT "2" echo $files + +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 1 + +#data dir will be in entry split-brain +ls $M0/data > /dev/null +EXPECT "2" echo $? + +TEST $CLI volume set $V0 cluster.favorite-child-policy mtime + +EXPECT_WITHIN $HEAL_TIMEOUT "^2$" afr_get_split_brain_count $V0 + + +ls $M0/data > /dev/null +EXPECT "0" echo $? + +EXPECT_WITHIN $HEAL_TIMEOUT "^0$" afr_get_split_brain_count $V0 +#Entry Split-brain is gone, but data self-heal is pending on the files +EXPECT_WITHIN $HEAL_TIMEOUT "^2$" get_pending_heal_count $V0 + +cat $M0/data/test > /dev/null +cat $M0/data/test1 > /dev/null + +EXPECT_WITHIN $HEAL_TIMEOUT "^0$" get_pending_heal_count $V0 +files=$(count_files $M0/data) +EXPECT "3" echo $files + +TEST force_umount $M0 +TEST rm $GET_MDATA_PATH/get-mdata-xattr + +cleanup diff --git a/tests/basic/afr/split-brain-heal-info.t b/tests/basic/afr/split-brain-heal-info.t new file mode 100644 index 00000000000..2e4742fff08 --- /dev/null +++ b/tests/basic/afr/split-brain-heal-info.t @@ -0,0 +1,62 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +cleanup; + +function volume_start_force() +{ + local vol=$1 + TEST $CLI volume start $vol force + EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $vol 0 + EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $vol 1 +} + +TESTS_EXPECTED_IN_LOOP=15 +SPB_FILES=0 +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 replica 2 $H0:$B0/${V0}{0,1} +TEST $CLI volume start $V0 +TEST $CLI volume set $V0 cluster.self-heal-daemon off +TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0 + +TEST mkdir $M0/dspb +TEST mkdir $M0/mspb +TEST mkdir $M0/espb +TEST touch $M0/dspb/file + +#### Simlulate data-split-brain +TEST kill_brick $V0 $H0 $B0/${V0}0 +TEST `echo "abc" > $M0/dspb/file` +volume_start_force $V0 +TEST kill_brick $V0 $H0 $B0/${V0}1 +TEST `echo "def" > $M0/dspb/file` +volume_start_force $V0 +SPB_FILES=$(($SPB_FILES + 1)) + +### Simulate metadata-split-brain +TEST kill_brick $V0 $H0 $B0/${V0}0 +TEST chmod 757 $M0/mspb +volume_start_force $V0 +TEST kill_brick $V0 $H0 $B0/${V0}1 +TEST chmod 747 $M0/mspb +volume_start_force $V0 +SPB_FILES=$(($SPB_FILES + 1)) + +#### Simulate entry-split-brain +TEST kill_brick $V0 $H0 $B0/${V0}0 +EXPECT_WITHIN ${PROCESS_DOWN_TIMEOUT} "^0$" afr_child_up_status $V0 0 +TEST touch $M0/espb/a +volume_start_force $V0 +TEST kill_brick $V0 $H0 $B0/${V0}1 +EXPECT_WITHIN ${PROCESS_DOWN_TIMEOUT} "^0$" afr_child_up_status $V0 1 +TEST mkdir $M0/espb/a +volume_start_force $V0 +SPB_FILES=$(($SPB_FILES + 1)) + +#Multiply by 2, for each brick in replica pair +SPB_FILES=$(($SPB_FILES * 2)) +EXPECT "$SPB_FILES" afr_get_split_brain_count $V0 +cleanup; diff --git a/tests/basic/afr/split-brain-healing-ctime.t b/tests/basic/afr/split-brain-healing-ctime.t new file mode 100644 index 00000000000..676788fce3f --- /dev/null +++ b/tests/basic/afr/split-brain-healing-ctime.t @@ -0,0 +1,252 @@ +#!/bin/bash + +#Test the split-brain resolution CLI commands. +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +function get_replicate_subvol_number { + local filename=$1 + #get_backend_paths + if [ -f $B0/${V0}1/$filename ] + then + echo 0 + elif [ -f $B0/${V0}3/$filename ] + then echo 1 + else + echo -1 + fi +} + +cleanup; + +AREQUAL_PATH=$(dirname $0)/../../utils +GET_MDATA_PATH=$(dirname $0)/../../utils +CFLAGS="" +test "`uname -s`" != "Linux" && { + CFLAGS="$CFLAGS -lintl"; +} +build_tester $AREQUAL_PATH/arequal-checksum.c $CFLAGS +build_tester $GET_MDATA_PATH/get-mdata-xattr.c + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 replica 2 $H0:$B0/${V0}{1,2,3,4} +TEST $CLI volume set $V0 cluster.self-heal-daemon off +TEST $CLI volume set $V0 cluster.data-self-heal off +TEST $CLI volume set $V0 cluster.metadata-self-heal off +TEST $CLI volume set $V0 cluster.entry-self-heal off +TEST $CLI volume start $V0 +TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0 + +cd $M0 +for i in {1..10} +do + echo "Initial content">>file$i +done + +replica_0_files_list=(`ls $B0/${V0}1|grep -v '^\.'`) +replica_1_files_list=(`ls $B0/${V0}3|grep -v '^\.'`) + +############ Create data split-brain in the files. ########################### +TEST kill_brick $V0 $H0 $B0/${V0}1 +for file in ${!replica_0_files_list[*]} +do + echo "B1 is down">>${replica_0_files_list[$file]} +done +TEST kill_brick $V0 $H0 $B0/${V0}3 +for file in ${!replica_1_files_list[*]} +do + echo "B3 is down">>${replica_1_files_list[$file]} +done + +SMALLER_FILE_SIZE=$(stat -c %s file1) + +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 2 + +TEST kill_brick $V0 $H0 $B0/${V0}2 +for file in ${!replica_0_files_list[*]} +do + echo "B2 is down">>${replica_0_files_list[$file]} + echo "appending more content to make it the bigger file">>${replica_0_files_list[$file]} +done +TEST kill_brick $V0 $H0 $B0/${V0}4 +for file in ${!replica_1_files_list[*]} +do + echo "B4 is down">>${replica_1_files_list[$file]} + echo "appending more content to make it the bigger file">>${replica_1_files_list[$file]} +done + +BIGGER_FILE_SIZE=$(stat -c %s file1) +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 3 + + +############### Acessing the files should now give EIO. ############################### +TEST ! cat file1 +TEST ! cat file2 +TEST ! cat file3 +TEST ! cat file4 +TEST ! cat file5 +TEST ! cat file6 +TEST ! cat file7 +TEST ! cat file8 +TEST ! cat file9 +TEST ! cat file10 +################### +TEST $CLI volume set $V0 cluster.self-heal-daemon on +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "Y" glustershd_up_status +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 1 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 2 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 3 + +################ Heal file1 using the bigger-file option ############## +$CLI volume heal $V0 split-brain bigger-file /file1 +EXPECT "0" echo $? +EXPECT $BIGGER_FILE_SIZE stat -c %s file1 + +################ Heal file2 using the bigger-file option and its gfid ############## +subvolume=$(get_replicate_subvol_number file2) +if [ $subvolume == 0 ] +then + GFID=$(gf_get_gfid_xattr $B0/${V0}1/file2) +elif [ $subvolume == 1 ] +then + GFID=$(gf_get_gfid_xattr $B0/${V0}3/file2) +fi +GFIDSTR="gfid:$(gf_gfid_xattr_to_str $GFID)" +$CLI volume heal $V0 split-brain bigger-file $GFIDSTR +EXPECT "0" echo $? + +################ Heal file3 using the source-brick option ############## +################ Use the brick having smaller file size as source ####### +subvolume=$(get_replicate_subvol_number file3) +if [ $subvolume == 0 ] +then + $CLI volume heal $V0 split-brain source-brick $H0:$B0/${V0}2 /file3 +elif [ $subvolume == 1 ] +then + $CLI volume heal $V0 split-brain source-brick $H0:$B0/${V0}4 /file3 +fi +EXPECT "0" echo $? +EXPECT $SMALLER_FILE_SIZE stat -c %s file3 + +################ Heal file4 using the source-brick option and it's gfid ############## +################ Use the brick having smaller file size as source ####### +subvolume=$(get_replicate_subvol_number file4) +if [ $subvolume == 0 ] +then + GFID=$(gf_get_gfid_xattr $B0/${V0}1/file4) + GFIDSTR="gfid:$(gf_gfid_xattr_to_str $GFID)" + $CLI volume heal $V0 split-brain source-brick $H0:$B0/${V0}2 $GFIDSTR +elif [ $subvolume == 1 ] +then + GFID=$(gf_get_gfid_xattr $B0/${V0}3/file4) + GFIDSTR="gfid:$(gf_gfid_xattr_to_str $GFID)" + $CLI volume heal $V0 split-brain source-brick $H0:$B0/${V0}4 $GFIDSTR +fi +EXPECT "0" echo $? +EXPECT $SMALLER_FILE_SIZE stat -c %s file4 + +# With ctime enabled, the ctime xattr ("trusted.glusterfs.mdata") gets healed +# as part of metadata heal. So mtime would be same, hence it can't be healed +# using 'latest-mtime' policy, use 'source-brick' option instead. +################ Heal file5 using the source-brick option ############## +subvolume=$(get_replicate_subvol_number file5) +if [ $subvolume == 0 ] +then + $CLI volume heal $V0 split-brain source-brick $H0:$B0/${V0}1 /file5 +elif [ $subvolume == 1 ] +then + $CLI volume heal $V0 split-brain source-brick $H0:$B0/${V0}3 /file5 +fi +EXPECT "0" echo $? + +if [ $subvolume == 0 ] +then + mtime1_after_heal=$(get_mtime $B0/${V0}1/file5) + mtime2_after_heal=$(get_mtime $B0/${V0}2/file5) +elif [ $subvolume == 1 ] +then + mtime1_after_heal=$(get_mtime $B0/${V0}3/file5) + mtime2_after_heal=$(get_mtime $B0/${V0}4/file5) +fi + +#TODO: To below comparisons on full sub-second resolution + +TEST [ $mtime1_after_heal -eq $mtime2_after_heal ] + +mtime_mount_after_heal=$(stat -c %Y file5) + +TEST [ $mtime1_after_heal -eq $mtime_mount_after_heal ] + +################ Heal file6 using the source-brick option and its gfid ############## +subvolume=$(get_replicate_subvol_number file6) +if [ $subvolume == 0 ] +then + GFID=$(gf_get_gfid_xattr $B0/${V0}1/file6) + GFIDSTR="gfid:$(gf_gfid_xattr_to_str $GFID)" + $CLI volume heal $V0 split-brain source-brick $H0:$B0/${V0}1 $GFIDSTR +elif [ $subvolume == 1 ] +then + GFID=$(gf_get_gfid_xattr $B0/${V0}3/file6) + GFIDSTR="gfid:$(gf_gfid_xattr_to_str $GFID)" + $CLI volume heal $V0 split-brain source-brick $H0:$B0/${V0}3 $GFIDSTR +fi +EXPECT "0" echo $? + +if [ $subvolume == 0 ] +then + mtime1_after_heal=$(get_mtime $B0/${V0}1/file6) + mtime2_after_heal=$(get_mtime $B0/${V0}2/file6) +elif [ $subvolume == 1 ] +then + mtime1_after_heal=$(get_mtime $B0/${V0}3/file6) + mtime2_after_heal=$(get_mtime $B0/${V0}4/file6) +fi + +#TODO: To below comparisons on full sub-second resolution + +TEST [ $mtime1_after_heal -eq $mtime2_after_heal ] + +mtime_mount_after_heal=$(stat -c %Y file6) + +TEST [ $mtime1_after_heal -eq $mtime_mount_after_heal ] + +################ Heal remaining SB'ed files of replica_0 using B1 as source ############## +$CLI volume heal $V0 split-brain source-brick $H0:$B0/${V0}1 +EXPECT "0" echo $? + +################ Heal remaining SB'ed files of replica_1 using B3 as source ############## +$CLI volume heal $V0 split-brain source-brick $H0:$B0/${V0}3 +EXPECT "0" echo $? + +############### Reading the files should now succeed. ############################### +TEST cat file1 +TEST cat file2 +TEST cat file3 +TEST cat file4 +TEST cat file5 +TEST cat file6 +TEST cat file7 +TEST cat file8 +TEST cat file9 +TEST cat file10 + +################ File contents on the bricks must be same. ################################ +TEST diff <(arequal-checksum -p $B0/$V01 -i .glusterfs) <(arequal-checksum -p $B0/$V02 -i .glusterfs) +TEST diff <(arequal-checksum -p $B0/$V03 -i .glusterfs) <(arequal-checksum -p $B0/$V04 -i .glusterfs) + +############### Trying to heal files not in SB should fail. ############################### +$CLI volume heal $V0 split-brain bigger-file /file1 +EXPECT "1" echo $? +$CLI volume heal $V0 split-brain source-brick $H0:$B0/${V0}4 /file3 +EXPECT "1" echo $? + +cd - +TEST rm $AREQUAL_PATH/arequal-checksum +TEST rm $GET_MDATA_PATH/get-mdata-xattr +cleanup diff --git a/tests/basic/afr/split-brain-healing.t b/tests/basic/afr/split-brain-healing.t new file mode 100644 index 00000000000..315e815eb7e --- /dev/null +++ b/tests/basic/afr/split-brain-healing.t @@ -0,0 +1,261 @@ +#!/bin/bash + +#Test the split-brain resolution CLI commands. +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +function get_replicate_subvol_number { + local filename=$1 + #get_backend_paths + if [ -f $B0/${V0}1/$filename ] + then + echo 0 + elif [ -f $B0/${V0}3/$filename ] + then echo 1 + else + echo -1 + fi +} + +cleanup; + +AREQUAL_PATH=$(dirname $0)/../../utils +GET_MDATA_PATH=$(dirname $0)/../../utils +CFLAGS="" +test "`uname -s`" != "Linux" && { + CFLAGS="$CFLAGS -lintl"; +} +build_tester $AREQUAL_PATH/arequal-checksum.c $CFLAGS +build_tester $GET_MDATA_PATH/get-mdata-xattr.c + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 replica 2 $H0:$B0/${V0}{1,2,3,4} +TEST $CLI volume set $V0 cluster.self-heal-daemon off +TEST $CLI volume set $V0 cluster.data-self-heal off +TEST $CLI volume set $V0 cluster.metadata-self-heal off +TEST $CLI volume set $V0 cluster.entry-self-heal off +TEST $CLI volume set $V0 ctime off +TEST $CLI volume start $V0 +TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0 + +cd $M0 +for i in {1..10} +do + echo "Initial content">>file$i +done + +replica_0_files_list=(`ls $B0/${V0}1|grep -v '^\.'`) +replica_1_files_list=(`ls $B0/${V0}3|grep -v '^\.'`) + +############ Create data split-brain in the files. ########################### +TEST kill_brick $V0 $H0 $B0/${V0}1 +for file in ${!replica_0_files_list[*]} +do + echo "B1 is down">>${replica_0_files_list[$file]} +done +TEST kill_brick $V0 $H0 $B0/${V0}3 +for file in ${!replica_1_files_list[*]} +do + echo "B3 is down">>${replica_1_files_list[$file]} +done + +SMALLER_FILE_SIZE=$(stat -c %s file1) + +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 2 + +TEST kill_brick $V0 $H0 $B0/${V0}2 +for file in ${!replica_0_files_list[*]} +do + echo "B2 is down">>${replica_0_files_list[$file]} + echo "appending more content to make it the bigger file">>${replica_0_files_list[$file]} +done +TEST kill_brick $V0 $H0 $B0/${V0}4 +for file in ${!replica_1_files_list[*]} +do + echo "B4 is down">>${replica_1_files_list[$file]} + echo "appending more content to make it the bigger file">>${replica_1_files_list[$file]} +done + +BIGGER_FILE_SIZE=$(stat -c %s file1) +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 3 + + +############### Acessing the files should now give EIO. ############################### +TEST ! cat file1 +TEST ! cat file2 +TEST ! cat file3 +TEST ! cat file4 +TEST ! cat file5 +TEST ! cat file6 +TEST ! cat file7 +TEST ! cat file8 +TEST ! cat file9 +TEST ! cat file10 +################### +TEST $CLI volume set $V0 cluster.self-heal-daemon on +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "Y" glustershd_up_status +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 1 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 2 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 3 + +################ Heal file1 using the bigger-file option ############## +$CLI volume heal $V0 split-brain bigger-file /file1 +EXPECT "0" echo $? +EXPECT $BIGGER_FILE_SIZE stat -c %s file1 + +################ Heal file2 using the bigger-file option and its gfid ############## +subvolume=$(get_replicate_subvol_number file2) +if [ $subvolume == 0 ] +then + GFID=$(gf_get_gfid_xattr $B0/${V0}1/file2) +elif [ $subvolume == 1 ] +then + GFID=$(gf_get_gfid_xattr $B0/${V0}3/file2) +fi +GFIDSTR="gfid:$(gf_gfid_xattr_to_str $GFID)" +$CLI volume heal $V0 split-brain bigger-file $GFIDSTR +EXPECT "0" echo $? + +################ Heal file3 using the source-brick option ############## +################ Use the brick having smaller file size as source ####### +subvolume=$(get_replicate_subvol_number file3) +if [ $subvolume == 0 ] +then + $CLI volume heal $V0 split-brain source-brick $H0:$B0/${V0}2 /file3 +elif [ $subvolume == 1 ] +then + $CLI volume heal $V0 split-brain source-brick $H0:$B0/${V0}4 /file3 +fi +EXPECT "0" echo $? +EXPECT $SMALLER_FILE_SIZE stat -c %s file3 + +################ Heal file4 using the source-brick option and it's gfid ############## +################ Use the brick having smaller file size as source ####### +subvolume=$(get_replicate_subvol_number file4) +if [ $subvolume == 0 ] +then + GFID=$(gf_get_gfid_xattr $B0/${V0}1/file4) + GFIDSTR="gfid:$(gf_gfid_xattr_to_str $GFID)" + $CLI volume heal $V0 split-brain source-brick $H0:$B0/${V0}2 $GFIDSTR +elif [ $subvolume == 1 ] +then + GFID=$(gf_get_gfid_xattr $B0/${V0}3/file4) + GFIDSTR="gfid:$(gf_gfid_xattr_to_str $GFID)" + $CLI volume heal $V0 split-brain source-brick $H0:$B0/${V0}4 $GFIDSTR +fi +EXPECT "0" echo $? +EXPECT $SMALLER_FILE_SIZE stat -c %s file4 + +################ Heal file5 using the latest-mtime option ############## +subvolume=$(get_replicate_subvol_number file5) +if [ $subvolume == 0 ] +then + mtime1=$(get_mtime $B0/${V0}1/file5) + mtime2=$(get_mtime $B0/${V0}2/file5) + LATEST_MTIME=$(($mtime1 > $mtime2 ? $mtime1:$mtime2)) +elif [ $subvolume == 1 ] +then + mtime1=$(get_mtime $B0/${V0}3/file5) + mtime2=$(get_mtime $B0/${V0}4/file5) + LATEST_MTIME=$(($mtime1 > $mtime2 ? $mtime1:$mtime2)) +fi +$CLI volume heal $V0 split-brain latest-mtime /file5 +EXPECT "0" echo $? + +if [ $subvolume == 0 ] +then + mtime1_after_heal=$(get_mtime $B0/${V0}1/file5) + mtime2_after_heal=$(get_mtime $B0/${V0}2/file5) +elif [ $subvolume == 1 ] +then + mtime1_after_heal=$(get_mtime $B0/${V0}3/file5) + mtime2_after_heal=$(get_mtime $B0/${V0}4/file5) +fi + +#TODO: To below comparisons on full sub-second resolution + +TEST [ $LATEST_MTIME -eq $mtime1_after_heal ] +TEST [ $LATEST_MTIME -eq $mtime2_after_heal ] + +mtime_mount_after_heal=$(stat -c %Y file5) + +TEST [ $LATEST_MTIME -eq $mtime_mount_after_heal ] + +################ Heal file6 using the latest-mtime option and its gfid ############## +subvolume=$(get_replicate_subvol_number file6) +if [ $subvolume == 0 ] +then + GFID=$(gf_get_gfid_xattr $B0/${V0}1/file6) + mtime1=$(get_mtime $B0/${V0}1/file6) + mtime2=$(get_mtime $B0/${V0}2/file6) + LATEST_MTIME=$(($mtime1 > $mtime2 ? $mtime1:$mtime2)) +elif [ $subvolume == 1 ] +then + GFID=$(gf_get_gfid_xattr $B0/${V0}3/file6) + mtime1=$(get_mtime $B0/${V0}3/file6) + mtime2=$(get_mtime $B0/${V0}4/file6) + LATEST_MTIME=$(($mtime1 > $mtime2 ? $mtime1:$mtime2)) +fi +GFIDSTR="gfid:$(gf_gfid_xattr_to_str $GFID)" +$CLI volume heal $V0 split-brain latest-mtime $GFIDSTR +EXPECT "0" echo $? + +if [ $subvolume == 0 ] +then + mtime1_after_heal=$(get_mtime $B0/${V0}1/file6) + mtime2_after_heal=$(get_mtime $B0/${V0}2/file6) +elif [ $subvolume == 1 ] +then + mtime1_after_heal=$(get_mtime $B0/${V0}3/file6) + mtime2_after_heal=$(get_mtime $B0/${V0}4/file6) +fi + +#TODO: To below comparisons on full sub-second resolution + +TEST [ $LATEST_MTIME -eq $mtime1_after_heal ] +TEST [ $LATEST_MTIME -eq $mtime2_after_heal ] + +mtime_mount_after_heal=$(stat -c %Y file6) + +TEST [ $LATEST_MTIME -eq $mtime_mount_after_heal ] + +################ Heal remaining SB'ed files of replica_0 using B1 as source ############## +$CLI volume heal $V0 split-brain source-brick $H0:$B0/${V0}1 +EXPECT "0" echo $? + +################ Heal remaining SB'ed files of replica_1 using B3 as source ############## +$CLI volume heal $V0 split-brain source-brick $H0:$B0/${V0}3 +EXPECT "0" echo $? + +############### Reading the files should now succeed. ############################### +TEST cat file1 +TEST cat file2 +TEST cat file3 +TEST cat file4 +TEST cat file5 +TEST cat file6 +TEST cat file7 +TEST cat file8 +TEST cat file9 +TEST cat file10 + +################ File contents on the bricks must be same. ################################ +TEST diff <(arequal-checksum -p $B0/$V01 -i .glusterfs) <(arequal-checksum -p $B0/$V02 -i .glusterfs) +TEST diff <(arequal-checksum -p $B0/$V03 -i .glusterfs) <(arequal-checksum -p $B0/$V04 -i .glusterfs) + +############### Trying to heal files not in SB should fail. ############################### +$CLI volume heal $V0 split-brain bigger-file /file1 +EXPECT "1" echo $? +$CLI volume heal $V0 split-brain source-brick $H0:$B0/${V0}4 /file3 +EXPECT "1" echo $? + +cd - +TEST rm $AREQUAL_PATH/arequal-checksum +TEST rm $GET_MDATA_PATH/get-mdata-xattr +cleanup diff --git a/tests/basic/afr/split-brain-open.t b/tests/basic/afr/split-brain-open.t new file mode 100644 index 00000000000..9b2f2856047 --- /dev/null +++ b/tests/basic/afr/split-brain-open.t @@ -0,0 +1,38 @@ +#!/bin/bash +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc +cleanup; + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 replica 2 $H0:$B0/${V0}{0,1} +TEST $CLI volume start $V0 + +#Disable self-heal-daemon +TEST $CLI volume heal $V0 disable + +TEST glusterfs --volfile-id=$V0 --volfile-server=$H0 --entry-timeout=0 $M0; + +TEST touch $M0/data-split-brain.txt + +#Create data split-brain +TEST kill_brick $V0 $H0 $B0/${V0}0 + +`echo "brick1_alive" > $M0/data-split-brain.txt` +TEST [ $? == 0 ]; + +TEST $CLI volume start $V0 force +TEST kill_brick $V0 $H0 $B0/${V0}1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0 + +`echo "brick0_alive" > $M0/data-split-brain.txt` +TEST [ $? == 0 ]; + +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 1 + +echo "all-alive" >> $M0/data-split-brain.txt +TEST [ $? != 0 ]; + +cleanup; diff --git a/tests/basic/afr/split-brain-resolution.t b/tests/basic/afr/split-brain-resolution.t new file mode 100644 index 00000000000..834237c96ec --- /dev/null +++ b/tests/basic/afr/split-brain-resolution.t @@ -0,0 +1,105 @@ +#!/bin/bash +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc +cleanup; + +function get_split_brain_status { + local path=$1 + echo `getfattr -n replica.split-brain-status $path` | cut -f2 -d"=" | sed -e 's/^"//' -e 's/"$//' +} + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 replica 2 $H0:$B0/${V0}{0,1} +TEST $CLI volume set $V0 cluster.data-self-heal on +TEST $CLI volume set $V0 cluster.metadata-self-heal on +TEST $CLI volume set $V0 cluster.entry-self-heal on +TEST $CLI volume start $V0 + +#Disable self-heal-daemon +TEST $CLI volume set $V0 cluster.self-heal-daemon off + +TEST $GFS --volfile-id=$V0 --volfile-server=$H0 $M0; + +TEST `echo "some-data" > $M0/data-split-brain.txt` +TEST `echo "some-data" > $M0/metadata-split-brain.txt` + +#Create data and metadata split-brain +TEST kill_brick $V0 $H0 $B0/${V0}0 + +TEST `echo "brick1_alive" > $M0/data-split-brain.txt` +TEST setfattr -n user.test -v brick1 $M0/metadata-split-brain.txt + +TEST $CLI volume start $V0 force +TEST kill_brick $V0 $H0 $B0/${V0}1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0 + +TEST `echo "brick0_alive" > $M0/data-split-brain.txt` +TEST setfattr -n user.test -v brick0 $M0/metadata-split-brain.txt + +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 1 + +EXPECT 4 get_pending_heal_count $V0 + +TEST ! cat $M0/data-split-brain.txt +TEST ! getfattr -n user.test $M0/metadata-split-brain.txt + +#Inspect file in data-split-brain +EXPECT "data-split-brain:yes metadata-split-brain:no Choices:patchy-client-0,patchy-client-1" get_split_brain_status $M0/data-split-brain.txt +TEST setfattr -n replica.split-brain-choice -v $V0-client-0 $M0/data-split-brain.txt + +#Should now be able to read the contents of data-split-brain.txt +EXPECT "brick0_alive" cat $M0/data-split-brain.txt + +TEST setfattr -n replica.split-brain-choice-timeout -v 10 $M0/ +TEST setfattr -n replica.split-brain-choice -v $V0-client-1 $M0/data-split-brain.txt + +#Should now be able to read the contents of data-split-brain.txt +EXPECT "brick1_alive" cat $M0/data-split-brain.txt + +#Inspect the file in metadata-split-brain +EXPECT "data-split-brain:no metadata-split-brain:yes Choices:patchy-client-0,patchy-client-1" get_split_brain_status $M0/metadata-split-brain.txt +TEST setfattr -n replica.split-brain-choice -v $V0-client-0 $M0/metadata-split-brain.txt + +EXPECT "brick0" get_text_xattr user.test $M0/metadata-split-brain.txt + +TEST setfattr -n replica.split-brain-choice -v $V0-client-1 $M0/metadata-split-brain.txt +EXPECT "brick1" get_text_xattr user.test $M0/metadata-split-brain.txt + +#Check that setting split-brain-choice to "none" results in EIO again +TEST setfattr -n replica.split-brain-choice -v none $M0/metadata-split-brain.txt +TEST setfattr -n replica.split-brain-choice -v none $M0/data-split-brain.txt +TEST ! getfattr -n user.test $M0/metadata-split-brain.txt +TEST ! cat $M0/data-split-brain.txt + +#Check that after timeout fops result in EIO again. +#Set one minute timeout +TEST setfattr -n replica.split-brain-choice-timeout -v 1 $M0/ +TEST setfattr -n replica.split-brain-choice -v $V0-client-1 $M0/data-split-brain.txt +EXPECT "brick1_alive" cat $M0/data-split-brain.txt +TEST setfattr -n replica.split-brain-choice -v $V0-client-0 $M0/metadata-split-brain.txt +EXPECT "brick0" get_text_xattr user.test $M0/metadata-split-brain.txt +#Wait until timeout completes and test that the fops fail again +sleep 62 +TEST ! getfattr -n user.test $M0/metadata-split-brain.txt +TEST ! cat $M0/data-split-brain.txt + +#Negative test cases should fail +TEST ! setfattr -n replica.split-brain-choice -v $V0-client-4 $M0/data-split-brain.txt +TEST ! setfattr -n replica.split-brain-heal-finalize -v $V0-client-4 $M0/metadata-split-brain.txt + +#Heal the files +TEST setfattr -n replica.split-brain-heal-finalize -v $V0-client-0 $M0/metadata-split-brain.txt +TEST setfattr -n replica.split-brain-heal-finalize -v $V0-client-1 $M0/data-split-brain.txt + +EXPECT "brick0" get_text_xattr user.test $M0/metadata-split-brain.txt +EXPECT "brick1_alive" cat $M0/data-split-brain.txt + +EXPECT 0 get_pending_heal_count $V0 + +cleanup; + +#G_TESTDEF_TEST_STATUS_NETBSD7=BAD_TEST,BUG=000000 +#G_TESTDEF_TEST_STATUS_CENTOS6=BAD_TEST,BUG=000000 diff --git a/tests/basic/afr/stale-file-lookup.t b/tests/basic/afr/stale-file-lookup.t new file mode 100644 index 00000000000..f30422fd009 --- /dev/null +++ b/tests/basic/afr/stale-file-lookup.t @@ -0,0 +1,30 @@ +#!/bin/bash + +#This file checks if stale file lookup fails or not. +#A file is deleted when a brick was down. Before self-heal could happen to it +#the file is accessed. It should fail. +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +cleanup; + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 replica 2 $H0:$B0/${V0}{0,1} +TEST $CLI volume set $V0 self-heal-daemon off +TEST $CLI volume set $V0 cluster.metadata-self-heal off +TEST $CLI volume set $V0 cluster.entry-self-heal off +TEST $CLI volume set $V0 cluster.data-self-heal off +TEST $CLI volume start $V0 + +TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0; +TEST touch $M0/a +TEST kill_brick $V0 $H0 $B0/${V0}0 +TEST rm -f $M0/a +TEST $CLI volume start $V0 force +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status $V0 0 +TEST stat $B0/${V0}0/a +TEST ! stat $B0/${V0}1/a +TEST ! ls -l $M0/a + +cleanup diff --git a/tests/basic/afr/ta-check-locks.t b/tests/basic/afr/ta-check-locks.t new file mode 100644 index 00000000000..c0102c35b7b --- /dev/null +++ b/tests/basic/afr/ta-check-locks.t @@ -0,0 +1,68 @@ +#!/bin/bash +#This test checks if all the locks on +#ta file are being held and released properly + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc +. $(dirname $0)/../../thin-arbiter.rc + +function get_lock_count_on_ta() +{ + tapid=`cat $B0/ta.pid` + local sfile=$(generate_statedump $tapid) + count=$(grep "inodelk-count" $sfile | cut -f2 -d'=' | tail -1) + ncount=$(grep "inodelk.inodelk" $sfile | grep "len=1" | wc -l) + echo "count = $count : ncount = $ncount" + if [ "$count" = "" ] + then + count=0 + fi + + if [ "$count" -eq "$ncount" ] + then + echo "$count" + else + echo "-1" + fi +} + +cleanup; +TEST ta_create_brick_and_volfile brick0 +TEST ta_create_brick_and_volfile brick1 +TEST ta_create_ta_and_volfile ta +TEST ta_start_brick_process brick0 +TEST ta_start_brick_process brick1 +TEST ta_start_ta_process ta + +TEST ta_create_mount_volfile brick0 brick1 ta +TEST ta_start_mount_process $M0 +TEST ta_start_mount_process $M1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" ta_up_status $V0 $M0 0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" ta_up_status $V0 $M1 0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "trusted.afr.patchy-ta-2" ls $B0/ta + +TEST ta_create_shd_volfile brick0 brick1 ta +TEST ta_start_shd_process glustershd +shd_pid=$(cat $B0/glustershd.pid) + +TEST touch $M0/a.txt +echo "Hello" >> $M0/a.txt +EXPECT_WITHIN $IO_WAIT_TIMEOUT "0" get_lock_count_on_ta + +TEST ta_kill_brick brick0 +echo "Hello" >> $M0/a.txt +EXPECT_WITHIN $IO_WAIT_TIMEOUT "1" get_lock_count_on_ta + +echo "Hello" >> $M1/a.txt +EXPECT_WITHIN $IO_WAIT_TIMEOUT "2" get_lock_count_on_ta + +echo "xyz" >> $M0/a.txt +EXPECT_WITHIN $IO_WAIT_TIMEOUT "2" get_lock_count_on_ta + +chmod 0666 $M0/a.txt +EXPECT_WITHIN $IO_WAIT_TIMEOUT "2" get_lock_count_on_ta + +TEST ta_start_brick_process brick0 +EXPECT_WITHIN $HEAL_TIMEOUT "0" get_lock_count_on_ta + +cleanup; diff --git a/tests/basic/afr/ta-read.t b/tests/basic/afr/ta-read.t new file mode 100644 index 00000000000..3cfc16b9b8a --- /dev/null +++ b/tests/basic/afr/ta-read.t @@ -0,0 +1,64 @@ +#!/bin/bash + +# Test read transaction logic for thin-arbiter. + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc +. $(dirname $0)/../../thin-arbiter.rc +cleanup; +TEST ta_create_brick_and_volfile brick0 +TEST ta_create_brick_and_volfile brick1 +TEST ta_create_ta_and_volfile ta +TEST ta_start_brick_process brick0 +TEST ta_start_brick_process brick1 +TEST ta_start_ta_process ta + +TEST ta_create_mount_volfile brick0 brick1 ta +TEST ta_start_mount_process $M0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" ta_up_status $V0 $M0 0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "trusted.afr.patchy-ta-2" ls $B0/ta + +TEST touch $M0/FILE +TEST ls $B0/brick0/FILE +TEST ls $B0/brick1/FILE +TEST ! ls $B0/ta/FILE + +# Kill one brick and write to FILE. +TEST ta_kill_brick brick0 +EXPECT_WITHIN $PROCESS_DOWN_TIMEOUT "0" ta_mount_child_up_status $M0 $V0 0 +echo "brick0 down">> $M0/FILE +TEST [ $? -eq 0 ] +EXPECT "000000010000000000000000" get_hex_xattr trusted.afr.$V0-client-0 $B0/brick1/FILE +EXPECT "000000010000000000000000" get_hex_xattr trusted.afr.$V0-client-0 $B0/ta/trusted.afr.patchy-ta-2 + +#Umount and mount to remove cached data. +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 +TEST ta_start_mount_process $M0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" ta_up_status $V0 $M0 0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" ta_mount_child_up_status $M0 $V0 1 +# Read must be allowed since good brick is up. +TEST cat $M0/FILE + +#Umount and mount to remove cached data. +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 +TEST ta_start_mount_process $M0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" ta_up_status $V0 $M0 0 +# Toggle good and bad data brick processes. +TEST ta_start_brick_process brick0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" ta_mount_child_up_status $M0 $V0 0 +TEST ta_kill_brick brick1 +EXPECT_WITHIN $PROCESS_DOWN_TIMEOUT "0" ta_mount_child_up_status $M0 $V0 1 +# Read must now fail. +TEST ! cat $M0/FILE + +# Bring all data bricks up, and kill TA. +TEST ta_start_brick_process brick1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" ta_mount_child_up_status $M0 $V0 1 +TA_PID=$(ta_get_pid_by_brick_name ta) +TEST [ -n $TA_PID ] +TEST ta_kill_brick ta +TA_PID=$(ta_get_pid_by_brick_name ta) +TEST [ -z $TA_PID ] +# Read must now succeed. +TEST cat $M0/FILE +cleanup; diff --git a/tests/basic/afr/ta-shd.t b/tests/basic/afr/ta-shd.t new file mode 100644 index 00000000000..96ecfc678e0 --- /dev/null +++ b/tests/basic/afr/ta-shd.t @@ -0,0 +1,49 @@ +#!/bin/bash +#Self-heal tests + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc +. $(dirname $0)/../../thin-arbiter.rc +cleanup; +TEST ta_create_brick_and_volfile brick0 +TEST ta_create_brick_and_volfile brick1 +TEST ta_create_ta_and_volfile ta +TEST ta_start_brick_process brick0 +TEST ta_start_brick_process brick1 +TEST ta_start_ta_process ta + +TEST ta_create_mount_volfile brick0 brick1 ta +TEST ta_start_mount_process $M0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" ta_up_status $V0 $M0 0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "trusted.afr.patchy-ta-2" ls $B0/ta + +TEST ta_create_shd_volfile brick0 brick1 ta +TEST ta_start_shd_process glustershd + +TEST touch $M0/a.txt +TEST ta_kill_brick brick0 +EXPECT_WITHIN $PROCESS_DOWN_TIMEOUT "0" ta_mount_child_up_status $M0 $V0 0 +echo "Hello" >> $M0/a.txt +EXPECT "000000010000000000000000" get_hex_xattr trusted.afr.$V0-client-0 $B0/brick1/a.txt +EXPECT "000000010000000000000000" get_hex_xattr trusted.afr.$V0-client-0 $B0/ta/trusted.afr.$V0-ta-2 + +#TODO: After the write txn changes are merged, take statedump of TA process and +#check whether AFR_TA_DOM_NOTIFY lock is held by the client here. Take the +#statedump again after line #38 to check AFR_TA_DOM_NOTIFY lock is released by +#the SHD process. + +TEST ta_start_brick_process brick0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" ta_mount_child_up_status $M0 $V0 0 +EXPECT_WITHIN $HEAL_TIMEOUT "000000000000000000000000" get_hex_xattr trusted.afr.$V0-client-0 $B0/brick1/a.txt +EXPECT_WITHIN $HEAL_TIMEOUT "000000000000000000000000" get_hex_xattr trusted.afr.$V0-client-0 $B0/ta/trusted.afr.$V0-ta-2 + +#Kill the previously up brick and try reading from other brick. Since the heal +#has happened file content should be same. +TEST ta_kill_brick brick1 +EXPECT_WITHIN $PROCESS_DOWN_TIMEOUT "0" ta_mount_child_up_status $M0 $V0 1 +#Umount and mount to remove cached data. +TEST umount $M0 +TEST ta_start_mount_process $M0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" ta_up_status $V0 $M0 0 +EXPECT "Hello" cat $M0/a.txt +cleanup; diff --git a/tests/basic/afr/ta-write-on-bad-brick.t b/tests/basic/afr/ta-write-on-bad-brick.t new file mode 100644 index 00000000000..096ca9f47cf --- /dev/null +++ b/tests/basic/afr/ta-write-on-bad-brick.t @@ -0,0 +1,51 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc +. $(dirname $0)/../../thin-arbiter.rc +cleanup; +TEST ta_create_brick_and_volfile brick0 +TEST ta_create_brick_and_volfile brick1 +TEST ta_create_ta_and_volfile ta +TEST ta_start_brick_process brick0 +TEST ta_start_brick_process brick1 +TEST ta_start_ta_process ta + +TEST ta_create_mount_volfile brick0 brick1 ta +TEST ta_start_mount_process $M0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" ta_up_status $V0 $M0 0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "trusted.afr.patchy-ta-2" ls $B0/ta + +TEST touch $M0/a.txt +TEST ls $B0/brick0/a.txt +TEST ls $B0/brick1/a.txt +TEST ! ls $B0/ta/a.txt + +TEST dd if=/dev/zero of=$M0/a.txt bs=1M count=5 + +#Good Data brick is down. TA and bad brick are UP + +TEST ta_kill_brick brick1 +EXPECT_WITHIN $PROCESS_DOWN_TIMEOUT "0" ta_mount_child_up_status $M0 $V0 1 +TEST dd if=/dev/zero of=$M0/a.txt bs=1M count=5 +TEST ta_kill_brick brick0 +EXPECT_WITHIN $PROCESS_DOWN_TIMEOUT "0" ta_mount_child_up_status $M0 $V0 0 +TEST ta_start_brick_process brick1 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" ta_mount_child_up_status $M0 $V0 1 +TEST ! dd if=/dev/zero of=$M0/a.txt bs=1M count=5 + +# Good Data brick is UP. Bad and TA are down +TEST ta_kill_brick brick1 +EXPECT_WITHIN $PROCESS_DOWN_TIMEOUT "0" ta_mount_child_up_status $M0 $V0 1 +TEST ta_start_brick_process brick0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" ta_mount_child_up_status $M0 $V0 0 +TEST ta_kill_brick ta +TEST ! dd if=/dev/zero of=$M0/a.txt bs=1M count=5 + +# Good and Bad data bricks are UP. TA is down +TEST ta_start_brick_process brick1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" ta_mount_child_up_status $M0 $V0 1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" ta_mount_child_up_status $M0 $V0 0 +TEST dd if=/dev/zero of=$M0/a.txt bs=1M count=5 + +cleanup; diff --git a/tests/basic/afr/ta.t b/tests/basic/afr/ta.t new file mode 100644 index 00000000000..05d48431c95 --- /dev/null +++ b/tests/basic/afr/ta.t @@ -0,0 +1,54 @@ +#!/bin/bash +#Self-heal tests + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc +. $(dirname $0)/../../thin-arbiter.rc +cleanup; +TEST ta_create_brick_and_volfile brick0 +TEST ta_create_brick_and_volfile brick1 +TEST ta_create_ta_and_volfile ta +TEST ta_start_brick_process brick0 +TEST ta_start_brick_process brick1 +TEST ta_start_ta_process ta + +TEST ta_create_mount_volfile brick0 brick1 ta +TEST ta_start_mount_process $M0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" ta_up_status $V0 $M0 0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "trusted.afr.patchy-ta-2" ls $B0/ta + +TEST touch $M0/a.txt +TEST ls $B0/brick0/a.txt +TEST ls $B0/brick1/a.txt +TEST ! ls $B0/ta/a.txt + +TEST ta_kill_brick brick0 +EXPECT_WITHIN $PROCESS_DOWN_TIMEOUT "0" afr_child_up_status_meta $M0 $V0-replicate-0 0 +TEST touch $M0/b.txt +EXPECT "000000000000000000000001" get_hex_xattr trusted.afr.$V0-client-0 $B0/brick1 +EXPECT "000000010000000200000000" get_hex_xattr trusted.afr.$V0-client-0 $B0/brick1/b.txt +#New entry mark lead to pending data on the file and on ta +EXPECT "000000010000000100000000" get_hex_xattr trusted.afr.$V0-client-0 $B0/ta/trusted.afr.patchy-ta-2 +TEST ! ls $B0/brick0/b.txt +TEST ls $B0/brick1/b.txt + +#Try to create an entry while good brick is down and bad brick is UP. Should not create +TEST ta_start_brick_process brick0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_meta $M0 $V0-replicate-0 0 +TEST ta_kill_brick brick1 +EXPECT_WITHIN $PROCESS_DOWN_TIMEOUT "0" afr_child_up_status_meta $M0 $V0-replicate-0 1 +TEST ! touch $M0/d.txt +EXPECT "000000010000000100000000" get_hex_xattr trusted.afr.$V0-client-0 $B0/ta/trusted.afr.patchy-ta-2 + +TEST ta_start_brick_process brick1 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_meta $M0 $V0-replicate-0 1 +TEST ta_kill_brick brick0 +EXPECT_WITHIN $PROCESS_DOWN_TIMEOUT "0" afr_child_up_status_meta $M0 $V0-replicate-0 0 + +TEST ta_kill_brick ta +# Entry create must fail if only one brick is UP, even if that is a good brick. +TEST ! touch $M0/c.txt +TEST ! ls $B0/brick0/c.txt +TEST ! ls $B0/brick1/c.txt + +cleanup; diff --git a/tests/basic/afr/tarissue.t b/tests/basic/afr/tarissue.t new file mode 100644 index 00000000000..83f7463130c --- /dev/null +++ b/tests/basic/afr/tarissue.t @@ -0,0 +1,39 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc +. $(dirname $0)/../../nfs.rc + +#G_TESTDEF_TEST_STATUS_CENTOS6=NFS_TEST + +TESTS_EXPECTED_IN_LOOP=10 +cleanup; + +#Basic checks +TEST glusterd +TEST pidof glusterd + +#Create a distributed-replicate volume +TEST $CLI volume create $V0 replica 2 $H0:$B0/${V0}{1..6}; +TEST $CLI volume set $V0 cluster.consistent-metadata on +TEST $CLI volume set $V0 cluster.post-op-delay-secs 0 +TEST $CLI volume set $V0 nfs.rdirplus off +TEST $CLI volume set $V0 nfs.disable false +TEST $CLI volume start $V0 +EXPECT_WITHIN $NFS_EXPORT_TIMEOUT "1" is_nfs_export_available; + +# Mount NFS +mount_nfs $H0:/$V0 $N0 vers=3 + +#Create files +TEST mkdir -p $N0/nfs/dir1/dir2 +for i in {1..10}; do + TEST_IN_LOOP dd if=/dev/urandom of=$N0/nfs/dir1/dir2/file$i bs=1024k count=1 +done +TEST tar cvf /tmp/dir1.tar.gz $N0/nfs/dir1 + +TEST rm -f /tmp/dir1.tar.gz + +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $N0 + +cleanup; diff --git a/tests/basic/all_squash.t b/tests/basic/all_squash.t new file mode 100644 index 00000000000..29766c50af7 --- /dev/null +++ b/tests/basic/all_squash.t @@ -0,0 +1,74 @@ +#!/bin/bash +. $(dirname $0)/../include.rc +. $(dirname $0)/../volume.rc +. $(dirname $0)/../nfs.rc + +#G_TESTDEF_TEST_STATUS_CENTOS6=NFS_TEST + +cleanup; + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 $H0:$B0/${V0}{0,1} +TEST $CLI volume set $V0 nfs.disable false +TEST $CLI volume start $V0; + +TEST glusterfs --entry-timeout=0 --attribute-timeout=0 -s $H0 --volfile-id $V0 $M0; +EXPECT_WITHIN $NFS_EXPORT_TIMEOUT "1" is_nfs_export_available; +TEST mount_nfs $H0:/$V0 $N0 nolock; + +# random uid/gid +uid=22162 +gid=5845 + +TEST $CLI volume set $V0 server.anonuid $uid; +TEST $CLI volume set $V0 server.anongid $gid; + +# Ensure server.all-squash is disabled +TEST $CLI volume set $V0 server.all-squash disable; + +# Tests for the fuse mount +mkdir $M0/other; +chown $uid:$gid $M0/other; + +TEST $CLI volume set $V0 server.all-squash enable; + +touch $M0/file 2>/dev/null; +TEST [ $? -ne 0 ] +mkdir $M0/dir 2>/dev/null; +TEST [ $? -ne 0 ] + +TEST touch $M0/other/file 2>/dev/null; +TEST [ "$(stat -c %u:%g $M0/other/file)" = "$uid:$gid" ]; +TEST mkdir $M0/other/dir 2>/dev/null; +TEST [ "$(stat -c %u:%g $M0/other/dir)" = "$uid:$gid" ]; + +TEST $CLI volume set $V0 server.all-squash disable; +TEST rm -rf $M0/other; + +sleep 1; + +# tests for nfs mount +mkdir $N0/other; +chown $uid:$gid $N0/other; + +TEST $CLI volume set $V0 server.all-squash enable; + +touch $N0/file 2>/dev/null; +TEST [ $? -ne 0 ] +mkdir $N0/dir 2>/dev/null; +TEST [ $? -ne 0 ] + +TEST touch $N0/other/file 2>/dev/null; +TEST [ "$(stat -c %u:%g $N0/other/file)" = "$uid:$gid" ]; +TEST mkdir $N0/other/dir 2>/dev/null; +TEST [ "$(stat -c %u:%g $N0/other/dir)" = "$uid:$gid" ]; + +TEST $CLI volume set $V0 server.all-squash disable; +TEST rm -rf $N0/other; +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $N0 + +TEST $CLI volume stop $V0; +TEST $CLI volume delete $V0; + +cleanup; diff --git a/tests/basic/bd.t b/tests/basic/bd.t deleted file mode 100755 index 3201b7460a0..00000000000 --- a/tests/basic/bd.t +++ /dev/null @@ -1,117 +0,0 @@ -#!/bin/bash - -. $(dirname $0)/../include.rc - -cleanup; - - -function execute() -{ - cmd=$1 - shift - ${cmd} $@ >/dev/null 2>&1 -} - -function bd_cleanup() -{ - execute vgremove -f ${VG} - execute pvremove ${ld} - execute losetup -d ${ld} - execute rm ${BD_DISK} - execute $CLI volume delete ${V0} - cleanup -} - -function check() -{ - if [ $? -ne 0 ]; then - echo prerequsite $@ failed - bd_cleanup - exit - fi -} - -VG=__bd_vg -SIZE=256 #in MB - -## Configure environment needed for BD backend volumes -## Create a file with configured size and -## set it as a temporary loop device to create -## physical volume & VG. These are basic things needed -## for testing BD xlator if anyone of these steps fail, -## test script exits -function configure() -{ - GLDIR=`$CLI system:: getwd` - BD_DISK=${GLDIR}/bd_disk - - execute truncate -s${SIZE}M ${BD_DISK} - check ${BD_DISK} creation - - execute losetup -f - check losetup - ld=`losetup -f` - - execute losetup ${ld} ${BD_DISK} - check losetup ${BD_DISK} - execute pvcreate -f ${ld} - check pvcreate ${ld} - execute vgcreate ${VG} ${ld} - check vgcreate ${VG} -} - -function volinfo_field() -{ - local vol=$1; - local field=$2; - - $CLI volume info $vol | grep "^$field: " | sed 's/.*: //'; -} - -TEST glusterd -TEST pidof glusterd -configure - -TEST $CLI volume create $V0 device vg ${H0}:/${VG} -EXPECT "$V0" volinfo_field $V0 'Volume Name'; -EXPECT 'Created' volinfo_field $V0 'Status'; - -## Start volume and verify -TEST $CLI volume start $V0; -EXPECT 'Started' volinfo_field $V0 'Status' - -TEST glusterfs --volfile-server=$H0 --volfile-id=$V0 $M0 - -## Create file (LV) -TEST touch $M0/$VG/lv1 -TEST stat /dev/$VG/lv1 - -TEST rm $M0/$VG/lv1; -TEST ! stat $M0/$VG/lv1; - -TEST touch $M0/$VG/lv1 -TEST truncate -s64M $M0/$VG/lv1 - -TEST ln $M0/$VG/lv1 $M0/$VG/lv2 -TEST stat /dev/$VG/lv2 - -rm $M0/$VG/lv1 -rm $M0/$VG/lv2 - -TEST $CLI bd create $V0:/$VG/lv1 4MB -TEST stat /dev/$VG/lv1 - -TEST $CLI bd clone $V0:/$VG/lv1 lv2 -TEST stat /dev/$VG/lv2 -TEST $CLI bd delete $V0:/$VG/lv2 - -TEST $CLI bd snapshot $V0:/$VG/lv1 lv2 1 -TEST stat /dev/$VG/lv2 -rm $M0/$VG/lv2 -rm $M0/$VG/lv1 - -TEST umount $M0 -TEST $CLI volume stop ${V0} -TEST $CLI volume delete ${V0} - -bd_cleanup diff --git a/tests/basic/cdc.t b/tests/basic/cdc.t new file mode 100755 index 00000000000..8653a77207a --- /dev/null +++ b/tests/basic/cdc.t @@ -0,0 +1,148 @@ +#!/bin/bash + +. $(dirname $0)/../include.rc +. $(dirname $0)/../volume.rc + +cleanup; + +function file_mime_type () { + mime_type=$(file --mime $1 2>/dev/null | sed '/^[^:]*: /s///') + echo $mime_type +} + +TEST glusterd +TEST pidof glusterd + +## Create a volume with one brick +TEST $CLI volume create $V0 $H0:$B0/${V0}1; +EXPECT "$V0" volinfo_field $V0 'Volume Name'; +EXPECT 'Created' volinfo_field $V0 'Status'; +EXPECT '1' brick_count $V0 + +## Turn off performance translators +## This is required for testing readv calls +TEST $CLI volume set $V0 performance.io-cache off +EXPECT 'off' volinfo_field $V0 'performance.io-cache' +TEST $CLI volume set $V0 performance.quick-read off +EXPECT 'off' volinfo_field $V0 'performance.quick-read' + +TEST $CLI volume set $V0 performance.strict-write-ordering on +EXPECT 'on' volinfo_field $V0 'performance.strict-write-ordering' + +## Turn on cdc xlator by setting network.compression to on +TEST $CLI volume set $V0 network.compression on +EXPECT 'on' volinfo_field $V0 'network.compression' + +## Make sure that user cannot change network.compression.mode +## This would break the cdc xlator if allowed! +TEST ! $CLI volume set $V0 network.compression.mode client + +## Turn on network.compression.debug option +## This will dump compressed data onto disk as gzip file +## This is used to check if compression actually happened +TEST $CLI volume set $V0 network.compression.debug on +EXPECT 'on' volinfo_field $V0 'network.compression.debug' + +## Start the volume +TEST $CLI volume start $V0; +EXPECT 'Started' volinfo_field $V0 'Status'; + +sleep 2 +## Mount FUSE with caching disabled +TEST $GFS -s $H0 --volfile-id $V0 $M0; + +#################### +## Testing writev ## +#################### + +## Create a 1K file locally and find the md5sum +TEST dd if=/dev/zero of=/tmp/cdc-orig count=1 bs=1k 2>/dev/null +checksum[original-file]=`md5sum /tmp/cdc-orig | cut -d' ' -f1` + +## Copy the file to mountpoint and find its md5sum on brick +TEST dd if=/tmp/cdc-orig of=$M0/cdc-server count=1 bs=1k 2>/dev/null +checksum[brick-file]=`md5sum $B0/${V0}1/cdc-server | cut -d' ' -f1` + +## Uncompress the gzip dump file and find its md5sum +# mime outputs for gzip are different for file version > 5.14 +TEST touch /tmp/gzipfile +TEST gzip /tmp/gzipfile +GZIP_MIME_TYPE=$(file_mime_type /tmp/gzipfile.gz) + +TEST rm -f /tmp/gzipfile.gz + +EXPECT "$GZIP_MIME_TYPE" echo $(file_mime_type /tmp/cdcdump.gz) + +TEST gunzip -f /tmp/cdcdump.gz +checksum[dump-file-writev]=`md5sum /tmp/cdcdump | cut -d' ' -f1` + +## Check if all 3 checksums are same +TEST test ${checksum[original-file]} = ${checksum[brick-file]} +TEST test ${checksum[brick-file]} = ${checksum[dump-file-writev]} + +## Cleanup files +TEST rm -f /tmp/cdcdump.gz + +################### +## Testing readv ## +################### + +## Copy file from mount point to client and find checksum +TEST dd if=$M0/cdc-server of=/tmp/cdc-client count=1 bs=1k 2>/dev/null +checksum[client-file]=`md5sum /tmp/cdc-client | cut -d' ' -f1` + +## Uncompress the gzip dump file and find its md5sum +# mime outputs for gzip are different for file version > 5.14 +EXPECT "$GZIP_MIME_TYPE" echo $(file_mime_type /tmp/cdcdump.gz) + +TEST gunzip -f /tmp/cdcdump.gz +checksum[dump-file-readv]=`md5sum /tmp/cdcdump | cut -d' ' -f1` + +## Check if all 3 checksums are same +TEST test ${checksum[brick-file]} = ${checksum[client-file]} +TEST test ${checksum[client-file]} = ${checksum[dump-file-readv]} + +## Cleanup files and unmount +TEST rm -f /tmp/cdc* $M0/cdc* +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 + +## Stop the volume +TEST $CLI volume stop $V0; +EXPECT 'Stopped' volinfo_field $V0 'Status'; + +## Turn on network.compression.min-size and set it to 100 bytes +## Compression should not take place if file size +## is less than 100 bytes +TEST $CLI volume set $V0 network.compression.min-size 100 +EXPECT '100' volinfo_field $V0 'network.compression.min-size' + +## Start the volume +TEST $CLI volume start $V0; +EXPECT 'Started' volinfo_field $V0 'Status'; + +## Mount FUSE with caching disabled +TEST $GFS -s $H0 --volfile-id $V0 $M0; + +## Create a file of size 99 bytes on mountpoint +## This is should not be compressed +TEST dd if=/dev/zero of=$M0/cdc-small count=1 bs=99 2>/dev/null +TEST ! test -e /tmp/cdcdump.gz + +## Cleanup files and unmount +TEST rm -f /tmp/cdc* $M0/cdc* +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 + +## Stop the volume +TEST $CLI volume stop $V0; +EXPECT 'Stopped' volinfo_field $V0 'Status'; + +## Reset the network.compression options +TEST $CLI volume reset $V0 network.compression.debug +TEST $CLI volume reset $V0 network.compression.min-size +TEST $CLI volume reset $V0 network.compression + +## Delete the volume +TEST $CLI volume delete $V0; +TEST ! $CLI volume info $V0; + +cleanup; diff --git a/tests/basic/changelog/changelog-api.t b/tests/basic/changelog/changelog-api.t new file mode 100644 index 00000000000..516c2f2f60d --- /dev/null +++ b/tests/basic/changelog/changelog-api.t @@ -0,0 +1,37 @@ +#!/bin/bash +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc +. $(dirname $0)/../../env.rc + +cleanup; + +CHANGELOG_BIN_PATH=$(dirname $0)/../../utils/changelog +build_tester $CHANGELOG_BIN_PATH/test-changelog-api.c -lgfchangelog + +CHANGELOG_PATH_0="$B0/${V0}0/.glusterfs/changelogs" +ROLLOVER_TIME=2 + +TEST glusterd +TEST pidof glusterd + +TEST $CLI volume create $V0 $H0:$B0/${V0}0 +TEST $CLI volume set $V0 changelog.changelog on +TEST $CLI volume set $V0 changelog.rollover-time $ROLLOVER_TIME +TEST $CLI volume start $V0 + +TEST $GFS --volfile-id=$V0 --volfile-server=$H0 $M0; + +sleep 3; + +#Listen to changelog journal notifcations +$CHANGELOG_BIN_PATH/test-changelog-api & +for i in {1..12};do echo "data" > $M0/file$i 2>/dev/null; sleep 1;done & + +#Wait for changelogs to be in .processed directory +sleep 12 + +EXPECT "Y" processed_changelogs "/tmp/scratch_v1/.processed" +TEST rm $CHANGELOG_BIN_PATH/test-changelog-api +rm -rf /tmp/scratch_v1 + +cleanup; diff --git a/tests/basic/changelog/changelog-history.t b/tests/basic/changelog/changelog-history.t new file mode 100644 index 00000000000..ea952619652 --- /dev/null +++ b/tests/basic/changelog/changelog-history.t @@ -0,0 +1,91 @@ +#!/bin/bash +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc +. $(dirname $0)/../../env.rc + +cleanup; + +SCRIPT_TIMEOUT=300 +HISTORY_BIN_PATH=$(dirname $0)/../../utils/changelog +build_tester $HISTORY_BIN_PATH/get-history.c -lgfchangelog + +time_before_enable1=$(date '+%s') +CHANGELOG_PATH_0="$B0/${V0}0/.glusterfs/changelogs" +ROLLOVER_TIME=2 + +TEST glusterd +TEST pidof glusterd + +sleep 3 +time_before_enable2=$(date '+%s') + +sleep 3 +TEST $CLI volume create $V0 $H0:$B0/${V0}0 +TEST $CLI volume set $V0 changelog.changelog on +TEST $CLI volume set $V0 changelog.rollover-time $ROLLOVER_TIME +TEST $CLI volume start $V0 + +sleep 3 +time_after_enable1=$(date '+%s') + +TEST $GFS --volfile-id=$V0 --volfile-server=$H0 $M0; +touch $M0/file{1..10} + +sleep 3 +time_after_enable2=$(date '+%s') + +let time_future=time_after_enable2+600 + +#Fails as start falls before changelog enable +EXPECT "-3" $HISTORY_BIN_PATH/get-history $time_before_enable1 $time_before_enable2 + +#Fails as start falls before changelog enable +EXPECT "-3" $HISTORY_BIN_PATH/get-history $time_before_enable2 $time_after_enable1 + +#Passes as start and end falls in same htime file +EXPECT "0" $HISTORY_BIN_PATH/get-history $time_after_enable1 $time_after_enable2 + +#Passes, gives the changelogs till continuous changelogs are available +# but returns 1 +EXPECT "1" $HISTORY_BIN_PATH/get-history $time_after_enable2 $time_future + +#Disable and enable changelog +TEST $CLI volume set $V0 changelog.changelog off +sleep 6 +time_between_htime=$(date '+%s') +sleep 6 +TEST $CLI volume set $V0 changelog.changelog on + +sleep 6 +touch $M0/test{1..10} +time_in_sec_htime1=$(date '+%s') + +sleep 6 +touch $M0/test1{1..10} +time_in_sec_htime2=$(date '+%s') + +sleep 3 +TEST $CLI volume set $V0 changelog.changelog off +sleep 3 +time_after_disable=$(date '+%s') + +TEST $CLI volume set $V0 changelog.changelog on +sleep 5 + +#Passes, gives the changelogs till continuous changelogs are available +# but returns 1 +EXPECT_WITHIN 10 "1" $HISTORY_BIN_PATH/get-history $time_after_enable1 $time_in_sec_htime2 + +#Fails as start falls between htime files +EXPECT_WITHIN 10 "-3" $HISTORY_BIN_PATH/get-history $time_between_htime $time_in_sec_htime1 + +#Passes as start and end falls in same htime file +EXPECT_WITHIN 10 "0" $HISTORY_BIN_PATH/get-history $time_in_sec_htime1 $time_in_sec_htime2 + +#Passes, gives the changelogs till continuous changelogs are available +EXPECT_WITHIN 10 "0" $HISTORY_BIN_PATH/get-history $time_in_sec_htime2 $time_after_disable + +TEST rm $HISTORY_BIN_PATH/get-history +rm -rf /tmp/scratch_v1/* + +cleanup; diff --git a/tests/basic/changelog/changelog-rename.t b/tests/basic/changelog/changelog-rename.t new file mode 100644 index 00000000000..9a0ef527b5b --- /dev/null +++ b/tests/basic/changelog/changelog-rename.t @@ -0,0 +1,44 @@ +#!/bin/bash +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc +cleanup; + +CHANGELOG_PATH_0="$B0/${V0}0/.glusterfs/changelogs" +ROLLOVER_TIME=30 + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 $H0:$B0/${V0}0 +TEST $CLI volume set $V0 changelog.changelog on +TEST $CLI volume set $V0 changelog.rollover-time $ROLLOVER_TIME +TEST $CLI volume start $V0 + +TEST $GFS --volfile-id=$V0 --volfile-server=$H0 $M0; +touch $M0/file1 +mv $M0/file1 $M0/rn_file1 +mkdir $M0/dir1 +mv $M0/dir1 $M0/rn_dir1 + +EXPECT "2" check_changelog_op ${CHANGELOG_PATH_0} "RENAME" + +cleanup; + +#####Test on multiple subvolume##### +#==========================================# + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 $H0:$B0/${V0}{0,1} +TEST $CLI volume set $V0 changelog.changelog on +TEST $CLI volume set $V0 changelog.rollover-time $ROLLOVER_TIME +TEST $CLI volume start $V0 + +TEST $GFS --volfile-id=$V0 --volfile-server=$H0 $M0; +touch $M0/gluster_file +mv $M0/gluster_file $M0/rn_gluster_file +mkdir $M0/dir1 +mv $M0/dir1 $M0/rn_dir1 + +EXPECT "2" check_changelog_op ${CHANGELOG_PATH_0} "RENAME" + +cleanup; diff --git a/tests/basic/changelog/history-api.t b/tests/basic/changelog/history-api.t new file mode 100644 index 00000000000..9e63118cef9 --- /dev/null +++ b/tests/basic/changelog/history-api.t @@ -0,0 +1,42 @@ +#!/bin/bash +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc +. $(dirname $0)/../../env.rc + +cleanup; + +HISTORY_BIN_PATH=$(dirname $0)/../../utils/changelog +build_tester $HISTORY_BIN_PATH/test-history-api.c -lgfchangelog + +CHANGELOG_PATH_0="$B0/${V0}0/.glusterfs/changelogs" +ROLLOVER_TIME=2 + +TEST glusterd +TEST pidof glusterd + +TEST $CLI volume create $V0 $H0:$B0/${V0}0 +TEST $CLI volume set $V0 changelog.changelog on +TEST $CLI volume set $V0 changelog.rollover-time $ROLLOVER_TIME +TEST $CLI volume start $V0 + +sleep 3 +start=$(date '+%s') + +TEST $GFS --volfile-id=$V0 --volfile-server=$H0 $M0; +touch $M0/file{1..10} + +for i in {1..12};do echo "data" > $M0/file$i; sleep 1;done +end=$(date '+%s') +sleep 2 + +#Passes as start and end falls in same htime file +EXPECT "0" $HISTORY_BIN_PATH/test-history-api $start $end + +#Wait for changelogs to be in .processed directory +sleep 2 + +EXPECT "Y" processed_changelogs "/tmp/scratch_v1/.history/.processed" +TEST rm $HISTORY_BIN_PATH/test-history-api +rm -rf /tmp/scratch_v1 + +cleanup; diff --git a/tests/basic/cloudsync-sanity.t b/tests/basic/cloudsync-sanity.t new file mode 100644 index 00000000000..834ba96430c --- /dev/null +++ b/tests/basic/cloudsync-sanity.t @@ -0,0 +1,29 @@ +#!/bin/bash + +. $(dirname $0)/../include.rc +. $(dirname $0)/../volume.rc + +cleanup; + +TEST glusterd +TEST pidof glusterd + +TEST $CLI volume create $V0 replica 3 $H0:$B0/${V0}{1,2,3,4,5,6,7,8,9}; +TEST $CLI volume set $V0 features.cloudsync enable; +TEST $CLI volume start $V0; + +## Mount FUSE +TEST $GFS -s $H0 --volfile-id $V0 $M1; + +# This test covers lookup, mkdir, mknod, symlink, link, rename, +# create operations +TEST $(dirname $0)/rpc-coverage.sh $M1 + + +TEST cp $(dirname ${0})/gfapi/glfsxmp-coverage.c glfsxmp.c +TEST build_tester ./glfsxmp.c -lgfapi +./glfsxmp $V0 $H0 +cleanup_tester ./glfsxmp +rm ./glfsxmp.c + +cleanup; diff --git a/tests/basic/ctime/ctime-ec-heal.t b/tests/basic/ctime/ctime-ec-heal.t new file mode 100644 index 00000000000..142237c5014 --- /dev/null +++ b/tests/basic/ctime/ctime-ec-heal.t @@ -0,0 +1,70 @@ +#!/bin/bash +# +# This will test self healing of ctime xattr 'trusted.glusterfs.mdata' +# +### + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc +. $(dirname $0)/../../afr.rc + +cleanup + +#cleate and start volume +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 disperse 3 redundancy 1 $H0:$B0/${V0}{1..3} +TEST $CLI volume start $V0 + +#Mount the volume +TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0; + +# Create files +mkdir $M0/dir1 +echo "Initial content" > $M0/file1 + +EXPECT_WITHIN $PROCESS_UP_TIMEOUT '3' get_mdata_count $B0/${V0}{1..3}/dir1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT '1' get_mdata_uniq_count $B0/${V0}{1..3}/dir1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT '3' get_mdata_count $B0/${V0}{1..3}/file1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT '1' get_mdata_uniq_count $B0/${V0}{1..3}/file1 + +# Kill brick +TEST kill_brick $V0 $H0 $B0/${V0}3 + +echo "B3 is down" >> $M0/file1 +echo "Change dir1 time attributes" > $M0/dir1/dir1_file1 +echo "Entry heal file" > $M0/entry_heal_file1 +mkdir $M0/entry_heal_dir1 + +# Check xattr +EXPECT_WITHIN $PROCESS_UP_TIMEOUT '3' get_mdata_count $B0/${V0}{1..3}/dir1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT '2' get_mdata_uniq_count $B0/${V0}{1..3}/dir1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT '3' get_mdata_count $B0/${V0}{1..3}/file1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT '2' get_mdata_uniq_count $B0/${V0}{1..3}/file1 + +EXPECT_WITHIN $PROCESS_UP_TIMEOUT '2' get_mdata_count $B0/${V0}{1..3}/dir1/dir1_file1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT '1' get_mdata_uniq_count $B0/${V0}{1..3}/dir1/dir1_file1 + +EXPECT_WITHIN $PROCESS_UP_TIMEOUT '2' get_mdata_count $B0/${V0}{1..3}/entry_heal_file1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT '1' get_mdata_uniq_count $B0/${V0}{1..3}/entry_heal_file1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT '2' get_mdata_count $B0/${V0}{1..3}/entry_heal_dir1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT '1' get_mdata_uniq_count $B0/${V0}{1..3}/entry_heal_dir1 + +TEST $CLI volume start $V0 force +$CLI volume heal $V0 + +# Check xattr +EXPECT_WITHIN $PROCESS_UP_TIMEOUT '3' get_mdata_count $B0/${V0}{1..3}/dir1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT '1' get_mdata_uniq_count $B0/${V0}{1..3}/dir1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT '3' get_mdata_count $B0/${V0}{1..3}/file1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT '1' get_mdata_uniq_count $B0/${V0}{1..3}/file1 + +EXPECT_WITHIN $PROCESS_UP_TIMEOUT '3' get_mdata_count $B0/${V0}{1..3}/dir1/dir1_file1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT '1' get_mdata_uniq_count $B0/${V0}{1..3}/dir1/dir1_file1 + +EXPECT_WITHIN $PROCESS_UP_TIMEOUT '3' get_mdata_count $B0/${V0}{1..3}/entry_heal_file1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT '1' get_mdata_uniq_count $B0/${V0}{1..3}/entry_heal_file1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT '3' get_mdata_count $B0/${V0}{1..3}/entry_heal_dir1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT '1' get_mdata_uniq_count $B0/${V0}{1..3}/entry_heal_dir1 + +cleanup; diff --git a/tests/basic/ctime/ctime-ec-rebalance.t b/tests/basic/ctime/ctime-ec-rebalance.t new file mode 100644 index 00000000000..2b73bcdd103 --- /dev/null +++ b/tests/basic/ctime/ctime-ec-rebalance.t @@ -0,0 +1,43 @@ +#!/bin/bash +# +# This will test healing of ctime xattr 'trusted.glusterfs.mdata' after add-brick and rebalance +# +### + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc +. $(dirname $0)/../../fallocate.rc + +cleanup + +#cleate and start volume +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 disperse 3 redundancy 1 $H0:$B0/${V0}{0..5} +TEST $CLI volume start $V0 + +#Mount the volume +TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0; +EXPECT_WITHIN $CHILD_UP_TIMEOUT "3" ec_child_up_count $V0 0 + +# Create files +mkdir $M0/dir1 +echo "test data" > $M0/dir1/file1 + +# Add brick +TEST $CLI volume add-brick $V0 $H0:$B0/${V0}{6..8} + +#Trigger rebalance +TEST $CLI volume rebalance $V0 start force +EXPECT_WITHIN $REBALANCE_TIMEOUT "completed" rebalance_status_field $V0 + +#Verify ctime xattr heal on directory +EXPECT_WITHIN $PROCESS_UP_TIMEOUT 'trusted.glusterfs.mdata' check_for_xattr 'trusted.glusterfs.mdata' "$B0/${V0}6/dir1" +EXPECT_WITHIN $PROCESS_UP_TIMEOUT 'trusted.glusterfs.mdata' check_for_xattr 'trusted.glusterfs.mdata' "$B0/${V0}7/dir1" +EXPECT_WITHIN $PROCESS_UP_TIMEOUT 'trusted.glusterfs.mdata' check_for_xattr 'trusted.glusterfs.mdata' "$B0/${V0}8/dir1" + +b6_mdata=$(get_mdata "$B0/${V0}6/dir1") +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "${b6_mdata}" get_mdata $B0/${V0}7/dir1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "${b6_mdata}" get_mdata $B0/${V0}8/dir1 + +cleanup; diff --git a/tests/basic/ctime/ctime-glfs-init.c b/tests/basic/ctime/ctime-glfs-init.c new file mode 100644 index 00000000000..e4f197b8f30 --- /dev/null +++ b/tests/basic/ctime/ctime-glfs-init.c @@ -0,0 +1,68 @@ +#include <fcntl.h> +#include <unistd.h> +#include <time.h> +#include <limits.h> +#include <string.h> +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <glusterfs/api/glfs.h> +#include <glusterfs/api/glfs-handles.h> + +#define LOG_ERR(msg) \ + do { \ + fprintf(stderr, "%s : Error (%s)\n", msg, strerror(errno)); \ + } while (0) + +int +main(int argc, char *argv[]) +{ + int ret = 0; + char *hostname = NULL; + char *volname = NULL; + char *logfile = NULL; + glfs_t *fs = NULL; + + if (argc != 4) { + fprintf(stderr, "Invalid argument\n"); + exit(1); + } + + hostname = argv[1]; + volname = argv[2]; + logfile = argv[3]; + + fs = glfs_new(volname); + if (!fs) { + LOG_ERR("glfs_new failed"); + return -1; + } + + ret = glfs_set_volfile_server(fs, "tcp", hostname, 24007); + if (ret < 0) { + LOG_ERR("glfs_set_volfile_server failed"); + goto err; + } + + ret = glfs_set_logging(fs, logfile, 7); + if (ret < 0) { + LOG_ERR("glfs_set_logging failed"); + goto err; + } + + ret = glfs_init(fs); + if (ret < 0) { + LOG_ERR("glfs_init failed"); + goto err; + } + + glfs_fini(fs); + fs = NULL; + return 0; +err: + glfs_fini(fs); + fs = NULL; + + return -1; +} diff --git a/tests/basic/ctime/ctime-glfs-init.t b/tests/basic/ctime/ctime-glfs-init.t new file mode 100644 index 00000000000..56d7d6caee0 --- /dev/null +++ b/tests/basic/ctime/ctime-glfs-init.t @@ -0,0 +1,23 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +cleanup; + +TEST glusterd + +TEST $CLI volume create $V0 replica 3 ${H0}:$B0/brick{1,2,3}; +TEST $CLI volume set $V0 performance.stat-prefetch off +TEST $CLI volume start $V0; + +logdir=`gluster --print-logdir` + +TEST build_tester $(dirname $0)/ctime-glfs-init.c -lgfapi -lpthread + +TEST ./$(dirname $0)/ctime-glfs-init ${H0} $V0 $logdir/ctime-glfs-init.log + +cleanup_tester $(dirname $0)/ctime-glfs-init + +cleanup; + diff --git a/tests/basic/ctime/ctime-heal-symlinks.t b/tests/basic/ctime/ctime-heal-symlinks.t new file mode 100644 index 00000000000..547b1807e94 --- /dev/null +++ b/tests/basic/ctime/ctime-heal-symlinks.t @@ -0,0 +1,65 @@ +#!/bin/bash +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc +. $(dirname $0)/../../afr.rc +cleanup; + +############################################################################### +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 replica 3 $H0:$B0/${V0}{0,1,2} +TEST $CLI volume set $V0 performance.stat-prefetch off +TEST $CLI volume start $V0 + +TEST glusterfs --volfile-id=$V0 --volfile-server=$H0 --entry-timeout=0 $M0; + +cd $M0 +TEST "echo hello_world > FILE" +TEST ln -s FILE SOFTLINK + +# Remove symlink only (not the .glusterfs entry) and trigger named heal. +TEST rm -f $B0/${V0}2/SOFTLINK +TEST stat SOFTLINK + +# To heal and clear new-entry mark on source bricks. +TEST $CLI volume heal $V0 +EXPECT_WITHIN $HEAL_TIMEOUT "^0$" get_pending_heal_count $V0 + +EXPECT 2 stat -c %h $B0/${V0}2/SOFTLINK +EXPECT "hello_world" cat $B0/${V0}2/SOFTLINK + +cd - +cleanup +############################################################################### + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 disperse 3 redundancy 1 $H0:$B0/${V0}{0,1,2} +TEST $CLI volume set $V0 performance.stat-prefetch off +TEST $CLI volume start $V0 + +TEST glusterfs --volfile-id=$V0 --volfile-server=$H0 --entry-timeout=0 $M0; + +cd $M0 +TEST "echo hello_world > FILE" +TEST ln -s FILE SOFTLINK + +# Remove symlink only (not the .glusterfs entry) and trigger named heal. +TEST rm -f $B0/${V0}2/SOFTLINK +TEST stat SOFTLINK + +# To heal and clear new-entry mark on source bricks. +TEST $CLI volume heal $V0 +EXPECT_WITHIN $HEAL_TIMEOUT "^0$" get_pending_heal_count $V0 + +EXPECT 2 stat -c %h $B0/${V0}2/SOFTLINK +TEST kill_brick $V0 $H0 $B0/${V0}0 +cd - +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 +TEST glusterfs --volfile-id=$V0 --volfile-server=$H0 --entry-timeout=0 $M0; +cd $M0 +EXPECT "hello_world" cat SOFTLINK + +cd - +cleanup +############################################################################### diff --git a/tests/basic/ctime/ctime-mdata-legacy-files.t b/tests/basic/ctime/ctime-mdata-legacy-files.t new file mode 100644 index 00000000000..2e782d5c99d --- /dev/null +++ b/tests/basic/ctime/ctime-mdata-legacy-files.t @@ -0,0 +1,83 @@ +#!/bin/bash +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc +. $(dirname $0)/../../afr.rc +cleanup; + +############################################################################### +#Replica volume + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 replica 3 $H0:$B0/${V0}{0,1,2} +TEST $CLI volume set $V0 performance.stat-prefetch off +TEST $CLI volume start $V0 + +TEST glusterfs --volfile-id=$V0 --volfile-server=$H0 --entry-timeout=0 $M0; + +#Disable ctime and create file, file doesn't contain "trusted.glusterfs.mdata" xattr +TEST $CLI volume set $V0 ctime off + +TEST "mkdir $M0/DIR" +TEST "echo hello_world > $M0/DIR/FILE" + +#Verify absence of xattr +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "" check_for_xattr 'trusted.glusterfs.mdata' "$B0/${V0}0/DIR" +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "" check_for_xattr 'trusted.glusterfs.mdata' "$B0/${V0}0/DIR/FILE" +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "" check_for_xattr 'trusted.glusterfs.mdata' "$B0/${V0}1/DIR" +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "" check_for_xattr 'trusted.glusterfs.mdata' "$B0/${V0}1/DIR/FILE" +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "" check_for_xattr 'trusted.glusterfs.mdata' "$B0/${V0}2/DIR" +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "" check_for_xattr 'trusted.glusterfs.mdata' "$B0/${V0}2/DIR/FILE" + +#Enable ctime +TEST $CLI volume set $V0 ctime on +sleep 3 +TEST stat $M0/DIR/FILE + +#Verify presence "trusted.glusterfs.mdata" xattr on backend +#The lookup above should have created xattr +EXPECT_WITHIN $PROCESS_UP_TIMEOUT 'trusted.glusterfs.mdata' check_for_xattr 'trusted.glusterfs.mdata' "$B0/${V0}0/DIR" +EXPECT_WITHIN $PROCESS_UP_TIMEOUT 'trusted.glusterfs.mdata' check_for_xattr 'trusted.glusterfs.mdata' "$B0/${V0}0/DIR/FILE" +EXPECT_WITHIN $PROCESS_UP_TIMEOUT 'trusted.glusterfs.mdata' check_for_xattr 'trusted.glusterfs.mdata' "$B0/${V0}1/DIR" +EXPECT_WITHIN $PROCESS_UP_TIMEOUT 'trusted.glusterfs.mdata' check_for_xattr 'trusted.glusterfs.mdata' "$B0/${V0}1/DIR/FILE" +EXPECT_WITHIN $PROCESS_UP_TIMEOUT 'trusted.glusterfs.mdata' check_for_xattr 'trusted.glusterfs.mdata' "$B0/${V0}2/DIR" +EXPECT_WITHIN $PROCESS_UP_TIMEOUT 'trusted.glusterfs.mdata' check_for_xattr 'trusted.glusterfs.mdata' "$B0/${V0}2/DIR/FILE" + +############################################################################### +#Disperse Volume + +TEST $CLI volume create $V1 disperse 3 redundancy 1 $H0:$B0/${V1}{0,1,2} +TEST $CLI volume set $V1 performance.stat-prefetch off +TEST $CLI volume start $V1 + +TEST glusterfs --volfile-id=$V1 --volfile-server=$H0 --entry-timeout=0 $M1; + +#Disable ctime and create file, file doesn't contain "trusted.glusterfs.mdata" xattr +TEST $CLI volume set $V1 ctime off +TEST "mkdir $M1/DIR" +TEST "echo hello_world > $M1/DIR/FILE" + +#Verify absence of xattr +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "" check_for_xattr 'trusted.glusterfs.mdata' "$B0/${V1}0/DIR" +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "" check_for_xattr 'trusted.glusterfs.mdata' "$B0/${V1}0/DIR/FILE" +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "" check_for_xattr 'trusted.glusterfs.mdata' "$B0/${V1}1/DIR" +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "" check_for_xattr 'trusted.glusterfs.mdata' "$B0/${V1}1/DIR/FILE" +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "" check_for_xattr 'trusted.glusterfs.mdata' "$B0/${V1}2/DIR" +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "" check_for_xattr 'trusted.glusterfs.mdata' "$B0/${V1}2/DIR/FILE" + +#Enable ctime +TEST $CLI volume set $V1 ctime on +sleep 3 +TEST stat $M1/DIR/FILE + +#Verify presence "trusted.glusterfs.mdata" xattr on backend +#The lookup above should have created xattr +EXPECT_WITHIN $PROCESS_UP_TIMEOUT 'trusted.glusterfs.mdata' check_for_xattr 'trusted.glusterfs.mdata' "$B0/${V1}0/DIR" +EXPECT_WITHIN $PROCESS_UP_TIMEOUT 'trusted.glusterfs.mdata' check_for_xattr 'trusted.glusterfs.mdata' "$B0/${V1}0/DIR/FILE" +EXPECT_WITHIN $PROCESS_UP_TIMEOUT 'trusted.glusterfs.mdata' check_for_xattr 'trusted.glusterfs.mdata' "$B0/${V1}1/DIR" +EXPECT_WITHIN $PROCESS_UP_TIMEOUT 'trusted.glusterfs.mdata' check_for_xattr 'trusted.glusterfs.mdata' "$B0/${V1}1/DIR/FILE" +EXPECT_WITHIN $PROCESS_UP_TIMEOUT 'trusted.glusterfs.mdata' check_for_xattr 'trusted.glusterfs.mdata' "$B0/${V1}2/DIR" +EXPECT_WITHIN $PROCESS_UP_TIMEOUT 'trusted.glusterfs.mdata' check_for_xattr 'trusted.glusterfs.mdata' "$B0/${V1}2/DIR/FILE" + +cleanup; +############################################################################### diff --git a/tests/basic/ctime/ctime-noatime.t b/tests/basic/ctime/ctime-noatime.t new file mode 100644 index 00000000000..609ccbd72c1 --- /dev/null +++ b/tests/basic/ctime/ctime-noatime.t @@ -0,0 +1,49 @@ +#!/bin/bash +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc +. $(dirname $0)/../../afr.rc +cleanup; + +function atime_compare { + local atime=$1 + local file_name=$2 + local atime1=$(stat -c "%X" $file_name) + + if [ $atime == $atime1 ] + then + echo "0" + else + echo "1" + fi +} + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 replica 3 $H0:$B0/${V0}{0,1,2} +TEST $CLI volume set $V0 performance.stat-prefetch off +TEST $CLI volume set $V0 performance.read-ahead off +TEST $CLI volume set $V0 performance.quick-read off +TEST $CLI volume set $V0 performance.read-after-open off +TEST $CLI volume set $V0 performance.open-behind off +TEST $CLI volume set $V0 performance.write-behind off +TEST $CLI volume set $V0 performance.io-cache off + +TEST $CLI volume start $V0 + +TEST glusterfs --volfile-id=$V0 --volfile-server=$H0 --entry-timeout=0 $M0; + +cd $M0 +TEST "echo hello_world > FILE" +atime1=$(stat -c "%X" FILE) + +TEST "cat FILE > /dev/null" +EXPECT "0" atime_compare $atime1 FILE + +sleep 1 + +TEST $CLI volume set $V0 noatime off +TEST "cat FILE > /dev/null" +EXPECT "1" atime_compare $atime1 FILE + +cd - +cleanup diff --git a/tests/basic/ctime/ctime-readdir.c b/tests/basic/ctime/ctime-readdir.c new file mode 100644 index 00000000000..8760db29ae8 --- /dev/null +++ b/tests/basic/ctime/ctime-readdir.c @@ -0,0 +1,29 @@ +#include <stdio.h> +#include <dirent.h> +#include <string.h> +#include <assert.h> + +int +main(int argc, char **argv) +{ + DIR *dir = NULL; + struct dirent *entry = NULL; + int ret = 0; + char *path = NULL; + + assert(argc == 2); + path = argv[1]; + + dir = opendir(path); + if (!dir) { + printf("opendir(%s) failed.\n", path); + return -1; + } + + while ((entry = readdir(dir)) != NULL) { + } + if (dir) + closedir(dir); + + return ret; +} diff --git a/tests/basic/ctime/ctime-readdir.t b/tests/basic/ctime/ctime-readdir.t new file mode 100644 index 00000000000..4564fc1b667 --- /dev/null +++ b/tests/basic/ctime/ctime-readdir.t @@ -0,0 +1,50 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +cleanup; + +TEST glusterd + +TEST $CLI volume create $V0 replica 3 ${H0}:$B0/brick{1,2,3}; +TEST $CLI volume set $V0 performance.stat-prefetch on +TEST $CLI volume set $V0 performance.readdir-ahead off +TEST $CLI volume start $V0; + +TEST glusterfs --volfile-id=$V0 --volfile-server=$H0 --entry-timeout=0 $M0; + +TEST mkdir $M0/dir0 +TEST "echo hello_world > $M0/dir0/FILE" + +ctime1=$(stat -c %Z $M0/dir0/FILE) +echo "Mount change time: $ctime1" + +sleep 2 + +#Write to back end directly to modify ctime of backend file +TEST "echo write_from_backend >> $B0/brick1/dir0/FILE" +TEST "echo write_from_backend >> $B0/brick2/dir0/FILE" +TEST "echo write_from_backend >> $B0/brick3/dir0/FILE" +echo "Backend change time" +echo "brick1: $(stat -c %Z $B0/brick1/dir0/FILE)" +echo "brick2: $(stat -c %Z $B0/brick2/dir0/FILE)" +echo "brick3: $(stat -c %Z $B0/brick3/dir0/FILE)" + +#Stop and start to hit the case of no inode for readdir +TEST umount $M0 +TEST $CLI volume stop $V0 +TEST $CLI volume start $V0 +TEST glusterfs --volfile-id=$V0 --volfile-server=$H0 --entry-timeout=0 $M0; + +TEST build_tester $(dirname $0)/ctime-readdir.c + +#Do readdir +TEST ./$(dirname $0)/ctime-readdir $M0/dir0 + +EXPECT "$ctime1" stat -c %Z $M0/dir0/FILE +echo "Mount change time after readdir $(stat -c %Z $M0/dir0/FILE)" + +cleanup_tester $(dirname $0)/ctime-readdir + +cleanup; diff --git a/tests/basic/ctime/ctime-rep-heal.t b/tests/basic/ctime/ctime-rep-heal.t new file mode 100644 index 00000000000..20517c74971 --- /dev/null +++ b/tests/basic/ctime/ctime-rep-heal.t @@ -0,0 +1,70 @@ +#!/bin/bash +# +# This will test self healing of ctime xattr 'trusted.glusterfs.mdata' +# +### + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc +. $(dirname $0)/../../afr.rc + +cleanup + +#cleate and start volume +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 replica 3 $H0:$B0/${V0}{1..3} +TEST $CLI volume start $V0 + +#Mount the volume +TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0; + +# Create files +mkdir $M0/dir1 +echo "Initial content" > $M0/file1 + +EXPECT_WITHIN $PROCESS_UP_TIMEOUT '3' get_mdata_count $B0/${V0}{1..3}/dir1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT '1' get_mdata_uniq_count $B0/${V0}{1..3}/dir1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT '3' get_mdata_count $B0/${V0}{1..3}/file1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT '1' get_mdata_uniq_count $B0/${V0}{1..3}/file1 + +# Kill brick +TEST kill_brick $V0 $H0 $B0/${V0}3 + +echo "B3 is down" >> $M0/file1 +echo "Change dir1 time attributes" > $M0/dir1/dir1_file1 +echo "Entry heal file" > $M0/entry_heal_file1 +mkdir $M0/entry_heal_dir1 + +# Check xattr +EXPECT_WITHIN $PROCESS_UP_TIMEOUT '3' get_mdata_count $B0/${V0}{1..3}/dir1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT '2' get_mdata_uniq_count $B0/${V0}{1..3}/dir1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT '3' get_mdata_count $B0/${V0}{1..3}/file1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT '2' get_mdata_uniq_count $B0/${V0}{1..3}/file1 + +EXPECT_WITHIN $PROCESS_UP_TIMEOUT '2' get_mdata_count $B0/${V0}{1..3}/dir1/dir1_file1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT '1' get_mdata_uniq_count $B0/${V0}{1..3}/dir1/dir1_file1 + +EXPECT_WITHIN $PROCESS_UP_TIMEOUT '2' get_mdata_count $B0/${V0}{1..3}/entry_heal_file1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT '1' get_mdata_uniq_count $B0/${V0}{1..3}/entry_heal_file1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT '2' get_mdata_count $B0/${V0}{1..3}/entry_heal_dir1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT '1' get_mdata_uniq_count $B0/${V0}{1..3}/entry_heal_dir1 + +TEST $CLI volume start $V0 force +$CLI volume heal $V0 + +# Check xattr +EXPECT_WITHIN $PROCESS_UP_TIMEOUT '3' get_mdata_count $B0/${V0}{1..3}/dir1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT '1' get_mdata_uniq_count $B0/${V0}{1..3}/dir1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT '3' get_mdata_count $B0/${V0}{1..3}/file1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT '1' get_mdata_uniq_count $B0/${V0}{1..3}/file1 + +EXPECT_WITHIN $PROCESS_UP_TIMEOUT '3' get_mdata_count $B0/${V0}{1..3}/dir1/dir1_file1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT '1' get_mdata_uniq_count $B0/${V0}{1..3}/dir1/dir1_file1 + +EXPECT_WITHIN $PROCESS_UP_TIMEOUT '3' get_mdata_count $B0/${V0}{1..3}/entry_heal_file1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT '1' get_mdata_uniq_count $B0/${V0}{1..3}/entry_heal_file1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT '3' get_mdata_count $B0/${V0}{1..3}/entry_heal_dir1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT '1' get_mdata_uniq_count $B0/${V0}{1..3}/entry_heal_dir1 + +cleanup; diff --git a/tests/basic/ctime/ctime-rep-rebalance.t b/tests/basic/ctime/ctime-rep-rebalance.t new file mode 100644 index 00000000000..866cf87e6cb --- /dev/null +++ b/tests/basic/ctime/ctime-rep-rebalance.t @@ -0,0 +1,41 @@ +#!/bin/bash +# +# This will test healing of ctime xattr 'trusted.glusterfs.mdata' after add-brick and rebalance +# +### + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc +. $(dirname $0)/../../afr.rc + +cleanup + +#cleate and start volume +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 replica 3 $H0:$B0/${V0}{0..5} +TEST $CLI volume start $V0 + +#Mount the volume +TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0; + +# Create files +mkdir $M0/dir1 + +# Add brick +TEST $CLI volume add-brick $V0 $H0:$B0/${V0}{6..8} + +#Trigger rebalance +TEST $CLI volume rebalance $V0 start force +EXPECT_WITHIN $REBALANCE_TIMEOUT "completed" rebalance_status_field $V0 + +#Verify ctime xattr heal on directory +EXPECT_WITHIN $PROCESS_UP_TIMEOUT 'trusted.glusterfs.mdata' check_for_xattr 'trusted.glusterfs.mdata' "$B0/${V0}6/dir1" +EXPECT_WITHIN $PROCESS_UP_TIMEOUT 'trusted.glusterfs.mdata' check_for_xattr 'trusted.glusterfs.mdata' "$B0/${V0}7/dir1" +EXPECT_WITHIN $PROCESS_UP_TIMEOUT 'trusted.glusterfs.mdata' check_for_xattr 'trusted.glusterfs.mdata' "$B0/${V0}8/dir1" + +b6_mdata=$(get_mdata "$B0/${V0}6/dir1") +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "${b6_mdata}" get_mdata $B0/${V0}7/dir1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "${b6_mdata}" get_mdata $B0/${V0}8/dir1 + +cleanup; diff --git a/tests/basic/ctime/ctime-utimesat.t b/tests/basic/ctime/ctime-utimesat.t new file mode 100644 index 00000000000..540e57aec83 --- /dev/null +++ b/tests/basic/ctime/ctime-utimesat.t @@ -0,0 +1,28 @@ +#!/bin/bash +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc +. $(dirname $0)/../../afr.rc +cleanup; + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 replica 3 $H0:$B0/${V0}{0,1,2} +TEST $CLI volume set $V0 performance.stat-prefetch off +TEST $CLI volume set $V0 performance.read-ahead off +TEST $CLI volume set $V0 performance.quick-read off +TEST $CLI volume set $V0 performance.read-after-open off +TEST $CLI volume set $V0 performance.open-behind off +TEST $CLI volume set $V0 performance.write-behind off +TEST $CLI volume set $V0 performance.io-cache off + +TEST $CLI volume start $V0 + +TEST glusterfs --volfile-id=$V0 --volfile-server=$H0 --entry-timeout=0 $M0; + +touch $M0/FILE + +atime=$(stat -c "%.X" $M0/FILE) +EXPECT $atime stat -c "%.Y" $M0/FILE +EXPECT $atime stat -c "%.Z" $M0/FILE + +cleanup diff --git a/tests/basic/distribute/brick-down.t b/tests/basic/distribute/brick-down.t new file mode 100644 index 00000000000..522ccc07210 --- /dev/null +++ b/tests/basic/distribute/brick-down.t @@ -0,0 +1,83 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc +. $(dirname $0)/../../common-utils.rc +. $(dirname $0)/../../dht.rc + +# Test 1 overview: +# ---------------- +# Test whether lookups are sent after a brick comes up again +# +# 1. Create a 3 brick pure distribute volume +# 2. Fuse mount the volume so the layout is set on the root +# 3. Kill one brick and try to create a directory which hashes to that brick. +# It should fail with EIO. +# 4. Restart the brick that was killed. +# 5. Do not remount the volume. Try to create the same directory as in step 3. + +cleanup + +TEST glusterd +TEST pidof glusterd + +TEST $CLI volume create $V0 $H0:$B0/$V0-{1..3} +TEST $CLI volume start $V0 + +# We want the lookup to reach DHT +TEST $CLI volume set $V0 performance.stat-prefetch off + +# Mount using FUSE and lookup the mount so a layout is set on the brick root +TEST glusterfs --entry-timeout=0 --attribute-timeout=0 -s $H0 --volfile-id $V0 $M0 + +ls $M0/ + +TEST mkdir $M0/level1 + +# Find a dirname that will hash to the brick we are going to kill +hashed=$V0-client-1 +TEST dht_first_filename_with_hashsubvol "$hashed" $M0 "dir-" +roottestdir=$fn_return_val + +hashed=$V0-client-1 +TEST dht_first_filename_with_hashsubvol "$hashed" $M0/level1 "dir-" +level1testdir=$fn_return_val + + +TEST kill_brick $V0 $H0 $B0/$V0-2 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "0" brick_up_status $V0 $H0 $B0/$V0-2 + +TEST $CLI volume status $V0 + + +# Unmount and mount the volume again so dht has an incomplete in memory layout + +umount -f $M0 +TEST glusterfs --entry-timeout=0 --attribute-timeout=0 -s $H0 --volfile-id $V0 $M0 + + +mkdir $M0/$roottestdir +TEST [ $? -ne 0 ] + +mkdir $M0/level1/$level1testdir +TEST [ $? -ne 0 ] + +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/$V0-2 + +#$CLI volume status + +# It takes a while for the client to reconnect to the brick +sleep 5 + + +mkdir $M0/$roottestdir +TEST [ $? -eq 0 ] + +mkdir $M0/$level1/level1testdir +TEST [ $? -eq 0 ] + +# Cleanup +cleanup + + diff --git a/tests/basic/distribute/bug-1265677-use-readdirp.t b/tests/basic/distribute/bug-1265677-use-readdirp.t new file mode 100644 index 00000000000..eef8affc8b9 --- /dev/null +++ b/tests/basic/distribute/bug-1265677-use-readdirp.t @@ -0,0 +1,38 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +# This test checks use-readdirp disable/enable for dht + +cleanup +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 $H0:$B0/${V0}{0..1} +TEST $CLI volume set $V0 nfs.disable yes +TEST $CLI volume set $V0 dht.force-readdirp yes +TEST $CLI volume set $V0 performance.readdir-ahead off +TEST $CLI volume set $V0 performance.force-readdirp no +TEST $CLI volume start $V0 +TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 --use-readdirp=no $M0; +TEST mkdir $M0/d +TEST touch $M0/d/{1..10} + +TEST $CLI volume profile $V0 start +#Clear all the fops till now +TEST $CLI volume profile $V0 info + +EXPECT "^10$" echo $(ls $M0/d | wc -l) +EXPECT_NOT "^0$" echo $($CLI volume profile $V0 info incremental | grep -w READDIRP | wc -l) +EXPECT "^10$" echo $(ls $M0/d | wc -l) +EXPECT "^0$" echo $($CLI volume profile $V0 info incremental | grep -w READDIR | wc -l) + +TEST $CLI volume set $V0 dht.force-readdirp no +EXPECT_WITHIN $CONFIG_UPDATE_TIMEOUT "0" mount_get_option_value $M0 $V0-dht use-readdirp + +EXPECT "^10$" echo $(ls $M0/d | wc -l) +EXPECT "^0$" echo $($CLI volume profile $V0 info incremental | grep -w READDIRP | wc -l) +EXPECT "^10$" echo $(ls $M0/d | wc -l) +EXPECT_NOT "^0$" echo $($CLI volume profile $V0 info incremental | grep -w READDIR | wc -l) + +cleanup diff --git a/tests/basic/distribute/debug-xattrs.t b/tests/basic/distribute/debug-xattrs.t new file mode 100644 index 00000000000..6d87c0e8671 --- /dev/null +++ b/tests/basic/distribute/debug-xattrs.t @@ -0,0 +1,54 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc +. $(dirname $0)/../../nfs.rc +. $(dirname $0)/../../common-utils.rc + +# Test overview: Test the virtual xattrs dht provides for debugging + +# Test 1 : "dht.file.hashed-subvol.<filename>" +# Get the hashed subvolume for file1 in dir1 using xattr +# Create file1 in dir1 +# Check if the file is created in the brick returned by xattr + +hashdebugxattr="dht.file.hashed-subvol." + +cleanup + +TEST glusterd +TEST pidof glusterd + +TEST $CLI volume create $V0 $H0:$B0/$V0-{0..3} +TEST $CLI volume start $V0 + +# Mount using FUSE and create a file +TEST glusterfs -s $H0 --volfile-id $V0 $M0 + +# Test 1 : "dht.file.hashed-subvol.<filename>" +# Get the hashed subvolume for file1 in dir1 using xattr +# Create file1 in dir1 +# Check if the file is created in the brick returned by xattr +# Create a directory on $M0 + +TEST mkdir $M0/dir1 + +xattrname=$hashdebugxattr"file1" + +hashed=$(getfattr --only-values -n "$xattrname" $M0/dir1) + +# Get the brick path for $hashed +brickpath=$(cat "$M0/.meta/graphs/active/$hashed/options/remote-subvolume") +brickpath=$brickpath"/dir1/file1" + +# Create the file for which we checked the xattr +TEST touch $M0/dir1/file1 +TEST stat $brickpath + +# Non-existent directory +TEST ! getfattr --only-values -n "$xattrname" $M0/dir2 + + +# Cleanup +cleanup + diff --git a/tests/basic/distribute/dir-heal.t b/tests/basic/distribute/dir-heal.t new file mode 100644 index 00000000000..851f765b245 --- /dev/null +++ b/tests/basic/distribute/dir-heal.t @@ -0,0 +1,145 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc +. $(dirname $0)/../../nfs.rc +. $(dirname $0)/../../common-utils.rc + +# Test 1 overview: +# ---------------- +# +# 1. Kill one brick of the volume. +# 2. Create directories and change directory properties. +# 3. Bring up the brick and access the directory +# 4. Check the permissions and xattrs on the backend + +cleanup + +TEST glusterd +TEST pidof glusterd + +TEST $CLI volume create $V0 $H0:$B0/$V0-{1..3} +TEST $CLI volume start $V0 + +# We want the lookup to reach DHT +TEST $CLI volume set $V0 performance.stat-prefetch off + +# Mount using FUSE , kill a brick and create directories +TEST glusterfs --entry-timeout=0 --attribute-timeout=0 -s $H0 --volfile-id $V0 $M0 + +ls $M0/ +cd $M0 + +TEST kill_brick $V0 $H0 $B0/$V0-1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "0" brick_up_status $V0 $H0 $B0/$V0-1 + +TEST mkdir dir{1..4} + +# No change for dir1 +# Change permissions for dir2 +# Set xattr on dir3 +# Change permissions and set xattr on dir4 + +TEST chmod 777 $M0/dir2 + +TEST setfattr -n "user.test" -v "test" $M0/dir3 + +TEST chmod 777 $M0/dir4 +TEST setfattr -n "user.test" -v "test" $M0/dir4 + + +# Start all bricks + +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/$V0-1 + +#$CLI volume status + +# It takes a while for the client to reconnect to the brick +sleep 5 + +stat $M0/dir* > /dev/null + +# Check that directories have been created on the brick that was killed + +TEST ls $B0/$V0-1/dir1 + +TEST ls $B0/$V0-1/dir2 +EXPECT "777" stat -c "%a" $B0/$V0-1/dir2 + +TEST ls $B0/$V0-1/dir3 +EXPECT "test" getfattr -n "user.test" --absolute-names --only-values $B0/$V0-1/dir3 + + +TEST ls $B0/$V0-1/dir4 +EXPECT "777" stat -c "%a" $B0/$V0-1/dir4 +EXPECT "test" getfattr -n "user.test" --absolute-names --only-values $B0/$V0-1/dir4 + + +TEST rm -rf $M0/* + +cd + +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 + + +# Test 2 overview: +# ---------------- +# 1. Create directories with all bricks up. +# 2. Kill a brick and change directory properties and set user xattr. +# 2. Bring up the brick and access the directory +# 3. Check the permissions and xattrs on the backend + + +TEST glusterfs --entry-timeout=0 --attribute-timeout=0 -s $H0 --volfile-id $V0 $M0 + +ls $M0/ +cd $M0 +TEST mkdir dir{1..4} + +TEST kill_brick $V0 $H0 $B0/$V0-1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "0" brick_up_status $V0 $H0 $B0/$V0-1 + +# No change for dir1 +# Change permissions for dir2 +# Set xattr on dir3 +# Change permissions and set xattr on dir4 + +TEST chmod 777 $M0/dir2 + +TEST setfattr -n "user.test" -v "test" $M0/dir3 + +TEST chmod 777 $M0/dir4 +TEST setfattr -n "user.test" -v "test" $M0/dir4 + + +# Start all bricks + +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/$V0-1 + +#$CLI volume status + +# It takes a while for the client to reconnect to the brick +sleep 5 + +stat $M0/dir* > /dev/null + +# Check directories on the brick that was killed + +TEST ls $B0/$V0-1/dir2 +EXPECT "777" stat -c "%a" $B0/$V0-1/dir2 + +TEST ls $B0/$V0-1/dir3 +EXPECT "test" getfattr -n "user.test" --absolute-names --only-values $B0/$V0-1/dir3 + + +TEST ls $B0/$V0-1/dir4 +EXPECT "777" stat -c "%a" $B0/$V0-1/dir4 +EXPECT "test" getfattr -n "user.test" --absolute-names --only-values $B0/$V0-1/dir4 +cd + + +# Cleanup +cleanup + diff --git a/tests/basic/distribute/file-create.t b/tests/basic/distribute/file-create.t new file mode 100644 index 00000000000..41b662eefe2 --- /dev/null +++ b/tests/basic/distribute/file-create.t @@ -0,0 +1,120 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc +. $(dirname $0)/../../common-utils.rc +. $(dirname $0)/../../dht.rc + +# Test overview: Test file creation in various scenarios + + +# Test 1 : "dht.file.hashed-subvol.<filename>" +# Get the hashed subvolume for file1 in dir1 using xattr +# Create file1 in dir1 +# Check if the file is created in the brick returned by xattr + +hashdebugxattr="dht.file.hashed-subvol." + +cleanup + +TEST glusterd +TEST pidof glusterd + +# We want fixed size bricks to test min-free-disk + +# Create 2 loop devices, one per brick. +TEST truncate -s 25M $B0/brick1 +TEST truncate -s 25M $B0/brick2 + +TEST L1=`SETUP_LOOP $B0/brick1` +TEST MKFS_LOOP $L1 + +TEST L2=`SETUP_LOOP $B0/brick2` +TEST MKFS_LOOP $L2 + + +TEST mkdir -p $B0/${V0}{1,2} + +TEST MOUNT_LOOP $L1 $B0/${V0}1 +TEST MOUNT_LOOP $L2 $B0/${V0}2 + + +# Create a plain distribute volume with 2 subvols. +TEST $CLI volume create $V0 $H0:$B0/${V0}{1,2}; +TEST $CLI volume start $V0; +EXPECT "Started" volinfo_field $V0 'Status'; + +TEST $CLI volume set $V0 cluster.min-free-disk 40% +#TEST $CLI volume set $V0 client-log-level DEBUG + +# Mount using FUSE and create a file +TEST glusterfs -s $H0 --volfile-id $V0 $M0 + +TEST mkdir $M0/dir1 + +###################################################### +# Test 1 : Test file creation on correct hashed subvol +###################################################### + +hashed="$V0-client-0" +TEST dht_first_filename_with_hashsubvol "$hashed" $M0/dir1 "big-" +firstfile=$fn_return_val + +#Create a large file to fill up $hashed past the min-free-disk limits +TEST dd if=/dev/zero of=$M0/dir1/$firstfile bs=1M count=15 + +brickpath_0=$(cat "$M0/.meta/graphs/active/$hashed/options/remote-subvolume") +brickpath_1=$(cat "$M0/.meta/graphs/active/$V0-client-1/options/remote-subvolume") + +TEST stat "$brickpath_0/dir1/$firstfile" +EXPECT "0" is_dht_linkfile "$brickpath_0/dir1/$firstfile" + + +###################################################### +# Test 2: Create a file which hashes to the subvol which has crossed +# the min-free-disk limit. It should be created on the other subvol +###################################################### + +# DHT only checks disk usage every second. Create a new file and introduce a +# delay here to ensure DHT updates the in memory disk usage +sleep 2 +TEST dd if=/dev/zero of=$M0/dir1/file-2 bs=1024 count=1 + +# Find a file that will hash to $hash_subvol +TEST dht_first_filename_with_hashsubvol $hashed $M0/dir1 "newfile-" +newfile=$fn_return_val +echo $newfile + +# Create $newfile - it should be created on the other subvol as its hash subvol +# has crossed the min-free-disk limit +TEST dd if=/dev/zero of=$M0/dir1/$newfile bs=1024 count=20 +TEST stat "$brickpath_0/dir1/$newfile" +EXPECT "1" is_dht_linkfile "$brickpath_0/dir1/$newfile" + + +#TEST rm -rf $M0/dir1/$firstfile +#TEST rm -rf $M0/dir1/$newfile + + +###################################################### +# Test 3: Test dht_filter_loc_subvol_key +###################################################### + +TEST dht_first_filename_with_hashsubvol $V0-client-1 $M0/dir1 "filter-" +newfile=$fn_return_val +echo $newfile +TEST dd if=/dev/zero of="$M0/dir1/$newfile@$V0-dht:$hashed" bs=1024 count=20 +TEST stat $M0/dir1/$newfile +TEST stat "$brickpath_0/dir1/$newfile" +EXPECT "1" is_dht_linkfile "$brickpath_1/dir1/$newfile" + + +force_umount $M0 +TEST $CLI volume stop $V0 +UMOUNT_LOOP ${B0}/${V0}{1,2} +rm -f ${B0}/brick{1,2} + + +# Cleanup +cleanup + diff --git a/tests/basic/distribute/file-rename.t b/tests/basic/distribute/file-rename.t new file mode 100644 index 00000000000..63111b8ad8f --- /dev/null +++ b/tests/basic/distribute/file-rename.t @@ -0,0 +1,1021 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc +. $(dirname $0)/../../nfs.rc +. $(dirname $0)/../../common-utils.rc + +# Test overview: +# Test all combinations of src-hashed/src-cached/dst-hashed/dst-cached + +hashdebugxattr="dht.file.hashed-subvol." + +function get_brick_index { + local inpath=$1 + brickroot=$(getfattr -m . -n trusted.glusterfs.pathinfo $inpath | tr ' ' '\n' | sed -n 's/<POSIX(\(.*\)):.*:.*>.*/\1/p') + echo ${brickroot:(-1)} +} + +function get_brick_path_for_subvol { + local in_subvol=$1 + local in_brickpath + + in_brickpath=$(cat "$M0/.meta/graphs/active/$in_subvol/options/remote-subvolume") + echo $in_brickpath + +} + +#Checks that file exists only on hashed and/or cached +function file_existence_check +{ + local in_file_path=$1 + local in_hashed=$2 + local in_cached=$3 + local in_client_subvol + local in_brickpath + local ret + + for i in {0..3} + do + in_client_subvol="$V0-client-$i" + in_brickpath=$(cat "$M0/.meta/graphs/active/$in_client_subvol/options/remote-subvolume") + stat "$in_brickpath/$in_file_path" 2>/dev/null + ret=$? + # Either the linkto or the data file must exist on the hashed + if [ "$in_client_subvol" == "$in_hashed" ]; then + if [ $ret -ne 0 ]; then + return 1 + fi + continue + fi + + # If the cached is non-null, we expect the file to exist on it + if [ "$in_client_subvol" == "$in_cached" ]; then + if [ $ret -ne 0 ]; then + return 1 + fi + continue + fi + + if [ $ret -eq 0 ]; then + return 2 + fi + done + return 0 +} + + +# Check if file exists on any of the bricks of the volume +function file_does_not_exist +{ + local inpath=$1 + for i in `seq 0 3` + do + file_path=$B0/$V0-$i/$inpath + if [ -f "$file_path" ]; then + echo "1" + return 1 + fi + done + return 0 +} + + +# Input: filename dirpath +function get_hash_subvol +{ + hash_subvol=$(getfattr --only-values -n "$hashdebugxattr$1" $2 2>/dev/null) +} + + + +# Find the first filename that hashes to a subvol +# other than $1 + +function first_filename_with_diff_hashsubvol +{ + local in_subvol=$1 + local in_path=$2 + local file_pattern=$3 + local in_hash_subvol + + for i in {1..100} + do + dstfilename="$file_pattern$i" + in_hash_subvol=$(get_hash_subvol "$dstfilename" "$in_path") + echo $in_hash_subvol + if [ "$in_subvol" != "$in_hash_subvol" ]; then + return 0 + fi + done + return 1 +} + +# Find the first filename that hashes to the same subvol +# as $1 +function first_filename_with_same_hashsubvol +{ + local in_subvol=$1 + local in_path=$2 + local in_hash_subvol + local file_pattern=$3 + + for i in {1..100} + do + dstfilename="$file_pattern$i" + get_hash_subvol "$dstfilename" "$in_path" + in_hash_subvol=$hash_subvol +# echo $in_hash_subvol + if [ "$in_subvol" == "$in_hash_subvol" ]; then + return 0 + fi + done + return 1 +} + +function file_is_linkto +{ + local brick_filepath=$1 + + test=$(stat $brick_filepath 2>&1) + if [ $? -ne 0 ]; then + echo "2" + return + fi + + test=$(getfattr -n trusted.glusterfs.dht.linkto -e text $brick_filepath 2>&1) + + if [ $? -eq 0 ]; then + echo "1" + else + echo "0" + fi +} + + + + +cleanup + +TEST glusterd +TEST pidof glusterd + + +# We need at least 4 bricks to test all combinations of hashed and +# cached files + +TEST $CLI volume create $V0 $H0:$B0/$V0-{0..3} +TEST $CLI volume start $V0 + +# Mount using FUSE +TEST glusterfs -s $H0 --volfile-id $V0 $M0 + + +################################################################ +# The first set of tests are those where the Dst file does not exist +# dst-cached = NULL +# +############################################################### + +################### Test 1 #################################### +# +# src-hashed = src-cached = dst-hashed +# dst-cached = null +# src-file = src-1 + +echo " **** Test 1 **** " + +src_file="src-1" + +TEST mkdir $M0/test-1 +TEST touch $M0/test-1/$src_file + +TEST get_hash_subvol $src_file $M0/test-1 +src_hashed=$hash_subvol +#echo "Hashed subvol for $src_file: " $src_hashed + +# Find a file name that hashes to the same subvol as $src_file +TEST first_filename_with_same_hashsubvol "$src_hashed" "$M0/test-1" "dst-" +#echo "dst-file name: " $dstfilename +dst_hashed=$src_hashed + +src_hash_brick=$(get_brick_path_for_subvol $src_hashed) + +echo "Renaming $src_file to $dstfilename" + +TEST mv $M0/test-1/$src_file $M0/test-1/$dstfilename + +# Expected: +# dst file is accessible from the mount point +# dst file exists only on the hashed brick. +# no linkto files on any bricks +# src files do not exist + + +TEST stat $M0/test-1/$dstfilename 2>/dev/null +TEST file_existence_check test-1/$dstfilename $src_hashed +TEST file_does_not_exist test-1/$src_file +EXPECT "0" file_is_linkto $src_hash_brick/test-1/$dstfilename + + +################### Test 2 #################################### + +# src-hashed = src-cached != dst-hashed +# dst-cached = null + +echo " **** Test 2 **** " + +src_file="src-1" + +TEST mkdir $M0/test-2 +TEST touch $M0/test-2/$src_file + +TEST get_hash_subvol $src_file $M0/test-2 +src_hashed=$hash_subvol +#echo "Hashed subvol for $src_file: " $src_hashed + +# Find a file name that hashes to a diff hashed subvol than $src_file +TEST first_filename_with_diff_hashsubvol "$src_hashed" "$M0/test-2" "dst-" +echo "dst-file name: " $dstfilename +TEST get_hash_subvol $dstfilename $M0/test-2 +dst_hashed=$hash_subvol + +src_hash_brick=$(get_brick_path_for_subvol $src_hashed) +dst_hash_brick=$(get_brick_path_for_subvol $dst_hashed) + +echo "Renaming $src_file to $dstfilename" + +TEST mv $M0/test-2/$src_file $M0/test-2/$dstfilename + + +# Expected: +# dst file is accessible from the mount point +# dst data file on src_hashed and dst linkto file on dst_hashed +# src files do not exist + + +TEST stat $M0/test-2/$dstfilename 2>/dev/null +TEST file_existence_check test-2/$dstfilename $dst_hashed $src_hashed +TEST file_does_not_exist test-2/$src_file +EXPECT "1" file_is_linkto $dst_hash_brick/test-2/$dstfilename +EXPECT "0" file_is_linkto $src_hash_brick/test-2/$dstfilename + +################### Test 3 #################################### + +# src-hashed = dst-hashed != src-cached + +echo " **** Test 3 **** " + +src_file0="abc-1" + +# 1. Create src file with src_cached != src_hashed +TEST mkdir $M0/test-3 +TEST touch $M0/test-3/$src_file0 + +TEST get_hash_subvol $src_file0 $M0/test-3 +src_cached=$hash_subvol +#echo "Hashed subvol for $src_file0: " $src_cached + +# Find a file name that hashes to a diff hashed subvol than $src_file0 +TEST first_filename_with_diff_hashsubvol "$src_cached" "$M0/test-3" "src-" +echo "dst-file name: " $dstfilename +src_file=$dstfilename + +TEST mv $M0/test-3/$src_file0 $M0/test-3/$src_file + +TEST get_hash_subvol $src_file $M0/test-3 +src_hashed=$hash_subvol + + +# 2. Rename src to dst +TEST first_filename_with_same_hashsubvol "$src_hashed" "$M0/test-3" "dst-" +#echo "dst-file name: " $dstfilename + +src_hash_brick=$(get_brick_path_for_subvol $src_hashed) +src_cached_brick=$(get_brick_path_for_subvol $src_cached) + +echo "Renaming $src_file to $dstfilename" + +TEST mv $M0/test-3/$src_file $M0/test-3/$dstfilename + + +# Expected: +# dst file is accessible from the mount point +TEST stat $M0/test-3/$dstfilename 2>/dev/null + +# src file does not exist +TEST file_does_not_exist test-3/$src_file + +# dst linkto file on src_hashed and dst data file on src_cached +TEST file_existence_check test-3/$dstfilename $src_hashed $src_cached + +EXPECT "1" file_is_linkto $src_hash_brick/test-3/$dstfilename +EXPECT "0" file_is_linkto $src_cached_brick/test-3/$dstfilename + + + +################### Test 4 #################################### + +# src-cached = dst-hashed != src-hashed + +echo " **** Test 4 **** " + +src_file0="abc-1" + +# 1. Create src file with src_cached != src_hashed +TEST mkdir $M0/test-4 +TEST touch $M0/test-4/$src_file0 + +TEST get_hash_subvol $src_file0 $M0/test-4 +src_cached=$hash_subvol +#echo "Hashed subvol for $src_file0: " $src_cached + +# Find a file name that hashes to a diff hashed subvol than $src_file0 +TEST first_filename_with_diff_hashsubvol "$src_cached" "$M0/test-4" "src-" +src_file=$dstfilename + +TEST mv $M0/test-4/$src_file0 $M0/test-4/$src_file + +TEST get_hash_subvol $src_file $M0/test-4 +src_hashed=$hash_subvol + + +# 2. Rename src to dst +TEST first_filename_with_same_hashsubvol "$src_cached" "$M0/test-4" "dst-" +#echo "dst-file name: " $dstfilename + +src_hash_brick=$(get_brick_path_for_subvol $src_hashed) +src_cached_brick=$(get_brick_path_for_subvol $src_cached) + +echo "Renaming $src_file to $dstfilename" + +TEST mv $M0/test-4/$src_file $M0/test-4/$dstfilename + +# Expected: +# dst file is accessible from the mount point +TEST stat $M0/test-4/$dstfilename 2>/dev/null + +# src file does not exist +TEST file_does_not_exist test-4/$src_file + +# dst linkto file on src_hashed and dst data file on src_cached +TEST file_existence_check test-4/$dstfilename $src_cached + +EXPECT "0" file_is_linkto $src_cached_brick/test-4/$dstfilename + + +################### Test 5 #################################### + +# src-cached != src-hashed +# src-hashed != dst-hashed +# src-cached != dst-hashed + + +echo " **** Test 5 **** " + +# 1. Create src and dst files + +TEST mkdir $M0/test-5 + +TEST first_filename_with_same_hashsubvol "$V0-client-0" "$M0/test-5" "abc-" +src_file0=$dstfilename + +TEST touch $M0/test-5/$src_file0 + +TEST get_hash_subvol $src_file0 $M0/test-5 +src_cached=$hash_subvol +#echo "Hashed subvol for $src_file0: " $src_cached + +# Find a file name that hashes to a diff hashed subvol than $src_file0 +TEST first_filename_with_same_hashsubvol "$V0-client-1" "$M0/test-5" "src-" +src_file=$dstfilename + +TEST mv $M0/test-5/$src_file0 $M0/test-5/$src_file + +TEST get_hash_subvol $src_file $M0/test-5 +src_hashed=$hash_subvol + +TEST first_filename_with_same_hashsubvol "$V0-client-2" "$M0/test-5" "dst-" +#echo "dst-file name: " $dstfilename + +dst_hash_brick=$(get_brick_path_for_subvol "$V0-client-2") +src_cached_brick=$(get_brick_path_for_subvol $src_cached) + + +# 2. Rename src to dst +echo "Renaming $src_file to $dstfilename" + +TEST mv $M0/test-5/$src_file $M0/test-5/$dstfilename + + +# 3. Validate + +# Expected: +# dst file is accessible from the mount point +TEST stat $M0/test-5/$dstfilename 2>/dev/null + +# src file does not exist +TEST file_does_not_exist test-5/$src_file + +# dst linkto file on src_hashed and dst data file on src_cached + +EXPECT "0" file_is_linkto $src_cached_brick/test-5/$dstfilename +EXPECT "1" file_is_linkto $dst_hash_brick/test-5/$dstfilename + + +######################################################################## +# +# The Dst file exists +# +######################################################################## + +################### Test 6 #################################### + +# src_hash = src_cached +# dst_hash = dst_cached +# dst_hash = src_hash + + +TEST mkdir $M0/test-6 + +# 1. Create src and dst files + +TEST first_filename_with_same_hashsubvol "$V0-client-0" "$M0/test-6" "src-" +src_file=$dstfilename + +TEST touch $M0/test-6/$src_file + +TEST first_filename_with_same_hashsubvol "$V0-client-0" "$M0/test-6" "dst-" +dst_file=$dstfilename + +TEST touch $M0/test-6/$dst_file + + +# 2. Rename src to dst + +TEST mv $M0/test-6/$src_file $M0/test-6/$dst_file + + +# 3. Validate + +dst_hash_brick=$(get_brick_path_for_subvol "$V0-client-0") + +TEST stat $M0/test-6/$dst_file 2>/dev/null +TEST file_existence_check test-6/$dst_file "$V0-client-0" +TEST file_does_not_exist test-6/$src_file +EXPECT "0" file_is_linkto $dst_hash_brick/test-6/$dst_file + + +################### Test 7 #################################### + +# src_hash = src_cached +# dst_hash = dst_cached +# dst_hash != src_hash + + +echo " **** Test 7 **** " + +TEST mkdir $M0/test-7 + +# 1. Create src and dst files + +TEST first_filename_with_same_hashsubvol "$V0-client-0" "$M0/test-7" "src-" +src_file=$dstfilename + +TEST touch $M0/test-7/$src_file + +TEST first_filename_with_same_hashsubvol "$V0-client-1" "$M0/test-7" "dst-" +dst_file=$dstfilename + +TEST touch $M0/test-7/$dst_file + + +# 2. Rename src to dst + +TEST mv $M0/test-7/$src_file $M0/test-7/$dst_file + + +# 3. Validate + +dst_hash_brick=$(get_brick_path_for_subvol "$V0-client-1") +src_hash_brick=$(get_brick_path_for_subvol "$V0-client-0") + +TEST stat $M0/test-7/$dst_file 2>/dev/null +TEST file_existence_check test-7/$dst_file "$V0-client-1" "$V0-client-0" +TEST file_does_not_exist test-7/$src_file + +EXPECT "0" file_is_linkto $src_hash_brick/test-7/$dst_file +EXPECT "1" file_is_linkto $dst_hash_brick/test-7/$dst_file + + +################### Test 8 #################################### + +# src_hash = src_cached +# dst_hash != dst_cached +# dst_hash != src_hash +# dst_cached != src_hash + +echo " **** Test 8 **** " + +TEST mkdir $M0/test-8 + + +# 1. Create src and dst files + +TEST first_filename_with_same_hashsubvol "$V0-client-0" "$M0/test-8" "src-" +src_file=$dstfilename +TEST touch $M0/test-8/$src_file + +TEST first_filename_with_same_hashsubvol "$V0-client-1" "$M0/test-8" "dst0-" +dst_file0=$dstfilename +TEST touch $M0/test-8/$dst_file0 + +TEST first_filename_with_same_hashsubvol "$V0-client-2" "$M0/test-8" "dst-" +dst_file=$dstfilename + +mv $M0/test-8/$dst_file0 $M0/test-8/$dst_file + + +# 2. Rename the file + +mv $M0/test-8/$src_file $M0/test-8/$dst_file + + +# 3. Validate + +dst_hash_brick=$(get_brick_path_for_subvol "$V0-client-2") +src_hash_brick=$(get_brick_path_for_subvol "$V0-client-0") + +TEST stat $M0/test-8/$dst_file 2>/dev/null +TEST file_existence_check test-8/$dst_file "$V0-client-2" "$V0-client-0" +TEST file_does_not_exist test-8/$src_file + +EXPECT "0" file_is_linkto $src_hash_brick/test-8/$dst_file +EXPECT "1" file_is_linkto $dst_hash_brick/test-8/$dst_file + +################### Test 9 #################################### + +# src_hash = src_cached = dst_hash +# dst_hash != dst_cached + +echo " **** Test 9 **** " + +TEST mkdir $M0/test-9 + + +# 1. Create src and dst files + + +TEST first_filename_with_same_hashsubvol "$V0-client-0" "$M0/test-9" "src-" +src_file=$dstfilename +TEST touch $M0/test-9/$src_file + + +TEST first_filename_with_same_hashsubvol "$V0-client-1" "$M0/test-9" "dst0-" +dst0_file=$dstfilename +TEST touch $M0/test-9/$dst0_file + +TEST first_filename_with_same_hashsubvol "$V0-client-0" "$M0/test-9" "dst-" +dst_file=$dstfilename + +TEST mv $M0/test-9/$dst0_file $M0/test-9/$dst_file + +# 2. Rename the file + +mv $M0/test-9/$src_file $M0/test-9/$dst_file + + +# 3. Validate + +dst_hash_brick=$(get_brick_path_for_subvol "$V0-client-0") + +TEST stat $M0/test-9/$dst_file 2>/dev/null +TEST file_existence_check test-9/$dst_file "$V0-client-0" +TEST file_does_not_exist test-9/$src_file +EXPECT "0" file_is_linkto $dst_hash_brick/test-9/$dst_file + + +################### Test 10 #################################### + +# src_hash = src_cached = dst_cached +# dst_hash != dst_cached + +echo " **** Test 10 **** " + +TEST mkdir $M0/test-10 + + +# 1. Create src and dst files + +TEST first_filename_with_same_hashsubvol "$V0-client-0" "$M0/test-10" "src-" +src_file=$dstfilename +TEST touch $M0/test-10/$src_file + +TEST first_filename_with_same_hashsubvol "$V0-client-0" "$M0/test-10" "dst0-" +dst0_file=$dstfilename +TEST touch $M0/test-10/$dst0_file + +TEST first_filename_with_same_hashsubvol "$V0-client-1" "$M0/test-10" "dst-" +dst_file=$dstfilename + +mv $M0/test-10/$dst0_file $M0/test-10/$dst_file + + +# 2. Rename the file + +mv $M0/test-10/$src_file $M0/test-10/$dst_file + + +# 3. Validate + +dst_hash_brick=$(get_brick_path_for_subvol "$V0-client-1") +dst_cached_brick=$(get_brick_path_for_subvol "$V0-client-0") + +TEST stat $M0/test-10/$dst_file 2>/dev/null +TEST file_existence_check test-10/$dst_file "$V0-client-1" "$V0-client-0" +TEST file_does_not_exist test-10/$src_file +EXPECT "1" file_is_linkto $dst_hash_brick/test-10/$dst_file +EXPECT "0" file_is_linkto $dst_cached_brick/test-10/$dst_file + + +################### Test 11 #################################### + +# src_hash != src_cached +# dst_hash = dst_cached = src_cached + +echo " **** Test 11 **** " + +TEST mkdir $M0/test-11 + + +# 1. Create src and dst files + +TEST first_filename_with_same_hashsubvol "$V0-client-0" "$M0/test-11" "src0-" +src0_file=$dstfilename +TEST touch $M0/test-11/$src0_file + +TEST first_filename_with_same_hashsubvol "$V0-client-1" "$M0/test-11" "src-" +src_file=$dstfilename + +mv $M0/test-11/$src0_file $M0/test-11/$src_file + + +TEST first_filename_with_same_hashsubvol "$V0-client-0" "$M0/test-11" "dst-" +dst_file=$dstfilename +TEST touch $M0/test-11/$dst_file + + +# 2. Rename the file + +mv $M0/test-11/$src_file $M0/test-11/$dst_file + + +# 3. Validate + +dst_hash_brick=$(get_brick_path_for_subvol "$V0-client-0") + +TEST stat $M0/test-11/$dst_file 2>/dev/null +TEST file_existence_check test-11/$dst_file "$V0-client-0" +TEST file_does_not_exist test-11/$src_file +EXPECT "0" file_is_linkto $dst_hash_brick/test-11/$dst_file + + +################### Test 12 #################################### + +# src_hash != src_cached +# dst_hash = dst_cached = src_hash + +echo " **** Test 12 **** " + +TEST mkdir $M0/test-12 + + +# 1. Create src and dst files + +TEST first_filename_with_same_hashsubvol "$V0-client-0" "$M0/test-12" "src0-" +src0_file=$dstfilename +TEST touch $M0/test-12/$src0_file + +TEST first_filename_with_same_hashsubvol "$V0-client-1" "$M0/test-12" "src-" +src_file=$dstfilename + +mv $M0/test-12/$src0_file $M0/test-12/$src_file + + +TEST first_filename_with_same_hashsubvol "$V0-client-1" "$M0/test-12" "dst-" +dst_file=$dstfilename +TEST touch $M0/test-12/$dst_file + + +# 2. Rename the file + +mv $M0/test-12/$src_file $M0/test-12/$dst_file + + +# 3. Validate + +dst_hash_brick=$(get_brick_path_for_subvol "$V0-client-1") +dst_cached_brick=$(get_brick_path_for_subvol "$V0-client-0") + +TEST stat $M0/test-12/$dst_file 2>/dev/null +TEST file_existence_check test-12/$dst_file "$V0-client-1" "$V0-client-0" +TEST file_does_not_exist test-12/$src_file +EXPECT "1" file_is_linkto $dst_hash_brick/test-12/$dst_file +EXPECT "0" file_is_linkto $dst_cached_brick/test-12/$dst_file + +################### Test 13 #################################### + +# src_hash != src_cached +# dst_hash = dst_cached +# dst_hash != src_cached +# dst_hash != src_hash + +echo " **** Test 13 **** " + +TEST mkdir $M0/test-13 + + +# 1. Create src and dst files + +TEST first_filename_with_same_hashsubvol "$V0-client-0" "$M0/test-13" "src0-" +src0_file=$dstfilename +TEST touch $M0/test-13/$src0_file + +TEST first_filename_with_same_hashsubvol "$V0-client-1" "$M0/test-13" "src-" +src_file=$dstfilename + +mv $M0/test-13/$src0_file $M0/test-13/$src_file + + +TEST first_filename_with_same_hashsubvol "$V0-client-2" "$M0/test-13" "dst-" +dst_file=$dstfilename +TEST touch $M0/test-13/$dst_file + +# 2. Rename the file + +mv $M0/test-13/$src_file $M0/test-13/$dst_file + + +# 3. Validate + +dst_hash_brick=$(get_brick_path_for_subvol "$V0-client-2") +dst_cached_brick=$(get_brick_path_for_subvol "$V0-client-0") + +TEST stat $M0/test-13/$dst_file 2>/dev/null +TEST file_existence_check test-13/$dst_file "$V0-client-2" "$V0-client-0" +TEST file_does_not_exist test-13/$src_file +EXPECT "1" file_is_linkto $dst_hash_brick/test-13/$dst_file +EXPECT "0" file_is_linkto $dst_cached_brick/test-13/$dst_file + + +################### Test 14 #################################### + +# src_hash != src_cached +# dst_hash = src_hash +# dst_cached = src_cached + +echo " **** Test 14 **** " + +TEST mkdir $M0/test-14 + + +# 1. Create src and dst files + +TEST first_filename_with_same_hashsubvol "$V0-client-0" "$M0/test-14" "src0-" +src0_file=$dstfilename +TEST touch $M0/test-14/$src0_file + +TEST first_filename_with_same_hashsubvol "$V0-client-1" "$M0/test-14" "src-" +src_file=$dstfilename + +mv $M0/test-14/$src0_file $M0/test-14/$src_file + + +TEST first_filename_with_same_hashsubvol "$V0-client-0" "$M0/test-14" "dst0-" +dst0_file=$dstfilename +TEST touch $M0/test-14/$dst0_file + +TEST first_filename_with_same_hashsubvol "$V0-client-1" "$M0/test-14" "dst-" +dst_file=$dstfilename + +mv $M0/test-14/$dst0_file $M0/test-14/$dst_file + + +# 2. Rename the file + +mv $M0/test-14/$src_file $M0/test-14/$dst_file + + +# 3. Validate + +dst_hash_brick=$(get_brick_path_for_subvol "$V0-client-1") +dst_cached_brick=$(get_brick_path_for_subvol "$V0-client-0") + +TEST stat $M0/test-14/$dst_file 2>/dev/null +TEST file_existence_check test-14/$dst_file "$V0-client-1" "$V0-client-0" +TEST file_does_not_exist test-14/$src_file +EXPECT "1" file_is_linkto $dst_hash_brick/test-14/$dst_file +EXPECT "0" file_is_linkto $dst_cached_brick/test-14/$dst_file + +################### Test 15 #################################### + +# src_hash != src_cached +# dst_hash != src_hash +# dst_hash != src_cached +# dst_cached = src_cached + +echo " **** Test 15 **** " + +TEST mkdir $M0/test-15 + + +# 1. Create src and dst files + +TEST first_filename_with_same_hashsubvol "$V0-client-0" "$M0/test-15" "src0-" +src0_file=$dstfilename +TEST touch $M0/test-15/$src0_file + +TEST first_filename_with_same_hashsubvol "$V0-client-1" "$M0/test-15" "src-" +src_file=$dstfilename + +mv $M0/test-15/$src0_file $M0/test-15/$src_file + + +TEST first_filename_with_same_hashsubvol "$V0-client-0" "$M0/test-15" "dst0-" +dst0_file=$dstfilename +TEST touch $M0/test-15/$dst0_file + +TEST first_filename_with_same_hashsubvol "$V0-client-2" "$M0/test-15" "dst-" +dst_file=$dstfilename + +mv $M0/test-15/$dst0_file $M0/test-15/$dst_file + + +# 2. Rename the file + +mv $M0/test-15/$src_file $M0/test-15/$dst_file + +# 3. Validate + +dst_hash_brick=$(get_brick_path_for_subvol "$V0-client-2") +dst_cached_brick=$(get_brick_path_for_subvol "$V0-client-0") + +TEST stat $M0/test-15/$dst_file 2>/dev/null +TEST file_existence_check test-15/$dst_file "$V0-client-2" "$V0-client-0" +TEST file_does_not_exist test-15/$src_file +EXPECT "1" file_is_linkto $dst_hash_brick/test-15/$dst_file +EXPECT "0" file_is_linkto $dst_cached_brick/test-15/$dst_file + + + +################### Test 16 #################################### + +# src_hash != src_cached +# dst_hash = src_cached +# dst_cached = src_hash + +echo " **** Test 16 **** " + +TEST mkdir $M0/test-16 + + +# 1. Create src and dst files + +TEST first_filename_with_same_hashsubvol "$V0-client-0" "$M0/test-16" "src0-" +src0_file=$dstfilename +TEST touch $M0/test-16/$src0_file + +TEST first_filename_with_same_hashsubvol "$V0-client-1" "$M0/test-16" "src-" +src_file=$dstfilename + +mv $M0/test-16/$src0_file $M0/test-16/$src_file + + +TEST first_filename_with_same_hashsubvol "$V0-client-1" "$M0/test-16" "dst0-" +dst0_file=$dstfilename +TEST touch $M0/test-16/$dst0_file + +TEST first_filename_with_same_hashsubvol "$V0-client-0" "$M0/test-16" "dst-" +dst_file=$dstfilename + +mv $M0/test-16/$dst0_file $M0/test-16/$dst_file + + +# 2. Rename the file + +mv $M0/test-16/$src_file $M0/test-16/$dst_file + +# 3. Validate + +dst_hash_brick=$(get_brick_path_for_subvol "$V0-client-0") + +TEST stat $M0/test-16/$dst_file 2>/dev/null +TEST file_existence_check test-16/$dst_file "$V0-client-0" +TEST file_does_not_exist test-16/$src_file +EXPECT "0" file_is_linkto $dst_hash_brick/test-16/$dst_file + + +################### Test 17 #################################### + +# src_hash != src_cached +# dst_hash != dst_cached +# dst_hash != src_hash != src_cached +# dst_cached = src_hash + + +echo " **** Test 17 **** " + +TEST mkdir $M0/test-17 + + +# 1. Create src and dst files + +TEST first_filename_with_same_hashsubvol "$V0-client-0" "$M0/test-17" "src0-" +src0_file=$dstfilename +TEST touch $M0/test-17/$src0_file + +TEST first_filename_with_same_hashsubvol "$V0-client-1" "$M0/test-17" "src-" +src_file=$dstfilename + +mv $M0/test-17/$src0_file $M0/test-17/$src_file + + +TEST first_filename_with_same_hashsubvol "$V0-client-1" "$M0/test-17" "dst0-" +dst0_file=$dstfilename +TEST touch $M0/test-17/$dst0_file + +TEST first_filename_with_same_hashsubvol "$V0-client-2" "$M0/test-17" "dst-" +dst_file=$dstfilename + +mv $M0/test-17/$dst0_file $M0/test-17/$dst_file + + +# 2. Rename the file + +mv $M0/test-17/$src_file $M0/test-17/$dst_file + +# 3. Validate + +dst_hash_brick=$(get_brick_path_for_subvol "$V0-client-2") +dst_cached_brick=$(get_brick_path_for_subvol "$V0-client-0") + +TEST stat $M0/test-17/$dst_file 2>/dev/null +TEST file_existence_check test-17/$dst_file "$V0-client-2" "$V0-client-0" +TEST file_does_not_exist test-17/$src_file +EXPECT "1" file_is_linkto $dst_hash_brick/test-17/$dst_file +EXPECT "0" file_is_linkto $dst_cached_brick/test-17/$dst_file + + +################### Test 18 #################################### + +# src_hash != src_cached +# dst_hash != dst_cached +# dst_hash != src_hash != src_cached != dst_cached + + +echo " **** Test 18 **** " + +TEST mkdir $M0/test-18 + + +# 1. Create src and dst files + +TEST first_filename_with_same_hashsubvol "$V0-client-0" "$M0/test-18" "src0-" +src0_file=$dstfilename +TEST touch $M0/test-18/$src0_file + +TEST first_filename_with_same_hashsubvol "$V0-client-1" "$M0/test-18" "src-" +src_file=$dstfilename + +mv $M0/test-18/$src0_file $M0/test-18/$src_file + + +TEST first_filename_with_same_hashsubvol "$V0-client-2" "$M0/test-18" "dst0-" +dst0_file=$dstfilename +TEST touch $M0/test-18/$dst0_file + +TEST first_filename_with_same_hashsubvol "$V0-client-3" "$M0/test-18" "dst-" +dst_file=$dstfilename + +mv $M0/test-18/$dst0_file $M0/test-18/$dst_file + + +# 2. Rename the file + +mv $M0/test-18/$src_file $M0/test-18/$dst_file + +# 3. Validate + +dst_hash_brick=$(get_brick_path_for_subvol "$V0-client-3") +dst_cached_brick=$(get_brick_path_for_subvol "$V0-client-0") + +TEST stat $M0/test-18/$dst_file 2>/dev/null +TEST file_existence_check test-18/$dst_file "$V0-client-3" "$V0-client-0" +TEST file_does_not_exist test-18/$src_file +EXPECT "1" file_is_linkto $dst_hash_brick/test-18/$dst_file +EXPECT "0" file_is_linkto $dst_cached_brick/test-18/$dst_file + + +# Cleanup +cleanup + diff --git a/tests/basic/distribute/force-migration.t b/tests/basic/distribute/force-migration.t new file mode 100644 index 00000000000..f6c4997a505 --- /dev/null +++ b/tests/basic/distribute/force-migration.t @@ -0,0 +1,50 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +#This tests checks if the file migration fails with force-migration +#option set to off. + +cleanup; + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 $H0:$B0/${V0}0 $H0:$B0/${V0}1 +TEST $CLI volume set $V0 performance.quick-read off +TEST $CLI volume set $V0 performance.io-cache off +TEST $CLI volume set $V0 performance.write-behind off +TEST $CLI volume set $V0 performance.stat-prefetch off +TEST $CLI volume set $V0 performance.read-ahead off +TEST $CLI volume start $V0 +TEST glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0 --attribute-timeout=0 --entry-timeout=0 +TEST touch $M0/file +#This rename creates a link file for tile in the other brick. +TEST mv $M0/file $M0/tile +#Lets keep writing to the file which will have a open fd +dd if=/dev/zero of=$M0/tile bs=1b & +bg_pid=$! +#Now rebalance will try to skip the file +TEST $CLI volume set $V0 force-migration off +TEST $CLI volume rebalance $V0 start force +EXPECT_WITHIN $REBALANCE_TIMEOUT "completed" rebalance_status_field $V0 +skippedcount=`gluster v rebalance $V0 status | awk 'NR==3{print $6}'` +TEST [[ $skippedcount -eq 1 ]] +#file should be migrated now +TEST $CLI volume set $V0 force-migration on +TEST $CLI volume rebalance $V0 start force +EXPECT_WITHIN $REBALANCE_TIMEOUT "completed" rebalance_status_field $V0 +skippedcount=`gluster v rebalance $V0 status | awk 'NR==3{print $6}'` +rebalancedcount=`gluster v rebalance $V0 status | awk 'NR==3{print $2}'` +TEST [[ $skippedcount -eq 0 ]] +TEST [[ $rebalancedcount -eq 1 ]] +kill -9 $bg_pid > /dev/null 2>&1 +wait > /dev/null 2>&1 +cleanup +#Bad test because we are not sure writes are happening at the time of +#rebalance. We need to write a test case which makes sure client +#writes happen during rebalance. One way would be to set S+T bits on +#src and write to file from client and then start rebalance. Currently +#marking this as bad test. +#G_TESTDEF_TEST_STATUS_CENTOS6=BAD_TEST,BUG=000000 + diff --git a/tests/basic/distribute/lookup.t b/tests/basic/distribute/lookup.t new file mode 100644 index 00000000000..f757bd99fd9 --- /dev/null +++ b/tests/basic/distribute/lookup.t @@ -0,0 +1,54 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc +. $(dirname $0)/../../nfs.rc +. $(dirname $0)/../../common-utils.rc + +# Test overview: +# Check that non-privileged users can also clean up stale linkto files +# +# 1. Use the current parallel-readdir behaviour of changing the DHT child subvols +# in the graph to generate stale linkto files +# 2. Access the file with the stale linkto file as a non-root user +# 3. This should now succeed (returned EIO before commit 3fb1df7870e03c9de) + +cleanup + +TEST glusterd +TEST pidof glusterd + +TEST $CLI volume create $V0 $H0:$B0/$V0-{1..3} +TEST $CLI volume start $V0 + +# Mount using FUSE and create a file +TEST glusterfs -s $H0 --volfile-id $V0 $M0 +TEST glusterfs -s $H0 --volfile-id $V0 $M1 + +ls $M0/FILE-1 +EXPECT "2" echo $? + + +# Create a file and a directory on $M0 +TEST dd if=/dev/urandom of=$M0/FILE-1 count=1 bs=16k +TEST mkdir $M0/dir1 + +ls $M0/FILE-1 +EXPECT "0" echo $? + +ls $M0/dir1 +EXPECT "0" echo $? + +#Use a fresh mount so as to trigger a fresh lookup +TEST glusterfs -s $H0 --volfile-id $V0 $M1 + +TEST ls $M1/FILE-1 +EXPECT "0" echo $? + + +ls $M1/dir1 +EXPECT "0" echo $? + +# Cleanup +cleanup + diff --git a/tests/basic/distribute/non-root-unlink-stale-linkto.t b/tests/basic/distribute/non-root-unlink-stale-linkto.t new file mode 100644 index 00000000000..d6c866ffc8e --- /dev/null +++ b/tests/basic/distribute/non-root-unlink-stale-linkto.t @@ -0,0 +1,51 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc +. $(dirname $0)/../../nfs.rc +. $(dirname $0)/../../common-utils.rc + +# Test overview: +# Check that non-privileged users can also clean up stale linkto files +# +# 1. Use the current parallel-readdir behaviour of changing the DHT child subvols +# in the graph to generate stale linkto files +# 2. Access the file with the stale linkto file as a non-root user +# 3. This should now succeed (returned EIO before commit 3fb1df7870e03c9de) + +USERNAME=user11 +cleanup + +TEST glusterd +TEST pidof glusterd + +TEST $CLI volume create $V0 $H0:$B0/$V0-{1,2} +TEST $CLI volume start $V0 +TEST $CLI volume set $V0 performance.parallel-readdir on + +# Mount using FUSE and create a file +TEST glusterfs -s $H0 --volfile-id $V0 $M0 + +# Create a file for testing +TEST dd if=/dev/urandom of=$M0/FILE-1 count=1 bs=16k + +#Rename to create a linkto file +TEST mv $M0/FILE-1 $M0/FILE-2 + +# This should change the graph and cause the linkto values to become stale +TEST $CLI volume set $V0 performance.parallel-readdir off + +$CLI volume set $V0 allow-insecure on + + +TEST useradd -m $USERNAME + +#Use a fresh mount so as to trigger a lookup everywhere +TEST glusterfs -s $H0 --volfile-id $V0 $M1 +TEST run_cmd_as_user $USERNAME "ls $M1/FILE-2" + + +# Cleanup +TEST userdel --force $USERNAME +cleanup + diff --git a/tests/basic/distribute/spare_file_rebalance.t b/tests/basic/distribute/spare_file_rebalance.t new file mode 100644 index 00000000000..061c02f7392 --- /dev/null +++ b/tests/basic/distribute/spare_file_rebalance.t @@ -0,0 +1,51 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc +. $(dirname $0)/../../dht.rc + +# Initialize +#------------------------------------------------------------ +cleanup; + +# Start glusterd +TEST glusterd; +TEST pidof glusterd; +TEST $CLI volume info; + +# Create a volume +TEST $CLI volume create $V0 $H0:$B0/${V0}{1,2}; + +# Verify volume creation +EXPECT "$V0" volinfo_field $V0 'Volume Name'; +EXPECT 'Created' volinfo_field $V0 'Status'; + +# Start volume and verify successful start +TEST $CLI volume start $V0; +EXPECT 'Started' volinfo_field $V0 'Status'; +TEST glusterfs --volfile-id=$V0 --volfile-server=$H0 --entry-timeout=0 $M0; + +#------------------------------------------------------------ + +# Test case - Create sparse files on MP and verify +# file info after rebalance +#------------------------------------------------------------ + +# Create some sparse files and get their size +TEST cd $M0; +dd if=/dev/urandom of=sparse_file bs=10k count=1 seek=2M +cp --sparse=always sparse_file sparse_file_3; + +# Add a 3rd brick +TEST $CLI volume add-brick $V0 $H0:$B0/${V0}3; + +# Trigger rebalance +TEST $CLI volume rebalance $V0 start force; +EXPECT_WITHIN $REBALANCE_TIMEOUT "0" rebalance_completed; + +# Compare original and rebalanced files +TEST cd $B0/${V0}2 +TEST cmp sparse_file $B0/${V0}3/sparse_file_3 +EXPECT_WITHIN 30 ""; + +cleanup; diff --git a/tests/basic/distribute/throttle-rebal.t b/tests/basic/distribute/throttle-rebal.t new file mode 100644 index 00000000000..f4823cf4f21 --- /dev/null +++ b/tests/basic/distribute/throttle-rebal.t @@ -0,0 +1,56 @@ +#!/bin/bash +# Test to check +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +#Check rebal-throttle set option sanity +cleanup; + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 $H0:$B0/brick1 $H0:$B0/brick2 +TEST $CLI volume start $V0 + +function set_throttle { + local level=$1 + $CLI volume set $V0 cluster.rebal-throttle $level 2>&1 |grep -oE 'success|failed' +} + +#Determine number of cores +cores=$(cat /proc/cpuinfo | grep processor | wc -l) +if [ "$cores" == "" ]; then + echo "Could not get number of cores available" +fi + +THROTTLE_LEVEL="lazy" +EXPECT "success" set_throttle $THROTTLE_LEVEL +EXPECT "$THROTTLE_LEVEL" echo `$CLI volume info | grep rebal-throttle | awk '{print $2}'` + +THROTTLE_LEVEL="normal" +EXPECT "success" set_throttle $THROTTLE_LEVEL +EXPECT "$THROTTLE_LEVEL" echo `$CLI volume info | grep rebal-throttle | awk '{print $2}'` + + +THROTTLE_LEVEL="aggressive" +EXPECT "success" set_throttle $THROTTLE_LEVEL +EXPECT "$THROTTLE_LEVEL" echo `$CLI volume info | grep rebal-throttle | awk '{print $2}'` + +THROTTLE_LEVEL="garbage" +EXPECT "failed" set_throttle $THROTTLE_LEVEL + +#check if throttle-level is still aggressive +EXPECT "aggressive" echo `$CLI volume info | grep rebal-throttle | awk '{print $2}'` + +EXPECT "success" set_throttle $cores + +#Setting thorttle number to be more than the number of cores should fail +THORTTLE_LEVEL=$((cores+1)) +TEST echo $THORTTLE_LEVEL +EXPECT "failed" set_throttle $THROTTLE_LEVEL +EXPECT "$cores" echo `$CLI volume info | grep rebal-throttle | awk '{print $2}'` + + +TEST $CLI volume stop $V0; +TEST $CLI volume delete $V0; + +cleanup; diff --git a/tests/basic/ec/dht-rename.t b/tests/basic/ec/dht-rename.t new file mode 100644 index 00000000000..81b41ff4c78 --- /dev/null +++ b/tests/basic/ec/dht-rename.t @@ -0,0 +1,19 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +# This test checks notify part of ec + +cleanup +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 disperse 3 redundancy 1 $H0:$B0/${V0}{0..5} +TEST $CLI volume start $V0 + +TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0; +EXPECT_WITHIN $CHILD_UP_TIMEOUT "3" ec_child_up_count $V0 0 + +TEST touch $M0/1 +TEST mv $M0/1 $M0/10 +cleanup diff --git a/tests/basic/ec/ec-1468261.t b/tests/basic/ec/ec-1468261.t new file mode 100644 index 00000000000..77d704cf880 --- /dev/null +++ b/tests/basic/ec/ec-1468261.t @@ -0,0 +1,95 @@ +#!/bin/bash +# +# This test case verifies handling node down scenario with optimistic +# changelog enabled on EC volume. +### + +SCRIPT_TIMEOUT=300 + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +cleanup + +#cleate and start volume +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 disperse 6 redundancy 2 $H0:$B0/${V0}{0..5} +TEST $CLI volume set $V0 disperse.optimistic-change-log on +TEST $CLI volume set $V0 disperse.other-eager-lock on +TEST $CLI volume start $V0 + +#Mount the volume +TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0; +EXPECT_WITHIN $CHILD_UP_TIMEOUT "6" ec_child_up_count $V0 0 + +#Verify that all is good +TEST mkdir $M0/test_dir +TEST touch $M0/test_dir/file +sleep 2 +EXPECT_WITHIN $IO_WAIT_TIMEOUT "^$" get_hex_xattr trusted.ec.dirty $B0/${V0}0/test_dir +EXPECT_WITHIN $IO_WAIT_TIMEOUT "^$" get_hex_xattr trusted.ec.dirty $B0/${V0}1/test_dir +EXPECT_WITHIN $IO_WAIT_TIMEOUT "^$" get_hex_xattr trusted.ec.dirty $B0/${V0}2/test_dir +EXPECT_WITHIN $IO_WAIT_TIMEOUT "^$" get_hex_xattr trusted.ec.dirty $B0/${V0}3/test_dir +EXPECT_WITHIN $IO_WAIT_TIMEOUT "^$" get_hex_xattr trusted.ec.dirty $B0/${V0}4/test_dir +EXPECT_WITHIN $IO_WAIT_TIMEOUT "^$" get_hex_xattr trusted.ec.dirty $B0/${V0}5/test_dir + +#Kill two bricks and touch a file +TEST kill_brick $V0 $H0 $B0/${V0}0 +TEST kill_brick $V0 $H0 $B0/${V0}1 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "4" ec_child_up_count $V0 0 +TEST touch $M0/test_dir/new_file +sleep 2 + +#Dirty should be set on up bricks +EXPECT_WITHIN $IO_WAIT_TIMEOUT "^00000000000000010000000000000001$" get_hex_xattr trusted.ec.dirty $B0/${V0}2/test_dir +EXPECT_WITHIN $IO_WAIT_TIMEOUT "^00000000000000010000000000000001$" get_hex_xattr trusted.ec.dirty $B0/${V0}3/test_dir +EXPECT_WITHIN $IO_WAIT_TIMEOUT "^00000000000000010000000000000001$" get_hex_xattr trusted.ec.dirty $B0/${V0}4/test_dir +EXPECT_WITHIN $IO_WAIT_TIMEOUT "^00000000000000010000000000000001$" get_hex_xattr trusted.ec.dirty $B0/${V0}5/test_dir + +#Bring up the down bricks +TEST $CLI volume start $V0 force +EXPECT_WITHIN $CHILD_UP_TIMEOUT "6" ec_child_up_count $V0 0 + +#remove mount point contents +TEST rm -rf $M0"/*" 2>/dev/null + +# unmount and remount the volume +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 +TEST glusterfs -s $H0 --volfile-id $V0 $M0; + +#Create a tar file +TEST mkdir /tmp/test_dir +seq 1 3000 | xargs -n 1 -P 20 -I {} dd if=/dev/urandom of=/tmp/test_dir/file-{} bs=10K count=1 +tar -cf /tmp/test_dir.tar /tmp/test_dir/ 2>/dev/null +rm -rf /tmp/test_dir/ + +#Untar the tar file +tar -C $M0 -xf /tmp/test_dir.tar 2>/dev/null& + +#Kill 1st and 2nd brick +TEST kill_brick $V0 $H0 $B0/${V0}0 +TEST kill_brick $V0 $H0 $B0/${V0}1 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "4" ec_child_up_count $V0 0 + +#Stop untaring +TEST kill %1 +rm -f /tmp/test_dir.tar + +#Bring up the down bricks +TEST $CLI volume start $V0 force +EXPECT_WITHIN $CHILD_UP_TIMEOUT "6" ec_child_up_count $V0 0 + +#Wait for heal to complete +EXPECT_WITHIN $HEAL_TIMEOUT "^0$" get_pending_heal_count $V0 + +#Kill 3rd and 4th brick +TEST kill_brick $V0 $H0 $B0/${V0}3 +TEST kill_brick $V0 $H0 $B0/${V0}4 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "4" ec_child_up_count $V0 0 + +#remove mount point contents +#this will fail if things are wrong +TEST rm -rf $M0"/*" 2>/dev/null + +cleanup diff --git a/tests/basic/ec/ec-3-1.t b/tests/basic/ec/ec-3-1.t new file mode 100644 index 00000000000..511ca6420a2 --- /dev/null +++ b/tests/basic/ec/ec-3-1.t @@ -0,0 +1,14 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +# This test checks basic dispersed volume functionality and cli interface + +DISPERSE=3 +REDUNDANCY=1 + +# This must be equal to 36 * $DISPERSE + 109 +TESTS_EXPECTED_IN_LOOP=217 + +. $(dirname $0)/ec-common diff --git a/tests/basic/ec/ec-4-1.t b/tests/basic/ec/ec-4-1.t new file mode 100644 index 00000000000..3f0d0c72e44 --- /dev/null +++ b/tests/basic/ec/ec-4-1.t @@ -0,0 +1,14 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +# This test checks basic dispersed volume functionality and cli interface + +DISPERSE=4 +REDUNDANCY=1 + +# This must be equal to 36 * $DISPERSE + 109 +TESTS_EXPECTED_IN_LOOP=253 + +. $(dirname $0)/ec-common diff --git a/tests/basic/ec/ec-5-2.t b/tests/basic/ec/ec-5-2.t new file mode 100644 index 00000000000..6d9e91b0f58 --- /dev/null +++ b/tests/basic/ec/ec-5-2.t @@ -0,0 +1,14 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +# This test checks basic dispersed volume functionality and cli interface + +DISPERSE=5 +REDUNDANCY=2 + +# This must be equal to 36 * $DISPERSE + 109 +TESTS_EXPECTED_IN_LOOP=289 + +. $(dirname $0)/ec-common diff --git a/tests/basic/ec/ec-6-2.t b/tests/basic/ec/ec-6-2.t new file mode 100644 index 00000000000..b4451f905a1 --- /dev/null +++ b/tests/basic/ec/ec-6-2.t @@ -0,0 +1,14 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +# This test checks basic dispersed volume functionality and cli interface + +DISPERSE=6 +REDUNDANCY=2 + +# This must be equal to 36 * $DISPERSE + 109 +TESTS_EXPECTED_IN_LOOP=325 + +. $(dirname $0)/ec-common diff --git a/tests/basic/ec/ec-anonymous-fd.t b/tests/basic/ec/ec-anonymous-fd.t new file mode 100644 index 00000000000..a61628182ef --- /dev/null +++ b/tests/basic/ec/ec-anonymous-fd.t @@ -0,0 +1,42 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc +. $(dirname $0)/../../fileio.rc + +cleanup +function num_entries { + ls -l $1 | wc -l +} + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 disperse 6 redundancy 2 $H0:$B0/${V0}{0..5} +TEST $CLI volume start $V0 +TEST glusterfs --entry-timeout=0 --attribute-timeout=0 -s $H0 --volfile-id $V0 $M0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "6" ec_child_up_count $V0 0 + +fd1=`fd_available` +TEST fd_open $fd1 'w' $M0/file1 +TEST fd_write $fd1 testing +TEST cat $M0/file1 +TEST rm -rf $M0/file1 +TEST fd_write $fd1 testing +TEST fd_write $fd1 testing +TEST fd_write $fd1 testing + +EXPECT "^2$" num_entries $B0/${V0}0/.glusterfs/unlink/ +EXPECT "^2$" num_entries $B0/${V0}1/.glusterfs/unlink/ +EXPECT "^2$" num_entries $B0/${V0}2/.glusterfs/unlink/ +EXPECT "^2$" num_entries $B0/${V0}3/.glusterfs/unlink/ +EXPECT "^2$" num_entries $B0/${V0}4/.glusterfs/unlink/ +EXPECT "^2$" num_entries $B0/${V0}5/.glusterfs/unlink/ +TEST fd_close $fd1; +EXPECT_WITHIN $UNLINK_TIMEOUT "^1$" num_entries $B0/${V0}0/.glusterfs/unlink/ +EXPECT_WITHIN $UNLINK_TIMEOUT "^1$" num_entries $B0/${V0}1/.glusterfs/unlink/ +EXPECT_WITHIN $UNLINK_TIMEOUT "^1$" num_entries $B0/${V0}2/.glusterfs/unlink/ +EXPECT_WITHIN $UNLINK_TIMEOUT "^1$" num_entries $B0/${V0}3/.glusterfs/unlink/ +EXPECT_WITHIN $UNLINK_TIMEOUT "^1$" num_entries $B0/${V0}4/.glusterfs/unlink/ +EXPECT_WITHIN $UNLINK_TIMEOUT "^1$" num_entries $B0/${V0}5/.glusterfs/unlink/ + +cleanup; diff --git a/tests/basic/ec/ec-background-heals.t b/tests/basic/ec/ec-background-heals.t new file mode 100644 index 00000000000..29778a4f818 --- /dev/null +++ b/tests/basic/ec/ec-background-heals.t @@ -0,0 +1,105 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +# This test checks background heals option + +cleanup +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 disperse 3 redundancy 1 $H0:$B0/${V0}{0..2} +TEST $CLI volume heal $V0 disable +TEST $CLI volume set $V0 performance.stat-prefetch off +TEST $CLI volume set $V0 performance.write-behind off +TEST $CLI volume set $V0 performance.quick-read off +TEST $CLI volume set $V0 performance.read-ahead off +TEST $CLI volume set $V0 performance.io-cache off +TEST $CLI volume set $V0 disperse.background-heals 0 +TEST $CLI volume set $V0 disperse.eager-lock off +TEST $CLI volume set $V0 disperse.other-eager-lock off +TEST $CLI volume start $V0 + +TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0; +EXPECT_WITHIN $CHILD_UP_TIMEOUT "3" ec_child_up_count $V0 0 +EXPECT_WITHIN $CONFIG_UPDATE_TIMEOUT "0" mount_get_option_value $M0 $V0-disperse-0 background-heals +EXPECT_WITHIN $CONFIG_UPDATE_TIMEOUT "0" mount_get_option_value $M0 $V0-disperse-0 heal-wait-qlength +TEST touch $M0/a +EXPECT_WITHIN $HEAL_TIMEOUT "^0$" count_sh_entries $B0/${V0}0 +EXPECT_WITHIN $HEAL_TIMEOUT "^0$" count_sh_entries $B0/${V0}1 +EXPECT_WITHIN $HEAL_TIMEOUT "^0$" count_sh_entries $B0/${V0}2 + +TEST kill_brick $V0 $H0 $B0/${V0}2 +echo abc > $M0/a +EXPECT 2 get_pending_heal_count $V0 #One for each active brick +$CLI volume start $V0 force +EXPECT_WITHIN $CHILD_UP_TIMEOUT "3" ec_child_up_count $V0 0 +#Accessing file shouldn't heal the file +EXPECT "abc" cat $M0/a +EXPECT 2 get_pending_heal_count $V0 #One for each active brick +TEST $CLI volume set $V0 disperse.background-heals 1 +EXPECT_WITHIN $CONFIG_UPDATE_TIMEOUT "1" mount_get_option_value $M0 $V0-disperse-0 background-heals +EXPECT_WITHIN $CONFIG_UPDATE_TIMEOUT "128" mount_get_option_value $M0 $V0-disperse-0 heal-wait-qlength +#Accessing file should heal the file now +EXPECT "abc" cat $M0/a +EXPECT_WITHIN $HEAL_TIMEOUT "^0$" get_pending_heal_count $V0 + +#Test above test cases with reset instead of setting background-heals to 1 +TEST $CLI volume set $V0 disperse.heal-wait-qlength 1024 +EXPECT_WITHIN $CONFIG_UPDATE_TIMEOUT "1" mount_get_option_value $M0 $V0-disperse-0 background-heals +EXPECT_WITHIN $CONFIG_UPDATE_TIMEOUT "1024" mount_get_option_value $M0 $V0-disperse-0 heal-wait-qlength +TEST $CLI volume set $V0 disperse.background-heals 0 +EXPECT_WITHIN $CONFIG_UPDATE_TIMEOUT "0" mount_get_option_value $M0 $V0-disperse-0 background-heals +EXPECT_WITHIN $CONFIG_UPDATE_TIMEOUT "0" mount_get_option_value $M0 $V0-disperse-0 heal-wait-qlength +TEST $CLI volume set $V0 disperse.heal-wait-qlength 200 #Changing qlength shouldn't affect anything now +EXPECT_WITHIN $CONFIG_UPDATE_TIMEOUT "0" mount_get_option_value $M0 $V0-disperse-0 background-heals +EXPECT_WITHIN $CONFIG_UPDATE_TIMEOUT "0" mount_get_option_value $M0 $V0-disperse-0 heal-wait-qlength +TEST kill_brick $V0 $H0 $B0/${V0}2 +echo abc > $M0/a +EXPECT 2 get_pending_heal_count $V0 #One for each active brick +$CLI volume start $V0 force +EXPECT_WITHIN $CHILD_UP_TIMEOUT "3" ec_child_up_count $V0 0 +#Accessing file shouldn't heal the file +EXPECT "abc" cat $M0/a +sleep 3 +EXPECT 2 get_pending_heal_count $V0 #One for each active brick +TEST $CLI volume reset $V0 disperse.background-heals +EXPECT_WITHIN $CONFIG_UPDATE_TIMEOUT "8" mount_get_option_value $M0 $V0-disperse-0 background-heals +EXPECT_WITHIN $CONFIG_UPDATE_TIMEOUT "200" mount_get_option_value $M0 $V0-disperse-0 heal-wait-qlength +#Accessing file should heal the file now +EXPECT "abc" cat $M0/a +EXPECT_WITHIN $HEAL_TIMEOUT "^0$" get_pending_heal_count $V0 + +#Test that disabling background-heals still drains the queue +TEST $CLI volume set $V0 disperse.background-heals 1 +TEST touch $M0/{a,b,c,d} +TEST kill_brick $V0 $H0 $B0/${V0}2 +EXPECT_WITHIN $CONFIG_UPDATE_TIMEOUT "1" mount_get_option_value $M0 $V0-disperse-0 background-heals +EXPECT_WITHIN $CONFIG_UPDATE_TIMEOUT "200" mount_get_option_value $M0 $V0-disperse-0 heal-wait-qlength +TEST truncate -s 1GB $M0/a +echo abc > $M0/b +echo abc > $M0/c +echo abc > $M0/d +TEST $CLI volume start $V0 force +EXPECT_WITHIN $CHILD_UP_TIMEOUT "3" ec_child_up_count $V0 0 +TEST chown root:root $M0/{a,b,c,d} +TEST $CLI volume set $V0 disperse.background-heals 0 +EXPECT_NOT "0" mount_get_option_value $M0 $V0-disperse-0 heal-waiters +TEST truncate -s 0 $M0/a # This completes the heal fast ;-) +EXPECT_WITHIN $HEAL_TIMEOUT "^0$" get_pending_heal_count $V0 + +#Test that background heals get rejected on meeting background-qlen limit +TEST $CLI volume set $V0 disperse.background-heals 1 +TEST $CLI volume set $V0 disperse.heal-wait-qlength 0 +TEST kill_brick $V0 $H0 $B0/${V0}2 +EXPECT_WITHIN $CONFIG_UPDATE_TIMEOUT "1" mount_get_option_value $M0 $V0-disperse-0 background-heals +EXPECT_WITHIN $CONFIG_UPDATE_TIMEOUT "0" mount_get_option_value $M0 $V0-disperse-0 heal-wait-qlength +TEST truncate -s 1GB $M0/a +echo abc > $M0/b +echo abc > $M0/c +echo abc > $M0/d +TEST $CLI volume start $V0 force +EXPECT_WITHIN $CHILD_UP_TIMEOUT "3" ec_child_up_count $V0 0 +TEST chown root:root $M0/{a,b,c,d} +EXPECT "0" mount_get_option_value $M0 $V0-disperse-0 heal-waiters +cleanup diff --git a/tests/basic/ec/ec-badfd.c b/tests/basic/ec/ec-badfd.c new file mode 100644 index 00000000000..8be23c10eaf --- /dev/null +++ b/tests/basic/ec/ec-badfd.c @@ -0,0 +1,124 @@ +#include <stdio.h> +#include <fcntl.h> +#include <unistd.h> +#include <time.h> +#include <limits.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <glusterfs/api/glfs.h> +#include <glusterfs/api/glfs-handles.h> + +int +fill_iov(struct iovec *iov, char fillchar, int count) +{ + int ret = -1; + + iov->iov_base = malloc(count + 1); + if (iov->iov_base == NULL) { + return ret; + } else { + iov->iov_len = count; + ret = 0; + } + memset(iov->iov_base, fillchar, count); + memset(iov->iov_base + count, '\0', 1); + + return ret; +} + +int +write_sync(glfs_t *fs, glfs_fd_t *glfd, int char_count) +{ + ssize_t ret = -1; + int flags = O_RDWR; + struct iovec iov = {0}; + + ret = fill_iov(&iov, 'a', char_count); + if (ret) { + fprintf(stderr, "failed to create iov"); + goto out; + } + + ret = glfs_pwritev(glfd, &iov, 1, 0, flags); +out: + if (ret < 0) { + fprintf(stderr, "glfs_pwritev failed, %d", errno); + } + return ret; +} + +int +main(int argc, char *argv[]) +{ + glfs_t *fs = NULL; + glfs_fd_t *fd = NULL; + int ret = 1; + char volume_cmd[4096] = {0}; + + if (argc != 4) { + fprintf(stderr, "Syntax: %s <host> <volname> <file>\n", argv[0]); + return 1; + } + + fs = glfs_new(argv[2]); + if (!fs) { + fprintf(stderr, "glfs_new: returned NULL\n"); + return 1; + } + + ret = glfs_set_volfile_server(fs, "tcp", argv[1], 24007); + if (ret != 0) { + fprintf(stderr, "glfs_set_volfile_server: returned %d\n", ret); + goto out; + } + ret = glfs_set_logging(fs, "/tmp/ec-badfd.log", 7); + if (ret != 0) { + fprintf(stderr, "glfs_set_logging: returned %d\n", ret); + goto out; + } + ret = glfs_init(fs); + if (ret != 0) { + fprintf(stderr, "glfs_init: returned %d\n", ret); + goto out; + } + + fd = glfs_open(fs, argv[3], O_RDWR); + if (fd == NULL) { + fprintf(stderr, "glfs_open: returned NULL\n"); + goto out; + } + + ret = write_sync(fs, fd, 16); + if (ret < 0) { + fprintf(stderr, "write_sync failed\n"); + } + + snprintf(volume_cmd, sizeof(volume_cmd), + "gluster --mode=script volume stop %s", argv[2]); + /*Stop the volume so that update-size-version fails*/ + system(volume_cmd); + sleep(8); /* 3 seconds more than eager-lock-timeout*/ + snprintf(volume_cmd, sizeof(volume_cmd), + "gluster --mode=script volume start %s", argv[2]); + system(volume_cmd); + sleep(8); /*wait for bricks to come up*/ + ret = glfs_fsync(fd, NULL, NULL); + if (ret == 0) { + fprintf(stderr, "fsync succeeded on a BADFD\n"); + exit(1); + } + + ret = glfs_close(fd); + if (ret == 0) { + fprintf(stderr, "flush succeeded on a BADFD\n"); + exit(1); + } + ret = 0; + +out: + unlink("/tmp/ec-badfd.log"); + glfs_fini(fs); + + return ret; +} diff --git a/tests/basic/ec/ec-badfd.t b/tests/basic/ec/ec-badfd.t new file mode 100755 index 00000000000..56feb47f115 --- /dev/null +++ b/tests/basic/ec/ec-badfd.t @@ -0,0 +1,26 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +cleanup; + +TEST glusterd +TEST pidof glusterd + +TEST $CLI volume create $V0 disperse 6 redundancy 2 $H0:$B0/${V0}{1..6} +TEST $CLI volume set $V0 performance.write-behind off +TEST $CLI volume set $V0 disperse.eager-lock-timeout 5 + +TEST $CLI volume start $V0 +EXPECT 'Started' volinfo_field $V0 'Status' + +TEST $GFS -s $H0 --volfile-id $V0 $M0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "6" ec_child_up_count $V0 0 +TEST touch $M0/file + +TEST build_tester $(dirname $0)/ec-badfd.c -lgfapi -Wall -O2 +TEST $(dirname $0)/ec-badfd $H0 $V0 /file +cleanup_tester $(dirname ${0})/ec-badfd + +cleanup; diff --git a/tests/basic/ec/ec-common b/tests/basic/ec/ec-common new file mode 100644 index 00000000000..152e3b51236 --- /dev/null +++ b/tests/basic/ec/ec-common @@ -0,0 +1,145 @@ +SIZE_LIST="1048576 1000 12345 0" + +LAST_BRICK=$(($DISPERSE - 1)) + +CHUNK_SIZE=512 + +function fragment_size +{ + local fragments=$(($DISPERSE - $REDUNDANCY)) + local block_size=$(($CHUNK_SIZE * $fragments)) + local size=$(($1 + $block_size - 1)) + + echo $((( $size - ( $size ) % $block_size ) / $fragments)) +} + +cleanup + +tmp=`mktemp -d -t ${0##*/}.XXXXXX` +if [ ! -d $tmp ]; then + exit 1 +fi + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 redundancy $REDUNDANCY $H0:$B0/${V0}{0..$LAST_BRICK} +EXPECT 'Created' volinfo_field $V0 'Status' +TEST $CLI volume start $V0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT 'Started' volinfo_field $V0 'Status' +TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "$DISPERSE" ec_child_up_count $V0 0 + +TEST dd if=/dev/urandom of=$tmp/small bs=1024 count=1 +TEST dd if=/dev/urandom of=$tmp/big bs=1024 count=4096 + +cs_small=$(sha1sum $tmp/small | awk '{ print $1 }') +cs_big=$(sha1sum $tmp/big | awk '{ print $1 }') +cp $tmp/small $tmp/small1 +for size in $SIZE_LIST; do + truncate -s $size $tmp/small1 + eval cs_small_truncate[$size]=$(sha1sum $tmp/small1 | awk '{ print $1 }') +done +cp $tmp/big $tmp/big1 +for size in $SIZE_LIST; do + truncate -s $size $tmp/big1 + eval cs_big_truncate[$size]=$(sha1sum $tmp/big1 | awk '{ print $1 }') +done + +TEST df -h $M0 +TEST stat $M0 + +for idx in `seq 0 $LAST_BRICK`; do + brick[$idx]=$(gf_get_gfid_backend_file_path $B0/$V0$idx) +done + +TEST stat $M0/ +TEST mkdir $M0/dir1 +TEST [ -d $M0/dir1 ] +TEST touch $M0/file1 +TEST [ -f $M0/file1 ] + +for dir in . dir1; do + TEST cp $tmp/small $M0/$dir/small + TEST [ -f $M0/$dir/small ] + fsize=$(fragment_size 1024) + EXPECT "1024" stat -c "%s" $M0/$dir/small + for idx in `seq 0 $LAST_BRICK`; do + EXPECT "$fsize" stat -c "%s" ${brick[$idx]}/$dir/small + done + + EXPECT "$cs_small" echo $(sha1sum $M0/$dir/small | awk '{ print $1 }') + + TEST cp $tmp/big $M0/$dir/big + TEST [ -f $M0/$dir/big ] + fsize=$(fragment_size 4194304) + EXPECT "4194304" stat -c "%s" $M0/$dir/big + for idx in `seq 0 $LAST_BRICK`; do + EXPECT "$fsize" stat -c "%s" ${brick[$idx]}/$dir/big + done + + EXPECT "$cs_big" echo $(sha1sum $M0/$dir/big | awk '{ print $1 }') + +# Give enough time for current operations to complete. Otherwise the +# following kill_brick can cause data corruption and self-heal will be +# needed, but this script is not prepared to handle self-healing. + sleep 2 + + for idx in `seq 0 $LAST_BRICK`; do + TEST kill_brick $V0 $H0 $B0/$V0$idx + + EXPECT "1024" stat -c "%s" $M0/$dir/small + EXPECT "4194304" stat -c "%s" $M0/$dir/big + + TEST $CLI volume start $V0 force + EXPECT_WITHIN $CHILD_UP_TIMEOUT "$DISPERSE" ec_child_up_count $V0 0 + done + + for size in $SIZE_LIST; do + TEST truncate -s $size $M0/$dir/small + TEST [ -f $M0/$dir/small ] + fsize=$(fragment_size $size) + EXPECT "$size" stat -c "%s" $M0/$dir/small + for idx in `seq 0 $LAST_BRICK`; do + EXPECT "$fsize" stat -c "%s" ${brick[$idx]}/$dir/small + done + + EXPECT "${cs_small_truncate[$size]}" echo $(sha1sum $M0/$dir/small | awk '{ print $1 }') + + TEST truncate -s $size $M0/$dir/big + TEST [ -f $M0/$dir/big ] + EXPECT "$size" stat -c "%s" $M0/$dir/big + for idx in `seq 0 $LAST_BRICK`; do + EXPECT "$fsize" stat -c "%s" ${brick[$idx]}/$dir/big + done + + EXPECT "${cs_big_truncate[$size]}" echo $(sha1sum $M0/$dir/big | awk '{ print $1 }') + done + + TEST rm -f $M0/$dir/small + TEST [ ! -e $M0/$dir/small ] + for idx in `seq 0 $LAST_BRICK`; do + TEST [ ! -e ${brick[$idx]}/$dir/small ] + done + + TEST rm -f $M0/$dir/big + TEST [ ! -e $M0/$dir/big ] + for idx in `seq 0 $LAST_BRICK`; do + TEST [ ! -e ${brick[$idx]}/$dir/big ] + done +done + +TEST rmdir $M0/dir1 +TEST [ ! -e $M0/dir1 ] +for idx in `seq 0 $LAST_BRICK`; do + TEST [ ! -e ${brick[$idx]}/dir1 ] +done + +TEST rm -f $M0/file1 +TEST [ ! -e $M0/file1 ] +for idx in `seq 0 $LAST_BRICK`; do + TEST [ ! -e ${brick[$idx]}/file1 ] +done + +rm -rf $tmp + +cleanup diff --git a/tests/basic/ec/ec-cpu-extensions.t b/tests/basic/ec/ec-cpu-extensions.t new file mode 100644 index 00000000000..c9af27ea234 --- /dev/null +++ b/tests/basic/ec/ec-cpu-extensions.t @@ -0,0 +1,62 @@ +#!/bin/bash + +DISPERSE=18 +REDUNDANCY=2 + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +TESTS_EXPECTED_IN_LOOP=96 + +function check_contents +{ + local src=$1 + local cs=$2 + + TEST cp $src $M0/file + TEST [ -f $M0/file ] + + for ext in none x64 sse avx; do + EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 + TEST $CLI volume set $V0 disperse.cpu-extensions $ext + TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0 + EXPECT_WITHIN $CHILD_UP_TIMEOUT "$DISPERSE" ec_child_up_count $V0 0 + + EXPECT "$cs" echo $(sha1sum $M0/file | awk '{ print $1 }') + done + + TEST rm -f $M0/file +} + +cleanup + +tmp=`mktemp -p ${LOGDIR} -d -t ${0##*/}.XXXXXX` +if [ ! -d $tmp ]; then + exit 1 +fi + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 redundancy $REDUNDANCY $H0:$B0/${V0}{1..$DISPERSE} +TEST $CLI volume set $V0 performance.flush-behind off +TEST $CLI volume set $V0 disperse.read-policy round-robin +EXPECT 'Created' volinfo_field $V0 'Status' +TEST $CLI volume start $V0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT 'Started' volinfo_field $V0 'Status' + +TEST dd if=/dev/urandom of=$tmp/file bs=1048576 count=1 +cs_file=$(sha1sum $tmp/file | awk '{ print $1 }') + +for ext in none x64 sse avx; do + TEST $CLI volume set $V0 disperse.cpu-extensions $ext + TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0 + EXPECT_WITHIN $CHILD_UP_TIMEOUT "$DISPERSE" ec_child_up_count $V0 0 + + check_contents $tmp/file $cs_file + + EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 +done + +TEST rm -rf $tmp + +cleanup diff --git a/tests/basic/ec/ec-data-heal.t b/tests/basic/ec/ec-data-heal.t new file mode 100755 index 00000000000..2672661c6b1 --- /dev/null +++ b/tests/basic/ec/ec-data-heal.t @@ -0,0 +1,75 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +#This test checks data corruption after heal while IO is going on + +cleanup +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 disperse 3 redundancy 1 $H0:$B0/${V0}{0..2} +TEST $CLI volume start $V0 + +TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0; +EXPECT_WITHIN $CHILD_UP_TIMEOUT "3" ec_child_up_count $V0 0 + +############ Start IO ########### +TEST touch $M0/file +#start background IO on file +dd if=/dev/urandom of=$M0/file conv=fdatasync & +iopid=$(echo $!) + + +############ Kill and start brick0 for heal ########### +TEST kill_brick $V0 $H0 $B0/${V0}0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "2" ec_child_up_count $V0 0 +#sleep so that data can be written which will be healed later +sleep 10 +TEST $CLI volume start $V0 force +##wait for heal info to become 0 and kill IO +EXPECT_WITHIN $IO_HEAL_TIMEOUT "^0$" get_pending_heal_count $V0 +kill $iopid +EXPECT_WITHIN $IO_HEAL_TIMEOUT "^0$" get_pending_heal_count $V0 + +############### Check md5sum ######################### + +## unmount and mount get md5sum after killing brick0 + +TEST kill_brick $V0 $H0 $B0/${V0}0 + +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 +TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0; +EXPECT_WITHIN $CHILD_UP_TIMEOUT "2" ec_child_up_count $V0 0 +mdsum0=`md5sum $M0/file | awk '{print $1}'` +TEST $CLI volume start $V0 force +EXPECT_WITHIN $CHILD_UP_TIMEOUT "3" ec_child_up_count $V0 0 + +## unmount and mount get md5sum after killing brick1 + +TEST kill_brick $V0 $H0 $B0/${V0}1 + +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 +TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0; +EXPECT_WITHIN $CHILD_UP_TIMEOUT "2" ec_child_up_count $V0 0 +mdsum1=`md5sum $M0/file | awk '{print $1}'` +TEST $CLI volume start $V0 force +EXPECT_WITHIN $CHILD_UP_TIMEOUT "3" ec_child_up_count $V0 0 + +## unmount and mount get md5sum after killing brick2 + +TEST kill_brick $V0 $H0 $B0/${V0}2 + +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 +TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0; +EXPECT_WITHIN $CHILD_UP_TIMEOUT "2" ec_child_up_count $V0 0 +mdsum2=`md5sum $M0/file | awk '{print $1}'` +TEST $CLI volume start $V0 force +EXPECT_WITHIN $CHILD_UP_TIMEOUT "3" ec_child_up_count $V0 0 + +# compare all the three md5sums +EXPECT "$mdsum0" echo $mdsum1 +EXPECT "$mdsum0" echo $mdsum2 +EXPECT "$mdsum1" echo $mdsum2 + +cleanup diff --git a/tests/basic/ec/ec-dirty-flags.t b/tests/basic/ec/ec-dirty-flags.t new file mode 100644 index 00000000000..68e66103f08 --- /dev/null +++ b/tests/basic/ec/ec-dirty-flags.t @@ -0,0 +1,23 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +# This checks if the fop keeps the dirty flags settings correctly after +# finishing the fop. + +cleanup +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 disperse 3 redundancy 1 $H0:$B0/${V0}{0..2} +TEST $CLI volume heal $V0 disable +TEST $CLI volume start $V0 + +TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0; +EXPECT_WITHIN $CHILD_UP_TIMEOUT "3" ec_child_up_count $V0 0 +cd $M0 +for i in {1..1000}; do dd if=/dev/zero of=file-${i} bs=512k count=2; done +cd - +EXPECT "^0$" get_pending_heal_count $V0 + +cleanup diff --git a/tests/basic/ec/ec-discard.t b/tests/basic/ec/ec-discard.t new file mode 100644 index 00000000000..001f4498c86 --- /dev/null +++ b/tests/basic/ec/ec-discard.t @@ -0,0 +1,205 @@ +#!/bin/bash +# +# Test discard functionality +# +# Test that basic discard (hole punch) functionality works via the fallocate +# command line tool. Hole punch deallocates a region of a file, creating a hole +# and a zero-filled data region. We verify that hole punch works, frees blocks +# and that subsequent reads do not read stale data (caches are invalidated). +# +# NOTE: fuse fallocate is known to be broken with regard to cache invalidation +# up to 3.9.0 kernels. Therefore, FOPEN_KEEP_CACHE is not used in this +# test (opens will invalidate the fuse cache). +### + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../fallocate.rc +. $(dirname $0)/../../volume.rc + +cleanup + +#cleate and start volume +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 disperse 6 redundancy 2 $H0:$B0/${V0}{0..5} +TEST $CLI volume set $V0 disperse.optimistic-change-log on +TEST $CLI volume start $V0 + +#Mount the volume +TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0; +EXPECT_WITHIN $CHILD_UP_TIMEOUT "6" ec_child_up_count $V0 0 + +#Check for fallocate and hole punch support +require_fallocate -l 1m $M0/file +require_fallocate -p -l 512k $M0/file && rm -f $M0/file + +#Write some data, punch a hole and verify the file content changes +TEST dd if=/dev/urandom of=$M0/file bs=1024k count=1 +TEST cp $M0/file $M0/file.copy.pre +TEST fallocate -p -o 512k -l 128k $M0/file +TEST ! cmp $M0/file.copy.pre $M0/file +TEST rm -f $M0/file $M0/file.copy.pre + +#Allocate some blocks, punch a hole and verify block allocation +TEST fallocate -l 1m $M0/file +blksz=`stat -c %B $M0/file` +nblks=`stat -c %b $M0/file` +TEST [ $(($blksz * $nblks)) -ge 1048576 ] +TEST fallocate -p -o 512k -l 128k $M0/file +nblks=`stat -c %b $M0/file` +TEST [ $(($blksz * $nblks)) -lt $((933889)) ] +TEST unlink $M0/file + +###Punch hole test cases without fallocate +##With write +#Touching starting boundary +TEST dd if=/dev/urandom of=$B0/test_file bs=1024 count=8 +TEST cp $B0/test_file $M0/test_file +TEST fallocate -p -o 0 -l 500 $B0/test_file +TEST fallocate -p -o 0 -l 500 $M0/test_file +TEST md5_sum=`get_md5_sum $B0/test_file` +EXPECT $md5_sum get_md5_sum $M0/test_file +TEST rm -f $B0/test_file $M0/test_file + +#Touching boundary +TEST dd if=/dev/urandom of=$B0/test_file bs=1024 count=8 +TEST cp $B0/test_file $M0/test_file +TEST fallocate -p -o 500 -l 1548 $B0/test_file +TEST fallocate -p -o 500 -l 1548 $M0/test_file +TEST md5_sum=`get_md5_sum $B0/test_file` +EXPECT $md5_sum get_md5_sum $M0/test_file +TEST rm -f $B0/test_file $M0/test_file + +#Not touching boundary +TEST dd if=/dev/urandom of=$B0/test_file bs=1024 count=8 +TEST cp $B0/test_file $M0/test_file +TEST fallocate -p -o 500 -l 1000 $B0/test_file +TEST fallocate -p -o 500 -l 1000 $M0/test_file +TEST md5_sum=`get_md5_sum $B0/test_file` +EXPECT $md5_sum get_md5_sum $M0/test_file +TEST rm -f $B0/test_file $M0/test_file + +#Over boundary +TEST dd if=/dev/urandom of=$B0/test_file bs=1024 count=8 +TEST cp $B0/test_file $M0/test_file +TEST fallocate -p -o 1500 -l 1000 $B0/test_file +TEST fallocate -p -o 1500 -l 1000 $M0/test_file +TEST md5_sum=`get_md5_sum $B0/test_file` +EXPECT $md5_sum get_md5_sum $M0/test_file +TEST rm -f $B0/test_file $M0/test_file + +###Punch hole test cases with fallocate +##Without write + +#Zero size +TEST dd if=/dev/urandom of=$M0/test_file bs=1024 count=8 +TEST ! fallocate -p -o 1500 -l 0 $M0/test_file + +#Negative size +TEST ! fallocate -p -o 1500 -l -100 $M0/test_file +TEST rm -f $M0/test_file + +#Touching boundary +TEST dd if=/dev/urandom of=$B0/test_file bs=1024 count=8 +TEST cp $B0/test_file $M0/test_file +TEST fallocate -p -o 2048 -l 2048 $B0/test_file +TEST fallocate -p -o 2048 -l 2048 $M0/test_file +TEST md5_sum=`get_md5_sum $B0/test_file` +EXPECT $md5_sum get_md5_sum $M0/test_file +TEST rm -f $B0/test_file $M0/test_file + +#Touching boundary,multiple stripe +TEST dd if=/dev/urandom of=$B0/test_file bs=1024 count=8 +TEST cp $B0/test_file $M0/test_file +TEST fallocate -p -o 2048 -l 4096 $B0/test_file +TEST fallocate -p -o 2048 -l 4096 $M0/test_file +TEST md5_sum=`get_md5_sum $B0/test_file` +EXPECT $md5_sum get_md5_sum $M0/test_file +TEST rm -f $B0/test_file $M0/test_file + +##With write + +#Size ends in boundary +TEST dd if=/dev/urandom of=$B0/test_file bs=1024 count=8 +TEST cp $B0/test_file $M0/test_file +TEST fallocate -p -o 600 -l 3496 $B0/test_file +TEST fallocate -p -o 600 -l 3496 $M0/test_file +TEST md5_sum=`get_md5_sum $B0/test_file` +EXPECT $md5_sum get_md5_sum $M0/test_file +TEST rm -f $B0/test_file $M0/test_file + +#Offset at boundary +TEST dd if=/dev/urandom of=$B0/test_file bs=1024 count=8 +TEST cp $B0/test_file $M0/test_file +TEST fallocate -p -o 2048 -l 3072 $B0/test_file +TEST fallocate -p -o 2048 -l 3072 $M0/test_file +TEST md5_sum=`get_md5_sum $B0/test_file` +EXPECT $md5_sum get_md5_sum $M0/test_file +TEST rm -f $B0/test_file $M0/test_file + +#Offset and Size not at boundary covering a stripe +TEST dd if=/dev/urandom of=$B0/test_file bs=1024 count=8 +TEST cp $B0/test_file $M0/test_file +TEST fallocate -p -o 1500 -l 3000 $B0/test_file +TEST fallocate -p -o 1500 -l 3000 $M0/test_file +TEST md5_sum=`get_md5_sum $B0/test_file` +EXPECT $md5_sum get_md5_sum $M0/test_file +TEST rm -f $B0/test_file $M0/test_file + +#Offset and Size not at boundary +TEST dd if=/dev/urandom of=$B0/test_file bs=1024 count=8 +TEST cp $B0/test_file $M0/test_file +TEST fallocate -p -o 1000 -l 3072 $B0/test_file +TEST fallocate -p -o 1000 -l 3072 $M0/test_file +TEST md5_sum=`get_md5_sum $B0/test_file` +EXPECT $md5_sum get_md5_sum $M0/test_file + +#Data Corruption Tests +#Kill brick1 and brick2 +TEST kill_brick $V0 $H0 $B0/${V0}0 +TEST kill_brick $V0 $H0 $B0/${V0}1 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "4" ec_child_up_count $V0 0 + +#Unmount and mount +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0; +TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0; +EXPECT_WITHIN $CHILD_UP_TIMEOUT "4" ec_child_up_count $V0 0 + +#verify md5 sum +EXPECT $md5_sum get_md5_sum $M0/test_file + +#Bring up the bricks +TEST $CLI volume start $V0 force +EXPECT_WITHIN $CHILD_UP_TIMEOUT "6" ec_child_up_count $V0 0 + +#Kill brick3 and brick4 +TEST kill_brick $V0 $H0 $B0/${V0}2 +TEST kill_brick $V0 $H0 $B0/${V0}3 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "4" ec_child_up_count $V0 0 + +#Unmount and mount +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0; +TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0; +EXPECT_WITHIN $CHILD_UP_TIMEOUT "4" ec_child_up_count $V0 0 + +#verify md5 sum +EXPECT $md5_sum get_md5_sum $M0/test_file + +#Bring up the bricks +TEST $CLI volume start $V0 force +EXPECT_WITHIN $CHILD_UP_TIMEOUT "6" ec_child_up_count $V0 0 + +#Kill brick5 and brick6 +TEST kill_brick $V0 $H0 $B0/${V0}4 +TEST kill_brick $V0 $H0 $B0/${V0}5 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "4" ec_child_up_count $V0 0 + +#Unmount and mount +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0; +TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0; +EXPECT_WITHIN $CHILD_UP_TIMEOUT "4" ec_child_up_count $V0 0 + +#verify md5 sum +EXPECT $md5_sum get_md5_sum $M0/test_file + +cleanup diff --git a/tests/basic/ec/ec-fallocate.t b/tests/basic/ec/ec-fallocate.t new file mode 100644 index 00000000000..1b827eed7df --- /dev/null +++ b/tests/basic/ec/ec-fallocate.t @@ -0,0 +1,72 @@ +#!/bin/bash +# +# Run several commands to verify basic fallocate functionality. We verify that +# fallocate creates and allocates blocks to a file. We also verify that the keep +# size option does not modify the file size. +### + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc +. $(dirname $0)/../../fallocate.rc + +cleanup + +#cleate and start volume +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 disperse 3 redundancy 1 $H0:$B0/${V0}{0..2} +TEST $CLI volume start $V0 + +#Mount the volume +TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0; +EXPECT_WITHIN $CHILD_UP_TIMEOUT "3" ec_child_up_count $V0 0 + +# check for fallocate support before continuing the test +require_fallocate -l 1m -n $M0/file && rm -f $M0/file + +# fallocate a file and verify blocks are allocated +TEST fallocate -l 1m $M0/file +blksz=`stat -c %b $M0/file` +nblks=`stat -c %B $M0/file` +TEST [ $(($blksz * $nblks)) -eq 1048576 ] + +TEST unlink $M0/file + +# truncate a file to a fixed size, fallocate and verify that the size does not +# change +TEST truncate -s 1M $M0/file +TEST fallocate -l 2m -n $M0/file +blksz=`stat -c %b $M0/file` +nblks=`stat -c %B $M0/file` +sz=`stat -c %s $M0/file` +TEST [ $sz -eq 1048576 ] +# Note that gluster currently incorporates a hack to limit the number of blocks +# reported as allocated to the file by the file size. We have allocated beyond the +# file size here. Just check for non-zero allocation to avoid setting a land mine +# for if/when that behavior might change. +TEST [ ! $(($blksz * $nblks)) -eq 0 ] +TEST unlink $M0/file + +# write some data, fallocate within and outside the range +# and check for data corruption. +TEST dd if=/dev/urandom of=$M0/file bs=1024k count=1 +TEST cp $M0/file $M0/file.copy.pre +TEST fallocate -o 512k -l 128k $M0/file +TEST cp $M0/file $M0/file.copy.post +TEST cmp $M0/file.copy.pre $M0/file.copy.post +TEST fallocate -o 1000k -l 128k $M0/file +TEST cp $M0/file $M0/file.copy.post2 +TEST ! cmp $M0/file.copy.pre $M0/file.copy.post2 +TEST truncate -s 1M $M0/file.copy.post2 +TEST cmp $M0/file.copy.pre $M0/file.copy.post2 +TEST unlink $M0/file + +#Make sure offset/size are modified so that 3 blocks are allocated +TEST touch $M0/f1 +TEST fallocate -o 1280 -l 1024 $M0/f1 +EXPECT "^2304$" stat -c "%s" $M0/f1 +EXPECT "^1536$" stat -c "%s" $B0/${V0}0/f1 + +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 + +cleanup; diff --git a/tests/basic/ec/ec-fast-fgetxattr.c b/tests/basic/ec/ec-fast-fgetxattr.c new file mode 100644 index 00000000000..bf982151861 --- /dev/null +++ b/tests/basic/ec/ec-fast-fgetxattr.c @@ -0,0 +1,129 @@ +#include <stdio.h> +#include <fcntl.h> +#include <unistd.h> +#include <time.h> +#include <limits.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <glusterfs/api/glfs.h> +#include <glusterfs/api/glfs-handles.h> + +int cbk_complete = 0; +ssize_t cbk_ret_val = 0; +int +fill_iov(struct iovec *iov, char fillchar, int count) +{ + int ret = -1; + + iov->iov_base = malloc(count + 1); + if (iov->iov_base == NULL) { + return ret; + } else { + iov->iov_len = count; + ret = 0; + } + memset(iov->iov_base, fillchar, count); + memset(iov->iov_base + count, '\0', 1); + + return ret; +} + +void +write_async_cbk(glfs_fd_t *fd, ssize_t ret, struct stat *prestat, + struct stat *poststat, void *cookie) +{ + if (ret < 0) { + fprintf(stderr, "glfs_write failed"); + } + cbk_ret_val = ret; + cbk_complete = 1; +} + +int +write_async(glfs_t *fs, glfs_fd_t *glfd, int char_count) +{ + ssize_t ret = -1; + int flags = O_RDWR; + struct iovec iov = {0}; + + ret = fill_iov(&iov, 'a', char_count); + if (ret) { + fprintf(stderr, "failed to create iov"); + goto out; + } + + ret = glfs_pwritev_async(glfd, &iov, 1, 0, flags, write_async_cbk, NULL); +out: + if (ret < 0) { + fprintf(stderr, "glfs_pwritev async failed"); + } + return ret; +} + +int +main(int argc, char *argv[]) +{ + glfs_t *fs = NULL; + glfs_fd_t *fd = NULL; + int ret = 1; + char buf[1024] = {0}; + + if (argc != 4) { + fprintf(stderr, "Syntax: %s <host> <volname> <file>\n", argv[0]); + return 1; + } + + fs = glfs_new(argv[2]); + if (!fs) { + fprintf(stderr, "glfs_new: returned NULL\n"); + return 1; + } + + ret = glfs_set_volfile_server(fs, "tcp", argv[1], 24007); + if (ret != 0) { + fprintf(stderr, "glfs_set_volfile_server: returned %d\n", ret); + goto out; + } + ret = glfs_set_logging(fs, "/tmp/ec-fgetxattr.log", 7); + if (ret != 0) { + fprintf(stderr, "glfs_set_logging: returned %d\n", ret); + goto out; + } + ret = glfs_init(fs); + if (ret != 0) { + fprintf(stderr, "glfs_init: returned %d\n", ret); + goto out; + } + + fd = glfs_open(fs, argv[3], O_RDWR | O_TRUNC); + if (fd == NULL) { + fprintf(stderr, "glfs_open: returned NULL\n"); + goto out; + } + + ret = write_async(fs, fd, 16); + if (ret) { + fprintf(stderr, "write_async failed\n"); + } + + sleep(1); + ret = glfs_fgetxattr(fd, "trusted.glusterfs.abc", buf, sizeof buf); + while (cbk_complete != 1) { + /* ret will be -ve as xattr doesn't exist, and fgetxattr should + * return waaaayyy before writev */ + ret = 0; + sleep(1); + } + if (cbk_ret_val < 0) { + fprintf(stderr, "cbk_ret_val is -ve\n"); + ret = -1; + } + glfs_close(fd); + +out: + unlink("/tmp/ec-fgetxattr.log"); + glfs_fini(fs); + + return ret; +} diff --git a/tests/basic/ec/ec-fast-fgetxattr.t b/tests/basic/ec/ec-fast-fgetxattr.t new file mode 100755 index 00000000000..eb12fa4a0ba --- /dev/null +++ b/tests/basic/ec/ec-fast-fgetxattr.t @@ -0,0 +1,40 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +cleanup; + +TEST glusterd +TEST pidof glusterd + +TEST $CLI volume create $V0 disperse 6 redundancy 2 $H0:$B0/${V0}{1..6} +TEST $CLI volume set $V0 performance.quick-read off +TEST $CLI volume set $V0 performance.write-behind off +TEST $CLI volume set $V0 performance.io-cache off +TEST $CLI volume set $V0 performance.stat-prefetch off +TEST $CLI volume set $V0 performance.client-io-threads off +TEST $CLI volume set $V0 brick-log-level DEBUG +TEST $CLI volume set $V0 delay-gen posix +TEST $CLI volume set $V0 delay-gen.delay-duration 10000000 +TEST $CLI volume set $V0 delay-gen.delay-percentage 100 +TEST $CLI volume set $V0 delay-gen.enable read,write + +TEST $CLI volume start $V0 +EXPECT 'Started' volinfo_field $V0 'Status' + +TEST $GFS -s $H0 --volfile-id $V0 $M0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "6" ec_child_up_count $V0 0 +TEST touch $M0/file + +# Perform two writes to make sure io-threads have enough threads to perform +# things in parallel when the test execution happens. +echo abc > $M0/file1 & +echo abc > $M0/file2 & +wait + +TEST build_tester $(dirname $0)/ec-fast-fgetxattr.c -lgfapi -Wall -O2 +TEST $(dirname $0)/ec-fast-fgetxattr $H0 $V0 /file +cleanup_tester $(dirname ${0})/ec-fast-fgetxattr + +cleanup; diff --git a/tests/basic/ec/ec-fix-openfd.t b/tests/basic/ec/ec-fix-openfd.t new file mode 100644 index 00000000000..04fdd802c62 --- /dev/null +++ b/tests/basic/ec/ec-fix-openfd.t @@ -0,0 +1,111 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc +. $(dirname $0)/../../fileio.rc + +# This test checks for open fd heal on EC + +#Create Volume +cleanup +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 disperse 3 redundancy 1 $H0:$B0/${V0}{0..2} +TEST $CLI volume set $V0 performance.read-after-open yes +TEST $CLI volume set $V0 performance.lazy-open no +TEST $CLI volume set $V0 performance.open-behind off +TEST $CLI volume set $V0 disperse.background-heals 0 +TEST $CLI volume heal $V0 disable +TEST $CLI volume start $V0 + +#Mount the volume +TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0; +EXPECT_WITHIN $CHILD_UP_TIMEOUT "3" ec_child_up_count $V0 0 + +#Touch a file +TEST touch "$M0/test_file" + +#Kill a brick +TEST kill_brick $V0 $H0 $B0/${V0}0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "2" ec_child_up_count $V0 0 + +#Open the file in write mode +TEST fd=`fd_available` +TEST fd_open $fd 'rw' "$M0/test_file" + +#Bring up the killed brick +TEST $CLI volume start $V0 force +EXPECT_WITHIN $CHILD_UP_TIMEOUT "3" ec_child_up_count $V0 0 + +sleep 1 + +#Test the fd count +EXPECT "0" get_fd_count $V0 $H0 $B0/${V0}0 test_file +EXPECT "1" get_fd_count $V0 $H0 $B0/${V0}1 test_file +EXPECT "1" get_fd_count $V0 $H0 $B0/${V0}2 test_file + +#Write to file +dd iflag=fullblock if=/dev/urandom bs=1024 count=2 >&$fd 2>/dev/null + +#Test the fd count +EXPECT "1" get_fd_count $V0 $H0 $B0/${V0}0 test_file + +#Close fd +TEST fd_close $fd + +#Stop the volume +TEST $CLI volume stop $V0 + +#Start the volume +TEST $CLI volume start $V0 + +#Kill brick1 +TEST kill_brick $V0 $H0 $B0/${V0}0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "2" ec_child_up_count $V0 0 + +#Unmount and mount +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0; +TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0; +EXPECT_WITHIN $CHILD_UP_TIMEOUT "2" ec_child_up_count $V0 0 + +#Calculate md5 sum +md5sum0=`get_md5_sum "$M0/test_file"` + +#Bring up the brick +TEST $CLI volume start $V0 force +EXPECT_WITHIN $CHILD_UP_TIMEOUT "3" ec_child_up_count $V0 0 + +#Kill brick2 +TEST kill_brick $V0 $H0 $B0/${V0}1 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "2" ec_child_up_count $V0 0 + +#Unmount and mount +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 +TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0; +EXPECT_WITHIN $CHILD_UP_TIMEOUT "2" ec_child_up_count $V0 0 + +#Calculate md5 sum +md5sum1=`get_md5_sum "$M0/test_file"` + +#Bring up the brick +TEST $CLI volume start $V0 force +EXPECT_WITHIN $CHILD_UP_TIMEOUT "3" ec_child_up_count $V0 0 + +#Kill brick3 +TEST kill_brick $V0 $H0 $B0/${V0}2 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "2" ec_child_up_count $V0 0 + +#Unmount and mount +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 +TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0; +EXPECT_WITHIN $CHILD_UP_TIMEOUT "2" ec_child_up_count $V0 0 + +#Calculate md5 sum +md5sum2=`get_md5_sum "$M0/test_file"` + +#compare the md5sum +EXPECT "$md5sum0" echo $md5sum1 +EXPECT "$md5sum0" echo $md5sum2 +EXPECT "$md5sum1" echo $md5sum2 + +cleanup diff --git a/tests/basic/ec/ec-internal-xattrs.t b/tests/basic/ec/ec-internal-xattrs.t new file mode 100644 index 00000000000..5ef0502e016 --- /dev/null +++ b/tests/basic/ec/ec-internal-xattrs.t @@ -0,0 +1,45 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +# This test checks internal xattr handling in ec +TESTS_EXPECTED_IN_LOOP=11 + +cleanup +function get_ec_xattrs +{ + getfattr -d -m. -e hex $1 | grep trusted.ec +} + +function get_xattr_count +{ + getfattr -d -m. -e hex $1 | grep "trusted" | wc -l +} + +declare -a xattrs=("trusted.ec.config" "trusted.ec.size" "trusted.ec.version" "trusted.ec.heal") + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 redundancy 2 $H0:$B0/${V0}{0..5} +TEST $CLI volume start $V0 +TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0; +# Wait until all 6 children have been recognized by the ec xlator +EXPECT_WITHIN $CHILD_UP_TIMEOUT "6" ec_child_up_count $V0 0 +TEST touch $M0/a + +#Check that internal xattrs are not modifiable or readable +for x in "${xattrs[@]}"; do + TEST_IN_LOOP ! setfattr -n $x "abc" $M0/a + TEST_IN_LOOP ! setfattr -x $x "abc" $M0/a + if [ $x != "trusted.ec.heal" ]; + then + TEST_IN_LOOP ! getfattr -n $x $M0/a + fi +done + +TEST ! get_ec_xattrs $M0/a +TEST setfattr -n trusted.abc -v 0x616263 $M0/a +EXPECT "616263" get_hex_xattr trusted.abc $M0/a +EXPECT "1" get_xattr_count $M0/a +cleanup diff --git a/tests/basic/ec/ec-new-entry.t b/tests/basic/ec/ec-new-entry.t new file mode 100644 index 00000000000..be97aecd8e2 --- /dev/null +++ b/tests/basic/ec/ec-new-entry.t @@ -0,0 +1,70 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +cleanup +function num_entries { + ls -l $1 | wc -l +} + +function get_md5sum { + md5sum $1 | awk '{print $1}' +} + +#after replace-brick immediately trusted.ec.version will be absent, so if it +#is present we can assume that heal attempted on root +function root_heal_attempted { + if [ -z $(get_hex_xattr trusted.ec.version $1) ]; + then + echo "N"; + else + echo "Y"; + fi +} + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 disperse 6 redundancy 2 $H0:$B0/${V0}{0..5} +TEST $CLI volume start $V0 +TEST glusterfs --entry-timeout=0 --attribute-timeout=0 -s $H0 --volfile-id $V0 $M0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "6" ec_child_up_count $V0 0 +touch $M0/{1..10} +touch $M0/11 +TEST mknod $M0/char c 1 5 +TEST mknod $M0/block b 4 5 +for i in {1..10}; do dd if=/dev/zero of=$M0/$i bs=1M count=1; done +TEST $CLI volume replace-brick $V0 $H0:$B0/${V0}5 $H0:$B0/${V0}6 commit force +EXPECT_WITHIN $CHILD_UP_TIMEOUT "6" ec_child_up_count $V0 0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "Y" glustershd_up_status +EXPECT_WITHIN $CHILD_UP_TIMEOUT "6" ec_child_up_count_shd $V0 0 +EXPECT_WITHIN $HEAL_TIMEOUT "Y" root_heal_attempted $B0/${V0}6 +EXPECT_WITHIN $HEAL_TIMEOUT "^0$" get_pending_heal_count $V0 +#ls -l gives "Total" line so number of lines will be 1 more +EXPECT "^14$" num_entries $B0/${V0}6 +EXPECT "^1 5$" stat -c "%t %T" $B0/${V0}6/char +EXPECT "^4 5$" stat -c "%t %T" $B0/${V0}6/block +ec_version=$(get_hex_xattr trusted.ec.version $B0/${V0}0) +EXPECT "$ec_version" get_hex_xattr trusted.ec.version $B0/${V0}1 +EXPECT "$ec_version" get_hex_xattr trusted.ec.version $B0/${V0}2 +EXPECT "$ec_version" get_hex_xattr trusted.ec.version $B0/${V0}3 +EXPECT "$ec_version" get_hex_xattr trusted.ec.version $B0/${V0}4 +EXPECT "$ec_version" get_hex_xattr trusted.ec.version $B0/${V0}6 +file_md5sum=$(get_md5sum $M0/1) +empty_md5sum=$(get_md5sum $M0/11) +TEST kill_brick $V0 $H0 $B0/${V0}0 +TEST kill_brick $V0 $H0 $B0/${V0}1 +echo $file_md5sum +EXPECT "$file_md5sum" get_md5sum $M0/1 +EXPECT "$file_md5sum" get_md5sum $M0/2 +EXPECT "$file_md5sum" get_md5sum $M0/3 +EXPECT "$file_md5sum" get_md5sum $M0/4 +EXPECT "$file_md5sum" get_md5sum $M0/5 +EXPECT "$file_md5sum" get_md5sum $M0/6 +EXPECT "$file_md5sum" get_md5sum $M0/7 +EXPECT "$file_md5sum" get_md5sum $M0/8 +EXPECT "$file_md5sum" get_md5sum $M0/9 +EXPECT "$file_md5sum" get_md5sum $M0/10 +EXPECT "$empty_md5sum" get_md5sum $M0/11 + +cleanup; diff --git a/tests/basic/ec/ec-notify.t b/tests/basic/ec/ec-notify.t new file mode 100644 index 00000000000..53290b7c798 --- /dev/null +++ b/tests/basic/ec/ec-notify.t @@ -0,0 +1,101 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +# This test checks notify part of ec + +# We *know* some of these mounts will succeed but not be actually usable +# (terrible idea IMO), so speed things up and eliminate some noise by +# overriding this function. +_GFS () { + glusterfs "$@" +} + +ec_up_brick_count () { + local bricknum + for bricknum in $(seq 0 2); do + brick_up_status $V0 $H0 $B0/$V0$bricknum + done | grep -E '^1$' | wc -l +} + +cleanup +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 disperse 3 redundancy 1 $H0:$B0/${V0}{0..2} +TEST $CLI volume start $V0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "3" ec_up_brick_count + +#First time mount tests. +# When all the bricks are up, mount should succeed and up-children +# count should be 3 +TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0; +EXPECT_WITHIN $CHILD_UP_TIMEOUT "3" ec_child_up_count $V0 0 +TEST stat $M0 +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 + +# When the volume is stopped mount succeeds and up-children will be 0 +TEST $CLI volume stop $V0 +TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0; +# Wait for 5 seconds even after that up_count should show 0 +sleep 5; +EXPECT_WITHIN $CHILD_UP_TIMEOUT "0" ec_child_up_count $V0 0 +TEST ! stat $M0 +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 + +# When 2 bricks are up, mount should succeed and up-children +# count should be 2 + +TEST $CLI volume start $V0 +TEST kill_brick $V0 $H0 $B0/${V0}2 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "2" ec_up_brick_count +TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0; +EXPECT_WITHIN $CHILD_UP_TIMEOUT "2" ec_child_up_count $V0 0 +TEST stat $M0 +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 + +# When only 1 brick is up mount should fail. +TEST kill_brick $V0 $H0 $B0/${V0}1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" ec_up_brick_count +TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0; +# Wait for 5 seconds even after that up_count should show 1 +sleep 5 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" ec_child_up_count $V0 0 +TEST ! stat $M0 +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 + +# Mount already succeeded. Test that the brick up down are leading to correct +# state changes in ec. +TEST $CLI volume stop $V0 +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "3" ec_up_brick_count +TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0; +EXPECT_WITHIN $CHILD_UP_TIMEOUT "3" ec_child_up_count $V0 0 +TEST touch $M0/a + +# kill 1 brick and the up_count should become 2, fops should still succeed +TEST kill_brick $V0 $H0 $B0/${V0}1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "2" ec_up_brick_count +EXPECT_WITHIN $CHILD_UP_TIMEOUT "2" ec_child_up_count $V0 0 +TEST touch $M0/b + +# kill one more brick and the up_count should become 1, fops should fail +TEST kill_brick $V0 $H0 $B0/${V0}2 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" ec_up_brick_count +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" ec_child_up_count $V0 0 +TEST ! touch $M0/c + +# kill one more brick and the up_count should become 0, fops should still fail +TEST kill_brick $V0 $H0 $B0/${V0}0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "0" ec_up_brick_count +EXPECT_WITHIN $CHILD_UP_TIMEOUT "0" ec_child_up_count $V0 0 +TEST ! touch $M0/c + +# Bring up all the bricks up and see that up_count is 3 and fops are succeeding +# again. +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "3" ec_up_brick_count +EXPECT_WITHIN $CHILD_UP_TIMEOUT "3" ec_child_up_count $V0 0 +TEST touch $M0/c + +cleanup diff --git a/tests/basic/ec/ec-optimistic-changelog.t b/tests/basic/ec/ec-optimistic-changelog.t new file mode 100644 index 00000000000..a372cd39a64 --- /dev/null +++ b/tests/basic/ec/ec-optimistic-changelog.t @@ -0,0 +1,153 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +# This test checks optimistic-change-log option + +cleanup +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 disperse 3 redundancy 1 $H0:$B0/${V0}{0..2} +TEST $CLI volume heal $V0 disable + +TEST $CLI volume set $V0 performance.stat-prefetch off +TEST $CLI volume set $V0 performance.write-behind off +TEST $CLI volume set $V0 performance.quick-read off +TEST $CLI volume set $V0 performance.read-ahead off +TEST $CLI volume set $V0 performance.io-cache off +TEST $CLI volume set $V0 disperse.background-heals 0 +TEST $CLI volume set $V0 disperse.optimistic-change-log off +TEST $CLI volume set $V0 disperse.eager-lock off +TEST $CLI volume set $V0 disperse.other-eager-lock off +TEST $CLI volume start $V0 + +TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0; +EXPECT_WITHIN $CHILD_UP_TIMEOUT "3" ec_child_up_count $V0 0 +EXPECT_WITHIN $CONFIG_UPDATE_TIMEOUT "0" mount_get_option_value $M0 $V0-disperse-0 background-heals +EXPECT_WITHIN $CONFIG_UPDATE_TIMEOUT "0" mount_get_option_value $M0 $V0-disperse-0 heal-wait-qlength + +TEST $CLI volume set $V0 disperse.background-heals 1 +TEST touch $M0/a +EXPECT_WITHIN $HEAL_TIMEOUT "^0$" count_sh_entries $B0/${V0}0 +EXPECT_WITHIN $HEAL_TIMEOUT "^0$" count_sh_entries $B0/${V0}1 +EXPECT_WITHIN $HEAL_TIMEOUT "^0$" count_sh_entries $B0/${V0}2 + + + +### optimistic-change-log = off ; All bricks good. Test file operation +echo abc > $M0/a +EXPECT_WITHIN $HEAL_TIMEOUT "^0$" get_pending_heal_count $V0 + +############################################################ + +## optimistic-change-log = off ; Kill one brick . Test file operation +TEST kill_brick $V0 $H0 $B0/${V0}2 +echo abc > $M0/a +EXPECT 2 get_pending_heal_count $V0 #One for each active brick +$CLI volume start $V0 force +EXPECT_WITHIN $CHILD_UP_TIMEOUT "3" ec_child_up_count $V0 0 +#Accessing file should heal the file now +EXPECT "abc" cat $M0/a +EXPECT_WITHIN $HEAL_TIMEOUT "^0$" get_pending_heal_count $V0 + +############################################################ + +## optimistic-change-log = off ; All bricks good. Test entry operation +TEST touch $M0/b +EXPECT_WITHIN $HEAL_TIMEOUT "^0$" get_pending_heal_count $V0 + +############################################################ + +## optimistic-change-log = off ; All bricks good. Test metadata operation +TEST chmod 0777 $M0/b +EXPECT_WITHIN $HEAL_TIMEOUT "^0$" get_pending_heal_count $V0 + +############################################################ + +## optimistic-change-log = off ; Kill one brick. Test entry operation + +TEST kill_brick $V0 $H0 $B0/${V0}2 +TEST touch $M0/c +EXPECT 4 get_pending_heal_count $V0 #two for each active brick +$CLI volume start $V0 force +EXPECT_WITHIN $CHILD_UP_TIMEOUT "3" ec_child_up_count $V0 0 +getfattr -d -m. -e hex $M0 2>&1 > /dev/null +getfattr -d -m. -e hex $M0/c 2>&1 > /dev/null +EXPECT_WITHIN $HEAL_TIMEOUT "^0$" get_pending_heal_count $V0 + +############################################################ + +## optimistic-change-log = off ; Kill one brick. Test metadata operation +TEST kill_brick $V0 $H0 $B0/${V0}2 +TEST chmod 0777 $M0/c +EXPECT 2 get_pending_heal_count $V0 #One for each active brick +$CLI volume start $V0 force +EXPECT_WITHIN $CHILD_UP_TIMEOUT "3" ec_child_up_count $V0 0 +getfattr -d -m. -e hex $M0/c 2>&1 > /dev/null +EXPECT_WITHIN $HEAL_TIMEOUT "^0$" get_pending_heal_count $V0 + +############################################################ + +TEST $CLI volume set $V0 disperse.optimistic-change-log on + +### optimistic-change-log = on ; All bricks good. Test file operation + +echo abc > $M0/aa +EXPECT_WITHIN $HEAL_TIMEOUT "^0$" get_pending_heal_count $V0 + +############################################################ + +## optimistic-change-log = on ; Kill one brick. Test file operation + +TEST kill_brick $V0 $H0 $B0/${V0}2 +echo abc > $M0/aa +EXPECT 2 get_pending_heal_count $V0 #One for each active brick +$CLI volume start $V0 force +EXPECT_WITHIN $CHILD_UP_TIMEOUT "3" ec_child_up_count $V0 0 +#Accessing file should heal the file now +getfattr -d -m. -e hex $M0/aa 2>&1 > /dev/null +EXPECT_WITHIN $HEAL_TIMEOUT "^0$" get_pending_heal_count $V0 + +############################################################ + +## optimistic-change-log = on ; All bricks good. Test entry operation + +TEST touch $M0/bb +EXPECT_WITHIN $HEAL_TIMEOUT "^0$" get_pending_heal_count $V0 + +############################################################ + +## optimistic-change-log = on ; All bricks good. Test metadata operation + +TEST chmod 0777 $M0/bb +EXPECT_WITHIN $HEAL_TIMEOUT "^0$" get_pending_heal_count $V0 + +############################################################ + +## optimistic-change-log = on ; Kill one brick. Test entry operation + +TEST kill_brick $V0 $H0 $B0/${V0}2 +TEST touch $M0/cc +EXPECT 4 get_pending_heal_count $V0 #two for each active brick +$CLI volume start $V0 force +EXPECT_WITHIN $CHILD_UP_TIMEOUT "3" ec_child_up_count $V0 0 +getfattr -d -m. -e hex $M0 2>&1 > /dev/null +getfattr -d -m. -e hex $M0/cc 2>&1 > /dev/null +EXPECT_WITHIN $HEAL_TIMEOUT "^0$" get_pending_heal_count $V0 + +############################################################ + +## optimistic-change-log = on ; Kill one brick. Test metadata operation + +TEST kill_brick $V0 $H0 $B0/${V0}2 +TEST chmod 0777 $M0/cc +EXPECT 2 get_pending_heal_count $V0 #One for each active brick +$CLI volume start $V0 force +EXPECT_WITHIN $CHILD_UP_TIMEOUT "3" ec_child_up_count $V0 0 +getfattr -d -m. -e hex $M0/cc 2>&1 > /dev/null +EXPECT_WITHIN $HEAL_TIMEOUT "^0$" get_pending_heal_count $V0 + +############################################################ + +cleanup diff --git a/tests/basic/ec/ec-quorum-count.t b/tests/basic/ec/ec-quorum-count.t new file mode 100644 index 00000000000..9310ebbb8f2 --- /dev/null +++ b/tests/basic/ec/ec-quorum-count.t @@ -0,0 +1,167 @@ + #!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc +. $(dirname $0)/../../ec.rc + +cleanup +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 disperse 6 redundancy 2 $H0:$B0/${V0}{0..5} +TEST $CLI volume create $V1 $H0:$B0/${V1}{0..5} +TEST $CLI volume set $V0 disperse.eager-lock-timeout 5 +TEST $CLI volume set $V0 performance.flush-behind off +TEST $CLI volume set $V0 disperse.background-heals 0 +TEST $CLI volume set $V0 disperse.heal-wait-qlength 0 + +#Should fail on non-disperse volume +TEST ! $CLI volume set $V1 disperse.quorum-count 5 + +#Should succeed on a valid range +TEST ! $CLI volume set $V0 disperse.quorum-count 0 +TEST ! $CLI volume set $V0 disperse.quorum-count -0 +TEST ! $CLI volume set $V0 disperse.quorum-count abc +TEST ! $CLI volume set $V0 disperse.quorum-count 10abc +TEST ! $CLI volume set $V0 disperse.quorum-count 1 +TEST ! $CLI volume set $V0 disperse.quorum-count 2 +TEST ! $CLI volume set $V0 disperse.quorum-count 3 +TEST $CLI volume set $V0 disperse.quorum-count 4 +TEST $CLI volume start $V0 +TEST glusterfs --entry-timeout=0 --attribute-timeout=0 -s $H0 --volfile-id $V0 $M0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "6" ec_child_up_count $V0 0 + +#Test that the option is reflected in the mount +EXPECT_WITHIN $CONFIG_UPDATE_TIMEOUT "^4$" ec_option_value $V0 $M0 0 quorum-count +TEST $CLI volume reset $V0 disperse.quorum-count +EXPECT_WITHIN $CONFIG_UPDATE_TIMEOUT "^0$" ec_option_value $V0 $M0 0 quorum-count +TEST $CLI volume set $V0 disperse.quorum-count 6 +EXPECT_WITHIN $CONFIG_UPDATE_TIMEOUT "^6$" ec_option_value $V0 $M0 0 quorum-count + +TEST touch $M0/a +TEST touch $M0/data +TEST setfattr -n trusted.def -v def $M0/a +TEST touch $M0/src +TEST touch $M0/del-me +TEST mkdir $M0/dir1 +TEST dd if=/dev/zero of=$M0/read-file bs=1M count=1 oflag=direct +TEST dd if=/dev/zero of=$M0/del-file bs=1M count=1 oflag=direct +TEST gf_rm_file_and_gfid_link $B0/${V0}0 del-file +#modify operations should fail as the file is not in quorum +TEST ! dd if=/dev/zero of=$M0/del-file bs=1M count=1 oflag=direct +TEST kill_brick $V0 $H0 $B0/${V0}0 +#Read should succeed even when quorum-count is not met +TEST dd if=$M0/read-file of=/dev/null iflag=direct +TEST ! touch $M0/a2 +TEST ! mkdir $M0/dir2 +TEST ! mknod $M0/b2 b 4 5 +TEST ! ln -s $M0/a $M0/symlink +TEST ! ln $M0/a $M0/link +TEST ! mv $M0/src $M0/dst +TEST ! rm -f $M0/del-me +TEST ! rmdir $M0/dir1 +TEST ! dd if=/dev/zero of=$M0/a bs=1M count=1 conv=notrunc +TEST ! dd if=/dev/zero of=$M0/data bs=1M count=1 conv=notrunc +TEST ! truncate -s 0 $M0/a +TEST ! setfattr -n trusted.abc -v abc $M0/a +TEST ! setfattr -x trusted.def $M0/a +TEST ! chmod +x $M0/a +TEST ! fallocate -l 2m -n $M0/a +TEST ! fallocate -p -l 512k $M0/a +TEST $CLI volume start $V0 force +EXPECT_WITHIN $HEAL_TIMEOUT "^0$" get_pending_heal_count ${V0} + +# reset the option and check whether the default redundancy count is +# accepted or not. +TEST $CLI volume reset $V0 disperse.quorum-count +EXPECT_WITHIN $CONFIG_UPDATE_TIMEOUT "^0$" ec_option_value $V0 $M0 0 quorum-count +TEST touch $M0/a1 +TEST touch $M0/data1 +TEST setfattr -n trusted.def -v def $M0/a1 +TEST touch $M0/src1 +TEST touch $M0/del-me1 +TEST mkdir $M0/dir11 +TEST kill_brick $V0 $H0 $B0/${V0}0 +TEST kill_brick $V0 $H0 $B0/${V0}1 +TEST touch $M0/a21 +TEST mkdir $M0/dir21 +TEST mknod $M0/b21 b 4 5 +TEST ln -s $M0/a1 $M0/symlink1 +TEST ln $M0/a1 $M0/link1 +TEST mv $M0/src1 $M0/dst1 +TEST rm -f $M0/del-me1 +TEST rmdir $M0/dir11 +TEST dd if=/dev/zero of=$M0/a1 bs=1M count=1 conv=notrunc +TEST dd if=/dev/zero of=$M0/data1 bs=1M count=1 conv=notrunc +TEST truncate -s 0 $M0/a1 +TEST setfattr -n trusted.abc -v abc $M0/a1 +TEST setfattr -x trusted.def $M0/a1 +TEST chmod +x $M0/a1 +TEST fallocate -l 2m -n $M0/a1 +TEST fallocate -p -l 512k $M0/a1 +TEST $CLI volume start $V0 force +EXPECT_WITHIN $CHILD_UP_TIMEOUT "6" ec_child_up_count $V0 0 + +TEST touch $M0/a2 +TEST touch $M0/data2 +TEST setfattr -n trusted.def -v def $M0/a1 +TEST touch $M0/src2 +TEST touch $M0/del-me2 +TEST mkdir $M0/dir12 +TEST kill_brick $V0 $H0 $B0/${V0}0 +TEST kill_brick $V0 $H0 $B0/${V0}1 +TEST kill_brick $V0 $H0 $B0/${V0}2 +TEST ! touch $M0/a22 +TEST ! mkdir $M0/dir22 +TEST ! mknod $M0/b22 b 4 5 +TEST ! ln -s $M0/a2 $M0/symlink2 +TEST ! ln $M0/a2 $M0/link2 +TEST ! mv $M0/src2 $M0/dst2 +TEST ! rm -f $M0/del-me2 +TEST ! rmdir $M0/dir12 +TEST ! dd if=/dev/zero of=$M0/a2 bs=1M count=1 conv=notrunc +TEST ! dd if=/dev/zero of=$M0/data2 bs=1M count=1 conv=notrunc +TEST ! truncate -s 0 $M0/a2 +TEST ! setfattr -n trusted.abc -v abc $M0/a2 +TEST ! setfattr -x trusted.def $M0/a2 +TEST ! chmod +x $M0/a2 +TEST ! fallocate -l 2m -n $M0/a2 +TEST ! fallocate -p -l 512k $M0/a2 +TEST $CLI volume start $V0 force +EXPECT_WITHIN $CHILD_UP_TIMEOUT "6" ec_child_up_count $V0 0 +EXPECT_WITHIN $HEAL_TIMEOUT "^0$" get_pending_heal_count ${V0} + +# Set quorum-count to 5 and kill 1 brick and the fops should pass +TEST $CLI volume set $V0 disperse.quorum-count 5 +EXPECT_WITHIN $CONFIG_UPDATE_TIMEOUT "^5$" ec_option_value $V0 $M0 0 quorum-count +TEST touch $M0/a3 +TEST touch $M0/data3 +TEST setfattr -n trusted.def -v def $M0/a3 +TEST touch $M0/src3 +TEST touch $M0/del-me3 +TEST mkdir $M0/dir13 +TEST kill_brick $V0 $H0 $B0/${V0}0 +TEST touch $M0/a31 +TEST mkdir $M0/dir31 +TEST mknod $M0/b31 b 4 5 +TEST ln -s $M0/a3 $M0/symlink3 +TEST ln $M0/a3 $M0/link3 +TEST mv $M0/src3 $M0/dst3 +TEST rm -f $M0/del-me3 +TEST rmdir $M0/dir13 +TEST dd if=/dev/zero of=$M0/a3 bs=1M count=1 conv=notrunc +TEST dd if=/dev/zero of=$M0/data3 bs=1M count=1 conv=notrunc +TEST truncate -s 0 $M0/a3 +TEST setfattr -n trusted.abc -v abc $M0/a3 +TEST setfattr -x trusted.def $M0/a3 +TEST chmod +x $M0/a3 +TEST fallocate -l 2m -n $M0/a3 +TEST fallocate -p -l 512k $M0/a3 +TEST dd if=/dev/urandom of=$M0/heal-file bs=1M count=1 oflag=direct +cksum_before_heal="$(md5sum $M0/heal-file | awk '{print $1}')" +TEST $CLI volume start $V0 force +EXPECT_WITHIN $HEAL_TIMEOUT "^0$" get_pending_heal_count ${V0} +TEST kill_brick $V0 $H0 $B0/${V0}4 +TEST kill_brick $V0 $H0 $B0/${V0}5 +cksum_after_heal=$(dd if=$M0/heal-file iflag=direct | md5sum | awk '{print $1}') +TEST [[ $cksum_before_heal == $cksum_after_heal ]] +cleanup; diff --git a/tests/basic/ec/ec-read-mask.t b/tests/basic/ec/ec-read-mask.t new file mode 100644 index 00000000000..ddb556f2973 --- /dev/null +++ b/tests/basic/ec/ec-read-mask.t @@ -0,0 +1,114 @@ + #!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc +. $(dirname $0)/../../ec.rc + +cleanup +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 disperse 6 redundancy 2 $H0:$B0/${V0}{0..5} +TEST $CLI volume start $V0 + +#Empty read-mask should fail +TEST ! $GFS --xlator-option=*.ec-read-mask="" -s $H0 --volfile-id $V0 $M0 + +#Less than 4 number of bricks should fail +TEST ! $GFS --xlator-option="*.ec-read-mask=0" -s $H0 --volfile-id $V0 $M0 +TEST ! $GFS --xlator-option="*.ec-read-mask=0:1" -s $H0 --volfile-id $V0 $M0 +TEST ! $GFS --xlator-option=*.ec-read-mask="0:1:2" -s $H0 --volfile-id $V0 $M0 + +#ids greater than 5 should fail +TEST ! $GFS --xlator-option="*.ec-read-mask=0:1:2:6" -s $H0 --volfile-id $V0 $M0 + +#ids less than 0 should fail +TEST ! $GFS --xlator-option="*.ec-read-mask=0:-1:2:5" -s $H0 --volfile-id $V0 $M0 + +#read-mask with non-alphabet or comma should fail +TEST ! $GFS --xlator-option="*.ec-read-mask=0:1:2:5:abc" -s $H0 --volfile-id $V0 $M0 +TEST ! $GFS --xlator-option="*.ec-read-mask=0:1:2:5a" -s $H0 --volfile-id $V0 $M0 + +#mount with at least 4 read-mask-ids and all of them valid should pass +TEST $GFS --xlator-option="*.ec-read-mask=0:1:2:5:4:3" -s $H0 --volfile-id $V0 $M0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "6" ec_child_up_count $V0 0 +EXPECT "^111111$" ec_option_value $V0 $M0 0 read-mask +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 + +TEST $GFS --xlator-option="*.ec-read-mask=0:1:2:5" -s $H0 --volfile-id $V0 $M0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "6" ec_child_up_count $V0 0 +EXPECT "^100111$" ec_option_value $V0 $M0 0 read-mask + +TEST dd if=/dev/urandom of=$M0/a bs=1M count=1 +md5=$(md5sum $M0/a | awk '{print $1}') +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 + +#Read on the file should fail if any of the read-mask is down when number of +#ids is data-count +TEST $GFS --xlator-option="*.ec-read-mask=0:1:2:5" -s $H0 --volfile-id $V0 $M0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "6" ec_child_up_count $V0 0 +EXPECT "^100111$" ec_option_value $V0 $M0 0 read-mask +TEST kill_brick $V0 $H0 $B0/${V0}0 +TEST ! dd if=$M0/a of=/dev/null +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 +TEST $CLI volume start $V0 force + +TEST $GFS --xlator-option="*.ec-read-mask=0:1:2:5" -s $H0 --volfile-id $V0 $M0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "6" ec_child_up_count $V0 0 +EXPECT "^100111$" ec_option_value $V0 $M0 0 read-mask +TEST kill_brick $V0 $H0 $B0/${V0}1 +TEST ! dd if=$M0/a of=/dev/null +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 +TEST $CLI volume start $V0 force + +TEST $GFS --xlator-option="*.ec-read-mask=0:1:2:5" -s $H0 --volfile-id $V0 $M0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "6" ec_child_up_count $V0 0 +EXPECT "^100111$" ec_option_value $V0 $M0 0 read-mask +TEST kill_brick $V0 $H0 $B0/${V0}2 +TEST ! dd if=$M0/a of=/dev/null +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 +TEST $CLI volume start $V0 force + +TEST $GFS --xlator-option="*.ec-read-mask=0:1:2:5" -s $H0 --volfile-id $V0 $M0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "6" ec_child_up_count $V0 0 +EXPECT "^100111$" ec_option_value $V0 $M0 0 read-mask +TEST kill_brick $V0 $H0 $B0/${V0}5 +TEST ! dd if=$M0/a of=/dev/null +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 +TEST $CLI volume start $V0 force + +#Read on file should succeed when non-read-mask bricks are down +TEST $GFS --xlator-option="*.ec-read-mask=0:1:2:5" -s $H0 --volfile-id $V0 $M0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "6" ec_child_up_count $V0 0 +EXPECT "^100111$" ec_option_value $V0 $M0 0 read-mask +TEST kill_brick $V0 $H0 $B0/${V0}3 +EXPECT "^$md5$" echo $(dd if=$M0/a | md5sum | awk '{print $1}') +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 +TEST $CLI volume start $V0 force + +TEST $GFS --xlator-option="*.ec-read-mask=0:1:2:5" -s $H0 --volfile-id $V0 $M0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "6" ec_child_up_count $V0 0 +EXPECT "^100111$" ec_option_value $V0 $M0 0 read-mask +TEST kill_brick $V0 $H0 $B0/${V0}4 +EXPECT "^$md5$" echo $(dd if=$M0/a | md5sum | awk '{print $1}') +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 +TEST $CLI volume start $V0 force + +TEST $GFS --xlator-option="*.ec-read-mask=0:1:2:5" -s $H0 --volfile-id $V0 $M0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "6" ec_child_up_count $V0 0 +EXPECT "^100111$" ec_option_value $V0 $M0 0 read-mask +TEST kill_brick $V0 $H0 $B0/${V0}3 +TEST kill_brick $V0 $H0 $B0/${V0}4 +EXPECT "^$md5$" echo $(dd if=$M0/a | md5sum | awk '{print $1}') +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 +TEST $CLI volume start $V0 force + +#Deliberately corrupt chunks 3: 4 and check that reads still give correct data +TEST dd if=/dev/zero of=$B0/${V0}3/a bs=256k count=1 +TEST dd if=/dev/zero of=$B0/${V0}4/a bs=256k count=1 +TEST $GFS --xlator-option="*.ec-read-mask=0:1:2:5" -s $H0 --volfile-id $V0 $M0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "6" ec_child_up_count $V0 0 +EXPECT "^100111$" ec_option_value $V0 $M0 0 read-mask +EXPECT "^$md5$" echo $(dd if=$M0/a | md5sum | awk '{print $1}') +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 + +cleanup; diff --git a/tests/basic/ec/ec-read-policy.t b/tests/basic/ec/ec-read-policy.t new file mode 100644 index 00000000000..fe6fe6576e7 --- /dev/null +++ b/tests/basic/ec/ec-read-policy.t @@ -0,0 +1,52 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +cleanup + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 disperse 6 redundancy 2 $H0:$B0/${V0}{0..5} +TEST $CLI volume set $V0 performance.quick-read off +TEST $CLI volume set $V0 performance.io-cache off +TEST $CLI volume set $V0 performance.write-behind off +TEST $CLI volume set $V0 performance.stat-prefetch off +TEST $CLI volume set $V0 performance.read-ahead off +TEST $CLI volume heal $V0 disable +TEST $CLI volume start $V0 + +#Disable all caching +TEST glusterfs --direct-io-mode=yes --entry-timeout=0 --attribute-timeout=0 -s $H0 --volfile-id $V0 $M0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "6" ec_child_up_count $V0 0 +#TEST volume operations work fine + +EXPECT "gfid-hash" mount_get_option_value $M0 $V0-disperse-0 read-policy +TEST $CLI volume set $V0 disperse.read-policy round-robin +EXPECT_WITHIN $CONFIG_UPDATE_TIMEOUT "round-robin" mount_get_option_value $M0 $V0-disperse-0 read-policy + +#TEST if the option gives the intended behavior. The way we perform this test +#is by performing reads from the mount and write to /dev/null. If the +#read-policy is round-robin, then all bricks should have read-fop where as +#with gfid-hash number of bricks with reads should be equal to (num-bricks - redundancy) +#count + +TEST $CLI volume profile $V0 start +TEST dd if=/dev/zero of=$M0/1 bs=1M count=4 +#Perform reads now from file on the mount, this only tests dispatch_min +TEST dd if=$M0/1 of=/dev/null bs=1M count=4 +#TEST that reads are executed on all bricks +rr_reads=$($CLI volume profile $V0 info cumulative| grep -w READ | wc -l) +EXPECT "^6$" echo $rr_reads +TEST $CLI volume profile $V0 info clear + +TEST $CLI volume set $V0 disperse.read-policy gfid-hash +EXPECT_WITHIN $CONFIG_UPDATE_TIMEOUT "gfid-hash" mount_get_option_value $M0 $V0-disperse-0 read-policy + +#Perform reads now from file on the mount, this only tests dispatch_min +TEST dd if=$M0/1 of=/dev/null bs=1M count=4 +#TEST that reads are executed on all bricks +gh_reads=$($CLI volume profile $V0 info cumulative| grep -w READ | wc -l) +EXPECT "^4$" echo $gh_reads + +cleanup; diff --git a/tests/basic/ec/ec-readdir.t b/tests/basic/ec/ec-readdir.t new file mode 100644 index 00000000000..fad101bcabe --- /dev/null +++ b/tests/basic/ec/ec-readdir.t @@ -0,0 +1,46 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +# This test checks that readdir works fine on distributed disperse volume + +cleanup +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 disperse 3 redundancy 1 $H0:$B0/${V0}{0..5} +TEST $CLI volume heal $V0 disable +TEST $CLI volume start $V0 + +TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0; +EXPECT_WITHIN $CHILD_UP_TIMEOUT "3" ec_child_up_count $V0 0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "3" ec_child_up_count $V0 1 + +TEST mkdir $M0/d +TEST touch $M0/d/{1..100} +EXPECT "100" echo $(ls $M0/d/* | wc -l) +TEST kill_brick $V0 $H0 $B0/${V0}0 +TEST kill_brick $V0 $H0 $B0/${V0}3 +TEST rm -rf $M0/d/{1..100} +TEST $CLI volume start $V0 force +EXPECT_WITHIN $CHILD_UP_TIMEOUT "3" ec_child_up_count $V0 0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "3" ec_child_up_count $V0 1 +#Do it 3 times so that even with all load balancing, readdir never falls +#on stale bricks +EXPECT "0" echo $(ls $M0/d/ | wc -l) +EXPECT "0" echo $(ls $M0/d/ | wc -l) +EXPECT "0" echo $(ls $M0/d/ | wc -l) +#Do the same test above for creation of entries +TEST mkdir $M0/d1 +TEST kill_brick $V0 $H0 $B0/${V0}0 +TEST kill_brick $V0 $H0 $B0/${V0}3 +TEST touch $M0/d1/{1..100} +TEST $CLI volume start $V0 force +EXPECT_WITHIN $CHILD_UP_TIMEOUT "3" ec_child_up_count $V0 0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "3" ec_child_up_count $V0 1 +#Do it 3 times so that even with all load balancing, readdir never falls +#on stale bricks +EXPECT "100" echo $(ls $M0/d1/ | wc -l) +EXPECT "100" echo $(ls $M0/d1/ | wc -l) +EXPECT "100" echo $(ls $M0/d1/ | wc -l) +cleanup diff --git a/tests/basic/ec/ec-rebalance.t b/tests/basic/ec/ec-rebalance.t new file mode 100644 index 00000000000..6cda3a3e4be --- /dev/null +++ b/tests/basic/ec/ec-rebalance.t @@ -0,0 +1,61 @@ +#!/bin/bash +# +# This will test the rebalance failure reported in 1447559 +# +### + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc +. $(dirname $0)/../../fallocate.rc + +cleanup + +#cleate and start volume +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 disperse 3 redundancy 1 $H0:$B0/${V0}{0..2} +TEST $CLI volume set $V0 lookup-optimize on +TEST $CLI volume start $V0 + +#Mount the volume +TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0; +EXPECT_WITHIN $CHILD_UP_TIMEOUT "3" ec_child_up_count $V0 0 + +# Create files +for i in {1..10} +do + dd if=/dev/urandom of=$M0/file$i bs=1024k count=1 +done + +md5_1=$(md5sum $M0/file1 | awk '{print $1}') +md5_2=$(md5sum $M0/file2 | awk '{print $1}') +md5_3=$(md5sum $M0/file3 | awk '{print $1}') +md5_4=$(md5sum $M0/file4 | awk '{print $1}') +md5_5=$(md5sum $M0/file5 | awk '{print $1}') +md5_6=$(md5sum $M0/file6 | awk '{print $1}') +md5_7=$(md5sum $M0/file7 | awk '{print $1}') +md5_8=$(md5sum $M0/file8 | awk '{print $1}') +md5_9=$(md5sum $M0/file9 | awk '{print $1}') +md5_10=$(md5sum $M0/file10 | awk '{print $1}') +# Add brick +TEST $CLI volume add-brick $V0 $H0:$B0/${V0}{3..5} + +#Trigger rebalance +TEST $CLI volume rebalance $V0 start force +EXPECT_WITHIN $REBALANCE_TIMEOUT "completed" rebalance_status_field $V0 + +#Remount to avoid any caches +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 +TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0; +EXPECT "$md5_1" echo $(md5sum $M0/file1 | awk '{print $1}') +EXPECT "$md5_2" echo $(md5sum $M0/file2 | awk '{print $1}') +EXPECT "$md5_3" echo $(md5sum $M0/file3 | awk '{print $1}') +EXPECT "$md5_4" echo $(md5sum $M0/file4 | awk '{print $1}') +EXPECT "$md5_5" echo $(md5sum $M0/file5 | awk '{print $1}') +EXPECT "$md5_6" echo $(md5sum $M0/file6 | awk '{print $1}') +EXPECT "$md5_7" echo $(md5sum $M0/file7 | awk '{print $1}') +EXPECT "$md5_8" echo $(md5sum $M0/file8 | awk '{print $1}') +EXPECT "$md5_9" echo $(md5sum $M0/file9 | awk '{print $1}') +EXPECT "$md5_10" echo $(md5sum $M0/file10 | awk '{print $1}') + +cleanup; diff --git a/tests/basic/ec/ec-reset-brick.t b/tests/basic/ec/ec-reset-brick.t new file mode 100644 index 00000000000..f1a625df4ff --- /dev/null +++ b/tests/basic/ec/ec-reset-brick.t @@ -0,0 +1,50 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +cleanup +function num_entries { + ls -l $1 | wc -l +} + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 disperse 6 redundancy 2 $H0:$B0/${V0}{0..5} +TEST $CLI volume start $V0 +TEST glusterfs --entry-timeout=0 --attribute-timeout=0 -s $H0 --volfile-id $V0 $M0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "6" ec_child_up_count $V0 0 + +mkdir $M0/dir +touch $M0/dir/{1..10} + +mkdir $M0/dir/dir1 +touch $M0/dir/dir1/{1..10} + +#kill brick process +TEST $CLI volume reset-brick $V0 $H0:$B0/${V0}5 start +EXPECT_WITHIN $CHILD_UP_TIMEOUT "5" ec_child_up_count $V0 0 + +#reset-brick by removing all the data and create dir again +rm -rf $B0/${V0}5 +mkdir $B0/${V0}5 + +#start brick process and heal by commiting reset-brick +TEST $CLI volume reset-brick $V0 $H0:$B0/${V0}5 $H0:$B0/${V0}5 commit force + +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "Y" glustershd_up_status +EXPECT_WITHIN $CHILD_UP_TIMEOUT "6" ec_child_up_count_shd $V0 0 + +EXPECT_WITHIN $HEAL_TIMEOUT "^0$" get_pending_heal_count ${V0} + +EXPECT "^12$" num_entries $B0/${V0}5/dir +EXPECT "^11$" num_entries $B0/${V0}5/dir/dir1 + +ec_version=$(get_hex_xattr trusted.ec.version $B0/${V0}0) +EXPECT "$ec_version" get_hex_xattr trusted.ec.version $B0/${V0}1 +EXPECT "$ec_version" get_hex_xattr trusted.ec.version $B0/${V0}2 +EXPECT "$ec_version" get_hex_xattr trusted.ec.version $B0/${V0}3 +EXPECT "$ec_version" get_hex_xattr trusted.ec.version $B0/${V0}4 +EXPECT "$ec_version" get_hex_xattr trusted.ec.version $B0/${V0}5 + +cleanup; diff --git a/tests/basic/ec/ec-root-heal.t b/tests/basic/ec/ec-root-heal.t new file mode 100644 index 00000000000..11ea7cdf9d4 --- /dev/null +++ b/tests/basic/ec/ec-root-heal.t @@ -0,0 +1,34 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +cleanup +function num_entries { + ls -l $1 | wc -l +} + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 disperse 6 redundancy 2 $H0:$B0/${V0}{0..5} +TEST $CLI volume start $V0 +TEST glusterfs --entry-timeout=0 --attribute-timeout=0 -s $H0 --volfile-id $V0 $M0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "6" ec_child_up_count $V0 0 +touch $M0/{1..10} +TEST $CLI volume replace-brick $V0 $H0:$B0/${V0}5 $H0:$B0/${V0}6 commit force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "Y" glustershd_up_status +EXPECT_WITHIN $CHILD_UP_TIMEOUT "6" ec_child_up_count_shd $V0 0 + +# active heal +TEST $CLI volume heal $V0 full +#ls -l gives "Total" line so number of lines will be 1 more +EXPECT_WITHIN $HEAL_TIMEOUT "^0$" get_pending_heal_count ${V0} +EXPECT "^11$" num_entries $B0/${V0}6 +ec_version=$(get_hex_xattr trusted.ec.version $B0/${V0}0) +EXPECT "$ec_version" get_hex_xattr trusted.ec.version $B0/${V0}1 +EXPECT "$ec_version" get_hex_xattr trusted.ec.version $B0/${V0}2 +EXPECT "$ec_version" get_hex_xattr trusted.ec.version $B0/${V0}3 +EXPECT "$ec_version" get_hex_xattr trusted.ec.version $B0/${V0}4 +EXPECT "$ec_version" get_hex_xattr trusted.ec.version $B0/${V0}6 + +cleanup; diff --git a/tests/basic/ec/ec-seek.t b/tests/basic/ec/ec-seek.t new file mode 100644 index 00000000000..5a7d31b9f8f --- /dev/null +++ b/tests/basic/ec/ec-seek.t @@ -0,0 +1,58 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +cleanup + +SEEK=$(dirname $0)/seek +build_tester $(dirname $0)/../seek.c -o ${SEEK} + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume info + +TEST mkdir -p $B0/${V0}{0..2} +TEST $CLI volume create $V0 disperse 3 redundancy 1 $H0:$B0/${V0}{0..2} + +EXPECT "$V0" volinfo_field $V0 'Volume Name' +EXPECT 'Created' volinfo_field $V0 'Status' +EXPECT '3' brick_count $V0 + +TEST $CLI volume start $V0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT 'Started' volinfo_field $V0 'Status' + +TEST $GFS -s $H0 --volfile-id $V0 $M0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "3" ec_child_up_count $V0 0 + +TEST ${SEEK} create ${M0}/test 0 1 1048576 1 +# Determine underlying filesystem allocation block size +BSIZE="$(($(${SEEK} scan ${M0}/test hole 0) * 2))" + +TEST ${SEEK} create ${M0}/test 0 ${BSIZE} $((${BSIZE} * 4 + 512)) ${BSIZE} + +EXPECT "^0$" ${SEEK} scan ${M0}/test data 0 +EXPECT "^$((${BSIZE} / 2))$" ${SEEK} scan ${M0}/test data $((${BSIZE} / 2)) +EXPECT "^$((${BSIZE} - 1))$" ${SEEK} scan ${M0}/test data $((${BSIZE} - 1)) +EXPECT "^$((${BSIZE} * 4))$" ${SEEK} scan ${M0}/test data ${BSIZE} +EXPECT "^$((${BSIZE} * 4))$" ${SEEK} scan ${M0}/test data $((${BSIZE} * 4)) +EXPECT "^$((${BSIZE} * 5))$" ${SEEK} scan ${M0}/test data $((${BSIZE} * 5)) +EXPECT "^$((${BSIZE} * 5 + 511))$" ${SEEK} scan ${M0}/test data $((${BSIZE} * 5 + 511)) +EXPECT "^ENXIO$" ${SEEK} scan ${M0}/test data $((${BSIZE} * 5 + 512)) +EXPECT "^ENXIO$" ${SEEK} scan ${M0}/test data $((${BSIZE} * 6)) + +EXPECT "^${BSIZE}$" ${SEEK} scan ${M0}/test hole 0 +EXPECT "^${BSIZE}$" ${SEEK} scan ${M0}/test hole $((${BSIZE} / 2)) +EXPECT "^${BSIZE}$" ${SEEK} scan ${M0}/test hole $((${BSIZE} - 1)) +EXPECT "^${BSIZE}$" ${SEEK} scan ${M0}/test hole ${BSIZE} +EXPECT "^$((${BSIZE} * 5 + 512))$" ${SEEK} scan ${M0}/test hole $((${BSIZE} * 4)) +EXPECT "^$((${BSIZE} * 5 + 512))$" ${SEEK} scan ${M0}/test hole $((${BSIZE} * 5)) +EXPECT "^$((${BSIZE} * 5 + 512))$" ${SEEK} scan ${M0}/test hole $((${BSIZE} * 5 + 511)) +EXPECT "^ENXIO$" ${SEEK} scan ${M0}/test hole $((${BSIZE} * 5 + 512)) +EXPECT "^ENXIO$" ${SEEK} scan ${M0}/test hole $((${BSIZE} * 6)) + +rm -f ${SEEK} +cleanup + +# Centos6 regression slaves seem to not support SEEK_DATA/SEEK_HOLE +#G_TESTDEF_TEST_STATUS_CENTOS6=BAD_TEST,BUG=000000 diff --git a/tests/basic/ec/ec-stripe.t b/tests/basic/ec/ec-stripe.t new file mode 100644 index 00000000000..98b92294feb --- /dev/null +++ b/tests/basic/ec/ec-stripe.t @@ -0,0 +1,227 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +# These tests will check the stripe cache functionality of +# disperse volume + +test_index=0 +stripe_count=4 +loop_test=0 + +TESTS_EXPECTED_IN_LOOP=182 + +function get_mount_stripe_cache { + local sd=$1 + local field=$2 + local val=$(grep "$field" $sd | cut -f2 -d'=' | tail -1) + echo $val +} + +function get_stripes_in_cache { + local target=$1 + local count=$2 + local c=0 + for (( c=0; c<$count; c++ )) + do + let x=102+$c*1024 + echo yy | dd of=$target oflag=seek_bytes,sync seek=$x conv=notrunc + if [ $? != 0 ] + then + break + fi + done + echo "$c" +} +# tests in this loop = 7 +function mount_get_test_files { + let test_index+=1 + let loop_test+=7 + echo "Test Case $test_index" + local stripe_count=$1 + TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0; + EXPECT_WITHIN $CHILD_UP_TIMEOUT "3" ec_child_up_count $V0 0 + TEST dd if=/dev/urandom of=$B0/test_file bs=1024 count=20 + TEST cp $B0/test_file $M0/test_file + TEST dd if=/dev/urandom of=$B0/misc_file bs=1024 count=20 + EXPECT_WITHIN $UMOUNT_TIMEOUT "$stripe_count" get_stripes_in_cache $B0/test_file $stripe_count + EXPECT_WITHIN $UMOUNT_TIMEOUT "$stripe_count" get_stripes_in_cache $M0/test_file $stripe_count +} + +#check_statedump_md5sum (hitcount misscount) +#tests in this loop = 4 +function check_statedump_md5sum { + statedump=$(generate_mount_statedump $V0) + let loop_test+=4 + sleep 1 + nhits=$(get_mount_stripe_cache $statedump "hits") + nmisses=$(get_mount_stripe_cache $statedump "misses") + EXPECT "$1" echo $nhits + EXPECT "$2" echo $nmisses + TEST md5_sum=`get_md5_sum $B0/test_file` + EXPECT $md5_sum get_md5_sum $M0/test_file +} + +#tests in this loop = 2 +function clean_file_unmount { + let loop_test+=2 + TEST rm -f $B0/test_file $M0/test_file $B0/misc_file + cleanup_mount_statedump $V0 + EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 +} + +cleanup +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 disperse 3 redundancy 1 $H0:$B0/${V0}{0..2} +TEST $CLI volume heal $V0 disable +TEST $CLI volume set $V0 performance.stat-prefetch off +TEST $CLI volume set $V0 performance.write-behind off +TEST $CLI volume set $V0 performance.quick-read off +TEST $CLI volume set $V0 performance.read-ahead off +TEST $CLI volume set $V0 performance.io-cache off +TEST $CLI volume set $V0 disperse.background-heals 0 +TEST $CLI volume set $V0 disperse.eager-lock on +TEST $CLI volume set $V0 disperse.other-eager-lock on +TEST $CLI volume set $V0 disperse.stripe-cache 8 +TEST $CLI volume start $V0 + +### 1 - offset and size in one stripes #### + +mount_get_test_files $stripe_count +# This should have 4 hits on cached stripes +get_stripes_in_cache $M0/test_file $stripe_count +check_statedump_md5sum 4 4 +clean_file_unmount + +### 2 - Length less than a stripe size, covering two stripes #### + +mount_get_test_files $stripe_count +TEST dd if=$B0/misc_file of=$B0/test_file bs=1022 count=1 oflag=seek_bytes,sync seek=102 conv=notrunc +TEST dd if=$B0/misc_file of=$M0/test_file bs=1022 count=1 oflag=seek_bytes,sync seek=102 conv=notrunc +check_statedump_md5sum 2 4 +clean_file_unmount + +### 3 -Length exactly equal to the stripe size, covering a single stripe #### + +mount_get_test_files $stripe_count +TEST dd if=$B0/misc_file of=$B0/test_file bs=1024 count=1 oflag=seek_bytes,sync seek=0 conv=notrunc +TEST dd if=$B0/misc_file of=$M0/test_file bs=1024 count=1 oflag=seek_bytes,sync seek=0 conv=notrunc +check_statedump_md5sum 0 4 +clean_file_unmount + +### 4 - Length exactly equal to the stripe size, covering two stripes #### + +mount_get_test_files $stripe_count +TEST dd if=$B0/misc_file of=$B0/test_file bs=2048 count=1 oflag=seek_bytes,sync seek=1024 conv=notrunc +TEST dd if=$B0/misc_file of=$M0/test_file bs=2048 count=1 oflag=seek_bytes,sync seek=1024 conv=notrunc +check_statedump_md5sum 0 4 +clean_file_unmount + +### 5 - Length greater than a stripe size, covering two stripes #### + +mount_get_test_files $stripe_count +TEST dd if=$B0/misc_file of=$B0/test_file bs=1030 count=1 oflag=seek_bytes,sync seek=500 conv=notrunc +TEST dd if=$B0/misc_file of=$M0/test_file bs=1030 count=1 oflag=seek_bytes,sync seek=500 conv=notrunc +check_statedump_md5sum 2 4 +clean_file_unmount + +### 6 - Length greater than a stripe size, covering three stripes #### + +mount_get_test_files $stripe_count +TEST dd if=$B0/misc_file of=$B0/test_file bs=2078 count=1 oflag=seek_bytes,sync seek=1000 conv=notrunc +TEST dd if=$B0/misc_file of=$M0/test_file bs=2078 count=1 oflag=seek_bytes,sync seek=1000 conv=notrunc +check_statedump_md5sum 2 4 +clean_file_unmount + +### 7 - Discard range - all stripe from cache should be invalidated complete stripes #### + +mount_get_test_files $stripe_count +TEST fallocate -p -o 0 -l 5120 $B0/test_file +TEST fallocate -p -o 0 -l 5120 $M0/test_file +TEST dd if=$B0/misc_file of=$B0/test_file bs=1024 count=6 oflag=seek_bytes,sync seek=1030 conv=notrunc +TEST dd if=$B0/misc_file of=$M0/test_file bs=1024 count=6 oflag=seek_bytes,sync seek=1030 conv=notrunc +check_statedump_md5sum 5 11 +clean_file_unmount + +### 8 - Discard range - starts in the middle of stripe, ends on the middle of next stripe#### + +mount_get_test_files $stripe_count +TEST fallocate -p -o 500 -l 1024 $B0/test_file +TEST fallocate -p -o 500 -l 1024 $M0/test_file +TEST dd if=$B0/misc_file of=$B0/test_file bs=1024 count=5 oflag=seek_bytes,sync seek=500 conv=notrunc +TEST dd if=$B0/misc_file of=$M0/test_file bs=1024 count=5 oflag=seek_bytes,sync seek=500 conv=notrunc +check_statedump_md5sum 10 6 +clean_file_unmount + +### 9 - Discard range - starts in the middle of stripe, ends on the middle of 3rd stripe##### + +mount_get_test_files $stripe_count +TEST fallocate -p -o 500 -l 2048 $B0/test_file +TEST fallocate -p -o 500 -l 2048 $M0/test_file +TEST dd if=$B0/misc_file of=$B0/test_file bs=1024 count=5 oflag=seek_bytes,sync seek=500 conv=notrunc +TEST dd if=$B0/misc_file of=$M0/test_file bs=1024 count=5 oflag=seek_bytes,sync seek=500 conv=notrunc +check_statedump_md5sum 9 7 +clean_file_unmount + +### 10 - Discard range - starts and end within one stripe #### + +mount_get_test_files $stripe_count +TEST fallocate -p -o 500 -l 100 $B0/test_file +TEST fallocate -p -o 500 -l 100 $M0/test_file +TEST dd if=$B0/misc_file of=$B0/test_file bs=1024 count=1 oflag=seek_bytes,sync seek=0 conv=notrunc +TEST dd if=$B0/misc_file of=$M0/test_file bs=1024 count=1 oflag=seek_bytes,sync seek=0 conv=notrunc +check_statedump_md5sum 1 4 +clean_file_unmount + +### 11 - Discard range - starts and end in one complete stripe #### + +mount_get_test_files $stripe_count +TEST fallocate -p -o 0 -l 1024 $B0/test_file +TEST fallocate -p -o 0 -l 1024 $M0/test_file +TEST dd if=$B0/misc_file of=$B0/test_file bs=1024 count=1 oflag=seek_bytes,sync seek=512 conv=notrunc +TEST dd if=$B0/misc_file of=$M0/test_file bs=1024 count=1 oflag=seek_bytes,sync seek=512 conv=notrunc +check_statedump_md5sum 1 5 +clean_file_unmount + +### 12 - Discard range - starts and end two complete stripe #### + +mount_get_test_files $stripe_count +TEST fallocate -p -o 0 -l 2048 $B0/test_file +TEST fallocate -p -o 0 -l 2048 $M0/test_file +TEST dd if=$B0/misc_file of=$B0/test_file bs=1024 count=4 oflag=seek_bytes,sync seek=300 conv=notrunc +TEST dd if=$B0/misc_file of=$M0/test_file bs=1024 count=4 oflag=seek_bytes,sync seek=300 conv=notrunc +check_statedump_md5sum 5 7 +clean_file_unmount + +### 13 - Truncate to invalidate all the stripe in cache #### + +mount_get_test_files $stripe_count +TEST truncate -s 0 $B0/test_file +TEST truncate -s 0 $M0/test_file +TEST dd if=$B0/misc_file of=$B0/test_file bs=1022 count=5 oflag=seek_bytes,sync seek=400 conv=notrunc +TEST dd if=$B0/misc_file of=$M0/test_file bs=1022 count=5 oflag=seek_bytes,sync seek=400 conv=notrunc +check_statedump_md5sum 4 4 +clean_file_unmount + +### 14 - Truncate to invalidate all but one the stripe in cache #### + +mount_get_test_files $stripe_count +TEST truncate -s 500 $B0/test_file +TEST truncate -s 500 $M0/test_file +TEST dd if=$B0/misc_file of=$B0/test_file bs=1024 count=1 oflag=seek_bytes,sync seek=525 conv=notrunc +TEST dd if=$B0/misc_file of=$M0/test_file bs=1024 count=1 oflag=seek_bytes,sync seek=525 conv=notrunc +check_statedump_md5sum 2 4 +clean_file_unmount + +### 15 - Truncate to invalidate all but one the stripe in cache #### +mount_get_test_files $stripe_count +TEST truncate -s 2148 $B0/test_file +TEST truncate -s 2148 $M0/test_file +TEST dd if=$B0/misc_file of=$B0/test_file bs=1000 count=1 oflag=seek_bytes,sync seek=2050 conv=notrunc +TEST dd if=$B0/misc_file of=$M0/test_file bs=1000 count=1 oflag=seek_bytes,sync seek=2050 conv=notrunc +check_statedump_md5sum 2 4 +clean_file_unmount +echo "Total loop tests $loop_test" +cleanup diff --git a/tests/basic/ec/ec-up.t b/tests/basic/ec/ec-up.t new file mode 100644 index 00000000000..d54e7e1d022 --- /dev/null +++ b/tests/basic/ec/ec-up.t @@ -0,0 +1,28 @@ +#!/bin/bash +#Tests that ec subvolume is up/down correctly + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc +. $(dirname $0)/../../ec.rc + +cleanup; + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 disperse-data 2 redundancy 1 $H0:$B0/${V0}{0,1,3,4,5,6} +TEST $CLI volume start $V0 +TEST $GFS --volfile-id=$V0 --volfile-server=$H0 $M0; +EXPECT "1" ec_up_status $V0 $M0 0 +EXPECT "1" ec_up_status $V0 $M0 1 + +#kill two bricks in first disperse subvolume and check that ec_up_status is 0 for it +TEST kill_brick $V0 $H0 $B0/${V0}0 +TEST kill_brick $V0 $H0 $B0/${V0}1 + +EXPECT_WITHIN $PROCESS_DOWN_TIMEOUT "0" ec_up_status $V0 $M0 0 +EXPECT "1" ec_up_status $V0 $M0 1 + +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" ec_up_status $V0 $M0 0 +EXPECT "1" ec_up_status $V0 $M0 1 +cleanup; diff --git a/tests/basic/ec/ec.t b/tests/basic/ec/ec.t new file mode 100644 index 00000000000..cc882771501 --- /dev/null +++ b/tests/basic/ec/ec.t @@ -0,0 +1,259 @@ +#!/bin/bash + +. $(dirname $0)/../../traps.rc +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +TEST_USER=test-ec-user +TEST_UID=27341 + +function my_getfattr { + getfattr --only-values -e text $* 2> /dev/null +} + +function get_rep_count { + v=$(my_getfattr -n trusted.jbr.rep-count $1) + #echo $v > /dev/tty + echo $v +} + +function create_file { + dd if=/dev/urandom of=$1 bs=4k count=$2 conv=sync 2> /dev/null +} + +function setup_perm_file { + mkdir $1/perm_dir || return 1 + chown ${TEST_USER} $1/perm_dir || return 1 + su ${TEST_USER} -c "touch $1/perm_dir/perm_file" || return 1 + return 0 +} + +# Functions to check repair for specific operation types. + +function check_create_write { + for b in $*; do + cmp $tmpdir/create-write $b/create-write || return 1 + done + return 0 +} + +function check_truncate { + truncate -s 8192 $tmpdir/truncate + for b in $*; do + cmp $tmpdir/truncate $b/truncate || return 1 + done + return 0 +} + +function check_hard_link { + stat $M0/hard-link-1 + stat $M0/hard-link-2 + for b in $*; do + inum1=$(ls -i $b/hard-link-1 | cut -d' ' -f1) + inum2=$(ls -i $b/hard-link-2 | cut -d' ' -f1) + if [ "$inum1" != "$inum2" ]; then + echo "N" + return 0 + fi + done + echo "Y" + return 0 +} + +function check_soft_link { + stat $M0/soft-link + for b in $*; do + if [ "$(readlink $b/soft-link)" != "soft-link-tgt" ]; then + echo "N" + return 0 + fi + done + echo "Y" + return 0 +} + +function check_unlink { + stat $M0/unlink + for b in $*; do + if [ -e $b/unlink ]; then + echo "N" + return 0 + fi + done + echo "Y" + return 0 +} + +function check_mkdir { + getfattr -m. -d $M0/mkdir + for b in $*; do + if [ ! -d $b/mkdir ]; then + echo "N" + return 0 + fi + done + echo "Y" + return 0 +} + +function check_rmdir { + getfattr -m. -d $M0/rmdir + for b in $*; do + if [ -e $b/rmdir ]; then + echo "N" + return 0 + fi + done + echo "Y" + return 0 +} + +function check_setxattr { + getfattr -d -m. -e hex $M0/setxattr + for b in $*; do + v=$(my_getfattr -n user.foo $b/setxattr) + if [ "$v" != "ash_nazg_durbatuluk" ]; then + echo "N" + return 0 + fi + done + echo "Y" + return 0 +} + +function check_removexattr { + getfattr -d -m. -e hex $M0/removexattr + for b in $*; do + my_getfattr -n user.bar $b/removexattr 2> /dev/null + if [ $? -eq 0 ]; then + echo "N" + return 0 + fi + done + echo "Y" + return 0 +} + +function check_perm_file { + stat $M0/perm_dir/perm_file + getfattr -m. -d $M0/perm_dir + b1=$1 + shift 1 + ftext=$(stat -c "%u %g %a" $b1/perm_dir/perm_file) + #echo "first u/g/a = $ftext" > /dev/tty + for b in $*; do + btext=$(stat -c "%u %g %a" $b/perm_dir/perm_file) + #echo " next u/a/a = $btext" > /dev/tty + if [ x"$btext" != x"$ftext" ]; then + echo "N" + return 0 + fi + done + echo "Y" + return 0 +} + +cleanup + +TEST useradd -o -M -u ${TEST_UID} ${TEST_USER} +push_trapfunc "userdel --force ${TEST_USER}" + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume info + +TEST mkdir -p $B0/${V0}{0,1,2,3,4,5,6,7,8,9} +TEST $CLI volume create $V0 disperse 10 redundancy 2 $H0:$B0/${V0}{0,1,2,3,4,5,6,7,8,9} + +EXPECT "$V0" volinfo_field $V0 'Volume Name' +EXPECT 'Created' volinfo_field $V0 'Status' +EXPECT '10' brick_count $V0 + +TEST $CLI volume start $V0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT 'Started' volinfo_field $V0 'Status' + +# Mount FUSE with caching disabled +TEST $GFS -s $H0 --volfile-id $V0 $M0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "10" ec_child_up_count $V0 0 + +# Create local files for comparisons etc. +tmpdir=$(mktemp -d -t ${0##*/}.XXXXXX) +push_trapfunc "rm -rf $tmpdir" +TEST create_file $tmpdir/create-write 10 +TEST create_file $tmpdir/truncate 10 + +# Prepare files and directories we'll need later. +TEST cp $tmpdir/truncate $M0/ +TEST touch $M0/hard-link-1 +TEST touch $M0/unlink +TEST mkdir $M0/rmdir +TEST touch $M0/setxattr +TEST touch $M0/removexattr +TEST setfattr -n user.bar -v "ash_nazg_gimbatul" $M0/removexattr + +sleep 2 + +# Kill a couple of bricks and allow some time for things to settle. +TEST kill_brick $V0 $H0 $B0/${V0}3 +TEST kill_brick $V0 $H0 $B0/${V0}8 +sleep 10 + +# Test create+write +TEST cp $tmpdir/create-write $M0/ +# Test truncate +TEST truncate -s 8192 $M0/truncate +# Test hard link +TEST ln $M0/hard-link-1 $M0/hard-link-2 +# Test soft link +TEST ln -s soft-link-tgt $M0/soft-link +# Test unlink +TEST rm $M0/unlink +# Test rmdir +TEST rmdir $M0/rmdir +# Test mkdir +TEST mkdir $M0/mkdir +# Test setxattr +TEST setfattr -n user.foo -v "ash_nazg_durbatuluk" $M0/setxattr +# Test removexattr +TEST setfattr -x user.bar $M0/removexattr +# Test uid/gid behavior +TEST setup_perm_file $M0 + +sleep 2 + +# Unmount/remount so that create/write and truncate don't see cached data. +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 +TEST $GFS -s $H0 --volfile-id $V0 $M1 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "8" ec_child_up_count $V0 0 + +# Test create/write and truncate *before* the bricks are brought back. +TEST check_create_write $M1 +TEST check_truncate $M1 + +# Restart the bricks and allow repair to occur. +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT 'Started' volinfo_field $V0 'Status' +EXPECT_WITHIN $CHILD_UP_TIMEOUT "10" ec_child_up_count $V0 0 + +# Unmount/remount again, same reason as before. +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M1 +TEST $GFS -s $H0 --volfile-id $V0 $M0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "10" ec_child_up_count $V0 0 + +# Make sure everything is as it should be. Most tests check for consistency +# between the bricks and the front end. This is not valid for disperse, so we +# check the mountpoint state instead. + +TEST check_create_write $M0 +TEST check_truncate $M0 + +EXPECT_WITHIN $HEAL_TIMEOUT "Y" check_hard_link $B0/${V0}{0..9} +EXPECT_WITHIN $HEAL_TIMEOUT "Y" check_soft_link $B0/${V0}{0..9} +EXPECT_WITHIN $HEAL_TIMEOUT "Y" check_unlink $B0/${V0}{0..9} +EXPECT_WITHIN $HEAL_TIMEOUT "Y" check_rmdir $B0/${V0}{0..9} +EXPECT_WITHIN $HEAL_TIMEOUT "Y" check_mkdir $B0/${V0}{0..9} +EXPECT_WITHIN $HEAL_TIMEOUT "Y" check_setxattr $B0/${V0}{0..9} +EXPECT_WITHIN $HEAL_TIMEOUT "Y" check_removexattr $B0/${V0}{0..9} +EXPECT_WITHIN $HEAL_TIMEOUT "Y" check_perm_file $B0/${V0}{0..9} + +cleanup diff --git a/tests/basic/ec/gfapi-ec-open-truncate.c b/tests/basic/ec/gfapi-ec-open-truncate.c new file mode 100644 index 00000000000..fb16807003a --- /dev/null +++ b/tests/basic/ec/gfapi-ec-open-truncate.c @@ -0,0 +1,171 @@ +#include <fcntl.h> +#include <unistd.h> +#include <time.h> +#include <limits.h> +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <glusterfs/api/glfs.h> +#include <glusterfs/api/glfs-handles.h> + +#define LOG_ERR(msg) \ + do { \ + fprintf(stderr, "%s : Error (%s)\n", msg, strerror(errno)); \ + } while (0) + +int +fill_iov(struct iovec *iov, char fillchar, int count) +{ + int ret = -1; + + iov->iov_base = calloc(count + 1, sizeof(fillchar)); + if (iov->iov_base == NULL) { + return ret; + } else { + iov->iov_len = count; + ret = 0; + } + memset(iov->iov_base, fillchar, count); + memset(iov->iov_base + count, '\0', 1); + + return ret; +} + +glfs_t * +init_glfs(const char *hostname, const char *volname, const char *logfile) +{ + int ret = -1; + glfs_t *fs = NULL; + + fs = glfs_new(volname); + if (!fs) { + LOG_ERR("glfs_new failed"); + return NULL; + } + + ret = glfs_set_volfile_server(fs, "tcp", hostname, 24007); + if (ret < 0) { + LOG_ERR("glfs_set_volfile_server failed"); + goto out; + } + + ret = glfs_set_logging(fs, logfile, 7); + if (ret < 0) { + LOG_ERR("glfs_set_logging failed"); + goto out; + } + + ret = glfs_init(fs); + if (ret < 0) { + LOG_ERR("glfs_init failed"); + goto out; + } + + ret = 0; +out: + if (ret) { + glfs_fini(fs); + fs = NULL; + } + + return fs; +} + +int +main(int argc, char *argv[]) +{ + char *hostname = NULL; + char *volname = NULL; + char *logfile = NULL; + glfs_t *fs = NULL; + glfs_fd_t *glfd = NULL; + int ret = 0; + int i = 0; + int count = 200; + struct iovec iov = {0}; + int flags = O_RDWR; + int bricksup = 0; + int fdopen = 0; + + if (argc != 4) { + fprintf(stderr, "Invalid argument\n"); + exit(1); + } + + hostname = argv[1]; + volname = argv[2]; + logfile = argv[3]; + + fs = init_glfs(hostname, volname, logfile); + if (fs == NULL) { + LOG_ERR("init_glfs failed"); + return -1; + } + + /* Brick is down and we are opening a file to trigger fd heal. */ + /* Bypass Write-behind */ + glfd = glfs_open(fs, "a", O_WRONLY | O_TRUNC | O_SYNC); + if (glfd == NULL) { + LOG_ERR("glfs_open_truncate failed"); + exit(1); + } + system("gluster --mode=script volume start patchy force"); + /*CHILD_UP_TIMEOUT is 20 seconds*/ + for (i = 0; i < 20; i++) { + ret = system( + "[ $(gluster --mode=script volume status patchy | " + "grep \" Y \" | awk '{print $(NF-1)}' | wc -l) == 3 ]"); + if (WIFEXITED(ret) && WEXITSTATUS(ret)) { + printf("Ret value of system: %d\n, ifexited: %d, exitstatus: %d", + ret, WIFEXITED(ret), WEXITSTATUS(ret)); + sleep(1); + continue; + } + printf("Number of loops: %d\n", i); + bricksup = 1; + break; + } + if (!bricksup) { + system("gluster --mode=script volume status patchy"); + LOG_ERR("Bricks didn't come up\n"); + exit(1); + } + + /*Not sure how to check that the child-up reached EC, so sleep 3 for now*/ + sleep(3); + ret = fill_iov(&iov, 'a', 200); + if (ret) { + LOG_ERR("failed to create iov"); + exit(1); + } + + /*write will trigger re-open*/ + ret = glfs_pwritev(glfd, &iov, 1, 0, flags); + if (ret < 0) { + LOG_ERR("glfs_test_function failed"); + exit(1); + } + /*Check reopen happened by checking for open-fds on the brick*/ + for (i = 0; i < 20; i++) { + ret = system( + "[ $(for i in $(pgrep glusterfsd); do ls -l /proc/$i/fd | grep " + "\"[.]glusterfs\" | grep -v \".glusterfs/[0-9a-f][0-9a-f]\" | grep " + "-v health_check; done | wc -l) == 3 ]"); + if (WIFEXITED(ret) && WEXITSTATUS(ret)) { + printf("Ret value of system: %d\n, ifexited: %d, exitstatus: %d", + ret, WIFEXITED(ret), WEXITSTATUS(ret)); + sleep(1); + continue; + } + fdopen = 1; + break; + } + + if (!fdopen) { + LOG_ERR("fd reopen didn't succeed"); + exit(1); + } + + return 0; +} diff --git a/tests/basic/ec/gfapi-ec-open-truncate.t b/tests/basic/ec/gfapi-ec-open-truncate.t new file mode 100644 index 00000000000..e22562c6ea3 --- /dev/null +++ b/tests/basic/ec/gfapi-ec-open-truncate.t @@ -0,0 +1,48 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +#This .t tests the functionality of open-fd-heal when opened with O_TRUNC. +#If re-open is not done with O_TRUNC then the test will pass. + +cleanup + +TEST glusterd + +TEST $CLI volume create $V0 disperse 3 ${H0}:$B0/brick{1,2,3} +EXPECT 'Created' volinfo_field $V0 'Status' +#Disable heals to prevent any chance of heals masking the problem +TEST $CLI volume set $V0 disperse.background-heals 0 +TEST $CLI volume set $V0 disperse.heal-wait-qlength 0 +TEST $CLI volume set $V0 performance.write-behind off + +#We need truncate fop to go through before pre-op completes for the write-fop +#which triggers open-fd heal. Otherwise truncate won't be allowed on 'bad' brick +TEST $CLI volume set $V0 delay-gen posix +TEST $CLI volume set $V0 delay-gen.enable fxattrop +TEST $CLI volume set $V0 delay-gen.delay-percentage 100 +TEST $CLI volume set $V0 delay-gen.delay-duration 1000000 + +TEST $CLI volume heal $V0 disable + +TEST $CLI volume start $V0 +TEST $CLI volume profile $V0 start +EXPECT 'Started' volinfo_field $V0 'Status' +TEST glusterfs --entry-timeout=0 --attribute-timeout=0 -s $H0 --volfile-id $V0 $M0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "3" ec_child_up_count $V0 0 +TEST touch $M0/a +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 + +TEST kill_brick $V0 $H0 $B0/brick1 +logdir=`gluster --print-logdir` + +TEST build_tester $(dirname $0)/gfapi-ec-open-truncate.c -lgfapi + +TEST $CLI volume profile $V0 info clear +TEST ./$(dirname $0)/gfapi-ec-open-truncate ${H0} $V0 $logdir/gfapi-ec-open-truncate.log + +EXPECT "^2$" echo $($CLI volume profile $V0 info incremental | grep -i truncate | wc -l) +cleanup_tester $(dirname $0)/gfapi-ec-open-truncate + +cleanup diff --git a/tests/basic/ec/heal-info.t b/tests/basic/ec/heal-info.t new file mode 100644 index 00000000000..1549d5fcdb0 --- /dev/null +++ b/tests/basic/ec/heal-info.t @@ -0,0 +1,74 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +# This test checks if heal info works as expected or not + +function create_files { + for i in {21..1000}; + do + dd if=/dev/zero of=$M0/$i bs=1M count=1 2>&1 > /dev/null; + done + rm -f $M0/lock +} + +cleanup + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 redundancy 2 $H0:$B0/${V0}{0..5} +TEST $CLI volume set $V0 client-log-level DEBUG +TEST $CLI volume heal $V0 disable +TEST $CLI volume start $V0 +TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 --direct-io-mode=yes $M0; +# Wait until all 6 childs have been recognized by the ec xlator +EXPECT_WITHIN $CHILD_UP_TIMEOUT "6" ec_child_up_count $V0 0 + +#heal info should give zero entries to be healed when I/O is going on +dd if=/dev/zero of=$M0/a bs=1M count=2048 & +dd_pid=$! +sleep 3 #Wait for I/O to proceed for some time +EXPECT "^0$" get_pending_heal_count $V0 +kill -9 $dd_pid +touch $M0/lock +create_files & + +total_heal_count=0 +while [ -f $M0/lock ]; +do + heal_count=$(get_pending_heal_count $V0) + total_heal_count=$((heal_count+total_heal_count)) +done +EXPECT "^0$" echo $total_heal_count + +#When only data heal is required it should print it +#There is no easy way to create this using commands so assigning xattrs directly +TEST setfattr -n trusted.ec.version -v 0x00000000000000020000000000000000 $B0/${V0}0/1000 +TEST setfattr -n trusted.ec.version -v 0x00000000000000020000000000000000 $B0/${V0}1/1000 +TEST setfattr -n trusted.ec.version -v 0x00000000000000020000000000000000 $B0/${V0}2/1000 +TEST setfattr -n trusted.ec.version -v 0x00000000000000020000000000000000 $B0/${V0}3/1000 +TEST setfattr -n trusted.ec.version -v 0x00000000000000020000000000000000 $B0/${V0}4/1000 +TEST setfattr -n trusted.ec.version -v 0x00000000000000010000000000000000 $B0/${V0}5/1000 +index_path=$B0/${V0}5/.glusterfs/indices/xattrop/$(gf_gfid_xattr_to_str $(gf_get_gfid_xattr $B0/${V0}5/1000)) +while [ -f $index_path ]; do :; done +TEST touch $index_path +EXPECT "^1$" get_pending_heal_count $V0 +TEST rm -f $M0/1000 + +#When files/directories need heal test that it prints them +TEST touch $M0/{1..10} +TEST kill_brick $V0 $H0 $B0/${V0}0 +for i in {11..20}; +do + echo abc > $M0/$i #Data + entry + metadata heal +done +for i in {1..10}; +do + chmod +x $M0/$i; +done + +EXPECT "^105$" get_pending_heal_count $V0 + +cleanup +#G_TESTDEF_TEST_STATUS_CENTOS6=BAD_TEST,BUG=1533815 diff --git a/tests/basic/ec/lock-contention.t b/tests/basic/ec/lock-contention.t new file mode 100644 index 00000000000..8f86cee16ad --- /dev/null +++ b/tests/basic/ec/lock-contention.t @@ -0,0 +1,62 @@ +#!/bin/bash + +# This test verifies that when 'lock-notify-contention' option is enabled, +# locks xlator actually sends an upcall notification that causes the acquired +# lock from one client to be released before it's supposed to when another +# client accesses the file. + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +function elapsed_time() { + local start="`date +%s`" + + if [[ "test" == `cat "$1"` ]]; then + echo "$((`date +%s` - ${start}))" + fi +} + +cleanup + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 disperse 3 redundancy 1 $H0:$B0/${V0}{0..2} +TEST $CLI volume set $V0 performance.stat-prefetch off +TEST $CLI volume set $V0 performance.write-behind off +TEST $CLI volume set $V0 performance.quick-read off +TEST $CLI volume set $V0 performance.read-ahead off +TEST $CLI volume set $V0 performance.io-cache off +TEST $CLI volume set $V0 features.locks-notify-contention off +TEST $CLI volume set $V0 disperse.eager-lock on +TEST $CLI volume set $V0 disperse.eager-lock-timeout 6 +TEST $CLI volume set $V0 disperse.other-eager-lock on +TEST $CLI volume set $V0 disperse.other-eager-lock-timeout 6 +TEST $CLI volume start $V0 + +TEST $GFS --direct-io-mode=yes --volfile-id=/$V0 --volfile-server=$H0 $M0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "3" ec_child_up_count $V0 0 $M0 + +TEST $GFS --direct-io-mode=yes --volfile-id=/$V0 --volfile-server=$H0 $M1 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "3" ec_child_up_count $V0 0 $M1 + +TEST $(echo "test" >$M0/file) + +# With locks-notify-contention set to off, accessing the file from another +# client should take 6 seconds. Checking against 3 seconds to be safe. +elapsed="$(elapsed_time $M1/file)" +TEST [[ ${elapsed} -ge 3 ]] + +elapsed="$(elapsed_time $M0/file)" +TEST [[ ${elapsed} -ge 3 ]] + +TEST $CLI volume set $V0 features.locks-notify-contention on + +# With locks-notify-contention set to on, accessing the file from another +# client should be fast. Checking against 3 seconds to be safe. +elapsed="$(elapsed_time $M1/file)" +TEST [[ ${elapsed} -le 3 ]] + +elapsed="$(elapsed_time $M0/file)" +TEST [[ ${elapsed} -le 3 ]] + +cleanup diff --git a/tests/basic/ec/nfs.t b/tests/basic/ec/nfs.t new file mode 100755 index 00000000000..3f51a640ef7 --- /dev/null +++ b/tests/basic/ec/nfs.t @@ -0,0 +1,29 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../nfs.rc + +#G_TESTDEF_TEST_STATUS_CENTOS6=NFS_TEST + +cleanup + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 redundancy 2 $H0:$B0/${V0}{0..5} +EXPECT "Created" volinfo_field $V0 'Status' +TEST $CLI volume set $V0 nfs.disable false +TEST $CLI volume start $V0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "Started" volinfo_field $V0 'Status' + +EXPECT_WITHIN $NFS_EXPORT_TIMEOUT "1" is_nfs_export_available; +TEST mount_nfs $H0:/$V0 $N0 nolock + +# The test below fails with "bs=1024k count=1k", but passes when "oflag=direct" +# is used. There also does not seem to be an issue on systems with sufficient +# memory. Reducing the "count" prevents hangs too. +TEST dd if=/dev/zero of=$N0/test bs=1024k count=32 + +## Before killing daemon to avoid deadlocks +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" umount_nfs $N0 + +cleanup diff --git a/tests/basic/ec/quota.t b/tests/basic/ec/quota.t new file mode 100755 index 00000000000..c9612c8b76a --- /dev/null +++ b/tests/basic/ec/quota.t @@ -0,0 +1,45 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +cleanup +QDD=$(dirname $0)/quota +# compile the test write program and run it +build_tester $(dirname $0)/../quota.c -o $QDD + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 disperse $H0:$B0/${V0}{0..2} +EXPECT 'Created' volinfo_field $V0 'Status' +TEST $CLI volume start $V0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT 'Started' volinfo_field $V0 'Status' +TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "3" ec_child_up_count $V0 0 + +TEST mkdir -p $M0/test + +TEST $CLI volume quota $V0 enable + +TEST $CLI volume quota $V0 limit-usage /test 10MB + +EXPECT "10.0MB" quota_hard_limit "/test"; +EXPECT "80%" quota_soft_limit "/test"; + +TEST $CLI volume quota $V0 soft-timeout 0 +TEST $CLI volume quota $V0 hard-timeout 0 + +TEST ! $QDD $M0/test/file1.txt 256 48 +TEST rm $M0/test/file1.txt + +EXPECT_WITHIN $MARKER_UPDATE_TIMEOUT "0Bytes" quotausage "/test" + +TEST $QDD $M0/test/file2.txt 256 32 +EXPECT_WITHIN $MARKER_UPDATE_TIMEOUT "8.0MB" quotausage "/test" + +TEST rm $M0/test/file2.txt +EXPECT_WITHIN $MARKER_UPDATE_TIMEOUT "0Bytes" quotausage "/test" +TEST $CLI volume stop $V0 + +rm -f $QDD +cleanup; diff --git a/tests/basic/ec/self-heal-read-write-fail.t b/tests/basic/ec/self-heal-read-write-fail.t new file mode 100644 index 00000000000..0ba591b5bb2 --- /dev/null +++ b/tests/basic/ec/self-heal-read-write-fail.t @@ -0,0 +1,69 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +#This test verifies that self-heal fails when read/write fails as part of heal +cleanup + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume info + +TEST $CLI volume create $V0 disperse 3 redundancy 1 $H0:$B0/${V0}{0,1,2} +TEST $CLI volume heal $V0 disable +TEST $CLI volume start $V0 + +TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "3" ec_child_up_count $V0 0 +TEST touch $M0/a +TEST kill_brick $V0 $H0 $B0/${V0}0 +echo abc >> $M0/a + +# Umount the volume to force all pending writes to reach the bricks +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 + +#Load error-gen and fail read fop and test that heal fails +TEST $CLI volume stop $V0 #Stop volume so that error-gen can be loaded +TEST $CLI volume set $V0 debug.error-gen posix +TEST $CLI volume set $V0 debug.error-fops read +TEST $CLI volume set $V0 debug.error-number EBADF +TEST $CLI volume set $V0 debug.error-failure 100 + +TEST $CLI volume start $V0 +TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "3" ec_child_up_count $V0 0 +EXPECT_WITHIN $HEAL_TIMEOUT "^2$" get_pending_heal_count $V0 +TEST ! getfattr -n trusted.ec.heal $M0/a +EXPECT_WITHIN $HEAL_TIMEOUT "^2$" get_pending_heal_count $V0 + +#fail write fop and test that heal fails +TEST $CLI volume stop $V0 +TEST $CLI volume set $V0 debug.error-fops write + +TEST $CLI volume start $V0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "3" ec_child_up_count $V0 0 +EXPECT_WITHIN $HEAL_TIMEOUT "^2$" get_pending_heal_count $V0 +TEST ! getfattr -n trusted.ec.heal $M0/a +EXPECT_WITHIN $HEAL_TIMEOUT "^2$" get_pending_heal_count $V0 + +TEST $CLI volume stop $V0 #Stop volume so that error-gen can be disabled +TEST $CLI volume reset $V0 debug.error-gen +TEST $CLI volume reset $V0 debug.error-fops +TEST $CLI volume reset $V0 debug.error-number +TEST $CLI volume reset $V0 debug.error-failure + +TEST $CLI volume start $V0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "3" ec_child_up_count $V0 0 +EXPECT_WITHIN $HEAL_TIMEOUT "^2$" get_pending_heal_count $V0 +TEST getfattr -n trusted.ec.heal $M0/a +EXPECT "^0$" get_pending_heal_count $V0 + +#Test that heal worked as expected by forcing read from brick0 +#remount to make sure data is not served from any cache +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 +TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0 +TEST kill_brick $V0 $H0 $B0/${V0}2 +EXPECT "abc" cat $M0/a + +cleanup diff --git a/tests/basic/ec/self-heal.t b/tests/basic/ec/self-heal.t new file mode 100644 index 00000000000..6329bb60248 --- /dev/null +++ b/tests/basic/ec/self-heal.t @@ -0,0 +1,235 @@ +#!/bin/bash + +SCRIPT_TIMEOUT=300 + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +# This test checks self-healing feature of dispersed volumes + +cleanup + +function check_mount_dir +{ + getfattr -d -m. -e hex $M0 2>&1 > /dev/null + for i in {1..20}; do + ls -l $M0/ | grep "dir1" + if [ $? -ne 0 ]; then + return 1 + fi + done + + return 0 +} + +function check_size +{ + cat $M0/$1 2>&1 > /dev/null + for i in "${brick[@]}"; do + res=`stat -c "%s" $i/$1` + if [ "$res" != "$2" ]; then + echo "N" + return 0 + fi + done + echo "Y" + return 0 +} + +function check_mode +{ + getfattr -d -m. -e hex $M0/$1 2>&1 > /dev/null + for i in "${brick[@]}"; do + res=`stat -c "%A" $i/$1` + if [ "$res" != "$2" ]; then + echo "N" + return 0 + fi + done + echo "Y" + return 0 +} + +function check_date +{ + getfattr -d -m. -e hex $M0/$1 2>&1 > /dev/null + for i in "${brick[@]}"; do + res=`stat -c "%Y" $i/$1` + if [ "$res" != "$2" ]; then + echo "N" + return 0 + fi + done + echo "Y" + return 0 +} + +function check_xattr +{ + getfattr -d -m. -e hex $M0/$1 2>&1 > /dev/null + for i in "${brick[@]}"; do + getfattr -n $2 $i/$1 2>/dev/null + if [ $? -eq 0 ]; then + echo "N" + return 0 + fi + done + echo "Y" + return 0 +} + +function check_dir +{ + getfattr -m. -d $M0/dir1 2>&1 > /dev/null + for i in "${brick[@]}"; do + if [ ! -d $i/dir1 ]; then + echo "N" + return 0 + fi + done + echo "Y" + return 0 +} + +function check_soft_link +{ + getfattr -d -m. -e hex $M0/test3 2>&1 > /dev/null + for i in "${brick[@]}"; do + if [ ! -h $i/test3 ]; then + echo "N" + return 0 + fi + done + echo "Y" + return 0 +} + +function check_hard_link +{ + getfattr -d -m. -e hex $M0/test4 2>&1 > /dev/null + for i in "${brick[@]}"; do + res=`stat -c "%h" $i/test4` + if [ "$res" != "3" ]; then + echo "N" + return 0 + fi + done + echo "Y" + return 0 +} + +tmp=`mktemp -d -t ${0##*/}.XXXXXX` +if [ ! -d $tmp ]; then + exit 1 +fi + +TESTS_EXPECTED_IN_LOOP=194 + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 redundancy 2 $H0:$B0/${V0}{0..5} +TEST $CLI volume set $V0 client-log-level DEBUG +#Write-behind has a bug where lookup can race over write which leads to size mismatch on the mount after a 'cp' +TEST $CLI volume set $V0 performance.write-behind off +#md-cache can return stale stat due to default timeout being 1 sec +TEST $CLI volume set $V0 performance.stat-prefetch off +EXPECT "Created" volinfo_field $V0 'Status' +TEST $CLI volume start $V0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "Started" volinfo_field $V0 'Status' +#direct-io-mode is to make sure 'cat' leads to READ fop which triggers heal +TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 --direct-io-mode=yes $M0; +# Wait until all 6 childs have been recognized by the ec xlator +EXPECT_WITHIN $CHILD_UP_TIMEOUT "6" ec_child_up_count $V0 0 + +TEST dd if=/dev/urandom of=$tmp/test bs=1024 count=1024 + +cs=$(sha1sum $tmp/test | awk '{ print $1 }') + +TEST df -h $M0 +TEST stat $M0 + +for idx in {0..5}; do + brick[$idx]=$(gf_get_gfid_backend_file_path $B0/$V0$idx) +done + +TEST cp $tmp/test $M0/test +TEST chmod 644 $M0/test +TEST touch -d "@946681200" $M0/test +EXPECT "-rw-r--r--" stat -c "%A" $M0/test +EXPECT "946681200" stat -c "%Y" $M0/test + +for idx1 in {0..5}; do + TEST chmod 666 ${brick[$idx1]}/test + TEST truncate -s 0 ${brick[$idx1]}/test + TEST setfattr -n user.test -v "test1" ${brick[$idx1]}/test + EXPECT "-rw-r--r--" stat -c "%A" $M0/test + EXPECT_WITHIN $HEAL_TIMEOUT "Y" check_size test "262144" + EXPECT_WITHIN $HEAL_TIMEOUT "Y" check_mode test "-rw-r--r--" + EXPECT_WITHIN $HEAL_TIMEOUT "Y" check_date test "946681200" + EXPECT_WITHIN $HEAL_TIMEOUT "Y" check_xattr test "user.test" +done + +for idx1 in {0..4}; do + for idx2 in `seq $(($idx1 + 1)) 5`; do + if [ $idx1 -ne $idx2 ]; then + TEST chmod 666 ${brick[$idx1]}/test + TEST chmod 600 ${brick[$idx2]}/test + TEST truncate -s 0 ${brick[$idx1]}/test + TEST truncate -s 2097152 ${brick[$idx2]}/test + TEST setfattr -n user.test -v "test1" ${brick[$idx1]}/test + TEST setfattr -n user.test -v "test2" ${brick[$idx2]}/test + EXPECT "-rw-r--r--" stat -c "%A" $M0/test + EXPECT_WITHIN $HEAL_TIMEOUT "Y" check_size test "262144" + EXPECT_WITHIN $HEAL_TIMEOUT "Y" check_mode test "-rw-r--r--" + EXPECT_WITHIN $HEAL_TIMEOUT "Y" check_date test "946681200" + EXPECT_WITHIN $HEAL_TIMEOUT "Y" check_xattr test "user.test" + fi + done +done + +sleep 2 + +TEST kill_brick $V0 $H0 $B0/${V0}0 +TEST kill_brick $V0 $H0 $B0/${V0}1 +TEST cp $tmp/test $M0/test2 +EXPECT "1048576" stat -c "%s" $M0/test2 +TEST chmod 777 $M0/test2 +EXPECT "-rwxrwxrwx" stat -c "%A" $M0/test2 + +TEST mkdir $M0/dir1 +TEST ls -al $M0/dir1 + +TEST ln -s test2 $M0/test3 +TEST [ -h $M0/test3 ] + +TEST ln $M0/test2 $M0/test4 +TEST [ -f $M0/test4 ] +EXPECT "2" stat -c "%h" $M0/test2 +EXPECT "2" stat -c "%h" $M0/test4 + +sleep 2 + +TEST $CLI volume start $V0 force +# Wait until the killed bricks have been started and recognized by the ec +# xlator +EXPECT_WITHIN $CHILD_UP_TIMEOUT "6" ec_child_up_count $V0 0 + +TEST check_mount_dir + +EXPECT "1048576" stat -c "%s" $M0/test2 +EXPECT "-rwxrwxrwx" stat -c "%A" $M0/test2 +EXPECT_WITHIN $HEAL_TIMEOUT "Y" check_size test2 "262144" +EXPECT_WITHIN $HEAL_TIMEOUT "Y" check_mode test2 "-rwxrwxrwx" + +TEST ls -al $M0/dir1 +EXPECT_WITHIN $HEAL_TIMEOUT "Y" check_dir + +TEST [ -h $M0/test3 ] +EXPECT_WITHIN $HEAL_TIMEOUT "Y" check_soft_link + +EXPECT "2" stat -c "%h" $M0/test4 +EXPECT_WITHIN $HEAL_TIMEOUT "Y" check_hard_link + +TEST rm -rf $tmp + +cleanup diff --git a/tests/basic/ec/statedump.t b/tests/basic/ec/statedump.t new file mode 100644 index 00000000000..8d311ec3d6d --- /dev/null +++ b/tests/basic/ec/statedump.t @@ -0,0 +1,28 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +cleanup + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 redundancy 1 $H0:$B0/${V0}{0..2} +EXPECT "Created" volinfo_field $V0 'Status' +TEST $CLI volume start $V0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "Started" volinfo_field $V0 'Status' +TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0 + +EXPECT_WITHIN $CHILD_UP_TIMEOUT "3" ec_child_up_count $V0 0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" ec_child_up_status $V0 0 0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" ec_child_up_status $V0 0 1 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" ec_child_up_status $V0 0 2 + +TEST kill_brick $V0 $H0 $B0/${V0}0 + +EXPECT_WITHIN $CHILD_UP_TIMEOUT "2" ec_child_up_count $V0 0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "0" ec_child_up_status $V0 0 0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" ec_child_up_status $V0 0 1 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" ec_child_up_status $V0 0 2 + +cleanup diff --git a/tests/basic/exports_parsing.t b/tests/basic/exports_parsing.t new file mode 100644 index 00000000000..da88bbcb2cc --- /dev/null +++ b/tests/basic/exports_parsing.t @@ -0,0 +1,57 @@ +#!/bin/bash + +. $(dirname $0)/../include.rc +. $(dirname $0)/../volume.rc + +EXP_FILES=$(dirname $0)/../configfiles + +cleanup + +function test_good_file () +{ + glusterfsd --print-exports $1 +} + +function test_long_netgroup() +{ + glusterfsd --print-exports $1 2>&1 | sed -n 1p +} + +function test_bad_line () +{ + glusterfsd --print-exports $1 2>&1 | sed -n 1p +} + +function test_big_file () +{ + glusterfsd --print-exports $1 | sed -n 3p +} + +function test_bad_opt () +{ + glusterfsd --print-exports $1 2>&1 | sed -n 1p +} + +function check_export_line() { + if [ "$1" == "$2" ]; then + echo "Y" + else + echo "N" + fi + return +} + +export_result=$(test_good_file $EXP_FILES/exports) +EXPECT "Y" check_export_line '/test @test(rw,anonuid=0,sec=sys,) 10.35.11.31(rw,anonuid=0,sec=sys,) ' "$export_result" + +export_result=$(test_good_file $EXP_FILES/exports-v6) +EXPECT "Y" check_export_line '/test @test(rw,anonuid=0,sec=sys,) 2401:db00:11:1:face:0:3d:0(rw,anonuid=0,sec=sys,) ' "$export_result" + +EXPECT_KEYWORD "Error parsing netgroups for:" test_bad_line $EXP_FILES/bad_exports +EXPECT_KEYWORD "Error parsing netgroups for:" test_long_netgroup $EXP_FILES/bad_exports + +EXPECT_KEYWORD "HDCDTY43SXOAH1TNUKB23MO9DE574W(rw,anonuid=0,sec=sys,)" test_big_file $EXP_FILES/big_exports + +EXPECT_KEYWORD "Could not find any valid options" test_bad_opt $EXP_FILES/exports_bad_opt + +cleanup diff --git a/tests/basic/fencing/afr-lock-heal-advanced.c b/tests/basic/fencing/afr-lock-heal-advanced.c new file mode 100644 index 00000000000..e202ccd5b29 --- /dev/null +++ b/tests/basic/fencing/afr-lock-heal-advanced.c @@ -0,0 +1,227 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <signal.h> +#include <unistd.h> +#include <glusterfs/api/glfs.h> +#include <glusterfs/api/glfs-handles.h> + +#define GF_ENFORCE_MANDATORY_LOCK "trusted.glusterfs.enforce-mandatory-lock" + +FILE *logfile_fp; + +#define LOG_ERR(func, err) \ + do { \ + if (!logfile_fp) { \ + fprintf(stderr, "%\n%d %s : returned error (%s)\n", __LINE__, \ + func, strerror(err)); \ + fflush(stderr); \ + } else { \ + fprintf(logfile_fp, "\n%d %s : returned error (%s)\n", __LINE__, \ + func, strerror(err)); \ + fflush(logfile_fp); \ + } \ + } while (0) + +glfs_t * +setup_client(char *hostname, char *volname, char *log_file) +{ + int ret = 0; + glfs_t *fs = NULL; + + fs = glfs_new(volname); + if (!fs) { + fprintf(logfile_fp, "\nglfs_new: returned NULL (%s)\n", + strerror(errno)); + goto error; + } + + ret = glfs_set_volfile_server(fs, "tcp", hostname, 24007); + if (ret < 0) { + fprintf(logfile_fp, "\nglfs_set_volfile_server failed ret:%d (%s)\n", + ret, strerror(errno)); + goto error; + } + + ret = glfs_set_logging(fs, log_file, 7); + if (ret < 0) { + fprintf(logfile_fp, "\nglfs_set_logging failed with ret: %d (%s)\n", + ret, strerror(errno)); + goto error; + } + + ret = glfs_init(fs); + if (ret < 0) { + fprintf(logfile_fp, "\nglfs_init failed with ret: %d (%s)\n", ret, + strerror(errno)); + goto error; + } + +out: + return fs; +error: + return NULL; +} + +glfs_fd_t * +open_file(glfs_t *fs, char *fname) +{ + glfs_fd_t *fd = NULL; + + fd = glfs_creat(fs, fname, O_CREAT, 0644); + if (!fd) { + LOG_ERR("glfs_creat", errno); + goto out; + } +out: + return fd; +} + +int +acquire_mandatory_lock(glfs_t *fs, glfs_fd_t *fd) +{ + struct flock lock; + int ret = 0; + + /* initialize lock */ + lock.l_type = F_WRLCK; + lock.l_whence = SEEK_SET; + lock.l_start = 0; + lock.l_len = 100; + + ret = glfs_fsetxattr(fd, GF_ENFORCE_MANDATORY_LOCK, "set", 8, 0); + if (ret < 0) { + LOG_ERR("glfs_fsetxattr", errno); + ret = -1; + goto out; + } + + /* take a write mandatory lock */ + ret = glfs_file_lock(fd, F_SETLKW, &lock, GLFS_LK_MANDATORY); + if (ret) { + LOG_ERR("glfs_file_lock", errno); + ret = -1; + goto out; + } + +out: + return ret; +} + +int +perform_test(glfs_t *fs, char *file1, char *file2) +{ + int ret = 0; + glfs_fd_t *fd1 = NULL; + glfs_fd_t *fd2 = NULL; + char *buf = "0123456789"; + + fd1 = open_file(fs, file1); + if (!fd1) { + ret = -1; + goto out; + } + fd2 = open_file(fs, file2); + if (!fd2) { + ret = -1; + goto out; + } + + /* Kill one brick from the .t.*/ + pause(); + + ret = acquire_mandatory_lock(fs, fd1); + if (ret) { + goto out; + } + ret = acquire_mandatory_lock(fs, fd2); + if (ret) { + goto out; + } + + /* Bring the brick up and let the locks heal. */ + pause(); + /*At this point, the .t would have killed and brought back 2 bricks, marking + * the fd bad.*/ + + ret = glfs_write(fd1, buf, 10, 0); + if (ret > 0) { + /* Write is supposed to fail with EBADFD*/ + LOG_ERR("glfs_write", ret); + goto out; + } + + ret = 0; +out: + if (fd1) + glfs_close(fd1); + if (fd2) + glfs_close(fd2); + return ret; +} + +static void +sigusr1_handler(int signo) +{ + /*Signal caught. Just continue with the execution.*/ +} + +int +main(int argc, char *argv[]) +{ + int ret = 0; + glfs_t *fs = NULL; + char *volname = NULL; + char log_file[100]; + char *hostname = NULL; + char *fname1 = NULL; + char *fname2 = NULL; + + if (argc != 7) { + fprintf(stderr, + "Expect following args %s <host> <volname> <file1> <file2> " + "<log file " + "location> <log_file_suffix>\n", + argv[0]); + return -1; + } + + hostname = argv[1]; + volname = argv[2]; + fname1 = argv[3]; + fname2 = argv[4]; + + /*Use SIGUSR1 and pause()as a means of hitting break-points this program + *when signalled from the .t test case.*/ + if (signal(SIGUSR1, sigusr1_handler) == SIG_ERR) { + LOG_ERR("SIGUSR1 handler error", errno); + exit(EXIT_FAILURE); + } + + sprintf(log_file, "%s/%s.%s.%s", argv[5], "lock-heal.c", argv[6], "log"); + logfile_fp = fopen(log_file, "w"); + if (!logfile_fp) { + fprintf(stderr, "\nfailed to open %s\n", log_file); + fflush(stderr); + return -1; + } + + sprintf(log_file, "%s/%s.%s.%s", argv[5], "glfs-client", argv[6], "log"); + fs = setup_client(hostname, volname, log_file); + if (!fs) { + LOG_ERR("setup_client", errno); + return -1; + } + + ret = perform_test(fs, fname1, fname2); + +error: + if (fs) { + /*glfs_fini(fs)*/; // glfs fini path is racy and crashes the program + } + + fclose(logfile_fp); + + return ret; +} diff --git a/tests/basic/fencing/afr-lock-heal-advanced.t b/tests/basic/fencing/afr-lock-heal-advanced.t new file mode 100644 index 00000000000..8a5b5989b5e --- /dev/null +++ b/tests/basic/fencing/afr-lock-heal-advanced.t @@ -0,0 +1,115 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +cleanup; +PROCESS_UP_TIMEOUT=90 + +function is_gfapi_program_alive() +{ + pid=$1 + ps -p $pid + if [ $? -eq 0 ] + then + echo "Y" + else + echo "N" + fi +} + +function get_active_lock_count { + brick=$1 + i1=$2 + i2=$3 + pattern="ACTIVE.*client-${brick: -1}" + + sdump=$(generate_brick_statedump $V0 $H0 $brick) + lock_count1="$(egrep "$i1" $sdump -A3| egrep "$pattern"|uniq|wc -l)" + lock_count2="$(egrep "$i2" $sdump -A3| egrep "$pattern"|uniq|wc -l)" + echo "$((lock_count1+lock_count2))" +} + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume info; + +TEST $CLI volume create $V0 replica 3 $H0:$B0/${V0}{0,1,2} +EXPECT 'Created' volinfo_field $V0 'Status'; +TEST $CLI volume set $V0 performance.write-behind off +TEST $CLI volume set $V0 performance.open-behind off +TEST $CLI volume set $V0 locks.mandatory-locking forced +TEST $CLI volume set $V0 enforce-mandatory-lock on +TEST $CLI volume start $V0; +EXPECT 'Started' volinfo_field $V0 'Status'; + +logdir=`gluster --print-logdir` +TEST build_tester $(dirname $0)/afr-lock-heal-advanced.c -lgfapi -ggdb + +#------------------------------------------------------------------------------ +# Use more than 1 fd from same client so that list_for_each_* loops are executed more than once. +$(dirname $0)/afr-lock-heal-advanced $H0 $V0 "/FILE1" "/FILE2" $logdir C1& +client_pid=$! +TEST [ $client_pid ] + +TEST sleep 5 # By now, the client would have opened an fd on FILE1 and FILE2 and waiting for a SIGUSR1. +EXPECT "Y" is_gfapi_program_alive $client_pid + +gfid_str1=$(gf_gfid_xattr_to_str $(gf_get_gfid_xattr $B0/${V0}0/FILE1)) +inode1="FILE1|gfid:$gfid_str1" +gfid_str2=$(gf_gfid_xattr_to_str $(gf_get_gfid_xattr $B0/${V0}0/FILE2)) +inode2="FILE2|gfid:$gfid_str2" + +# Kill brick-3 and let client-1 take lock on both files. +TEST kill_brick $V0 $H0 $B0/${V0}2 +TEST kill -SIGUSR1 $client_pid +# If program is still alive, glfs_file_lock() was a success. +EXPECT "Y" is_gfapi_program_alive $client_pid + +# Check lock is present on brick-1 and brick-2 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "2" get_active_lock_count $B0/${V0}0 $inode1 $inode2 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "2" get_active_lock_count $B0/${V0}1 $inode1 $inode2 + +# Restart brick-3 and check that the lock has healed on it. +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}2 +TEST sleep 10 #Needed for client to re-open fd? Otherwise client_pre_lk_v2() fails with EBADFD for remote-fd. + +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "2" get_active_lock_count $B0/${V0}2 $inode1 $inode2 + +#------------------------------------------------------------------------------ +# Kill same brick before heal completes the first time and check it completes the second time. +TEST $CLI volume set $V0 delay-gen locks +TEST $CLI volume set $V0 delay-gen.delay-duration 5000000 +TEST $CLI volume set $V0 delay-gen.delay-percentage 100 +TEST $CLI volume set $V0 delay-gen.enable finodelk + +TEST kill_brick $V0 $H0 $B0/${V0}0 +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}0 +TEST kill_brick $V0 $H0 $B0/${V0}0 +TEST $CLI volume reset $V0 delay-gen +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "2" get_active_lock_count $B0/${V0}0 $inode1 $inode2 + +#------------------------------------------------------------------------------ +# Kill 2 bricks and bring it back. The fds must be marked bad. +TEST kill_brick $V0 $H0 $B0/${V0}0 +TEST kill_brick $V0 $H0 $B0/${V0}1 +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}1 + +# TODO: `gluster v statedump $V0 client localhost:$client_pid` is not working, +# so sleep for 20 seconds for the client to connect to connect to the bricks. +TEST sleep $CHILD_UP_TIMEOUT + +# Try to write to FILE1 from the .c; it must fail. +TEST kill -SIGUSR1 $client_pid +wait $client_pid +ret=$? +TEST [ $ret == 0 ] + +cleanup_tester $(dirname $0)/afr-lock-heal-advanced +cleanup; diff --git a/tests/basic/fencing/afr-lock-heal-basic.c b/tests/basic/fencing/afr-lock-heal-basic.c new file mode 100644 index 00000000000..768c9e57181 --- /dev/null +++ b/tests/basic/fencing/afr-lock-heal-basic.c @@ -0,0 +1,182 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <signal.h> +#include <unistd.h> +#include <glusterfs/api/glfs.h> +#include <glusterfs/api/glfs-handles.h> + +#define GF_ENFORCE_MANDATORY_LOCK "trusted.glusterfs.enforce-mandatory-lock" + +FILE *logfile_fp; + +#define LOG_ERR(func, err) \ + do { \ + if (!logfile_fp) { \ + fprintf(stderr, "%\n%d %s : returned error (%s)\n", __LINE__, \ + func, strerror(err)); \ + fflush(stderr); \ + } else { \ + fprintf(logfile_fp, "\n%d %s : returned error (%s)\n", __LINE__, \ + func, strerror(err)); \ + fflush(logfile_fp); \ + } \ + } while (0) + +glfs_t * +setup_client(char *hostname, char *volname, char *log_file) +{ + int ret = 0; + glfs_t *fs = NULL; + + fs = glfs_new(volname); + if (!fs) { + fprintf(logfile_fp, "\nglfs_new: returned NULL (%s)\n", + strerror(errno)); + goto error; + } + + ret = glfs_set_volfile_server(fs, "tcp", hostname, 24007); + if (ret < 0) { + fprintf(logfile_fp, "\nglfs_set_volfile_server failed ret:%d (%s)\n", + ret, strerror(errno)); + goto error; + } + + ret = glfs_set_logging(fs, log_file, 7); + if (ret < 0) { + fprintf(logfile_fp, "\nglfs_set_logging failed with ret: %d (%s)\n", + ret, strerror(errno)); + goto error; + } + + ret = glfs_init(fs); + if (ret < 0) { + fprintf(logfile_fp, "\nglfs_init failed with ret: %d (%s)\n", ret, + strerror(errno)); + goto error; + } + +out: + return fs; +error: + return NULL; +} + +int +acquire_mandatory_lock(glfs_t *fs, char *fname) +{ + struct flock lock; + int ret = 0; + glfs_fd_t *fd = NULL; + + fd = glfs_creat(fs, fname, O_CREAT, 0644); + if (!fd) { + if (errno != EEXIST) { + LOG_ERR("glfs_creat", errno); + ret = -1; + goto out; + } + fd = glfs_open(fs, fname, O_RDWR | O_NONBLOCK); + if (!fd) { + LOG_ERR("glfs_open", errno); + ret = -1; + goto out; + } + } + + /* initialize lock */ + lock.l_type = F_WRLCK; + lock.l_whence = SEEK_SET; + lock.l_start = 0; + lock.l_len = 100; + + ret = glfs_fsetxattr(fd, GF_ENFORCE_MANDATORY_LOCK, "set", 8, 0); + if (ret < 0) { + LOG_ERR("glfs_fsetxattr", errno); + ret = -1; + goto out; + } + + pause(); + + /* take a write mandatory lock */ + ret = glfs_file_lock(fd, F_SETLKW, &lock, GLFS_LK_MANDATORY); + if (ret) { + LOG_ERR("glfs_file_lock", errno); + goto out; + } + + pause(); + +out: + if (fd) { + glfs_close(fd); + } + + return ret; +} + +static void +sigusr1_handler(int signo) +{ + /*Signal caught. Just continue with the execution.*/ +} + +int +main(int argc, char *argv[]) +{ + int ret = 0; + glfs_t *fs = NULL; + char *volname = NULL; + char log_file[100]; + char *hostname = NULL; + char *fname = NULL; + + if (argc != 6) { + fprintf(stderr, + "Expect following args %s <host> <volname> <file> <log file " + "location> <log_file_suffix>\n", + argv[0]); + return -1; + } + + hostname = argv[1]; + volname = argv[2]; + fname = argv[3]; + + /*Use SIGUSR1 and pause()as a means of hitting break-points this program + *when signalled from the .t test case.*/ + if (signal(SIGUSR1, sigusr1_handler) == SIG_ERR) { + LOG_ERR("SIGUSR1 handler error", errno); + exit(EXIT_FAILURE); + } + + sprintf(log_file, "%s/%s.%s.%s", argv[4], "lock-heal-basic.c", argv[5], + "log"); + logfile_fp = fopen(log_file, "w"); + if (!logfile_fp) { + fprintf(stderr, "\nfailed to open %s\n", log_file); + fflush(stderr); + return -1; + } + + sprintf(log_file, "%s/%s.%s.%s", argv[4], "glfs-client", argv[5], "log"); + fs = setup_client(hostname, volname, log_file); + if (!fs) { + LOG_ERR("setup_client", errno); + return -1; + } + + ret = acquire_mandatory_lock(fs, fname); + +error: + if (fs) { + /*glfs_fini(fs)*/; // glfs fini path is racy and crashes the program + } + + fclose(logfile_fp); + + return ret; +} diff --git a/tests/basic/fencing/afr-lock-heal-basic.t b/tests/basic/fencing/afr-lock-heal-basic.t new file mode 100644 index 00000000000..69131af085d --- /dev/null +++ b/tests/basic/fencing/afr-lock-heal-basic.t @@ -0,0 +1,102 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +cleanup; + +function is_gfapi_program_alive() +{ + pid=$1 + ps -p $pid + if [ $? -eq 0 ] + then + echo "Y" + else + echo "N" + fi +} + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume info; + +TEST $CLI volume create $V0 replica 3 $H0:$B0/${V0}{0,1,2} +EXPECT 'Created' volinfo_field $V0 'Status'; +TEST $CLI volume set $V0 performance.write-behind off +TEST $CLI volume set $V0 performance.open-behind off +TEST $CLI volume set $V0 locks.mandatory-locking forced +TEST $CLI volume set $V0 enforce-mandatory-lock on +TEST $CLI volume start $V0; +EXPECT 'Started' volinfo_field $V0 'Status'; + +logdir=`gluster --print-logdir` +TEST build_tester $(dirname $0)/afr-lock-heal-basic.c -lgfapi -ggdb + +$(dirname $0)/afr-lock-heal-basic $H0 $V0 "/FILE" $logdir C1& +client1_pid=$! +TEST [ $client1_pid ] + +$(dirname $0)/afr-lock-heal-basic $H0 $V0 "/FILE" $logdir C2& +client2_pid=$! +TEST [ $client2_pid ] + +TEST sleep 5 # By now, the 2 clients would have opened an fd on FILE and waiting for a SIGUSR1. +EXPECT "Y" is_gfapi_program_alive $client1_pid +EXPECT "Y" is_gfapi_program_alive $client2_pid + +gfid_str=$(gf_gfid_xattr_to_str $(gf_get_gfid_xattr $B0/${V0}0/FILE)) +inode="FILE|gfid:$gfid_str" + +# Kill brick-3 and let client-1 take lock on the file. +TEST kill_brick $V0 $H0 $B0/${V0}2 +TEST kill -SIGUSR1 $client1_pid +# If program is still alive, glfs_file_lock() was a success. +EXPECT "Y" is_gfapi_program_alive $client1_pid + +# Check lock is present on brick-1 and brick-2 +b1_sdump=$(generate_brick_statedump $V0 $H0 $B0/${V0}0) +c1_lock_on_b1="$(egrep "$inode" $b1_sdump -A3| egrep 'ACTIVE.*client-0'| uniq| awk '{print $1,$2,$3,S4,$5,$6,$7,$8}'|tr -d '(,), ,')" +b2_sdump=$(generate_brick_statedump $V0 $H0 $B0/${V0}1) +c1_lock_on_b2="$(egrep "$inode" $b2_sdump -A3| egrep 'ACTIVE.*client-1'| uniq| awk '{print $1,$2,$3,S4,$5,$6,$7,$8}'|tr -d '(,), ,')" +TEST [ "$c1_lock_on_b1" == "$c1_lock_on_b2" ] + +# Restart brick-3 and check that the lock has healed on it. +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}2 +TEST sleep 10 #Needed for client to re-open fd? Otherwise client_pre_lk_v2() fails with EBADFD for remote-fd. Also wait for lock heal. + +b3_sdump=$(generate_brick_statedump $V0 $H0 $B0/${V0}2) +c1_lock_on_b3="$(egrep "$inode" $b3_sdump -A3| egrep 'ACTIVE.*client-2'| uniq| awk '{print $1,$2,$3,S4,$5,$6,$7,$8}'|tr -d '(,), ,')" +TEST [ "$c1_lock_on_b1" == "$c1_lock_on_b3" ] + +# Kill brick-1 and let client-2 preempt the lock on bricks 2 and 3. +TEST kill_brick $V0 $H0 $B0/${V0}0 +TEST kill -SIGUSR1 $client2_pid +# If program is still alive, glfs_file_lock() was a success. +EXPECT "Y" is_gfapi_program_alive $client2_pid + +# Restart brick-1 and let lock healing complete. +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}0 +TEST sleep 10 #Needed for client to re-open fd? Otherwise client_pre_lk_v2() fails with EBADFD for remote-fd. Also wait for lock heal. + +# Check that all bricks now have locks from client 2 only. +b1_sdump=$(generate_brick_statedump $V0 $H0 $B0/${V0}0) +c2_lock_on_b1="$(egrep "$inode" $b1_sdump -A3| egrep 'ACTIVE.*client-0'| uniq| awk '{print $1,$2,$3,S4,$5,$6,$7,$8}'|tr -d '(,), ,')" +b2_sdump=$(generate_brick_statedump $V0 $H0 $B0/${V0}1) +c2_lock_on_b2="$(egrep "$inode" $b2_sdump -A3| egrep 'ACTIVE.*client-1'| uniq| awk '{print $1,$2,$3,S4,$5,$6,$7,$8}'|tr -d '(,), ,')" +b3_sdump=$(generate_brick_statedump $V0 $H0 $B0/${V0}2) +c2_lock_on_b3="$(egrep "$inode" $b3_sdump -A3| egrep 'ACTIVE.*client-2'| uniq| awk '{print $1,$2,$3,S4,$5,$6,$7,$8}'|tr -d '(,), ,')" +TEST [ "$c2_lock_on_b1" == "$c2_lock_on_b2" ] +TEST [ "$c2_lock_on_b1" == "$c2_lock_on_b3" ] +TEST [ "$c2_lock_on_b1" != "$c1_lock_on_b1" ] + +#Let the client programs run and exit. +TEST kill -SIGUSR1 $client1_pid +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "N" is_gfapi_program_alive $client1_pid +TEST kill -SIGUSR1 $client2_pid +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "N" is_gfapi_program_alive $client2_pid + +cleanup_tester $(dirname $0)/afr-lock-heal-basic +cleanup; diff --git a/tests/basic/fencing/fence-basic.c b/tests/basic/fencing/fence-basic.c new file mode 100644 index 00000000000..4aa452e19b0 --- /dev/null +++ b/tests/basic/fencing/fence-basic.c @@ -0,0 +1,229 @@ +#include <glusterfs/api/glfs.h> +#include <glusterfs/api/glfs-handles.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#define NO_INIT 1 +#define GF_ENFORCE_MANDATORY_LOCK "trusted.glusterfs.enforce-mandatory-lock" + +FILE *fp; +char *buf = "0123456789"; + +#define LOG_ERR(func, err) \ + do { \ + if (!fp) { \ + fprintf(stderr, "%\n%d %s : returned error (%s)\n", __LINE__, \ + func, strerror(err)); \ + fflush(stderr); \ + } else { \ + fprintf(fp, "\n%d %s : returned error (%s)\n", __LINE__, func, \ + strerror(err)); \ + fflush(fp); \ + } \ + } while (0) + +glfs_t * +setup_new_client(char *hostname, char *volname, char *log_file, int flag) +{ + int ret = 0; + glfs_t *fs = NULL; + + fs = glfs_new(volname); + if (!fs) { + fprintf(fp, "\nglfs_new: returned NULL (%s)\n", strerror(errno)); + goto error; + } + + ret = glfs_set_volfile_server(fs, "tcp", hostname, 24007); + if (ret < 0) { + fprintf(fp, "\nglfs_set_volfile_server failed ret:%d (%s)\n", ret, + strerror(errno)); + goto error; + } + + ret = glfs_set_logging(fs, log_file, 7); + if (ret < 0) { + fprintf(fp, "\nglfs_set_logging failed with ret: %d (%s)\n", ret, + strerror(errno)); + goto error; + } + + if (flag == NO_INIT) + goto out; + + ret = glfs_init(fs); + if (ret < 0) { + fprintf(fp, "\nglfs_init failed with ret: %d (%s)\n", ret, + strerror(errno)); + goto error; + } + +out: + return fs; +error: + return NULL; +} + +/* test plan + * + * - take mandatory lock from client 1 + * - preempt mandatory lock from client 2 + * - write from client 1 which should fail + */ + +int +test(glfs_t *fs1, glfs_t *fs2, char *fname) +{ + struct flock lock; + int ret = 0; + glfs_fd_t *fd1, *fd2 = NULL; + + fd1 = glfs_creat(fs1, fname, O_RDWR, 0777); + if (ret) { + LOG_ERR("glfs_creat", errno); + ret = -1; + goto out; + } + + fd2 = glfs_open(fs2, fname, O_RDWR | O_NONBLOCK); + if (ret) { + LOG_ERR("glfs_open", errno); + ret = -1; + goto out; + } + + /* initialize lock */ + lock.l_type = F_WRLCK; + lock.l_whence = SEEK_SET; + lock.l_start = 0; + lock.l_len = 100; + + ret = glfs_fsetxattr(fd1, GF_ENFORCE_MANDATORY_LOCK, "set", 8, 0); + if (ret < 0) { + LOG_ERR("glfs_fsetxattr", errno); + ret = -1; + goto out; + } + + /* take a write mandatory lock */ + ret = glfs_file_lock(fd1, F_SETLKW, &lock, GLFS_LK_MANDATORY); + if (ret) { + LOG_ERR("glfs_file_lock", errno); + goto out; + } + + ret = glfs_write(fd1, buf, 10, 0); + if (ret != 10) { + LOG_ERR("glfs_write", errno); + ret = -1; + goto out; + } + + /* write should fail */ + ret = glfs_write(fd2, buf, 10, 0); + if (ret != -1) { + LOG_ERR("glfs_write", errno); + ret = -1; + goto out; + } + + /* preempt mandatory lock from client 1*/ + ret = glfs_file_lock(fd2, F_SETLKW, &lock, GLFS_LK_MANDATORY); + if (ret) { + LOG_ERR("glfs_file_lock", errno); + goto out; + } + + /* write should succeed from client 2 */ + ret = glfs_write(fd2, buf, 10, 0); + if (ret == -1) { + LOG_ERR("glfs_write", errno); + goto out; + } + + /* write should fail from client 1 */ + ret = glfs_write(fd1, buf, 10, 0); + if (ret == 10) { + LOG_ERR("glfs_write", errno); + ret = -1; + goto out; + } + + ret = 0; + +out: + if (fd1) { + glfs_close(fd1); + } + + if (fd2) { + glfs_close(fd2); + } + + return ret; +} + +int +main(int argc, char *argv[]) +{ + int ret = 0; + glfs_t *fs1 = NULL; + glfs_t *fs2 = NULL; + char *volname = NULL; + char log_file[100]; + char *hostname = NULL; + char *fname = "/file"; + glfs_fd_t *fd1 = NULL; + glfs_fd_t *fd2 = NULL; + + if (argc != 4) { + fprintf( + stderr, + "Expect following args %s <hostname> <Vol> <log file location>\n", + argv[0]); + return -1; + } + + hostname = argv[1]; + volname = argv[2]; + + sprintf(log_file, "%s/%s", argv[3], "fence-basic.log"); + fp = fopen(log_file, "w"); + if (!fp) { + fprintf(stderr, "\nfailed to open %s\n", log_file); + fflush(stderr); + return -1; + } + + sprintf(log_file, "%s/%s", argv[3], "glfs-client-1.log"); + fs1 = setup_new_client(hostname, volname, log_file, 0); + if (!fs1) { + LOG_ERR("setup_new_client", errno); + return -1; + } + + sprintf(log_file, "%s/%s", argv[3], "glfs-client-2.log"); + fs2 = setup_new_client(hostname, volname, log_file, 0); + if (!fs2) { + LOG_ERR("setup_new_client", errno); + ret = -1; + goto error; + } + + ret = test(fs1, fs2, fname); + +error: + if (fs1) { + glfs_fini(fs1); + } + + if (fs2) { + glfs_fini(fs2); + } + + fclose(fp); + + return ret; +} diff --git a/tests/basic/fencing/fence-basic.t b/tests/basic/fencing/fence-basic.t new file mode 100755 index 00000000000..30f379e7b20 --- /dev/null +++ b/tests/basic/fencing/fence-basic.t @@ -0,0 +1,31 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +cleanup; + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume info; + +TEST $CLI volume create $V0 $H0:$B0/brick1 +EXPECT 'Created' volinfo_field $V0 'Status'; + +TEST $CLI volume start $V0; +EXPECT 'Started' volinfo_field $V0 'Status'; + +TEST $CLI volume set $V0 diagnostics.client-log-flush-timeout 30 +TEST $CLI volume set $V0 performance.write-behind off +TEST $CLI volume set $V0 locks.mandatory-locking forced +TEST $CLI volume set $V0 enforce-mandatory-lock on + + +logdir=`gluster --print-logdir` + +TEST build_tester $(dirname $0)/fence-basic.c -lgfapi -ggdb +TEST $(dirname $0)/fence-basic $H0 $V0 $logdir + +cleanup_tester $(dirname $0)/fence-basic + +cleanup;
\ No newline at end of file diff --git a/tests/basic/fencing/fencing-crash-conistency.t b/tests/basic/fencing/fencing-crash-conistency.t new file mode 100644 index 00000000000..0c69411e90c --- /dev/null +++ b/tests/basic/fencing/fencing-crash-conistency.t @@ -0,0 +1,62 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +cleanup; + +# with lock enforcement flag write should fail with out lock + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume info; + +TEST $CLI volume create $V0 $H0:$B0/${V0}1 +EXPECT 'Created' volinfo_field $V0 'Status'; +TEST $CLI volume start $V0; +EXPECT 'Started' volinfo_field $V0 'Status'; +TEST $CLI volume set $V0 performance.write-behind off +TEST glusterfs -s $H0 --volfile-id $V0 $M0 + +TEST touch $M0/file + +#write should pass +TEST "echo "test" > $M0/file" +TEST "truncate -s 0 $M0/file" + +#enable mandatory locking +TEST $CLI volume set $V0 locks.mandatory-locking forced +TEST $CLI volume set $V0 enforce-mandatory-lock on + +#write should pass +TEST "echo "test" >> $M0/file" +TEST "truncate -s 0 $M0/file" + +#enforce lock on the file +TEST setfattr -n trusted.glusterfs.enforce-mandatory-lock -v 1 $M0/file + +#write should fail +TEST ! "echo "test" >> $M0/file" +TEST ! "truncate -s 0 $M0/file" + +#remove lock enforcement flag +TEST setfattr -x trusted.glusterfs.enforce-mandatory-lock $M0/file + +#write should pass +TEST "echo "test" >> $M0/file" +TEST "truncate -s 0 $M0/file" + +#enforce lock on the file +TEST setfattr -n trusted.glusterfs.enforce-mandatory-lock -v 1 $M0/file +#kill brick +TEST kill_brick $V0 $H0 $B0/${V0}1 + +TEST $CLI volume start $V0 force + +# wait one second for the brick to come online +sleep 2 +#write should fail (lock xlator gets lock enforcement info from disk) +TEST ! "echo "test" >> $M0/file" +TEST ! "truncate -s 0 $M0/file" + +cleanup;
\ No newline at end of file diff --git a/tests/basic/fencing/test-fence-option.t b/tests/basic/fencing/test-fence-option.t new file mode 100644 index 00000000000..115cbe7dbdf --- /dev/null +++ b/tests/basic/fencing/test-fence-option.t @@ -0,0 +1,37 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +cleanup; + +# with lock enforcement flag write should fail with out lock + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume info; + +TEST $CLI volume create $V0 $H0:$B0/${V0}1 +EXPECT 'Created' volinfo_field $V0 'Status'; +TEST $CLI volume start $V0; +EXPECT 'Started' volinfo_field $V0 'Status'; +TEST glusterfs -s $H0 --volfile-id $V0 $M0 + +TEST touch $M0/file + +#setfattr for mandatory-enforcement will fail +TEST ! setfattr -n trusted.glusterfs.enforce-mandatory-lock -v 1 $M0/file + +#enable mandatory locking +TEST $CLI volume set $V0 locks.mandatory-locking forced + +#setfattr will fail +TEST ! setfattr -n trusted.glusterfs.enforce-mandatory-lock -v 1 $M0/file + +#set lock-enforcement option +TEST $CLI volume set $V0 enforce-mandatory-lock on + +#setfattr should succeed +TEST setfattr -n trusted.glusterfs.enforce-mandatory-lock -v 1 $M0/file + +cleanup;
\ No newline at end of file diff --git a/tests/basic/fop-sampling.t b/tests/basic/fop-sampling.t new file mode 100644 index 00000000000..cea8aa737c0 --- /dev/null +++ b/tests/basic/fop-sampling.t @@ -0,0 +1,61 @@ +#!/bin/bash +# + +. $(dirname $0)/../include.rc +. $(dirname $0)/../volume.rc + +SAMPLE_FILE="$(gluster --print-logdir)/samples/glusterfs_${V0}.samp" + +function print_cnt() { + local FOP_TYPE=$1 + local FOP_CNT=$(grep ,${FOP_TYPE} ${SAMPLE_FILE} | wc -l) + echo $FOP_CNT +} + +# Verify we got non-zero counts for stats/lookup/readdir +check_samples() { + STAT_CNT=$(print_cnt STAT) + if [ "$STAT_CNT" -le "0" ]; then + echo "STAT count is zero" + return + fi + + LOOKUP_CNT=$(print_cnt LOOKUP) + if [ "$LOOKUP_CNT" -le "0" ]; then + echo "LOOKUP count is zero" + return + fi + + READDIR_CNT=$(print_cnt READDIR) + if [ "$READDIR_CNT" -le "0" ]; then + echo "READDIR count is zero" + return + fi + + echo "OK" +} + +cleanup; +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 replica 3 $H0:$B0/${V0}{0,1,2} +TEST $CLI volume set $V0 nfs.disable off +TEST $CLI volume set $V0 diagnostics.latency-measurement on +TEST $CLI volume set $V0 diagnostics.count-fop-hits on +TEST $CLI volume set $V0 diagnostics.stats-dump-interval 2 +TEST $CLI volume set $V0 diagnostics.fop-sample-buf-size 65535 +TEST $CLI volume set $V0 diagnostics.fop-sample-interval 1 +TEST $CLI volume set $V0 diagnostics.stats-dnscache-ttl-sec 3600 + +TEST $CLI volume start $V0 +TEST glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0 --attribute-timeout=0 --entry-timeout=0 + +for i in {1..5} +do + dd if=/dev/zero of=${M0}/testfile$i bs=4k count=1 +done + +TEST ls -l $M0 +EXPECT_WITHIN 6 "OK" check_samples + +cleanup diff --git a/tests/basic/fops-sanity.c b/tests/basic/fops-sanity.c new file mode 100644 index 00000000000..ef00aa0f088 --- /dev/null +++ b/tests/basic/fops-sanity.c @@ -0,0 +1,1033 @@ +/* Copyright (c) 2014 Red Hat, Inc. All rights reserved. + +* This copyrighted material is made available to anyone wishing +* to use, modify, copy, or redistribute it subject to the terms +* and conditions of the GNU General Public License version 2. + +* This program is distributed in the hope that it will be +* useful, but WITHOUT ANY WARRANTY; without even the implied +* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +* PURPOSE. See the GNU General Public License for more details. + +* You should have received a copy of the GNU General Public +* License along with this program; if not, write to the Free +* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +* Boston, MA 02110-1301, USA. +*/ + +/* Filesystem basic sanity check, tests all (almost) fops. */ + +#include <stdio.h> +#include <fcntl.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/xattr.h> +#include <errno.h> +#include <string.h> +#include <dirent.h> +#include <sys/sysmacros.h> + +#ifndef linux +#include <sys/socket.h> +#include <sys/types.h> +#include <sys/un.h> +#endif + +/* for fd based fops after unlink */ +int +fd_based_fops_1(char *filename); +/* for fd based fops before unlink */ +int +fd_based_fops_2(char *filename); +/* fops based on fd after dup */ +int +dup_fd_based_fops(char *filename); +/* for fops based on path */ +int +path_based_fops(char *filename); +/* for fops which operate on directory */ +int +dir_based_fops(char *filename); +/* for fops which operate in link files (symlinks) */ +int +link_based_fops(char *filename); +/* to test open syscall with open modes available. */ +int +test_open_modes(char *filename); +/* generic function which does open write and read. */ +int +generic_open_read_write(char *filename, int flag, mode_t mode); + +#define OPEN_MODE 0666 + +int +main(int argc, char *argv[]) +{ + int ret = -1; + int result = 0; + char filename[255] = { + 0, + }; + + if (argc > 1) + strcpy(filename, argv[1]); + else + strcpy(filename, "temp-xattr-test-file"); + + ret = fd_based_fops_1(strcat(filename, "_1")); + if (ret < 0) { + fprintf(stderr, "fd based file operation 1 failed\n"); + result |= ret; + } else { + fprintf(stdout, "fd based file operation 1 passed\n"); + } + + ret = fd_based_fops_2(strcat(filename, "_2")); + if (ret < 0) { + result |= ret; + fprintf(stderr, "fd based file operation 2 failed\n"); + } else { + fprintf(stdout, "fd based file operation 2 passed\n"); + } + + ret = dup_fd_based_fops(strcat(filename, "_3")); + if (ret < 0) { + result |= ret; + fprintf(stderr, "dup fd based file operation failed\n"); + } else { + fprintf(stdout, "dup fd based file operation passed\n"); + } + + ret = path_based_fops(strcat(filename, "_4")); + if (ret < 0) { + result |= ret; + fprintf(stderr, "path based file operation failed\n"); + } else { + fprintf(stdout, "path based file operation passed\n"); + } + + ret = dir_based_fops(strcat(filename, "_5")); + if (ret < 0) { + result |= ret; + fprintf(stderr, "directory based file operation failed\n"); + } else { + fprintf(stdout, "directory based file operation passed\n"); + } + + ret = link_based_fops(strcat(filename, "_5")); + if (ret < 0) { + result |= ret; + fprintf(stderr, "link based file operation failed\n"); + } else { + fprintf(stdout, "link based file operation passed\n"); + } + + ret = test_open_modes(strcat(filename, "_5")); + if (ret < 0) { + result |= ret; + fprintf(stderr, "testing modes of `open' call failed\n"); + } else { + fprintf(stdout, "testing modes of `open' call passed\n"); + } + return result; +} + +/* Execute all possible fops on a fd which is unlinked */ +int +fd_based_fops_1(char *filename) +{ + int fd = 0; + int ret = -1; + int result = 0; + struct stat stbuf = { + 0, + }; + char wstr[50] = { + 0, + }; + char rstr[50] = { + 0, + }; + + fd = open(filename, O_RDWR | O_CREAT, OPEN_MODE); + if (fd < 0) { + fprintf(stderr, "open failed : %s\n", strerror(errno)); + return ret; + } + + ret = unlink(filename); + if (ret < 0) { + fprintf(stderr, "unlink failed : %s\n", strerror(errno)); + result |= ret; + } + + strcpy(wstr, "This is my string\n"); + ret = write(fd, wstr, strlen(wstr)); + if (ret <= 0) { + fprintf(stderr, "write failed: %s\n", strerror(errno)); + result |= ret; + } + + ret = lseek(fd, 0, SEEK_SET); + if (ret < 0) { + fprintf(stderr, "lseek failed: %s\n", strerror(errno)); + result |= ret; + } + + ret = read(fd, rstr, strlen(wstr)); + if (ret <= 0) { + fprintf(stderr, "read failed: %s\n", strerror(errno)); + result |= ret; + } + + ret = memcmp(rstr, wstr, strlen(wstr)); + if (ret != 0) { + fprintf(stderr, "read returning junk\n"); + result |= ret; + } + + ret = ftruncate(fd, 0); + if (ret < 0) { + fprintf(stderr, "ftruncate failed : %s\n", strerror(errno)); + result |= ret; + } + + ret = fstat(fd, &stbuf); + if (ret < 0) { + fprintf(stderr, "fstat failed : %s\n", strerror(errno)); + result |= ret; + } + + ret = fsync(fd); + if (ret < 0) { + fprintf(stderr, "fsync failed : %s\n", strerror(errno)); + result |= ret; + } + + ret = fdatasync(fd); + if (ret < 0) { + fprintf(stderr, "fdatasync failed : %s\n", strerror(errno)); + result |= ret; + } + + /* + * These metadata operations fail at the moment because kernel doesn't + * pass the client fd in the operation. + * The following bug tracks this change. + * https://bugzilla.redhat.com/show_bug.cgi?id=1084422 + * ret = fchmod (fd, 0640); + * if (ret < 0) { + * fprintf (stderr, "fchmod failed : %s\n", strerror (errno)); + * result |= ret; + * } + + * ret = fchown (fd, 10001, 10001); + * if (ret < 0) { + * fprintf (stderr, "fchown failed : %s\n", strerror (errno)); + * result |= ret; + * } + + * ret = fsetxattr (fd, "trusted.xattr-test", "working", 8, 0); + * if (ret < 0) { + * fprintf (stderr, "fsetxattr failed : %s\n", strerror + (errno)); + * result |= ret; + * } + + * ret = flistxattr (fd, NULL, 0); + * if (ret <= 0) { + * fprintf (stderr, "flistxattr failed : %s\n", strerror + (errno)); + * result |= ret; + * } + + * ret = fgetxattr (fd, "trusted.xattr-test", NULL, 0); + * if (ret <= 0) { + * fprintf (stderr, "fgetxattr failed : %s\n", strerror + (errno)); + * result |= ret; + * } + + * ret = fremovexattr (fd, "trusted.xattr-test"); + * if (ret < 0) { + * fprintf (stderr, "fremovexattr failed : %s\n", strerror + (errno)); + * result |= ret; + * } + */ + + if (fd) + close(fd); + return result; +} + +int +fd_based_fops_2(char *filename) +{ + int fd = 0; + int ret = -1; + int result = 0; + struct stat stbuf = { + 0, + }; + char wstr[50] = { + 0, + }; + char rstr[50] = { + 0, + }; + + fd = open(filename, O_RDWR | O_CREAT, OPEN_MODE); + if (fd < 0) { + fprintf(stderr, "open failed : %s\n", strerror(errno)); + return ret; + } + + ret = ftruncate(fd, 0); + if (ret < 0) { + fprintf(stderr, "ftruncate failed : %s\n", strerror(errno)); + result |= ret; + } + + strcpy(wstr, "This is my second string\n"); + ret = write(fd, wstr, strlen(wstr)); + if (ret < 0) { + fprintf(stderr, "write failed: %s\n", strerror(errno)); + result |= ret; + } + + lseek(fd, 0, SEEK_SET); + if (ret < 0) { + fprintf(stderr, "lseek failed: %s\n", strerror(errno)); + result |= ret; + } + + ret = read(fd, rstr, strlen(wstr)); + if (ret <= 0) { + fprintf(stderr, "read failed: %s\n", strerror(errno)); + result |= ret; + } + + ret = memcmp(rstr, wstr, strlen(wstr)); + if (ret != 0) { + fprintf(stderr, "read returning junk\n"); + result |= ret; + } + + ret = fstat(fd, &stbuf); + if (ret < 0) { + fprintf(stderr, "fstat failed : %s\n", strerror(errno)); + result |= ret; + } + + ret = fchmod(fd, 0640); + if (ret < 0) { + fprintf(stderr, "fchmod failed : %s\n", strerror(errno)); + result |= ret; + } + + ret = fchown(fd, 10001, 10001); + if (ret < 0) { + fprintf(stderr, "fchown failed : %s\n", strerror(errno)); + result |= ret; + } + + ret = fsync(fd); + if (ret < 0) { + fprintf(stderr, "fsync failed : %s\n", strerror(errno)); + result |= ret; + } + + ret = fsetxattr(fd, "trusted.xattr-test", "working", 8, 0); + if (ret < 0) { + fprintf(stderr, "fsetxattr failed : %s\n", strerror(errno)); + result |= ret; + } + + ret = fdatasync(fd); + if (ret < 0) { + fprintf(stderr, "fdatasync failed : %s\n", strerror(errno)); + result |= ret; + } + + ret = flistxattr(fd, NULL, 0); + if (ret <= 0) { + fprintf(stderr, "flistxattr failed : %s\n", strerror(errno)); + result |= ret; + } + + ret = fgetxattr(fd, "trusted.xattr-test", NULL, 0); + if (ret <= 0) { + fprintf(stderr, "fgetxattr failed : %s\n", strerror(errno)); + result |= ret; + } + + ret = fremovexattr(fd, "trusted.xattr-test"); + if (ret < 0) { + fprintf(stderr, "fremovexattr failed : %s\n", strerror(errno)); + result |= ret; + } + + if (fd) + close(fd); + unlink(filename); + + return result; +} + +int +path_based_fops(char *filename) +{ + int ret = -1; + int fd = 0; + int result = 0; + struct stat stbuf = { + 0, + }; + char newfilename[255] = { + 0, + }; + char *hardlink = "linkfile-hard.txt"; + char *symlnk = "linkfile-soft.txt"; + char buf[1024] = { + 0, + }; + + fd = creat(filename, 0644); + if (fd < 0) { + fprintf(stderr, "creat failed: %s\n", strerror(errno)); + return ret; + } + + ret = truncate(filename, 0); + if (ret < 0) { + fprintf(stderr, "truncate failed: %s\n", strerror(errno)); + result |= ret; + } + + ret = stat(filename, &stbuf); + if (ret < 0) { + fprintf(stderr, "stat failed: %s\n", strerror(errno)); + result |= ret; + } + + ret = chmod(filename, 0640); + if (ret < 0) { + fprintf(stderr, "chmod failed: %s\n", strerror(errno)); + result |= ret; + } + + ret = chown(filename, 10001, 10001); + if (ret < 0) { + fprintf(stderr, "chown failed: %s\n", strerror(errno)); + result |= ret; + } + + ret = setxattr(filename, "trusted.xattr-test", "working", 8, 0); + if (ret < 0) { + fprintf(stderr, "setxattr failed: %s\n", strerror(errno)); + result |= ret; + } + + ret = listxattr(filename, NULL, 0); + if (ret <= 0) { + ret = -1; + fprintf(stderr, "listxattr failed: %s\n", strerror(errno)); + result |= ret; + } + + ret = getxattr(filename, "trusted.xattr-test", NULL, 0); + if (ret <= 0) { + fprintf(stderr, "getxattr failed: %s\n", strerror(errno)); + result |= ret; + } + + ret = removexattr(filename, "trusted.xattr-test"); + if (ret < 0) { + fprintf(stderr, "removexattr failed: %s\n", strerror(errno)); + result |= ret; + } + + ret = access(filename, R_OK | W_OK); + if (ret < 0) { + fprintf(stderr, "access failed: %s\n", strerror(errno)); + result |= ret; + } + + ret = link(filename, hardlink); + if (ret < 0) { + fprintf(stderr, "link failed: %s\n", strerror(errno)); + result |= ret; + } + unlink(hardlink); + + ret = symlink(filename, symlnk); + if (ret < 0) { + fprintf(stderr, "symlink failed: %s\n", strerror(errno)); + result |= ret; + } + + ret = readlink(symlnk, buf, sizeof(buf)); + if (ret < 0) { + fprintf(stderr, "readlink failed: %s\n", strerror(errno)); + result |= ret; + } + unlink(symlnk); + + /* Create a character special file */ + ret = mknod("cspecial", S_IFCHR | S_IRWXU | S_IRWXG, makedev(2, 3)); + if (ret < 0) { + fprintf(stderr, "cpsecial mknod failed: %s\n", strerror(errno)); + result |= ret; + } + unlink("cspecial"); + + ret = mknod("bspecial", S_IFBLK | S_IRWXU | S_IRWXG, makedev(4, 5)); + if (ret < 0) { + fprintf(stderr, "bspecial mknod failed: %s\n", strerror(errno)); + result |= ret; + } + unlink("bspecial"); + +#ifdef linux + ret = mknod("fifo", S_IFIFO | S_IRWXU | S_IRWXG, 0); +#else + ret = mkfifo("fifo", 0); +#endif + if (ret < 0) { + fprintf(stderr, "fifo mknod failed: %s\n", strerror(errno)); + result |= ret; + } + unlink("fifo"); + +#ifdef linux + ret = mknod("sock", S_IFSOCK | S_IRWXU | S_IRWXG, 0); + if (ret < 0) { + fprintf(stderr, "sock mknod failed: %s\n", strerror(errno)); + result |= ret; + } +#else + { + int s; + const char *pathname = "sock"; + struct sockaddr_un addr; + + s = socket(PF_LOCAL, SOCK_STREAM, 0); + memset(&addr, 0, sizeof(addr)); + strncpy(addr.sun_path, pathname, sizeof(addr.sun_path)); + ret = bind(s, (const struct sockaddr *)&addr, SUN_LEN(&addr)); + if (ret < 0) { + fprintf(stderr, "fifo mknod failed: %s\n", strerror(errno)); + result |= ret; + } + close(s); + } +#endif + unlink("sock"); + + strcpy(newfilename, filename); + strcat(newfilename, "_new"); + ret = rename(filename, newfilename); + if (ret < 0) { + fprintf(stderr, "rename failed: %s\n", strerror(errno)); + result |= ret; + } + unlink(newfilename); + + if (fd) + close(fd); + + unlink(filename); + return result; +} + +int +dup_fd_based_fops(char *filename) +{ + int fd = 0; + int result = 0; + int newfd = 0; + int ret = -1; + struct stat stbuf = { + 0, + }; + char wstr[50] = { + 0, + }; + char rstr[50] = { + 0, + }; + + fd = open(filename, O_RDWR | O_CREAT, OPEN_MODE); + if (fd < 0) { + fprintf(stderr, "open failed : %s\n", strerror(errno)); + return ret; + } + + newfd = dup(fd); + if (newfd < 0) { + fprintf(stderr, "dup failed: %s\n", strerror(errno)); + result |= ret; + } + + close(fd); + + strcpy(wstr, "This is my string\n"); + ret = write(newfd, wstr, strlen(wstr)); + if (ret <= 0) { + fprintf(stderr, "write failed: %s\n", strerror(errno)); + result |= ret; + } + + ret = lseek(newfd, 0, SEEK_SET); + if (ret < 0) { + fprintf(stderr, "lseek failed: %s\n", strerror(errno)); + result |= ret; + } + + ret = read(newfd, rstr, strlen(wstr)); + if (ret <= 0) { + fprintf(stderr, "read failed: %s\n", strerror(errno)); + result |= ret; + } + + ret = memcmp(rstr, wstr, strlen(wstr)); + if (ret != 0) { + fprintf(stderr, "read returning junk\n"); + result |= ret; + } + + ret = ftruncate(newfd, 0); + if (ret < 0) { + fprintf(stderr, "ftruncate failed : %s\n", strerror(errno)); + result |= ret; + } + + ret = fstat(newfd, &stbuf); + if (ret < 0) { + fprintf(stderr, "fstat failed : %s\n", strerror(errno)); + result |= ret; + } + + ret = fchmod(newfd, 0640); + if (ret < 0) { + fprintf(stderr, "fchmod failed : %s\n", strerror(errno)); + result |= ret; + } + + ret = fchown(newfd, 10001, 10001); + if (ret < 0) { + fprintf(stderr, "fchown failed : %s\n", strerror(errno)); + result |= ret; + } + + ret = fsync(newfd); + if (ret < 0) { + fprintf(stderr, "fsync failed : %s\n", strerror(errno)); + result |= ret; + } + + ret = fsetxattr(newfd, "trusted.xattr-test", "working", 8, 0); + if (ret < 0) { + fprintf(stderr, "fsetxattr failed : %s\n", strerror(errno)); + result |= ret; + } + + ret = fdatasync(newfd); + if (ret < 0) { + fprintf(stderr, "fdatasync failed : %s\n", strerror(errno)); + result |= ret; + } + + ret = flistxattr(newfd, NULL, 0); + if (ret <= 0) { + fprintf(stderr, "flistxattr failed : %s\n", strerror(errno)); + result |= ret; + } + + ret = fgetxattr(newfd, "trusted.xattr-test", NULL, 0); + if (ret <= 0) { + fprintf(stderr, "fgetxattr failed : %s\n", strerror(errno)); + result |= ret; + } + + ret = fremovexattr(newfd, "trusted.xattr-test"); + if (ret < 0) { + fprintf(stderr, "fremovexattr failed : %s\n", strerror(errno)); + result |= ret; + } + + if (newfd) + close(newfd); + ret = unlink(filename); + if (ret < 0) { + fprintf(stderr, "unlink failed : %s\n", strerror(errno)); + result |= ret; + } + return result; +} + +int +dir_based_fops(char *dirname) +{ + int ret = -1; + int result = 0; + DIR *dp = NULL; + char buff[255] = { + 0, + }; + struct dirent *dbuff = { + 0, + }; + struct stat stbuff = { + 0, + }; + char newdname[255] = { + 0, + }; + char *cwd = NULL; + + ret = mkdir(dirname, 0755); + if (ret < 0) { + fprintf(stderr, "mkdir failed: %s\n", strerror(errno)); + return ret; + } + + dp = opendir(dirname); + if (dp == NULL) { + fprintf(stderr, "opendir failed: %s\n", strerror(errno)); + result |= ret; + } + + dbuff = readdir(dp); + if (NULL == dbuff) { + fprintf(stderr, "readdir failed: %s\n", strerror(errno)); + result |= ret; + } + + ret = closedir(dp); + if (ret < 0) { + fprintf(stderr, "closedir failed: %s\n", strerror(errno)); + result |= ret; + } + + ret = stat(dirname, &stbuff); + if (ret < 0) { + fprintf(stderr, "stat failed: %s\n", strerror(errno)); + result |= ret; + } + + ret = chmod(dirname, 0744); + if (ret < 0) { + fprintf(stderr, "chmod failed: %s\n", strerror(errno)); + result |= ret; + } + + ret = chown(dirname, 10001, 10001); + if (ret < 0) { + fprintf(stderr, "chmod failed: %s\n", strerror(errno)); + result |= ret; + } + + ret = setxattr(dirname, "trusted.xattr-test", "working", 8, 0); + if (ret < 0) { + fprintf(stderr, "setxattr failed: %s\n", strerror(errno)); + result |= ret; + } + + ret = listxattr(dirname, NULL, 0); + if (ret <= 0) { + ret = -1; + fprintf(stderr, "listxattr failed: %s\n", strerror(errno)); + result |= ret; + } + + ret = getxattr(dirname, "trusted.xattr-test", NULL, 0); + if (ret <= 0) { + ret = -1; + fprintf(stderr, "getxattr failed: %s\n", strerror(errno)); + result |= ret; + } + + ret = removexattr(dirname, "trusted.xattr-test"); + if (ret < 0) { + fprintf(stderr, "removexattr failed: %s\n", strerror(errno)); + result |= ret; + } + + strcpy(newdname, dirname); + strcat(newdname, "/../"); + ret = chdir(newdname); + if (ret < 0) { + fprintf(stderr, "chdir failed: %s\n", strerror(errno)); + result |= ret; + } + + cwd = getcwd(buff, 255); + if (NULL == cwd) { + fprintf(stderr, "getcwd failed: %s\n", strerror(errno)); + result |= ret; + } + + strcpy(newdname, dirname); + strcat(newdname, "new"); + ret = rename(dirname, newdname); + if (ret < 0) { + fprintf(stderr, "rename failed: %s\n", strerror(errno)); + result |= ret; + } + + ret = rmdir(newdname); + if (ret < 0) { + fprintf(stderr, "rmdir failed: %s\n", strerror(errno)); + result |= ret; + } + + rmdir(dirname); + return result; +} + +int +link_based_fops(char *filename) +{ + int ret = -1; + int result = 0; + int fd = 0; + char newname[255] = { + 0, + }; + char linkname[255] = { + 0, + }; + struct stat lstbuf = { + 0, + }; + + fd = creat(filename, 0644); + if (fd < 0) { + fd = 0; + fprintf(stderr, "creat failed: %s\n", strerror(errno)); + return ret; + } + + strcpy(newname, filename); + strcat(newname, "_hlink"); + ret = link(filename, newname); + if (ret < 0) { + fprintf(stderr, "link failed: %s\n", strerror(errno)); + result |= ret; + } + + ret = unlink(filename); + if (ret < 0) { + fprintf(stderr, "unlink failed: %s\n", strerror(errno)); + result |= ret; + } + + strcpy(linkname, filename); + strcat(linkname, "_slink"); + ret = symlink(newname, linkname); + if (ret < 0) { + fprintf(stderr, "symlink failed: %s\n", strerror(errno)); + result |= ret; + } + + ret = lstat(linkname, &lstbuf); + if (ret < 0) { + fprintf(stderr, "lstbuf failed: %s\n", strerror(errno)); + result |= ret; + } + + ret = lchown(linkname, 10001, 10001); + if (ret < 0) { + fprintf(stderr, "lchown failed: %s\n", strerror(errno)); + result |= ret; + } + + ret = lsetxattr(linkname, "trusted.lxattr-test", "working", 8, 0); + if (ret < 0) { + fprintf(stderr, "lsetxattr failed: %s\n", strerror(errno)); + result |= ret; + } + + ret = llistxattr(linkname, NULL, 0); + if (ret < 0) { + ret = -1; + fprintf(stderr, "llistxattr failed: %s\n", strerror(errno)); + result |= ret; + } + + ret = lgetxattr(linkname, "trusted.lxattr-test", NULL, 0); + if (ret < 0) { + ret = -1; + fprintf(stderr, "lgetxattr failed: %s\n", strerror(errno)); + result |= ret; + } + + ret = lremovexattr(linkname, "trusted.lxattr-test"); + if (ret < 0) { + fprintf(stderr, "lremovexattr failed: %s\n", strerror(errno)); + result |= ret; + } + + if (fd) + close(fd); + unlink(linkname); + unlink(newname); + return result; +} + +int +test_open_modes(char *filename) +{ + int ret = -1; + int result = 0; + + ret = generic_open_read_write(filename, O_CREAT | O_WRONLY, OPEN_MODE); + if (ret != 0) { + fprintf(stderr, "flag O_CREAT|O_WRONLY failed: \n"); + result |= ret; + } + + ret = generic_open_read_write(filename, O_CREAT | O_RDWR, OPEN_MODE); + if (ret != 0) { + fprintf(stderr, "flag O_CREAT|O_RDWR failed\n"); + result |= ret; + } + + ret = generic_open_read_write(filename, O_CREAT | O_RDONLY, OPEN_MODE); + if (ret != 0) { + fprintf(stderr, "flag O_CREAT|O_RDONLY failed\n"); + result |= ret; + } + + ret = creat(filename, 0644); + close(ret); + ret = generic_open_read_write(filename, O_WRONLY, 0); + if (ret != 0) { + fprintf(stderr, "flag O_WRONLY failed\n"); + result |= ret; + } + + ret = creat(filename, 0644); + close(ret); + ret = generic_open_read_write(filename, O_RDWR, 0); + if (0 != ret) { + fprintf(stderr, "flag O_RDWR failed\n"); + result |= ret; + } + + ret = creat(filename, 0644); + close(ret); + ret = generic_open_read_write(filename, O_RDONLY, 0); + if (0 != ret) { + fprintf(stderr, "flag O_RDONLY failed\n"); + result |= ret; + } + + ret = creat(filename, 0644); + close(ret); + ret = generic_open_read_write(filename, O_TRUNC | O_WRONLY, 0); + if (0 != ret) { + fprintf(stderr, "flag O_TRUNC|O_WRONLY failed\n"); + result |= ret; + } + +#if 0 /* undefined behaviour, unable to reliably test */ + ret = creat (filename, 0644); + close (ret); + ret = generic_open_read_write (filename, O_TRUNC|O_RDONLY, 0); + if (0 != ret) { + fprintf (stderr, "flag O_TRUNC|O_RDONLY failed\n"); + result |= ret; + } +#endif + + ret = generic_open_read_write(filename, O_CREAT | O_RDWR | O_SYNC, + OPEN_MODE); + if (0 != ret) { + fprintf(stderr, "flag O_CREAT|O_RDWR|O_SYNC failed\n"); + result |= ret; + } + + ret = creat(filename, 0644); + close(ret); + ret = generic_open_read_write(filename, O_CREAT | O_EXCL, OPEN_MODE); + if (0 != ret) { + fprintf(stderr, "flag O_CREAT|O_EXCL failed\n"); + result |= ret; + } + + return result; +} + +int +generic_open_read_write(char *filename, int flag, mode_t mode) +{ + int fd = 0; + int ret = -1; + char wstring[50] = { + 0, + }; + char rstring[50] = { + 0, + }; + + fd = open(filename, flag, mode); + if (fd < 0) { + if (flag == (O_CREAT | O_EXCL) && errno == EEXIST) { + unlink(filename); + return 0; + } else { + fprintf(stderr, "open failed: %s\n", strerror(errno)); + return -1; + } + } + + strcpy(wstring, "My string to write\n"); + ret = write(fd, wstring, strlen(wstring)); + if (ret <= 0) { + if (errno != EBADF) { + fprintf(stderr, "write failed: %s\n", strerror(errno)); + close(fd); + unlink(filename); + return ret; + } + } + + ret = lseek(fd, 0, SEEK_SET); + if (ret < 0) { + close(fd); + unlink(filename); + return ret; + } + + ret = read(fd, rstring, strlen(wstring)); + if (ret < 0 && flag != (O_CREAT | O_WRONLY) && flag != O_WRONLY && + flag != (O_TRUNC | O_WRONLY)) { + close(fd); + unlink(filename); + return ret; + } + + /* Compare the rstring with wstring. But we do not want to return + * error when the flag is either O_RDONLY, O_CREAT|O_RDONLY or + * O_TRUNC|O_RDONLY. Because in that case we are not writing + * anything to the file.*/ + + ret = memcmp(wstring, rstring, strlen(wstring)); + if (0 != ret && flag != (O_TRUNC | O_WRONLY) && flag != O_WRONLY && + flag != (O_CREAT | O_WRONLY) && + !(flag == (O_CREAT | O_RDONLY) || flag == O_RDONLY || + flag == (O_TRUNC | O_RDONLY))) { + fprintf(stderr, "read is returning junk\n"); + close(fd); + unlink(filename); + return ret; + } + + close(fd); + unlink(filename); + return 0; +} diff --git a/tests/basic/fops-sanity.t b/tests/basic/fops-sanity.t new file mode 100755 index 00000000000..8962f3a2fba --- /dev/null +++ b/tests/basic/fops-sanity.t @@ -0,0 +1,27 @@ +#!/bin/bash + +. $(dirname $0)/../include.rc + +cleanup; + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume info; + +TEST $CLI volume create $V0 $H0:$B0/brick1; +EXPECT 'Created' volinfo_field $V0 'Status'; + +TEST $CLI volume start $V0; +EXPECT 'Started' volinfo_field $V0 'Status'; + +#mount on a random dir +TEST glusterfs --entry-timeout=3600 --attribute-timeout=3600 -s $H0 --volfile-id=$V0 $M0 --direct-io-mode=yes + +build_tester $(dirname $0)/fops-sanity.c + +TEST cp $(dirname $0)/fops-sanity $M0 +cd $M0 +TEST ./fops-sanity $V0 +cd - +TEST rm -f $(dirname $0)/fops-sanity +cleanup; diff --git a/tests/basic/fuse/Makefile b/tests/basic/fuse/Makefile new file mode 100644 index 00000000000..c446d253228 --- /dev/null +++ b/tests/basic/fuse/Makefile @@ -0,0 +1,12 @@ +CFLAGS = -Wall -g +LDFLAGS = + +BINARIES = seek + +%: %.c + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ + +all: $(BINARIES) + +clean: + -$(RM) $(BINARIES) diff --git a/tests/basic/fuse/active-io-graph-switch.t b/tests/basic/fuse/active-io-graph-switch.t new file mode 100644 index 00000000000..6ec3e1fcbfa --- /dev/null +++ b/tests/basic/fuse/active-io-graph-switch.t @@ -0,0 +1,65 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +TESTS_EXPECTED_IN_LOOP=12 + +function perform_io_on_mount { + local m="$1" + local f="$2" + local lockfile="$3" + while [ -f "$m/$lockfile" ]; + do + dd if=/dev/zero of=$m/$f bs=1M count=1 + done +} + +function perform_graph_switch { + for i in {1..3} + do + TEST_IN_LOOP $CLI volume set $V0 performance.stat-prefetch off + sleep 3 + TEST_IN_LOOP $CLI volume set $V0 performance.stat-prefetch on + sleep 3 + done +} + +function count_files { + ls $M0 | wc -l +} + +cleanup; +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 replica 3 $H0:$B0/${V0}{0,1,2} +TEST $CLI volume set $V0 flush-behind off +TEST $CLI volume start $V0 +TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0 +TEST touch $M0/lock +for i in {1..100}; do perform_io_on_mount $M0 $i lock & done +EXPECT_WITHIN 5 "101" count_files + +perform_graph_switch +TEST rm -f $M0/lock +wait +EXPECT "100" count_files +TEST rm -f $M0/{1..100} +EXPECT "0" count_files + +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 + +#Repeat the tests with reader-thread-count +TEST $GFS --reader-thread-count=10 --volfile-id=/$V0 --volfile-server=$H0 $M0 +TEST touch $M0/lock +for i in {1..100}; do perform_io_on_mount $M0 $i lock & done +EXPECT_WITHIN 5 "101" count_files + +perform_graph_switch +TEST rm -f $M0/lock +wait +EXPECT "100" count_files +TEST rm -f $M0/{1..100} +EXPECT "0" count_files + +cleanup diff --git a/tests/basic/fuse/seek.c b/tests/basic/fuse/seek.c new file mode 100644 index 00000000000..30943ad0f33 --- /dev/null +++ b/tests/basic/fuse/seek.c @@ -0,0 +1,82 @@ +/* seek.c - use lseek() to find holes in a file + * + * Author: Niels de Vos <ndevos@redhat.com> + */ + +/* needed for SEEK_HOLE/SEEK_DATA */ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +int +main(int argc, char **argv) +{ + int ret = EXIT_SUCCESS; + int fd = -1; + char *filename = NULL; + struct stat st = { + 0, + }; + off_t hole_start = 0; + off_t hole_end = 0; + + if (argc != 2) { + fprintf(stderr, "Invalid argument, use %s <file>\n", argv[0]); + return EXIT_FAILURE; + } + + filename = argv[1]; + + fd = open(filename, O_RDONLY); + if (fd <= 0) { + perror("open"); + return EXIT_FAILURE; + } + + if (fstat(fd, &st)) { + perror("fstat"); + return EXIT_FAILURE; + } + + while (hole_end < st.st_size) { + hole_start = lseek(fd, hole_end, SEEK_HOLE); + if (hole_start == -1 && errno == ENXIO) { + /* no more holes */ + break; + } else if (hole_start == -1 && errno == ENOTSUP) { + /* SEEK_HOLE is not supported */ + perror("lseek(SEEK_HOLE)"); + ret = EXIT_FAILURE; + break; + } else if (hole_start == -1) { + perror("no more holes"); + break; + } + + hole_end = lseek(fd, hole_start, SEEK_DATA); + if (hole_end == -1 && errno == ENXIO) { + /* no more data */ + break; + } else if (hole_end == -1 && errno == ENOTSUP) { + /* SEEK_DATA is not supported */ + perror("lseek(SEEK_DATA)"); + ret = EXIT_FAILURE; + break; + } + + printf("HOLE found: %ld - %ld%s\n", hole_start, hole_end, + (hole_end == st.st_size) ? " (EOF)" : ""); + } + + close(fd); + + return ret; +} diff --git a/tests/basic/geo-replication/marker-xattrs.t b/tests/basic/geo-replication/marker-xattrs.t new file mode 100755 index 00000000000..7e5ea8eebec --- /dev/null +++ b/tests/basic/geo-replication/marker-xattrs.t @@ -0,0 +1,80 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +TEST glusterd +TEST pidof glusterd + +## Start and create a replicated volume +TEST $CLI volume create $V0 replica 3 $H0:$B0/${V0}-{0,1,2,3,4,5} + +TEST $CLI volume set $V0 indexing on + +TEST $CLI volume start $V0; + +## Mount native +TEST glusterfs --volfile-server=$H0 --volfile-id=$V0 $M0 + +## Mount client-pid=-1 +TEST glusterfs --volfile-server=$H0 --volfile-id=$V0 --client-pid=-1 $M1 + +TEST touch $M0 + +vol_uuid=$(get_volume_mark $M1) +xtime=trusted.glusterfs.$vol_uuid.xtime + +TEST "getfattr -n $xtime $B0/${V0}-1 | grep -q ${xtime}=" + +TEST kill_brick $V0 $H0 $B0/${V0}-0 + +TEST "getfattr -n $xtime $B0/${V0}-1 | grep -q ${xtime}=" + +TEST getfattr -d -m. -e hex $M1 +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M1 + +TEST $CLI volume stop $V0; +TEST $CLI volume delete $V0; + +cleanup +TEST glusterd +TEST pidof glusterd +## Start and create a disperse volume +TEST $CLI volume create $V0 disperse 3 redundancy 1 $H0:$B0/${V0}-{0,1,2} + +TEST $CLI volume set $V0 indexing on + +TEST $CLI volume start $V0; + +## Mount native +TEST glusterfs --volfile-server=$H0 --volfile-id=$V0 $M0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "3" mount_get_option_value $M0 $V0-disperse-0 childs_up + +## Mount client-pid=-1 +TEST glusterfs --volfile-server=$H0 --volfile-id=$V0 --client-pid=-1 $M1 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "3" mount_get_option_value $M1 $V0-disperse-0 childs_up + +TEST touch $M0 + +vol_uuid=$(get_volume_mark $M1) +xtime=trusted.glusterfs.$vol_uuid.xtime +stime=trusted.glusterfs.$vol_uuid.stime + +stime_val=$(getfattr -e hex -n $xtime $B0/${V0}-1 | grep ${xtime}= | cut -f2 -d'=') +TEST "setfattr -n $stime -v $stime_val $B0/${V0}-1" +TEST "getfattr -n $xtime $B0/${V0}-1 | grep -q ${xtime}=" + +TEST kill_brick $V0 $H0 $B0/${V0}-0 + +TEST "getfattr -n $xtime $B0/${V0}-1 | grep -q ${xtime}=" +TEST "getfattr -n $stime $M1 | grep -q ${stime}=" + +TEST getfattr -d -m. -e hex $M1 +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M1 + +TEST $CLI volume stop $V0; +TEST $CLI volume delete $V0; + +cleanup diff --git a/tests/basic/gfapi/Makefile b/tests/basic/gfapi/Makefile new file mode 100644 index 00000000000..1c5cf03ca3d --- /dev/null +++ b/tests/basic/gfapi/Makefile @@ -0,0 +1,22 @@ +## compiles against the *system* version of libgfapi, +## but not the libgfapi for the testcases + +CFLAGS = -Wall -g $(shell pkg-config --cflags glusterfs-api) +LDFLAGS = $(shell pkg-config --libs glusterfs-api) + +BINARIES = upcall-cache-invalidate libgfapi-fini-hang anonymous_fd seek \ + bug1283983 bug1291259 gfapi-ssl-test gfapi-load-volfile \ + mandatory-lock-optimal + +%: %.c + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ + +all: check-pkgconfig $(BINARIES) + +clean: + -$(RM) $(BINARIES) + +.phony: check-pkgconfig + +check-pkgconfig: + pkg-config --exists glusterfs-api diff --git a/tests/basic/gfapi/anonymous_fd.t b/tests/basic/gfapi/anonymous_fd.t new file mode 100755 index 00000000000..bc0fb0fa2f0 --- /dev/null +++ b/tests/basic/gfapi/anonymous_fd.t @@ -0,0 +1,26 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +cleanup; + +TEST glusterd + +TEST $CLI volume create $V0 $H0:$B0/brick1; +EXPECT 'Created' volinfo_field $V0 'Status'; + +TEST $CLI volume start $V0; +EXPECT 'Started' volinfo_field $V0 'Status'; + +logdir=`gluster --print-logdir` + +TEST build_tester $(dirname $0)/anonymous_fd_read_write.c -lgfapi -o $(dirname $0)/anonymous_fd +TEST ./$(dirname $0)/anonymous_fd $H0 $V0 $logdir/anonymous_fd.log + +cleanup_tester $(dirname $0)/anonymous_fd + +TEST $CLI volume stop $V0 +TEST $CLI volume delete $V0 + +cleanup; diff --git a/tests/basic/gfapi/anonymous_fd_read_write.c b/tests/basic/gfapi/anonymous_fd_read_write.c new file mode 100644 index 00000000000..fc276ca4310 --- /dev/null +++ b/tests/basic/gfapi/anonymous_fd_read_write.c @@ -0,0 +1,106 @@ +#include <fcntl.h> +#include <unistd.h> +#include <time.h> +#include <limits.h> +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <glusterfs/api/glfs.h> +#include <glusterfs/api/glfs-handles.h> + +#define LOG_ERR(func, ret) \ + do { \ + if (ret != 0) { \ + fprintf(stderr, "%s : returned error %d (%s)\n", func, ret, \ + strerror(errno)); \ + goto out; \ + } else { \ + fprintf(stderr, "%s : returned %d\n", func, ret); \ + } \ + } while (0) + +int +main(int argc, char *argv[]) +{ + int ret = 0; + glfs_t *fs = NULL; + struct glfs_object *root = NULL, *file_obj = NULL; + struct stat sb = { + 0, + }; + char readbuf[32], writebuf[32]; + char *filename = "file.txt"; + char *logfile = NULL; + char *volname = NULL; + char *hostname = NULL; + + if (argc != 4) { + fprintf(stderr, "Invalid argument\n"); + exit(1); + } + + hostname = argv[1]; + volname = argv[2]; + logfile = argv[3]; + + fs = glfs_new(volname); + if (!fs) { + fprintf(stderr, "glfs_new: returned NULL\n"); + ret = -1; + } + + ret = glfs_set_volfile_server(fs, "tcp", hostname, 24007); + LOG_ERR("glfs_set_volfile_server", ret); + + ret = glfs_set_logging(fs, logfile, 7); + LOG_ERR("glfs_set_logging", ret); + + ret = glfs_init(fs); + LOG_ERR("glfs_init", ret); + + root = glfs_h_lookupat(fs, NULL, "/", &sb, 0); + if (root == NULL) { + fprintf(stderr, "glfs_h_lookupat: error on lookup of / ,%s\n", + strerror(errno)); + goto out; + } + + file_obj = glfs_h_creat(fs, root, filename, O_CREAT, 0644, &sb); + if (file_obj == NULL) { + fprintf(stderr, "glfs_h_creat: error on create of %s: from (%p),%s\n", + filename, root, strerror(errno)); + goto out; + } + + /* test read/write based on anonymous fd */ + memcpy(writebuf, "abcdefghijklmnopqrstuvwxyz012345", 32); + + ret = glfs_h_anonymous_write(fs, file_obj, writebuf, 32, 0); + if (ret < 0) + LOG_ERR("glfs_h_anonymous_write", ret); + + ret = glfs_h_anonymous_read(fs, file_obj, readbuf, 32, 0); + if (ret < 0) + LOG_ERR("glfs_h_anonymous_read", ret); + + if (memcmp(readbuf, writebuf, 32)) { + fprintf(stderr, "Failed to read what I wrote: %s %s\n", readbuf, + writebuf); + ret = -1; + goto out; + } + + ret = 0; +out: + if (file_obj) + glfs_h_close(file_obj); + + if (fs) { + ret = glfs_fini(fs); + fprintf(stderr, "glfs_fini(fs) returned %d \n", ret); + } + if (ret) + exit(1); + exit(0); +} diff --git a/tests/basic/gfapi/bug-1241104.c b/tests/basic/gfapi/bug-1241104.c new file mode 100644 index 00000000000..78c87595a71 --- /dev/null +++ b/tests/basic/gfapi/bug-1241104.c @@ -0,0 +1,93 @@ +#include <fcntl.h> +#include <unistd.h> +#include <time.h> +#include <limits.h> +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <glusterfs/api/glfs.h> +#include <glusterfs/api/glfs-handles.h> +#include <sys/wait.h> + +int gfapi = 1; + +#define LOG_ERR(func, ret) \ + do { \ + if (ret != 0) { \ + fprintf(stderr, "%s : returned error %d (%s)\n", func, ret, \ + strerror(errno)); \ + goto out; \ + } else { \ + fprintf(stderr, "%s : returned %d\n", func, ret); \ + } \ + } while (0) + +int +main(int argc, char *argv[]) +{ + glfs_t *fs = NULL; + int ret = 0, i, status = 0; + glfs_fd_t *fd = NULL; + char *filename = "file_tmp"; + char *volname = NULL; + char *logfile = NULL; + char *hostname = NULL; + struct flock lock = { + 0, + }; + + if (argc != 4) { + fprintf(stderr, "Invalid argument\n"); + exit(1); + } + + hostname = argv[1]; + volname = argv[2]; + logfile = argv[3]; + + fs = glfs_new(volname); + if (!fs) { + fprintf(stderr, "glfs_new: returned NULL\n"); + return -1; + } + + ret = glfs_set_volfile_server(fs, "tcp", hostname, 24007); + LOG_ERR("glfs_set_volfile_server", ret); + + ret = glfs_set_logging(fs, logfile, 7); + LOG_ERR("glfs_set_logging", ret); + + ret = glfs_init(fs); + LOG_ERR("glfs_init", ret); + + fd = glfs_creat(fs, filename, O_RDWR | O_SYNC, 0644); + if (fd <= 0) { + ret = -1; + LOG_ERR("glfs_creat", ret); + } + fprintf(stderr, "glfs-create fd - %d\n", fd); + + /* validate locks for negative range */ + lock.l_type = F_WRLCK; + lock.l_whence = SEEK_SET; + lock.l_start = 10; + lock.l_len = -9; + + ret = glfs_posix_lock(fd, F_SETLK, &lock); + LOG_ERR("glfs_posix_lock", ret); + +err: + glfs_close(fd); + LOG_ERR("glfs_close", ret); + +out: + if (fs) { + ret = glfs_fini(fs); + fprintf(stderr, "glfs_fini(fs) returned %d \n", ret); + } + + if (ret) + exit(1); + exit(0); +} diff --git a/tests/basic/gfapi/bug-1241104.t b/tests/basic/gfapi/bug-1241104.t new file mode 100755 index 00000000000..e7f4759c3d5 --- /dev/null +++ b/tests/basic/gfapi/bug-1241104.t @@ -0,0 +1,30 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +cleanup; + +TEST glusterd + +TEST $CLI volume create $V0 $H0:$B0/brick1; +EXPECT 'Created' volinfo_field $V0 'Status'; + +TEST $CLI volume start $V0; +EXPECT 'Started' volinfo_field $V0 'Status'; + +logdir=`gluster --print-logdir` + +## Enable Upcall cache-invalidation feature +TEST $CLI volume set $V0 features.cache-invalidation on; + +TEST build_tester $(dirname $0)/bug-1241104.c -lgfapi + +TEST ./$(dirname $0)/bug-1241104 $H0 $V0 $logdir/bug-1241104.log + +cleanup_tester $(dirname $0)/bug-1241104 + +TEST $CLI volume stop $V0 +TEST $CLI volume delete $V0 + +cleanup; diff --git a/tests/basic/gfapi/bug-1507896.c b/tests/basic/gfapi/bug-1507896.c new file mode 100644 index 00000000000..1cc20849c2b --- /dev/null +++ b/tests/basic/gfapi/bug-1507896.c @@ -0,0 +1,49 @@ +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <glusterfs/api/glfs.h> +#include <glusterfs/api/glfs-handles.h> + +#define VALIDATE_AND_GOTO_LABEL_ON_ERROR(func, ret, label) \ + do { \ + if (ret < 0) { \ + fprintf(stderr, "%s : returned error %d (%s)\n", func, ret, \ + strerror(errno)); \ + goto label; \ + } \ + } while (0) + +int +main(int argc, char *argv[]) +{ + int ret = -1; + glfs_t *fs = NULL; + char *volname = NULL; + char *logfile = NULL; + char *hostname = NULL; + + hostname = argv[1]; + volname = argv[2]; + logfile = argv[3]; + + fs = glfs_new(volname); + if (!fs) + VALIDATE_AND_GOTO_LABEL_ON_ERROR("glfs_new(fs)", ret, out); + + ret = glfs_set_volfile_server(fs, "tcp", hostname, 24007); + VALIDATE_AND_GOTO_LABEL_ON_ERROR("glfs_set_volfile_server(fs)", ret, out); + + ret = glfs_set_logging(fs, logfile, 7); + VALIDATE_AND_GOTO_LABEL_ON_ERROR("glfs_set_logging(fs)", ret, out); + + ret = glfs_init(fs); + VALIDATE_AND_GOTO_LABEL_ON_ERROR("glfs_init(fs)", ret, out); + +out: + if (fs) { + ret = glfs_fini(fs); + if (ret) + fprintf(stderr, "glfs_fini(fs) returned %d\n", ret); + } + return ret; +} diff --git a/tests/basic/gfapi/bug-1507896.t b/tests/basic/gfapi/bug-1507896.t new file mode 100644 index 00000000000..4764e650232 --- /dev/null +++ b/tests/basic/gfapi/bug-1507896.t @@ -0,0 +1,33 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +cleanup; + +TEST glusterd + +TEST $CLI volume create $V0 $H0:$B0/brick1; +EXPECT 'Created' volinfo_field $V0 'Status'; + +TEST $CLI volume start $V0; +EXPECT 'Started' volinfo_field $V0 'Status'; + +logdir=`gluster --print-logdir` + +TEST build_tester $(dirname $0)/bug-1507896.c -lgfapi + +TEST ./$(dirname $0)/bug-1507896 $H0 $V0 $logdir/bug-1507896.log + +#volume name precedding with '/' +TEST ! ./$(dirname $0)/bug-1507896 $H0 /$V0 $logdir/bug-1507896.log + +#volume name passed with any special characters +TEST ! ./$(dirname $0)/bug-1507896 $H0 test@_$V0 $logdir/bug-1507896.log + +cleanup_tester $(dirname $0)/bug-1507896 + +TEST $CLI volume stop $V0 +TEST $CLI volume delete $V0 + +cleanup; diff --git a/tests/basic/gfapi/bug1283983.c b/tests/basic/gfapi/bug1283983.c new file mode 100644 index 00000000000..b920013d0e0 --- /dev/null +++ b/tests/basic/gfapi/bug1283983.c @@ -0,0 +1,122 @@ +#include <fcntl.h> +#include <unistd.h> +#include <time.h> +#include <limits.h> +#include <string.h> +#include <stdio.h> +#include <errno.h> +#include <stdlib.h> +#include <glusterfs/api/glfs.h> +#include <glusterfs/api/glfs-handles.h> +int gfapi = 1; + +#define LOG_ERR(func, ret) \ + do { \ + if (ret != 0) { \ + fprintf(stderr, "%s : returned error ret(%d), errno(%d)\n", func, \ + ret, errno); \ + exit(1); \ + } else { \ + fprintf(stderr, "%s : returned %d\n", func, ret); \ + } \ + } while (0) +#define LOG_IF_NO_ERR(func, ret) \ + do { \ + if (ret == 0) { \ + fprintf(stderr, "%s : hasn't returned error %d\n", func, ret); \ + exit(1); \ + } else { \ + fprintf(stderr, "%s : returned %d\n", func, ret); \ + } \ + } while (0) +int +main(int argc, char *argv[]) +{ + glfs_t *fs = NULL; + int ret = 0, i; + glfs_fd_t *fd = NULL; + char *filename = "/a1"; + char *filename2 = "/a2"; + struct stat sb = { + 0, + }; + struct glfs_upcall *cbk = NULL; + char *logfile = NULL; + char *volname = NULL; + int cnt = 1; + struct glfs_upcall_inode *in_arg = NULL; + struct glfs_object *root = NULL, *leaf = NULL; + + fprintf(stderr, "Starting libgfapi_fini\n"); + if (argc != 4) { + fprintf(stderr, "Invalid argument\n"); + exit(1); + } + + hostname = argv[1] volname = argv[2]; + logfile = argv[3]; + + fs = glfs_new(volname); + if (!fs) { + fprintf(stderr, "glfs_new: returned NULL\n"); + return 1; + } + + ret = glfs_set_volfile_server(fs, "tcp", hostname, 24007); + LOG_ERR("glfs_set_volfile_server", ret); + + ret = glfs_set_logging(fs, logfile, 7); + LOG_ERR("glfs_set_logging", ret); + + ret = glfs_init(fs); + LOG_ERR("glfs_init", ret); + + sleep(2); + root = glfs_h_lookupat(fs, NULL, "/", &sb, 0); + if (!root) { + ret = -1; + LOG_ERR("glfs_h_lookupat root", ret); + } + leaf = glfs_h_lookupat(fs, root, filename, &sb, 0); + if (!leaf) { + ret = -1; + LOG_IF_NO_ERR("glfs_h_lookupat leaf", ret); + } + + leaf = glfs_h_creat(fs, root, filename, O_RDWR, 0644, &sb); + if (!leaf) { + ret = -1; + LOG_ERR("glfs_h_lookupat leaf", ret); + } + fprintf(stderr, "glfs_h_create leaf - %p\n", leaf); + + leaf = glfs_h_lookupat(fs, root, filename2, &sb, 0); + if (!leaf) { + ret = -1; + LOG_IF_NO_ERR("glfs_h_lookupat leaf", ret); + } + + ret = glfs_h_rename(fs, root, filename, root, filename2); + LOG_ERR("glfs_rename", ret); + + while (cnt++ < 5) { + ret = glfs_h_poll_upcall(fs, &cbk); + LOG_ERR("glfs_h_poll_upcall", ret); + + /* There should not be any upcalls sent */ + if (glfs_upcall_get_reason(cbk) != GLFS_UPCALL_EVENT_NULL) { + fprintf(stderr, "Error: Upcall received(%d)\n", + glfs_upcall_get_reason(cbk)); + exit(1); + } + + glfs_free(cbk); + } + + ret = glfs_fini(fs); + LOG_ERR("glfs_fini", ret); + + fprintf(stderr, "End of libgfapi_fini\n"); + + exit(0); +} diff --git a/tests/basic/gfapi/bug1283983.sh b/tests/basic/gfapi/bug1283983.sh new file mode 100755 index 00000000000..931a0b55935 --- /dev/null +++ b/tests/basic/gfapi/bug1283983.sh @@ -0,0 +1,33 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +cleanup; + +TEST glusterd + +TEST $CLI volume create $V0 $H0:$B0/brick1; +EXPECT 'Created' volinfo_field $V0 'Status'; + +TEST $CLI volume start $V0; +EXPECT 'Started' volinfo_field $V0 'Status'; + +logdir=`gluster --print-logdir` + +## Enable Upcall cache-invalidation feature +TEST $CLI volume set $V0 features.cache-invalidation on; + +build_tester $(dirname $0)/bug1283983.c -lgfapi + +TEST ./$(dirname $0)/bug1283983 $H0 $V0 $logdir/bug1283983.log + +## There shouldn't be any NULL gfid messages logged +TEST ! cat $logdir/bug1283983.log | grep "upcall" | grep "00000000-0000-0000-0000-000000000000" + +cleanup_tester $(dirname $0)/bug1283983 + +TEST $CLI volume stop $V0 +TEST $CLI volume delete $V0 + +cleanup; diff --git a/tests/basic/gfapi/bug1291259.c b/tests/basic/gfapi/bug1291259.c new file mode 100644 index 00000000000..cd7bc65268b --- /dev/null +++ b/tests/basic/gfapi/bug1291259.c @@ -0,0 +1,181 @@ +#include <fcntl.h> +#include <unistd.h> +#include <time.h> +#include <limits.h> +#include <string.h> +#include <stdio.h> +#include <errno.h> +#include <stdlib.h> +#include <glusterfs/api/glfs.h> +#include <glusterfs/api/glfs-handles.h> +int gfapi = 1; + +#define LOG_ERR(func, ret) \ + do { \ + if (ret != 0) { \ + fprintf(stderr, "%s : returned error ret(%d), errno(%d)\n", func, \ + ret, errno); \ + exit(1); \ + } else { \ + fprintf(stderr, "%s : returned %d\n", func, ret); \ + } \ + } while (0) +#define LOG_IF_NO_ERR(func, ret) \ + do { \ + if (ret == 0) { \ + fprintf(stderr, "%s : hasn't returned error %d\n", func, ret); \ + exit(1); \ + } else { \ + fprintf(stderr, "%s : returned %d\n", func, ret); \ + } \ + } while (0) + +#define GLAPI_UUID_LENGTH 16 +int +main(int argc, char *argv[]) +{ + glfs_t *fs = NULL; + glfs_t *fs2 = NULL; + int ret = 0, i; + glfs_fd_t *fd = NULL; + char *filename = "/a1"; + char *filename2 = "/a2"; + struct stat sb = { + 0, + }; + char *logfile = NULL; + char *volname = NULL; + char *hostname = NULL; + int cnt = 1; + int upcall_received = 0; + struct glfs_upcall *cbk = NULL; + struct glfs_object *root = NULL, *leaf = NULL; + unsigned char globjhdl[GFAPI_HANDLE_LENGTH]; + unsigned char globjhdl2[GFAPI_HANDLE_LENGTH]; + + fprintf(stderr, "Starting libgfapi_fini\n"); + if (argc != 4) { + fprintf(stderr, "Invalid argument\n"); + exit(1); + } + + hostname = argv[1]; + volname = argv[2]; + logfile = argv[3]; + + fs = glfs_new(volname); + if (!fs) { + fprintf(stderr, "glfs_new: returned NULL\n"); + return 1; + } + + ret = glfs_set_volfile_server(fs, "tcp", hostname, 24007); + LOG_ERR("glfs_set_volfile_server", ret); + + ret = glfs_set_logging(fs, logfile, 7); + LOG_ERR("glfs_set_logging", ret); + + ret = glfs_init(fs); + LOG_ERR("glfs_init", ret); + + /* This does not block, but enables caching of events. Real + * applications like NFS-Ganesha run this in a thread before activity + * on the fs (through this instance) happens. */ + ret = glfs_h_poll_upcall(fs, &cbk); + LOG_ERR("glfs_h_poll_upcall", ret); + + fs2 = glfs_new(volname); + if (!fs) { + fprintf(stderr, "glfs_new: returned NULL\n"); + return 1; + } + + ret = glfs_set_volfile_server(fs2, "tcp", hostname, 24007); + LOG_ERR("glfs_set_volfile_server", ret); + + ret = glfs_set_logging(fs2, logfile, 7); + LOG_ERR("glfs_set_logging", ret); + + ret = glfs_init(fs2); + LOG_ERR("glfs_init", ret); + + sleep(2); + root = glfs_h_lookupat(fs, NULL, "/", &sb, 0); + if (!root) { + ret = -1; + LOG_ERR("glfs_h_lookupat root", ret); + } + leaf = glfs_h_lookupat(fs, root, filename, &sb, 0); + if (!leaf) { + ret = -1; + LOG_IF_NO_ERR("glfs_h_lookupat leaf", ret); + } + + root = glfs_h_lookupat(fs2, NULL, "/", &sb, 0); + if (!root) { + ret = -1; + LOG_ERR("glfs_h_lookupat root", ret); + } + leaf = glfs_h_creat(fs2, root, filename, O_RDWR, 0644, &sb); + if (!leaf) { + ret = -1; + LOG_ERR("glfs_h_lookupat leaf", ret); + } + fprintf(stderr, "glfs_h_create leaf - %p\n", leaf); + + while (cnt++ < 5 && !upcall_received) { + enum glfs_upcall_reason reason = 0; + struct glfs_upcall_inode *in_arg = NULL; + + ret = glfs_h_poll_upcall(fs, &cbk); + LOG_ERR("glfs_h_poll_upcall", ret); + if (ret) + goto retry; + + reason = glfs_upcall_get_reason(cbk); + fprintf(stderr, "Upcall received(%d)\n", reason); + + if (reason == GLFS_UPCALL_INODE_INVALIDATE) { + struct glfs_object *object = NULL; + + in_arg = glfs_upcall_get_event(cbk); + object = glfs_upcall_inode_get_object(in_arg); + + ret = glfs_h_extract_handle(root, globjhdl + GLAPI_UUID_LENGTH, + GFAPI_HANDLE_LENGTH); + LOG_ERR("glfs_h_extract_handle", (ret != 16)); + + ret = glfs_h_extract_handle(object, globjhdl2 + GLAPI_UUID_LENGTH, + GFAPI_HANDLE_LENGTH); + LOG_ERR("glfs_h_extract_handle", (ret != 16)); + + if (memcmp(globjhdl + GLAPI_UUID_LENGTH, + globjhdl2 + GLAPI_UUID_LENGTH, 16)) { + fprintf(stderr, "Error: gfid mismatch\n"); + exit(1); + } + upcall_received = 1; + } + + retry: + if (!upcall_received) + sleep(1); /* glfs_h_poll_upcall() does not block */ + + if (!ret) { + glfs_free(cbk); + cbk = NULL; + } + } + + if (!upcall_received) { + fprintf(stderr, "Error: Upcall not received\n"); + exit(1); + } + + ret = glfs_fini(fs); + LOG_ERR("glfs_fini", ret); + + fprintf(stderr, "End of libgfapi_fini\n"); + + exit(0); +} diff --git a/tests/basic/gfapi/bug1291259.t b/tests/basic/gfapi/bug1291259.t new file mode 100755 index 00000000000..999cda2da3a --- /dev/null +++ b/tests/basic/gfapi/bug1291259.t @@ -0,0 +1,32 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +cleanup; + +TEST glusterd + +TEST $CLI volume create $V0 $H0:$B0/brick1; +EXPECT 'Created' volinfo_field $V0 'Status'; + +TEST $CLI volume start $V0; +EXPECT 'Started' volinfo_field $V0 'Status'; + +logdir=`gluster --print-logdir` + +## Enable Upcall cache-invalidation feature +TEST $CLI volume set $V0 features.cache-invalidation on; + +TEST build_tester $(dirname $0)/bug1291259.c -lgfapi + +TEST ./$(dirname $0)/bug1291259 $H0 $V0 $logdir/bug1291259.log + +cleanup_tester $(dirname $0)/bug1291259 + +TEST $CLI volume stop $V0 +TEST $CLI volume delete $V0 + +cleanup; +#G_TESTDEF_TEST_STATUS_CENTOS6=BAD_TEST,BUG=1405301 +#G_TESTDEF_TEST_STATUS_NETBSD7=BAD_TEST,BUG=1405301 diff --git a/tests/basic/gfapi/bug1613098.c b/tests/basic/gfapi/bug1613098.c new file mode 100644 index 00000000000..ee67e97a034 --- /dev/null +++ b/tests/basic/gfapi/bug1613098.c @@ -0,0 +1,96 @@ +#include <inttypes.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> + +#include <glusterfs/api/glfs.h> +#include <glusterfs/api/glfs-handles.h> + +#define ACL_TYPE_ACCESS (0x8000) + +#define VALIDATE_AND_GOTO_LABEL_ON_ERROR(func, ret, label) \ + do { \ + if (ret < 0) { \ + fprintf(stderr, "%s : returned error %d (%s)\n", func, ret, \ + strerror(errno)); \ + goto label; \ + } \ + } while (0) + +int +main(int argc, char *argv[]) +{ + int ret = -1; + int flags = O_RDWR | O_SYNC; + glfs_t *fs = NULL; + glfs_fd_t *fd = NULL; + char *volname = NULL; + char *logfile = NULL; + const char *filename = "file_tmp"; + struct glfs_object *object = NULL; + acl_t acl = NULL; + struct stat sb; + + if (argc != 3) { + fprintf(stderr, "Invalid argument\n"); + return 1; + } + + volname = argv[1]; + logfile = argv[2]; + + fs = glfs_new(volname); + if (!fs) + VALIDATE_AND_GOTO_LABEL_ON_ERROR("glfs_new", ret, out); + + ret = glfs_set_volfile_server(fs, "tcp", "localhost", 24007); + VALIDATE_AND_GOTO_LABEL_ON_ERROR("glfs_set_volfile_server", ret, out); + + ret = glfs_set_logging(fs, logfile, 7); + VALIDATE_AND_GOTO_LABEL_ON_ERROR("glfs_set_logging", ret, out); + + ret = glfs_init(fs); + VALIDATE_AND_GOTO_LABEL_ON_ERROR("glfs_init", ret, out); + + fd = glfs_creat(fs, filename, flags, 0044); + if (fd == NULL) { + ret = -1; + VALIDATE_AND_GOTO_LABEL_ON_ERROR("glfs_creat", ret, out); + } + glfs_close(fd); + + object = glfs_h_lookupat(fs, NULL, filename, NULL, 0); + if (object == NULL) { + ret = -1; + VALIDATE_AND_GOTO_LABEL_ON_ERROR("glfs_h_lookupat", ret, out); + } + + ret = glfs_chown(fs, filename, 99, 99); + VALIDATE_AND_GOTO_LABEL_ON_ERROR("glfs_chown", ret, out); + + ret = glfs_setfsuid(99); + VALIDATE_AND_GOTO_LABEL_ON_ERROR("glfs_setfsuid", ret, out); + + ret = glfs_setfsgid(99); + VALIDATE_AND_GOTO_LABEL_ON_ERROR("glfs_setfsgid", ret, out); + + acl = glfs_h_acl_get(fs, object, ACL_TYPE_ACCESS); + if (acl == NULL) { + ret = -1; + VALIDATE_AND_GOTO_LABEL_ON_ERROR("glfs_h_acl_get", ret, out); + } + + ret = glfs_h_acl_set(fs, object, ACL_TYPE_ACCESS, acl); + VALIDATE_AND_GOTO_LABEL_ON_ERROR("glfs_h_acl_get", ret, out); +out: + glfs_setfsuid(0); + glfs_setfsgid(0); + + if (object) + glfs_h_close(object); + + if (fs) + glfs_fini(fs); + + return ret; +} diff --git a/tests/basic/gfapi/bug1613098.t b/tests/basic/gfapi/bug1613098.t new file mode 100755 index 00000000000..e4acc2b76bf --- /dev/null +++ b/tests/basic/gfapi/bug1613098.t @@ -0,0 +1,22 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +TEST glusterd + +TEST $CLI volume create $V0 ${H0}:$B0/brick1; +EXPECT 'Created' volinfo_field $V0 'Status'; + +TEST $CLI volume start $V0; +EXPECT 'Started' volinfo_field $V0 'Status'; + +logdir=`gluster --print-logdir` + +build_tester $(dirname $0)/bug1613098.c -lgfapi + +TEST ./$(dirname $0)/bug1613098 $V0 $logdir/bug1613098.log + +cleanup_tester $(dirname $0)/bug1613098 + +cleanup; diff --git a/tests/basic/gfapi/gfapi-async-calls-test.c b/tests/basic/gfapi/gfapi-async-calls-test.c new file mode 100644 index 00000000000..55835b14709 --- /dev/null +++ b/tests/basic/gfapi/gfapi-async-calls-test.c @@ -0,0 +1,494 @@ +#include <fcntl.h> +#include <unistd.h> +#include <time.h> +#include <limits.h> +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <glusterfs/api/glfs.h> +#include <glusterfs/api/glfs-handles.h> + +#define LOG_ERR(msg) \ + do { \ + fprintf(stderr, "%s : Error (%s)\n", msg, strerror(errno)); \ + } while (0) + +int cbk_complete = 0; +int cbk_ret_val = -1; + +void +cbk_check() +{ + while (cbk_complete != 1) { + sleep(1); + } + if (cbk_ret_val < 0) { + fprintf(stderr, "cbk_ret_val is -ve\n"); + } +} + +int +fill_iov(struct iovec *iov, char fillchar, int count) +{ + int ret = -1; + + iov->iov_base = malloc(count + 1); + if (iov->iov_base == NULL) { + return ret; + } else { + iov->iov_len = count; + ret = 0; + } + memset(iov->iov_base, fillchar, count); + memset(iov->iov_base + count, '\0', 1); + + return ret; +} + +glfs_t * +init_glfs(const char *hostname, const char *volname, const char *logfile) +{ + int ret = -1; + glfs_t *fs = NULL; + + fs = glfs_new(volname); + if (!fs) { + LOG_ERR("glfs_new failed"); + return NULL; + } + + ret = glfs_set_volfile_server(fs, "tcp", hostname, 24007); + if (ret < 0) { + LOG_ERR("glfs_set_volfile_server failed"); + goto out; + } + + ret = glfs_set_logging(fs, logfile, 7); + if (ret < 0) { + LOG_ERR("glfs_set_logging failed"); + goto out; + } + + ret = glfs_init(fs); + if (ret < 0) { + LOG_ERR("glfs_init failed"); + goto out; + } + + ret = 0; +out: + if (ret) { + glfs_fini(fs); + fs = NULL; + } + + return fs; +} + +void +pwritev_async_cbk(glfs_fd_t *fd, ssize_t ret, struct stat *prestat, + struct stat *poststat, void *cookie) +{ + if (ret < 0) { + LOG_ERR("glfs_pwritev failed"); + } + cbk_ret_val = ret; + cbk_complete = 1; +} + +int +pwritev_async(glfs_t *fs, glfs_fd_t *glfd, int char_count) +{ + ssize_t ret = -1; + int flags = O_RDWR; + struct iovec iov = {0}; + void *write_cookie = NULL; + + ret = fill_iov(&iov, 'a', char_count); + if (ret) { + LOG_ERR("failed to create iov"); + goto out; + } + + write_cookie = strdup("write_cookie"); + ret = glfs_pwritev_async(glfd, &iov, 1, 0, flags, pwritev_async_cbk, + &write_cookie); +out: + if (ret < 0) { + LOG_ERR("glfs_pwritev async failed"); + } + return ret; +} + +void +pwrite_async_cbk(glfs_fd_t *fd, ssize_t ret, struct stat *prestat, + struct stat *poststat, void *cookie) +{ + if (ret < 0) { + LOG_ERR("glfs_pwrite_cbk failed"); + } + cbk_ret_val = ret; + cbk_complete = 1; +} + +int +pwrite_async(glfs_fd_t *glfd) +{ + ssize_t ret = -1; + int flags = O_RDWR; + char buf1[10]; + char *buf2 = "ten bytes!"; + void *write_cookie = strdup("write_cookie"); + ret = glfs_pwrite_async(glfd, buf1, 10, 0, flags, pwrite_async_cbk, + &write_cookie); + + if (ret < 0) { + LOG_ERR("glfs_pwrite_async failed"); + } + return ret; +} + +void +writev_async_cbk(glfs_fd_t *fd, ssize_t ret, struct stat *prestat, + struct stat *poststat, void *cookie) +{ + if (ret < 0) { + LOG_ERR("glfs_writev_cbk failed"); + } + cbk_ret_val = ret; + cbk_complete = 1; +} + +int +writev_async(glfs_t *fs, glfs_fd_t *glfd, int char_count) +{ + ssize_t ret = -1; + int flags = O_RDWR; + struct iovec iov = {0}; + void *write_cookie = NULL; + + ret = fill_iov(&iov, 'a', char_count); + if (ret) { + LOG_ERR("failed to create iov"); + goto out; + } + + write_cookie = strdup("write_cookie"); + ret = glfs_writev_async(glfd, &iov, 1, flags, writev_async_cbk, + &write_cookie); +out: + if (ret < 0) { + LOG_ERR("glfs_writev_async failed"); + } + return ret; +} + +void +write_async_cbk(glfs_fd_t *fd, ssize_t ret, struct stat *prestat, + struct stat *poststat, void *cookie) +{ + if (ret < 0) { + LOG_ERR("glfs_write_cbk failed"); + } + cbk_ret_val = ret; + cbk_complete = 1; +} + +int +write_async(glfs_fd_t *glfd) +{ + ssize_t ret = -1; + int flags = O_RDWR; + char buf1[10]; + char *buf2 = "ten bytes!"; + void *write_cookie = strdup("write_cookie"); + ret = glfs_write_async(glfd, buf1, 10, flags, write_async_cbk, + &write_cookie); + + if (ret < 0) { + LOG_ERR("glfs_write_async failed"); + } + return ret; +} + +void +preadv_async_cbk(glfs_fd_t *fd, ssize_t ret, struct stat *prestat, + struct stat *poststat, void *cookie) +{ + if (ret < 0) { + LOG_ERR("glfs_preadv_cbk failed"); + } + cbk_ret_val = ret; + cbk_complete = 1; +} + +int +preadv_async(glfs_t *fs, glfs_fd_t *glfd, int char_count) +{ + ssize_t ret = -1; + int flags = O_RDWR; + struct iovec iov = {0}; + void *read_cookie = NULL; + + ret = fill_iov(&iov, 'a', char_count); + if (ret) { + LOG_ERR("failed to create iov"); + goto out; + } + + read_cookie = strdup("preadv_cookie"); + ret = glfs_preadv_async(glfd, &iov, 1, 0, flags, preadv_async_cbk, + &read_cookie); +out: + if (ret < 0) { + LOG_ERR("glfs_preadv async failed"); + } + return ret; +} + +void +pread_async_cbk(glfs_fd_t *fd, ssize_t ret, struct stat *prestat, + struct stat *poststat, void *cookie) +{ + if (ret < 0) { + LOG_ERR("glfs_pread_cbk failed"); + } + cbk_ret_val = ret; + cbk_complete = 1; +} + +int +pread_async(glfs_fd_t *glfd) +{ + ssize_t ret = -1; + int flags = O_RDWR; + char buf1[10]; + void *read_cookie = strdup("read_cookie"); + ret = glfs_pread_async(glfd, buf1, 10, 0, flags, pread_async_cbk, + &read_cookie); + if (ret < 0) { + LOG_ERR("glfs_pread_async failed"); + } + + return ret; +} + +void +readv_async_cbk(glfs_fd_t *fd, ssize_t ret, struct stat *prestat, + struct stat *poststat, void *cookie) +{ + if (ret < 0) { + LOG_ERR("glfs_readv_cbk failed"); + } + cbk_ret_val = ret; + cbk_complete = 1; +} + +int +readv_async(glfs_t *fs, glfs_fd_t *glfd, int char_count) +{ + ssize_t ret = -1; + int flags = O_RDWR; + struct iovec iov = {0}; + void *read_cookie = NULL; + + ret = fill_iov(&iov, 'a', char_count); + if (ret) { + LOG_ERR("failed to create iov"); + goto out; + } + + read_cookie = strdup("read_cookie"); + ret = glfs_readv_async(glfd, &iov, 1, flags, readv_async_cbk, &read_cookie); +out: + if (ret < 0) { + LOG_ERR("glfs_readv_async failed"); + } + return ret; +} + +void +read_async_cbk(glfs_fd_t *fd, ssize_t ret, struct stat *prestat, + struct stat *poststat, void *cookie) +{ + if (ret < 0) { + LOG_ERR("glfs_read_cbk failed"); + } + cbk_ret_val = ret; + cbk_complete = 1; +} + +int +read_async(glfs_fd_t *glfd) +{ + ssize_t ret = -1; + int flags = O_RDWR; + char buf1[10]; + void *read_cookie = strdup("read_cookie"); + ret = glfs_read_async(glfd, buf1, 10, flags, read_async_cbk, &read_cookie); + + if (ret < 0) { + LOG_ERR("glfs_read_async failed"); + } + return ret; +} + +void +fsync_async_cbk(glfs_fd_t *fd, ssize_t ret, struct stat *prestat, + struct stat *poststat, void *cookie) +{ + if (ret < 0) { + LOG_ERR("glfs_fsync_async_cbk failed"); + } + cbk_ret_val = ret; + cbk_complete = 1; +} + +void +fdatasync_async_cbk(glfs_fd_t *fd, ssize_t ret, struct stat *prestat, + struct stat *poststat, void *cookie) +{ + if (ret < 0) { + LOG_ERR("glfs_fdatasync_async_cbk failed"); + } + cbk_ret_val = ret; + cbk_complete = 1; +} + +void +ftruncate_async_cbk(glfs_fd_t *fd, ssize_t ret, struct stat *prestat, + struct stat *poststat, void *cookie) +{ + if (ret < 0) { + LOG_ERR("glfs_ftruncate_async_cbk failed"); + } + cbk_ret_val = ret; + cbk_complete = 1; +} + +int +main(int argc, char *argv[]) +{ + int ret = 0; + char *hostname = NULL; + char *volname = NULL; + char *logfile = NULL; + glfs_t *fs = NULL; + const char *filename = "glfs_test.txt"; + int flags = (O_RDWR | O_CREAT); + glfs_fd_t *glfd = NULL; + int count = 200; + void *data = strdup("Sample_text"); + + if (argc != 4) { + fprintf(stderr, "Invalid argument\n"); + exit(1); + } + + hostname = argv[1]; + volname = argv[2]; + logfile = argv[3]; + + fs = init_glfs(hostname, volname, logfile); + if (fs == NULL) { + LOG_ERR("init_glfs failed"); + return -1; + } + + glfd = glfs_creat(fs, filename, flags, 0644); + if (glfd == NULL) { + LOG_ERR("glfs_creat failed"); + exit(1); + } + + ret = pwritev_async(fs, glfd, count); + if (ret) { + LOG_ERR("glfs_pwritev_async_test failed"); + exit(1); + } + cbk_check(); + + ret = writev_async(fs, glfd, count); + if (ret) { + LOG_ERR("glfs_writev_async_test failed"); + exit(1); + } + cbk_check(); + + ret = write_async(glfd); + if (ret) { + LOG_ERR("glfs_write_async_test failed"); + exit(1); + } + cbk_check(); + + ret = preadv_async(fs, glfd, count); + if (ret) { + LOG_ERR("glfs_preadv_async_test failed"); + exit(1); + } + cbk_check(); + + ret = pread_async(glfd); + if (ret) { + LOG_ERR("glfs_pread_async_test failed"); + exit(1); + } + cbk_check(); + + ret = readv_async(fs, glfd, count); + if (ret) { + LOG_ERR("glfs_readv_async_test failed"); + exit(1); + } + cbk_check(); + + ret = read_async(glfd); + if (ret) { + LOG_ERR("glfs_read_async_test failed"); + exit(1); + } + cbk_check(); + + ret = glfs_fsync(glfd, NULL, NULL); + if (ret < 0) { + LOG_ERR("glfs_fsync failed"); + exit(1); + } + + ret = glfs_fdatasync(glfd, NULL, NULL); + if (ret < 0) { + LOG_ERR("glfs_fdatasync failed"); + exit(1); + } + + ret = glfs_fsync_async(glfd, fsync_async_cbk, data); + if (ret < 0) { + LOG_ERR("glfs_fsync_async failed"); + exit(1); + } + cbk_check(); + + ret = glfs_fdatasync_async(glfd, fdatasync_async_cbk, data); + if (ret < 0) { + LOG_ERR("glfs_fdatasync_async failed"); + exit(1); + } + cbk_check(); + + ret = glfs_ftruncate_async(glfd, 4, ftruncate_async_cbk, data); + if (ret < 0) { + LOG_ERR("glfs_ftruncate_async failed"); + exit(1); + } + + ret = glfs_close(glfd); + if (ret < 0) { + LOG_ERR("glfs close failed"); + } + + ret = glfs_fini(fs); + + return ret; +} diff --git a/tests/basic/gfapi/gfapi-async-calls-test.t b/tests/basic/gfapi/gfapi-async-calls-test.t new file mode 100644 index 00000000000..9e5cd7c92cc --- /dev/null +++ b/tests/basic/gfapi/gfapi-async-calls-test.t @@ -0,0 +1,26 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +cleanup; +EXIT_EARLY=1; + +TEST glusterd + +TEST $CLI volume create $V0 ${H0}:$B0/brick1; +EXPECT 'Created' volinfo_field $V0 'Status'; + +TEST $CLI volume start $V0; +EXPECT 'Started' volinfo_field $V0 'Status'; + +logdir=`gluster --print-logdir` + +TEST build_tester $(dirname $0)/gfapi-async-calls-test.c -lgfapi + + +TEST ./$(dirname $0)/gfapi-async-calls-test ${H0} $V0 $logdir/gfapi-async-calls-test.log + +cleanup_tester $(dirname $0)/gfapi-async-calls-test + +cleanup; diff --git a/tests/basic/gfapi/gfapi-copy-file-range.t b/tests/basic/gfapi/gfapi-copy-file-range.t new file mode 100644 index 00000000000..a56d3a58e07 --- /dev/null +++ b/tests/basic/gfapi/gfapi-copy-file-range.t @@ -0,0 +1,82 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +cleanup; + +mkfs.xfs 2>&1 | grep reflink +if [ $? -ne 0 ]; then + SKIP_TESTS + exit +fi + + +TEST glusterd + +TEST truncate -s 2G $B0/xfs_image +# for now, a xfs filesystem with reflink support is created. +# In future, better to make changes in MKFS_LOOP so that, +# once can create a xfs filesystem with reflink enabled in +# generic and simple way, instead of doing below steps each +# time. +TEST mkfs.xfs -f -i size=512 -m reflink=1 $B0/xfs_image; + +TEST mkdir $B0/bricks +TEST mount -t xfs -o loop $B0/xfs_image $B0/bricks + +# Just a single brick volume. More test cases need to be +# added in future for distribute, replicate, +# distributed replicate and distributed replicated sharded +# volumes. +TEST $CLI volume create $V0 $H0:$B0/bricks/brick1; +EXPECT 'Created' volinfo_field $V0 'Status'; + +TEST $CLI volume start $V0; +EXPECT 'Started' volinfo_field $V0 'Status'; + +TEST glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0 + +TEST dd if=/dev/urandom of=$M0/file bs=1M count=555; + +# check for the existence of the created file +TEST stat $M0/file; + +# grab the size of the file +SRC_SIZE=$(stat -c %s $M0/file); + +logdir=`gluster --print-logdir` + +# TODO: +# For now, do not call copy-file-range utility. This is because, +# the regression machines are centos-7 based which does not have +# copy_file_range API available. So, instead of this testcase +# causing regression failures, for now, this is just a dummy test +# case. Uncomment the below tests (until volume stop) when there +# is support for copy_file_range in the regression machines. +# + +TEST build_tester $(dirname $0)/glfs-copy-file-range.c -lgfapi + +TEST ./$(dirname $0)/glfs-copy-file-range $H0 $V0 $logdir/gfapi-copy-file-range.log /file /new + +# check whether the destination file is created or not +TEST stat $M0/new + +# check the size of the destination file +DST_SIZE=$(stat -c %s $M0/new); + +# The sizes of the source and destination should be same. +# Atleast it ensures that, copy_file_range API is working +# as expected. Whether the actual cloning happened via reflink +# or a read/write happened is different matter. +TEST [ $SRC_SIZE == $DST_SIZE ]; + +cleanup_tester $(dirname $0)/glfs-copy-file-range + +TEST $CLI volume stop $V0 +TEST $CLI volume delete $V0 + +UMOUNT_LOOP $B0/bricks; + +cleanup; diff --git a/tests/basic/gfapi/gfapi-dup.c b/tests/basic/gfapi/gfapi-dup.c new file mode 100644 index 00000000000..028108e4590 --- /dev/null +++ b/tests/basic/gfapi/gfapi-dup.c @@ -0,0 +1,84 @@ +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <glusterfs/api/glfs.h> +#include <glusterfs/api/glfs-handles.h> + +#define VALIDATE_AND_GOTO_LABEL_ON_ERROR(func, ret, label) \ + do { \ + if (ret < 0) { \ + fprintf(stderr, "%s : returned error %d (%s)\n", func, ret, \ + strerror(errno)); \ + goto label; \ + } \ + } while (0) + +int +main(int argc, char *argv[]) +{ + int ret = -1; + int flags = O_RDWR | O_SYNC; + glfs_t *fs = NULL; + glfs_fd_t *fd1 = NULL; + glfs_fd_t *fd2 = NULL; + char *volname = NULL; + char *logfile = NULL; + char *hostname = NULL; + const char *filename = "file_tmp"; + const char *buff = + "An opinion should be the result of thought, " + "not a substitute for it."; + + if (argc != 4) { + fprintf(stderr, "Invalid argument\n"); + return 1; + } + + hostname = argv[1]; + volname = argv[2]; + logfile = argv[3]; + + fs = glfs_new(volname); + if (!fs) + VALIDATE_AND_GOTO_LABEL_ON_ERROR("glfs_new", ret, out); + + ret = glfs_set_volfile_server(fs, "tcp", hostname, 24007); + VALIDATE_AND_GOTO_LABEL_ON_ERROR("glfs_set_volfile_server", ret, out); + + ret = glfs_set_logging(fs, logfile, 7); + VALIDATE_AND_GOTO_LABEL_ON_ERROR("glfs_set_logging", ret, out); + + ret = glfs_init(fs); + VALIDATE_AND_GOTO_LABEL_ON_ERROR("glfs_init", ret, out); + + fd1 = glfs_creat(fs, filename, flags, 0644); + if (fd1 == NULL) { + ret = -1; + VALIDATE_AND_GOTO_LABEL_ON_ERROR("glfs_creat", ret, out); + } + + ret = glfs_write(fd1, buff, strlen(buff), flags); + VALIDATE_AND_GOTO_LABEL_ON_ERROR("glfs_write", ret, out); + + fd2 = glfs_dup(fd1); + if (fd2 == NULL) { + ret = -1; + VALIDATE_AND_GOTO_LABEL_ON_ERROR("glfs_dup", ret, out); + } + + ret = glfs_lseek(fd2, 0, SEEK_SET); + VALIDATE_AND_GOTO_LABEL_ON_ERROR("glfs_lseek", ret, out); + +out: + if (fd1 != NULL) + glfs_close(fd1); + if (fd2 != NULL) + glfs_close(fd2); + if (fs) { + ret = glfs_fini(fs); + if (ret) + fprintf(stderr, "glfs_fini(fs) returned %d\n", ret); + } + + return ret; +} diff --git a/tests/basic/gfapi/gfapi-dup.t b/tests/basic/gfapi/gfapi-dup.t new file mode 100755 index 00000000000..849b106f90f --- /dev/null +++ b/tests/basic/gfapi/gfapi-dup.t @@ -0,0 +1,27 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +cleanup; + +TEST glusterd + +TEST $CLI volume create $V0 $H0:$B0/brick1; +EXPECT 'Created' volinfo_field $V0 'Status'; + +TEST $CLI volume start $V0; +EXPECT 'Started' volinfo_field $V0 'Status'; + +logdir=`gluster --print-logdir` + +TEST build_tester $(dirname $0)/gfapi-dup.c -lgfapi + +TEST ./$(dirname $0)/gfapi-dup $H0 $V0 $logdir/gfapi-dup.log + +cleanup_tester $(dirname $0)/gfapi-dup + +TEST $CLI volume stop $V0 +TEST $CLI volume delete $V0 + +cleanup; diff --git a/tests/basic/gfapi/gfapi-graph-switch-open-fd.t b/tests/basic/gfapi/gfapi-graph-switch-open-fd.t new file mode 100644 index 00000000000..2e666be7ec7 --- /dev/null +++ b/tests/basic/gfapi/gfapi-graph-switch-open-fd.t @@ -0,0 +1,44 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +cleanup; + +TEST glusterd + +TEST $CLI volume create $V0 replica 3 ${H0}:$B0/brick{0..2}; +EXPECT 'Created' volinfo_field $V0 'Status'; + +TEST $CLI volume start $V0; +EXPECT 'Started' volinfo_field $V0 'Status'; + +TEST $GFS --volfile-id=$V0 --volfile-server=$H0 $M0; +TEST touch $M0/sync +logdir=`gluster --print-logdir` + +TEST build_tester $(dirname $0)/gfapi-keep-writing.c -lgfapi + + +#Launch a program to keep doing writes on an fd +./$(dirname $0)/gfapi-keep-writing ${H0} $V0 $logdir/gfapi-async-calls-test.log sync & +p=$! +sleep 1 #Let some writes go through +#Check if graph switch will lead to any pending markers for ever +TEST $CLI volume set $V0 performance.quick-read off +TEST $CLI volume set $V0 performance.io-cache off +TEST $CLI volume set $V0 performance.stat-prefetch off +TEST $CLI volume set $V0 performance.read-ahead off + + +TEST rm -f $M0/sync #Make sure the glfd is closed +TEST wait #Wait for background process to die +#Goal is to check if there is permanent FOOL changelog +sleep 5 +EXPECT "0x000000000000000000000000" afr_get_changelog_xattr $B0/brick0/glfs_test.txt trusted.afr.dirty +EXPECT "0x000000000000000000000000" afr_get_changelog_xattr $B0/brick1/glfs_test.txt trusted.afr.dirty +EXPECT "0x000000000000000000000000" afr_get_changelog_xattr $B0/brick2/glfs_test.txt trusted.afr.dirty + +cleanup_tester $(dirname $0)/gfapi-async-calls-test + +cleanup; diff --git a/tests/basic/gfapi/gfapi-keep-writing.c b/tests/basic/gfapi/gfapi-keep-writing.c new file mode 100644 index 00000000000..91b59cea02b --- /dev/null +++ b/tests/basic/gfapi/gfapi-keep-writing.c @@ -0,0 +1,129 @@ +#include <fcntl.h> +#include <unistd.h> +#include <time.h> +#include <limits.h> +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <glusterfs/api/glfs.h> +#include <glusterfs/api/glfs-handles.h> + +#define LOG_ERR(msg) \ + do { \ + fprintf(stderr, "%s : Error (%s)\n", msg, strerror(errno)); \ + } while (0) + +glfs_t * +init_glfs(const char *hostname, const char *volname, const char *logfile) +{ + int ret = -1; + glfs_t *fs = NULL; + + fs = glfs_new(volname); + if (!fs) { + LOG_ERR("glfs_new failed"); + return NULL; + } + + ret = glfs_set_volfile_server(fs, "tcp", hostname, 24007); + if (ret < 0) { + LOG_ERR("glfs_set_volfile_server failed"); + goto out; + } + + ret = glfs_set_logging(fs, logfile, 7); + if (ret < 0) { + LOG_ERR("glfs_set_logging failed"); + goto out; + } + + ret = glfs_init(fs); + if (ret < 0) { + LOG_ERR("glfs_init failed"); + goto out; + } + + ret = 0; +out: + if (ret) { + glfs_fini(fs); + fs = NULL; + } + + return fs; +} + +int +glfs_test_function(const char *hostname, const char *volname, + const char *logfile, const char *syncfile) +{ + int ret = -1; + int flags = O_CREAT | O_RDWR; + glfs_t *fs = NULL; + glfs_fd_t *glfd = NULL; + const char *buff = "This is from my prog\n"; + const char *filename = "glfs_test.txt"; + struct stat buf = {0}; + + fs = init_glfs(hostname, volname, logfile); + if (fs == NULL) { + LOG_ERR("init_glfs failed"); + return -1; + } + + glfd = glfs_creat(fs, filename, flags, 0644); + if (glfd == NULL) { + LOG_ERR("glfs_creat failed"); + goto out; + } + + while (glfs_stat(fs, syncfile, &buf) == 0) { + ret = glfs_write(glfd, buff, strlen(buff), flags); + if (ret < 0) { + LOG_ERR("glfs_write failed"); + goto out; + } + } + + ret = glfs_close(glfd); + if (ret < 0) { + LOG_ERR("glfs_write failed"); + goto out; + } + +out: + ret = glfs_fini(fs); + if (ret) { + LOG_ERR("glfs_fini failed"); + } + + return ret; +} + +int +main(int argc, char *argv[]) +{ + int ret = 0; + char *hostname = NULL; + char *volname = NULL; + char *logfile = NULL; + char *syncfile = NULL; + + if (argc != 5) { + fprintf(stderr, "Invalid argument\n"); + exit(1); + } + + hostname = argv[1]; + volname = argv[2]; + logfile = argv[3]; + syncfile = argv[4]; + + ret = glfs_test_function(hostname, volname, logfile, syncfile); + if (ret) { + LOG_ERR("glfs_test_function failed"); + } + + return ret; +} diff --git a/tests/basic/gfapi/gfapi-load-volfile.c b/tests/basic/gfapi/gfapi-load-volfile.c new file mode 100644 index 00000000000..fbfc6045cd7 --- /dev/null +++ b/tests/basic/gfapi/gfapi-load-volfile.c @@ -0,0 +1,65 @@ +/* + * Create a glfs instance based on a .vol file + * + * This is used to measure memory leaks by initializing a graph through a .vol + * file and destroying it again. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include <glusterfs/api/glfs.h> + +#define PROGNAME "gfapi-load-volfile" + +void +usage(FILE *output) +{ + fprintf(output, "Usage: " PROGNAME " <volfile>\n"); +} + +void +main(int argc, char **argv) +{ + int ret = 0; + glfs_t *fs = NULL; + + if (argc != 2) { + usage(stderr); + exit(EXIT_FAILURE); + } + + if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "-h")) { + usage(stdout); + exit(EXIT_SUCCESS); + } + + fs = glfs_new(PROGNAME); + if (!fs) { + perror("glfs_new failed"); + exit(EXIT_FAILURE); + } + + glfs_set_logging(fs, PROGNAME ".log", 9); + + ret = glfs_set_volfile(fs, argv[1]); + if (ret) { + perror("glfs_set_volfile failed"); + ret = EXIT_FAILURE; + goto out; + } + + ret = glfs_init(fs); + if (ret) { + perror("glfs_init failed"); + ret = EXIT_FAILURE; + goto out; + } + + ret = EXIT_SUCCESS; +out: + glfs_fini(fs); + + exit(ret); +} diff --git a/tests/basic/gfapi/gfapi-load-volfile.t b/tests/basic/gfapi/gfapi-load-volfile.t new file mode 100644 index 00000000000..d914cacd819 --- /dev/null +++ b/tests/basic/gfapi/gfapi-load-volfile.t @@ -0,0 +1,28 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +cleanup + +TEST glusterd + +TEST $CLI volume create ${V0} ${H0}:${B0}/brick0 +EXPECT 'Created' volinfo_field ${V0} 'Status' + +TEST $CLI volume start ${V0} +EXPECT 'Started' volinfo_field ${V0} 'Status' + +TEST build_tester $(dirname ${0})/gfapi-load-volfile.c -lgfapi + +sed -e "s,@@HOSTNAME@@,${H0},g" -e "s,@@BRICKPATH@@,${B0}/brick0,g" \ + $(dirname ${0})/protocol-client.vol.in \ + > $(dirname ${0})/protocol-client.vol + +TEST ./$(dirname ${0})/gfapi-load-volfile \ + $(dirname ${0})/protocol-client.vol + +cleanup_tester $(dirname ${0})/gfapi-load-volfile +cleanup_tester $(dirname ${0})/protocol-client.vol + +cleanup diff --git a/tests/basic/gfapi/gfapi-ssl-load-volfile-test.c b/tests/basic/gfapi/gfapi-ssl-load-volfile-test.c new file mode 100644 index 00000000000..7beb8dd1fe4 --- /dev/null +++ b/tests/basic/gfapi/gfapi-ssl-load-volfile-test.c @@ -0,0 +1,127 @@ +#include <fcntl.h> +#include <unistd.h> +#include <time.h> +#include <limits.h> +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <glusterfs/api/glfs.h> +#include <glusterfs/api/glfs-handles.h> + +#define LOG_ERR(msg) \ + do { \ + fprintf(stderr, "%s : Error (%s)\n", msg, strerror(errno)); \ + } while (0) + +glfs_t * +init_glfs(const char *hostname, const char *volname, const char *volfile, + const char *logfile) +{ + int ret = -1; + glfs_t *fs = NULL; + + fs = glfs_new(volname); + if (!fs) { + LOG_ERR("glfs_new failed"); + return NULL; + } + + ret = glfs_set_volfile(fs, volfile); + if (ret < 0) { + LOG_ERR("glfs_set_volfile failed"); + goto out; + } + + ret = glfs_set_logging(fs, logfile, 7); + if (ret < 0) { + LOG_ERR("glfs_set_logging failed"); + goto out; + } + + ret = glfs_init(fs); + if (ret < 0) { + LOG_ERR("glfs_init failed"); + goto out; + } + + ret = 0; +out: + if (ret) { + glfs_fini(fs); + fs = NULL; + } + + return fs; +} + +int +glfs_test_function(const char *hostname, const char *volname, + const char *volfile, const char *logfile) +{ + int ret = -1; + int flags = O_CREAT | O_RDWR; + glfs_t *fs = NULL; + glfs_fd_t *glfd = NULL; + const char *buff = "This is from my prog\n"; + const char *filename = "glfs_test.txt"; + + fs = init_glfs(hostname, volname, volfile, logfile); + if (fs == NULL) { + LOG_ERR("init_glfs failed"); + return -1; + } + + glfd = glfs_creat(fs, filename, flags, 0644); + if (glfd == NULL) { + LOG_ERR("glfs_creat failed"); + goto out; + } + + ret = glfs_write(glfd, buff, strlen(buff), flags); + if (ret < 0) { + LOG_ERR("glfs_write failed"); + goto out; + } + + ret = glfs_close(glfd); + if (ret < 0) { + LOG_ERR("glfs_write failed"); + goto out; + } + +out: + ret = glfs_fini(fs); + if (ret) { + LOG_ERR("glfs_fini failed"); + } + + return ret; +} + +int +main(int argc, char *argv[]) +{ + int ret = 0; + char *hostname = NULL; + char *volname = NULL; + char *volfile = NULL; + char *logfile = NULL; + + if (argc != 5) { + fprintf(stderr, "Invalid argument\n"); + exit(1); + } + + hostname = argv[1]; + volname = argv[2]; + volfile = argv[3]; + logfile = argv[4]; + + ret = glfs_test_function(hostname, volname, volfile, logfile); + if (ret) { + LOG_ERR("glfs_test_function failed"); + } + + return ret; +} diff --git a/tests/basic/gfapi/gfapi-ssl-load-volfile-test.t b/tests/basic/gfapi/gfapi-ssl-load-volfile-test.t new file mode 100755 index 00000000000..8e94df9d321 --- /dev/null +++ b/tests/basic/gfapi/gfapi-ssl-load-volfile-test.t @@ -0,0 +1,76 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc +. $(dirname $0)/../../traps.rc +. $(dirname $0)/../../ssl.rc + +cleanup; + +sed -e "s,@@HOSTNAME@@,${H0},g" -e "s,@@BRICKPATH@@,${B0}/brick1,g" \ + -e "s,@@SSL@@,off,g" \ + $(dirname ${0})/protocol-client-ssl.vol.in \ + > $(dirname ${0})/protocol-client-ssl.vol + +TEST create_self_signed_certs + +TEST glusterd + +TEST $CLI volume create $V0 $H0:$B0/brick1; +EXPECT 'Created' volinfo_field $V0 'Status'; + +TEST $CLI volume start $V0; +EXPECT 'Started' volinfo_field $V0 'Status'; +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" online_brick_count + +logdir=`gluster --print-logdir` + +TEST build_tester $(dirname $0)/gfapi-ssl-load-volfile-test.c -lgfapi + +# Run test without I/O or management encryption +TEST $(dirname $0)/gfapi-ssl-load-volfile-test $H0 $V0 \ + $(dirname ${0})/protocol-client-ssl.vol \ + $logdir/gfapi-ssl-load-volfile-test.log + +# Enable management encryption +touch $GLUSTERD_WORKDIR/secure-access + +killall_gluster + +TEST glusterd +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" online_brick_count + +# Run test with management encryption (No I/O encryption) +TEST $(dirname $0)/gfapi-ssl-load-volfile-test $H0 $V0 \ + $(dirname ${0})/protocol-client-ssl.vol \ + $logdir/gfapi-ssl-load-volfile-test.log + +# Enable I/O encryption +TEST $CLI volume set $V0 server.ssl on + +killall_gluster + +sed -e "s,@@HOSTNAME@@,${H0},g" -e "s,@@BRICKPATH@@,${B0}/brick1,g" \ + -e "s,@@SSL@@,on,g" \ + $(dirname ${0})/protocol-client-ssl.vol.in \ + > $(dirname ${0})/protocol-client-ssl.vol + +TEST glusterd +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" online_brick_count + +# Run test without I/O or management encryption +TEST $(dirname $0)/gfapi-ssl-load-volfile-test $H0 $V0 \ + $(dirname ${0})/protocol-client-ssl.vol \ + $logdir/gfapi-ssl-load-volfile-test.log + +cleanup_tester $(dirname $0)/gfapi-ssl-load-volfile-test + +TEST $CLI volume stop $V0 +TEST $CLI volume delete $V0 + +cleanup; + +# NetBSD build scripts are not up to date therefore this test +# is failing in NetBSD. Therefore skipping the test in NetBSD +# as of now. +#G_TESTDEF_TEST_STATUS_NETBSD7=KNOWN_ISSUE,BUG=000000 diff --git a/tests/basic/gfapi/gfapi-ssl-test.c b/tests/basic/gfapi/gfapi-ssl-test.c new file mode 100644 index 00000000000..a27b5233702 --- /dev/null +++ b/tests/basic/gfapi/gfapi-ssl-test.c @@ -0,0 +1,124 @@ +#include <fcntl.h> +#include <unistd.h> +#include <time.h> +#include <limits.h> +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <glusterfs/api/glfs.h> +#include <glusterfs/api/glfs-handles.h> + +#define LOG_ERR(msg) \ + do { \ + fprintf(stderr, "%s : Error (%s)\n", msg, strerror(errno)); \ + } while (0) + +glfs_t * +init_glfs(const char *hostname, const char *volname, const char *logfile) +{ + int ret = -1; + glfs_t *fs = NULL; + + fs = glfs_new(volname); + if (!fs) { + LOG_ERR("glfs_new failed"); + return NULL; + } + + ret = glfs_set_volfile_server(fs, "tcp", hostname, 24007); + if (ret < 0) { + LOG_ERR("glfs_set_volfile_server failed"); + goto out; + } + + ret = glfs_set_logging(fs, logfile, 7); + if (ret < 0) { + LOG_ERR("glfs_set_logging failed"); + goto out; + } + + ret = glfs_init(fs); + if (ret < 0) { + LOG_ERR("glfs_init failed"); + goto out; + } + + ret = 0; +out: + if (ret) { + glfs_fini(fs); + fs = NULL; + } + + return fs; +} + +int +glfs_test_function(const char *hostname, const char *volname, + const char *logfile) +{ + int ret = -1; + int flags = O_CREAT | O_RDWR; + glfs_t *fs = NULL; + glfs_fd_t *glfd = NULL; + const char *buff = "This is from my prog\n"; + const char *filename = "glfs_test.txt"; + + fs = init_glfs(hostname, volname, logfile); + if (fs == NULL) { + LOG_ERR("init_glfs failed"); + return -1; + } + + glfd = glfs_creat(fs, filename, flags, 0644); + if (glfd == NULL) { + LOG_ERR("glfs_creat failed"); + goto out; + } + + ret = glfs_write(glfd, buff, strlen(buff), flags); + if (ret < 0) { + LOG_ERR("glfs_write failed"); + goto out; + } + + ret = glfs_close(glfd); + if (ret < 0) { + LOG_ERR("glfs_write failed"); + goto out; + } + +out: + ret = glfs_fini(fs); + if (ret) { + LOG_ERR("glfs_fini failed"); + } + + return ret; +} + +int +main(int argc, char *argv[]) +{ + int ret = 0; + char *hostname = NULL; + char *volname = NULL; + char *logfile = NULL; + + if (argc != 4) { + fprintf(stderr, "Invalid argument\n"); + exit(1); + } + + hostname = argv[1]; + volname = argv[2]; + logfile = argv[3]; + + ret = glfs_test_function(hostname, volname, logfile); + if (ret) { + LOG_ERR("glfs_test_function failed"); + } + + return ret; +} diff --git a/tests/basic/gfapi/gfapi-ssl-test.t b/tests/basic/gfapi/gfapi-ssl-test.t new file mode 100755 index 00000000000..937fcc83a4c --- /dev/null +++ b/tests/basic/gfapi/gfapi-ssl-test.t @@ -0,0 +1,61 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc +. $(dirname $0)/../../traps.rc +. $(dirname $0)/../../ssl.rc + +cleanup; + +TEST create_self_signed_certs + +TEST glusterd + +TEST $CLI volume create $V0 $H0:$B0/brick1; +EXPECT 'Created' volinfo_field $V0 'Status'; + +TEST $CLI volume start $V0; +EXPECT 'Started' volinfo_field $V0 'Status'; +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" online_brick_count + +logdir=`gluster --print-logdir` + +TEST build_tester $(dirname $0)/gfapi-ssl-test.c -lgfapi + +# Run test without I/O or management encryption +TEST ./$(dirname $0)/gfapi-ssl-test $H0 $V0 $logdir/gfapi-ssl-test.log + +# Enable management encryption +touch $GLUSTERD_WORKDIR/secure-access + +killall_gluster + +TEST glusterd +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" online_brick_count + +# Run test with management encryption (No I/O encryption) +TEST ./$(dirname $0)/gfapi-ssl-test $H0 $V0 $logdir/gfapi-ssl-test.log + +# Enable I/O encryption +TEST $CLI volume set $V0 client.ssl on +TEST $CLI volume set $V0 server.ssl on + +killall_gluster + +TEST glusterd +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" online_brick_count + +# Run test without I/O or management encryption +TEST ./$(dirname $0)/gfapi-ssl-test $H0 $V0 $logdir/gfapi-ssl-test.log + +cleanup_tester $(dirname $0)/gfapi-ssl-test + +TEST $CLI volume stop $V0 +TEST $CLI volume delete $V0 + +cleanup; + +# NetBSD build scripts are not up to date therefore this test +# is failing in NetBSD. Therefore skipping the test in NetBSD +# as of now. +#G_TESTDEF_TEST_STATUS_NETBSD7=KNOWN_ISSUE,BUG=000000 diff --git a/tests/basic/gfapi/gfapi-statx-basic.c b/tests/basic/gfapi/gfapi-statx-basic.c new file mode 100644 index 00000000000..a4943fa0fd1 --- /dev/null +++ b/tests/basic/gfapi/gfapi-statx-basic.c @@ -0,0 +1,184 @@ +#include <stdio.h> +#include <errno.h> +#include <string.h> +#include <stdbool.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <glusterfs/api/glfs.h> + +#define VALIDATE_AND_GOTO_LABEL_ON_ERROR(func, ret, label) \ + do { \ + if (ret < 0) { \ + fprintf(stderr, "%s : returned error %d (%s)\n", func, ret, \ + strerror(errno)); \ + goto label; \ + } \ + } while (0) + +#define GOTO_LABEL_ON_FALSE(compstr, ret, label) \ + do { \ + if (ret == false) { \ + fprintf(stderr, "%s : comparison failed!\n", compstr); \ + goto label; \ + } \ + } while (0) + +#define WRITE_SIZE 513 +#define TRUNC_SIZE 4096 + +/* Using private function and hence providing a forward declation in sync with +code in glfs-internal.h */ +int +glfs_statx(struct glfs *fs, const char *path, unsigned int mask, + struct glfs_stat *statxbuf); + +int +main(int argc, char *argv[]) +{ + int ret = -1; + int flags = O_RDWR | O_SYNC; + glfs_t *fs = NULL; + glfs_fd_t *fd1 = NULL; + char *volname = NULL; + char *logfile = NULL; + const char *filename = "file_tmp"; + const char buff[WRITE_SIZE]; + struct stat sb; + unsigned int mask; + struct glfs_stat statx; + bool bret; + + if (argc != 3) { + fprintf(stderr, "Invalid argument\n"); + fprintf(stderr, "Usage: %s <volname> <logfile>\n", argv[0]); + return 1; + } + + volname = argv[1]; + logfile = argv[2]; + + fs = glfs_new(volname); + if (!fs) + VALIDATE_AND_GOTO_LABEL_ON_ERROR("glfs_new", ret, out); + + ret = glfs_set_volfile_server(fs, "tcp", "localhost", 24007); + VALIDATE_AND_GOTO_LABEL_ON_ERROR("glfs_set_volfile_server", ret, out); + + ret = glfs_set_logging(fs, logfile, 7); + VALIDATE_AND_GOTO_LABEL_ON_ERROR("glfs_set_logging", ret, out); + + ret = glfs_init(fs); + VALIDATE_AND_GOTO_LABEL_ON_ERROR("glfs_init", ret, out); + + fd1 = glfs_creat(fs, filename, flags, 0644); + if (fd1 == NULL) { + ret = -1; + VALIDATE_AND_GOTO_LABEL_ON_ERROR("glfs_creat", ret, out); + } + + ret = glfs_truncate(fs, filename, TRUNC_SIZE); + VALIDATE_AND_GOTO_LABEL_ON_ERROR("glfs_truncate", ret, out); + + ret = glfs_write(fd1, buff, WRITE_SIZE, flags); + VALIDATE_AND_GOTO_LABEL_ON_ERROR("glfs_write", ret, out); + + ret = glfs_fstat(fd1, &sb); + VALIDATE_AND_GOTO_LABEL_ON_ERROR("glfs_fstat", ret, out); + + if (sb.st_size != TRUNC_SIZE) { + fprintf(stderr, "wrong size %jd should be %jd\n", (intmax_t)sb.st_size, + (intmax_t)2048); + ret = -1; + goto out; + } + + glfs_close(fd1); + fd1 = NULL; + + /* TEST 1: Invalid mask to statx */ + mask = 0xfafadbdb; + ret = glfs_statx(fs, filename, mask, NULL); + if (ret == 0 || ((ret == -1) && (errno != EINVAL))) { + fprintf(stderr, + "Invalid args passed, but error returned is" + " incorrect (ret - %d, errno - %d)\n", + ret, errno); + ret = -1; + goto out; + } + ret = 0; + + /* TEST 2: Call statx and validate fields against prior fstat data */ + /* NOTE: This fails, as iatt->ia_flags are not carried through the stack, + * for example if mdc_to_iatt is invoked to serve cached stat, we will loose + * the flags. */ + mask = GLFS_STAT_ALL; + ret = glfs_statx(fs, filename, mask, &statx); + VALIDATE_AND_GOTO_LABEL_ON_ERROR("glfs_statx", ret, out); + + if ((statx.glfs_st_mask & GLFS_STAT_BASIC_STATS) != GLFS_STAT_BASIC_STATS) { + fprintf(stderr, "Invalid glfs_st_mask, expecting 0x%x got 0x%x\n", + GLFS_STAT_ALL, statx.glfs_st_mask); + ret = -1; + goto out; + } + + bret = (sb.st_ino == statx.glfs_st_ino); + GOTO_LABEL_ON_FALSE("(sb.st_ino == statx.glfs_st_ino)", bret, out); + + bret = (sb.st_mode == statx.glfs_st_mode); + GOTO_LABEL_ON_FALSE("(sb.st_mode == statx.glfs_st_mode)", bret, out); + + bret = (sb.st_nlink == statx.glfs_st_nlink); + GOTO_LABEL_ON_FALSE("(sb.st_nlink == statx.glfs_st_nlink)", bret, out); + + bret = (sb.st_uid == statx.glfs_st_uid); + GOTO_LABEL_ON_FALSE("(sb.st_uid == statx.glfs_st_uid)", bret, out); + + bret = (sb.st_gid == statx.glfs_st_gid); + GOTO_LABEL_ON_FALSE("(sb.st_gid == statx.glfs_st_gid)", bret, out); + + bret = (sb.st_size == statx.glfs_st_size); + GOTO_LABEL_ON_FALSE("(sb.st_size == statx.glfs_st_size)", bret, out); + + bret = (sb.st_blksize == statx.glfs_st_blksize); + GOTO_LABEL_ON_FALSE("(sb.st_blksize == statx.glfs_st_blksize)", bret, out); + + bret = (sb.st_blocks == statx.glfs_st_blocks); + GOTO_LABEL_ON_FALSE("(sb.st_blocks == statx.glfs_st_blocks)", bret, out); + + bret = (!memcmp(&sb.st_atim, &statx.glfs_st_atime, + sizeof(struct timespec))); + GOTO_LABEL_ON_FALSE("(sb.st_atim == statx.glfs_st_atime)", bret, out); + + bret = (!memcmp(&sb.st_mtim, &statx.glfs_st_mtime, + sizeof(struct timespec))); + GOTO_LABEL_ON_FALSE("(sb.st_mtim == statx.glfs_st_mtime)", bret, out); + + bret = (!memcmp(&sb.st_ctim, &statx.glfs_st_ctime, + sizeof(struct timespec))); + GOTO_LABEL_ON_FALSE("(sb.st_ctim == statx.glfs_st_ctime)", bret, out); + + /* TEST 3: Check if partial masks are accepted */ + mask = GLFS_STAT_TYPE | GLFS_STAT_UID | GLFS_STAT_GID; + ret = glfs_statx(fs, filename, mask, &statx); + VALIDATE_AND_GOTO_LABEL_ON_ERROR("glfs_statx", ret, out); + + /* We currently still return all stats, as is acceptable based on the API + * definition in the header (and in statx as well) */ + if ((statx.glfs_st_mask & GLFS_STAT_BASIC_STATS) != GLFS_STAT_BASIC_STATS) { + fprintf(stderr, "Invalid glfs_st_mask, expecting 0x%x got 0x%x\n", + GLFS_STAT_ALL, statx.glfs_st_mask); + ret = -1; + goto out; + } +out: + if (fd1 != NULL) + glfs_close(fd1); + if (fs) { + (void)glfs_fini(fs); + } + + return ret; +} diff --git a/tests/basic/gfapi/gfapi-statx-basic.t b/tests/basic/gfapi/gfapi-statx-basic.t new file mode 100755 index 00000000000..d9acbce2f99 --- /dev/null +++ b/tests/basic/gfapi/gfapi-statx-basic.t @@ -0,0 +1,30 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +cleanup; + +TEST glusterd + +TEST $CLI volume create $V0 ${H0}:$B0/brick1; +EXPECT 'Created' volinfo_field $V0 'Status'; + +TEST $CLI volume start $V0; +EXPECT 'Started' volinfo_field $V0 'Status'; + +# NOTE: Test is passing due to very specific volume configuration +# Disable md-cache, as it does not save and return ia_flags from iatt +# This is possibly going to be true of other xlators as well (ec/afr), need to +# ensure these are fixed, or hack statx to return all basic attrs anyway. +TEST $CLI volume set $V0 performance.md-cache-timeout 0 + +logdir=`gluster --print-logdir` + +build_tester $(dirname $0)/gfapi-statx-basic.c -lgfapi + +TEST ./$(dirname $0)/gfapi-statx-basic $V0 $logdir/gfapi-statx-basic.log + +cleanup_tester $(dirname $0)/gfapi-statx-basic + +cleanup; diff --git a/tests/basic/gfapi/gfapi-trunc.c b/tests/basic/gfapi/gfapi-trunc.c new file mode 100644 index 00000000000..769f6cfa1d9 --- /dev/null +++ b/tests/basic/gfapi/gfapi-trunc.c @@ -0,0 +1,89 @@ +#include <inttypes.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <glusterfs/api/glfs.h> +#include <glusterfs/api/glfs-handles.h> + +#define VALIDATE_AND_GOTO_LABEL_ON_ERROR(func, ret, label) \ + do { \ + if (ret < 0) { \ + fprintf(stderr, "%s : returned error %d (%s)\n", func, ret, \ + strerror(errno)); \ + goto label; \ + } \ + } while (0) + +#define WRITE_SIZE 4096 +#define TRUNC_SIZE 1234 +/* Make sure TRUNC_SIZE is smaller than WRITE_SIZE at compile time. */ +typedef char _size_check[WRITE_SIZE - TRUNC_SIZE]; + +int +main(int argc, char *argv[]) +{ + int ret = -1; + int flags = O_RDWR | O_SYNC; + glfs_t *fs = NULL; + glfs_fd_t *fd1 = NULL; + char *volname = NULL; + char *logfile = NULL; + const char *filename = "file_tmp"; + const char buff[WRITE_SIZE]; + struct stat sb; + + if (argc != 3) { + fprintf(stderr, "Invalid argument\n"); + return 1; + } + + volname = argv[1]; + logfile = argv[2]; + + fs = glfs_new(volname); + if (!fs) + VALIDATE_AND_GOTO_LABEL_ON_ERROR("glfs_new", ret, out); + + ret = glfs_set_volfile_server(fs, "tcp", "localhost", 24007); + VALIDATE_AND_GOTO_LABEL_ON_ERROR("glfs_set_volfile_server", ret, out); + + ret = glfs_set_logging(fs, logfile, 7); + VALIDATE_AND_GOTO_LABEL_ON_ERROR("glfs_set_logging", ret, out); + + ret = glfs_init(fs); + VALIDATE_AND_GOTO_LABEL_ON_ERROR("glfs_init", ret, out); + + fd1 = glfs_creat(fs, filename, flags, 0644); + if (fd1 == NULL) { + ret = -1; + VALIDATE_AND_GOTO_LABEL_ON_ERROR("glfs_creat", ret, out); + } + + ret = glfs_write(fd1, buff, WRITE_SIZE, flags); + VALIDATE_AND_GOTO_LABEL_ON_ERROR("glfs_write", ret, out); + + ret = glfs_truncate(fs, filename, TRUNC_SIZE); + VALIDATE_AND_GOTO_LABEL_ON_ERROR("glfs_truncate", ret, out); + + ret = glfs_fstat(fd1, &sb); + VALIDATE_AND_GOTO_LABEL_ON_ERROR("glfs_fstat", ret, out); + + if (sb.st_size != TRUNC_SIZE) { + fprintf(stderr, "wrong size %jd should be %jd\n", (intmax_t)sb.st_size, + (intmax_t)2048); + ret = -1; + } + +out: + if (fd1 != NULL) + glfs_close(fd1); + if (fs) { + /* + * If this fails (as it does on Special Snowflake NetBSD for no + * good reason), it shouldn't affect the result of the test. + */ + (void)glfs_fini(fs); + } + + return ret; +} diff --git a/tests/basic/gfapi/gfapi-trunc.t b/tests/basic/gfapi/gfapi-trunc.t new file mode 100644 index 00000000000..4943a6be898 --- /dev/null +++ b/tests/basic/gfapi/gfapi-trunc.t @@ -0,0 +1,22 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +TEST glusterd + +TEST $CLI volume create $V0 ${H0}:$B0/brick1; +EXPECT 'Created' volinfo_field $V0 'Status'; + +TEST $CLI volume start $V0; +EXPECT 'Started' volinfo_field $V0 'Status'; + +logdir=`gluster --print-logdir` + +build_tester $(dirname $0)/gfapi-trunc.c -lgfapi + +TEST ./$(dirname $0)/gfapi-trunc $V0 $logdir/gfapi-trunc.log + +cleanup_tester $(dirname $0)/gfapi-trunc + +cleanup; diff --git a/tests/basic/gfapi/glfd-lkowner.c b/tests/basic/gfapi/glfd-lkowner.c new file mode 100644 index 00000000000..ec0429dc3c4 --- /dev/null +++ b/tests/basic/gfapi/glfd-lkowner.c @@ -0,0 +1,214 @@ +#include <fcntl.h> +#include <unistd.h> +#include <time.h> +#include <limits.h> +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <glusterfs/api/glfs.h> +#include <glusterfs/api/glfs-handles.h> +#include <sys/wait.h> +#include <stdbool.h> + +int gfapi = 1; + +#define LOG_ERR(func, ret) \ + do { \ + if (ret != 0) { \ + fprintf(stderr, "%s : returned error %d (%s)\n", func, ret, \ + strerror(errno)); \ + goto out; \ + } else { \ + fprintf(stderr, "%s : returned %d\n", func, ret); \ + } \ + } while (0) + +char lownera[8] = "lownera", lownerb[8] = "lownerb"; +char lownerc[8] = "lownerc"; + +int +lock_test(glfs_fd_t *glfd1, glfs_fd_t *glfd2, bool should_fail, int l1_start, + int l1_len, char *l1_owner, int lo1_len, int l2_start, int l2_len, + char *l2_owner, int lo2_len) +{ + int ret = -1, f_ret = -1; + struct flock lock1 = + { + 0, + }, + lock2 = { + 0, + }; + +lock1: + if (!glfd1) + goto lock2; + + /* lock on glfd1 */ + lock1.l_type = F_WRLCK; + lock1.l_whence = SEEK_SET; + lock1.l_start = l1_start; + lock1.l_len = l1_len; + + ret = glfs_fd_set_lkowner(glfd1, l1_owner, lo1_len); + LOG_ERR("glfs_fd_set_lkowner on glfd1", ret); + + ret = glfs_posix_lock(glfd1, F_SETLK, &lock1); + LOG_ERR("glfs_posix_lock on glfd1", ret); + +lock2: + if (!glfd2) + goto out; + + /* lock on glfd2 */ + lock2.l_type = F_WRLCK; + lock2.l_whence = SEEK_SET; + lock2.l_start = l2_start; + lock2.l_len = l2_len; + + ret = glfs_fd_set_lkowner(glfd2, l2_owner, lo2_len); + LOG_ERR("glfs_fd_set_lkowner on glfd2", ret); + + ret = glfs_posix_lock(glfd2, F_SETLK, &lock2); + + if (should_fail && ret) { + f_ret = 0; + } else if (!ret && !should_fail) { + f_ret = 0; + } else { + f_ret = -1; + } +out: + fprintf(stderr, + "Lock test on glfd1 (start(%d), len(%d)," + " lk_owner(%s)) and glfd2 (start(%d), len(%d), " + "lk_owner(%s)) - expected(%s) - result(%s)\n", + l1_start, l1_len, l1_owner, l2_start, l2_len, l2_owner, + (should_fail ? "FAIL" : "SUCCESS"), (ret ? "FAIL" : "SUCCESS")); + return f_ret; +} + +int +main(int argc, char *argv[]) +{ + glfs_t *fs = NULL; + int ret = 0, i, status = 0; + glfs_fd_t *fd1 = NULL; + glfs_fd_t *fd2 = NULL; + glfs_fd_t *fd3 = NULL; + char *filename = "file_tmp"; + char *volname = NULL; + char *logfile = NULL; + char *hostname = NULL; + + if (argc != 4) { + fprintf(stderr, "Invalid argument\n"); + exit(1); + } + + hostname = argv[1]; + volname = argv[2]; + logfile = argv[3]; + + fs = glfs_new(volname); + if (!fs) { + fprintf(stderr, "glfs_new: returned NULL\n"); + return -1; + } + + ret = glfs_set_volfile_server(fs, "tcp", hostname, 24007); + LOG_ERR("glfs_set_volfile_server", ret); + + ret = glfs_set_logging(fs, logfile, 7); + LOG_ERR("glfs_set_logging", ret); + + ret = glfs_init(fs); + LOG_ERR("glfs_init", ret); + + fd1 = glfs_creat(fs, filename, O_RDWR | O_SYNC, 0644); + if (fd1 <= 0) { + ret = -1; + LOG_ERR("glfs_creat", ret); + } + fprintf(stderr, "glfs-create fd1 - %d\n", fd1); + + fd2 = glfs_dup(fd1); + fprintf(stderr, "glfs-dup fd2 - %d\n", fd2); + + fd3 = glfs_open(fs, filename, O_RDWR | O_SYNC); + if (fd2 <= 0) { + ret = -1; + LOG_ERR("glfs_open", ret); + } + fprintf(stderr, "glfs-open fd3 - %d\n", fd3); + + /* TEST 1: Conflicting ranges, same lk_owner + * lock1 (0, 10, lownera) + * lock2 (5, 10, lownera) + * Expected: should not fail but get merged + */ + ret = lock_test(fd1, fd2, false, 0, 10, lownera, 8, 5, 10, lownera, 8); + LOG_ERR("==== glfs_lock_test_1", ret); + + /* TEST 2: Conflicting ranges, different lk_owner + * lock1 (0, 10, lownera) - already taken + * lock2 (5, 10, lownerb) + * Expected: should fail and not get merged + */ + ret = lock_test(NULL, fd2, true, 0, 10, lownera, 8, 5, 10, lownerb, 8); + LOG_ERR("==== glfs_lock_test_2", ret); + + /* TEST 3: Different ranges, same lk_owner + * lock1 (0, 10, lownera) - already taken + * lock2 (30, 10, lownera) + * Expected: should not fail + */ + ret = lock_test(NULL, fd2, false, 0, 10, lownera, 8, 30, 10, lownera, 8); + LOG_ERR("==== glfs_lock_test_3", ret); + + /* TEST 4: Conflicting ranges, different lk_owner + * lock1 (0, 10, lownera) - already taken + * lock2 (50, 10, lownerb) + * Expected: should not fail + */ + ret = lock_test(NULL, fd2, false, 0, 10, lownera, 8, 50, 10, lownerb, 8); + LOG_ERR("==== glfs_lock_test_4", ret); + + /* TEST 5: Close fd1 & retry TEST2 + * lock1 (not applicable) + * lock2 (5, 10, lownerb) + * Expected: should succeed now + */ + ret = glfs_close(fd1); + LOG_ERR("glfs_close", ret); + + ret = lock_test(NULL, fd2, false, 0, 10, lownera, 8, 5, 10, lownerb, 8); + LOG_ERR("==== glfs_lock_test_5", ret); + + /* TEST 6: Check closing fd1 doesn't flush fd2 locks + * retry TEST 4 but with fd2 and fd3. + * lock1 (50, 10, lownerb) - already taken + * lock2 (55, 10, lownerc) + * Expected: should fail + */ + ret = lock_test(NULL, fd3, true, 50, 10, lownerb, 8, 55, 10, lownerc, 8); + LOG_ERR("==== glfs_lock_test_6", ret); + +err: + ret = glfs_close(fd2); + LOG_ERR("glfs_close", ret); + + ret = glfs_close(fd3); + LOG_ERR("glfs_close", ret); + +out: + if (fs) { + ret = glfs_fini(fs); + fprintf(stderr, "glfs_fini(fs) returned %d\n", ret); + } + + if (ret) + exit(1); + exit(0); +} diff --git a/tests/basic/gfapi/glfd-lkowner.t b/tests/basic/gfapi/glfd-lkowner.t new file mode 100755 index 00000000000..ad7b0260a14 --- /dev/null +++ b/tests/basic/gfapi/glfd-lkowner.t @@ -0,0 +1,27 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +cleanup; + +TEST glusterd + +TEST $CLI volume create $V0 $H0:$B0/brick1; +EXPECT 'Created' volinfo_field $V0 'Status'; + +TEST $CLI volume start $V0; +EXPECT 'Started' volinfo_field $V0 'Status'; + +logdir=`gluster --print-logdir` + +TEST build_tester $(dirname $0)/glfd-lkowner.c -lgfapi + +TEST ./$(dirname $0)/glfd-lkowner $H0 $V0 $logdir/glfd-lkowner.log + +cleanup_tester $(dirname $0)/glfd-lkowner + +TEST $CLI volume stop $V0 +TEST $CLI volume delete $V0 + +cleanup; diff --git a/tests/basic/gfapi/glfs-copy-file-range.c b/tests/basic/gfapi/glfs-copy-file-range.c new file mode 100644 index 00000000000..1c5fd81fc87 --- /dev/null +++ b/tests/basic/gfapi/glfs-copy-file-range.c @@ -0,0 +1,180 @@ +/* + Copyright (c) 2018 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <glusterfs/api/glfs.h> +#include <glusterfs/api/glfs-handles.h> +#include <string.h> +#include <time.h> +#include <libgen.h> + +static void +cleanup(glfs_t *fs) +{ + if (!fs) + return; +#if 0 + /* glfs fini path is still racy and crashing the program. Since + * this program any way has to die, we are not going to call fini + * in the released versions. i.e. final builds. For all + * internal testing lets enable this so that glfs_fini code + * path becomes stable. */ + glfs_fini (fs); +#endif +} + +int +main(int argc, char **argv) +{ + glfs_t *fs = NULL; + int ret = -1; + char *volname = NULL; + char *logfilepath = NULL; + char *path_src = NULL; + char *path_dst = NULL; + glfs_fd_t *glfd_in = NULL; + glfs_fd_t *glfd_out = NULL; + char *volfile_server = NULL; + + struct stat stbuf = { + 0, + }; + struct glfs_stat stat_src = { + 0, + }; + struct glfs_stat prestat_dst = { + 0, + }; + struct glfs_stat poststat_dst = { + 0, + }; + size_t len; + + if (argc < 6) { + printf("%s <volume> <log file path> <source> <destination>", argv[0]); + ret = -1; + goto out; + } + + volfile_server = argv[1]; + volname = argv[2]; + logfilepath = argv[3]; + path_src = argv[4]; + path_dst = argv[5]; + + if (path_src[0] != '/') { + fprintf(stderr, "source path %s is not absolute", path_src); + errno = EINVAL; + goto out; + } + + if (path_dst[0] != '/') { + fprintf(stderr, "destination path %s is not absolute", path_dst); + errno = EINVAL; + goto out; + } + + fs = glfs_new(volname); + if (!fs) { + ret = -errno; + fprintf(stderr, "Not able to initialize volume '%s'", volname); + goto out; + } + + ret = glfs_set_volfile_server(fs, "tcp", volfile_server, 24007); + if (ret < 0) { + ret = -errno; + fprintf(stderr, + "Failed to set the volfile server, " + "%s", + strerror(errno)); + goto out; + } + + ret = glfs_set_logging(fs, logfilepath, 7); + if (ret < 0) { + ret = -errno; + fprintf(stderr, + "Failed to set the log file path, " + "%s", + strerror(errno)); + goto out; + } + + ret = glfs_init(fs); + if (ret < 0) { + ret = -errno; + if (errno == ENOENT) { + fprintf(stderr, "Volume %s does not exist", volname); + } else { + fprintf(stderr, + "%s: Not able to fetch " + "volfile from glusterd", + volname); + } + goto out; + } + + glfd_in = glfs_open(fs, path_src, O_RDONLY | O_NONBLOCK); + if (!glfd_in) { + ret = -errno; + goto out; + } else { + printf("OPEN_SRC: opening %s is success\n", path_src); + } + + glfd_out = glfs_creat(fs, path_dst, O_RDWR, 0644); + if (!glfd_out) { + fprintf(stderr, + "FAILED_DST_OPEN: failed to " + "open (create) %s (%s)\n", + path_dst, strerror(errno)); + ret = -errno; + goto out; + } else { + printf("OPEN_DST: opening %s is success\n", path_dst); + } + + ret = glfs_fstat(glfd_in, &stbuf); + if (ret < 0) { + ret = -errno; + goto out; + } else { + printf("FSTAT_SRC: fstat on %s is success\n", path_dst); + } + + len = stbuf.st_size; + + do { + ret = glfs_copy_file_range(glfd_in, NULL, glfd_out, NULL, len, 0, + &stat_src, &prestat_dst, &poststat_dst); + if (ret == -1) { + fprintf(stderr, "copy_file_range failed with %s\n", + strerror(errno)); + ret = -errno; + break; + } else { + printf("copy_file_range successful\n"); + len -= ret; + } + } while (len > 0); + +out: + if (glfd_in) + glfs_close(glfd_in); + if (glfd_out) + glfs_close(glfd_out); + + cleanup(fs); + + return ret; +} diff --git a/tests/basic/gfapi/glfs_h_creat_open.c b/tests/basic/gfapi/glfs_h_creat_open.c new file mode 100644 index 00000000000..7672561e73f --- /dev/null +++ b/tests/basic/gfapi/glfs_h_creat_open.c @@ -0,0 +1,118 @@ +#include <fcntl.h> +#include <unistd.h> +#include <time.h> +#include <limits.h> +#include <string.h> +#include <stdio.h> +#include <errno.h> +#include <stdlib.h> +#include <glusterfs/api/glfs.h> +#include <glusterfs/api/glfs-handles.h> + +#define LOG_ERR(func, ret) \ + do { \ + if (ret != 0) { \ + fprintf(stderr, "%s : returned error ret(%d), errno(%d)\n", func, \ + ret, errno); \ + exit(1); \ + } else { \ + fprintf(stderr, "%s : returned %d\n", func, ret); \ + } \ + } while (0) +#define LOG_IF_NO_ERR(func, ret) \ + do { \ + if (ret == 0) { \ + fprintf(stderr, "%s : hasn't returned error %d\n", func, ret); \ + exit(1); \ + } else { \ + fprintf(stderr, "%s : returned %d\n", func, ret); \ + } \ + } while (0) +int +main(int argc, char *argv[]) +{ + glfs_t *fs = NULL; + int ret = 0; + struct glfs_object *root = NULL, *leaf = NULL; + glfs_fd_t *fd = NULL; + char *filename = "/ro-file"; + struct stat sb = { + 0, + }; + char *logfile = NULL; + char *volname = NULL; + char *hostname = NULL; + char buf[32] = "abcdefghijklmnopqrstuvwxyz012345"; + + fprintf(stderr, "Starting glfs_h_creat_open\n"); + + if (argc != 4) { + fprintf(stderr, "Invalid argument\n"); + exit(1); + } + + hostname = argv[1]; + volname = argv[2]; + logfile = argv[3]; + + fs = glfs_new(volname); + if (!fs) { + fprintf(stderr, "glfs_new: returned NULL\n"); + return 1; + } + + ret = glfs_set_volfile_server(fs, "tcp", hostname, 24007); + LOG_ERR("glfs_set_volfile_server", ret); + + ret = glfs_set_logging(fs, logfile, 7); + LOG_ERR("glfs_set_logging", ret); + + ret = glfs_init(fs); + LOG_ERR("glfs_init", ret); + + sleep(2); + root = glfs_h_lookupat(fs, NULL, "/", &sb, 0); + if (!root) { + ret = -1; + LOG_ERR("glfs_h_lookupat root", ret); + } + leaf = glfs_h_lookupat(fs, root, filename, &sb, 0); + if (!leaf) { + ret = -1; + LOG_IF_NO_ERR("glfs_h_lookupat leaf", ret); + } + + leaf = glfs_h_creat_open(fs, root, filename, O_RDONLY, 00444, &sb, &fd); + if (!leaf || !fd) { + ret = -1; + LOG_ERR("glfs_h_creat leaf", ret); + } + fprintf(stderr, "glfs_h_create_open leaf - %p\n", leaf); + + ret = glfs_write(fd, buf, 32, 0); + if (ret < 0) { + fprintf(stderr, "glfs_write: error writing to file %s, %s\n", filename, + strerror(errno)); + goto out; + } + + ret = glfs_h_getattrs(fs, leaf, &sb); + LOG_ERR("glfs_h_getattrs", ret); + + if (sb.st_size != 32) { + fprintf(stderr, "glfs_write: post size mismatch\n"); + goto out; + } + + fprintf(stderr, "Successfully opened and written to a read-only file \n"); +out: + if (fd) + glfs_close(fd); + + ret = glfs_fini(fs); + LOG_ERR("glfs_fini", ret); + + fprintf(stderr, "End of libgfapi_fini\n"); + + exit(0); +} diff --git a/tests/basic/gfapi/glfs_h_creat_open.t b/tests/basic/gfapi/glfs_h_creat_open.t new file mode 100755 index 00000000000..f24ae7395be --- /dev/null +++ b/tests/basic/gfapi/glfs_h_creat_open.t @@ -0,0 +1,27 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +cleanup; + +TEST glusterd + +TEST $CLI volume create $V0 $H0:$B0/brick1; +EXPECT 'Created' volinfo_field $V0 'Status'; + +TEST $CLI volume start $V0; +EXPECT 'Started' volinfo_field $V0 'Status'; + +logdir=`gluster --print-logdir` + +TEST build_tester $(dirname $0)/glfs_h_creat_open.c -lgfapi + +TEST ./$(dirname $0)/glfs_h_creat_open $H0 $V0 $logdir/glfs.log + +cleanup_tester $(dirname $0)/glfs_h_creat_open + +TEST $CLI volume stop $V0 +TEST $CLI volume delete $V0 + +cleanup; diff --git a/tests/basic/gfapi/glfs_sysrq.c b/tests/basic/gfapi/glfs_sysrq.c new file mode 100644 index 00000000000..13e06be6df2 --- /dev/null +++ b/tests/basic/gfapi/glfs_sysrq.c @@ -0,0 +1,60 @@ +/** glfs_sysrq.c + * + * Simple test application to run all glfs_syqrq() debugging calls. + * + * Usage: ./glfs_sysrq <host> <volume> <logfile> + */ +#include <errno.h> +#include <stdio.h> + +#include <glusterfs/api/glfs.h> + +int +main(int argc, char *argv[]) +{ + /* cmdline arguments */ + char *host = NULL; + char *volume = NULL; + char *logfile = NULL; + + /* other variables */ + glfs_t *fs = NULL; + int ret = 0; + + if (argc != 4) { + fprintf(stderr, "Usage: %s <host> <volume> <logfile>\n", argv[0]); + return -1; + } + + host = argv[1]; + volume = argv[2]; + logfile = argv[3]; + + fs = glfs_new(volume); + if (!fs) { + return -1; + } + + ret = glfs_set_logging(fs, logfile, 7); + if (ret < 0) { + return -1; + } + + ret = glfs_set_volfile_server(fs, "tcp", host, 24007); + if (ret < 0) { + return -1; + } + + ret = glfs_init(fs); + if (ret < 0) { + return -1; + } + + /* checking of the results is easier in the script running this test */ + glfs_sysrq(fs, GLFS_SYSRQ_HELP); + glfs_sysrq(fs, GLFS_SYSRQ_STATEDUMP); + + glfs_fini(fs); + + return 0; +} diff --git a/tests/basic/gfapi/glfs_sysrq.t b/tests/basic/gfapi/glfs_sysrq.t new file mode 100755 index 00000000000..d1a0e9bc248 --- /dev/null +++ b/tests/basic/gfapi/glfs_sysrq.t @@ -0,0 +1,39 @@ +#!/bin/bash +# +# Run glfs_sysrq, a gfapi applications calling all glfs_sysrq() commands. +# Each command generates a specific log message, or something else that can be +# tested for existance. +# + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +cleanup + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 $H0:$B0/brick1 +EXPECT 'Created' volinfo_field $V0 'Status' + +TEST $CLI volume start $V0; +EXPECT 'Started' volinfo_field $V0 'Status' + +logdir=$(gluster --print-logdir) + +# clear all statedumps +cleanup_statedump +TEST ! test -e $statedumpdir/*.dump.* +# vim friendly command */ + +build_tester $(dirname $0)/glfs_sysrq.c -lgfapi +TEST $(dirname $0)/glfs_sysrq $H0 $V0 $logdir/glfs_sysrq.log + +# check for the help message in the log +TEST grep -q '"(H)elp"' $logdir/glfs_sysrq.log + +# see if there is a statedump +TEST test -e $statedumpdir/*.dump.* +# vim friendly command */ + +cleanup_tester $(dirname $0)/glfs_sysrq +cleanup diff --git a/tests/basic/gfapi/glfs_xreaddirplus_r.c b/tests/basic/gfapi/glfs_xreaddirplus_r.c new file mode 100644 index 00000000000..0c4c79123eb --- /dev/null +++ b/tests/basic/gfapi/glfs_xreaddirplus_r.c @@ -0,0 +1,242 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <glusterfs/api/glfs.h> +#include <glusterfs/api/glfs-handles.h> +#include <time.h> + +#define VALIDATE_AND_GOTO_LABEL_ON_ERROR(func, ret, label) \ + do { \ + if (ret < 0) { \ + fprintf(stderr, "%s : returned error %d (%s)\n", func, ret, \ + strerror(errno)); \ + goto label; \ + } \ + } while (0) + +#define VALIDATE_BOOL_AND_GOTO_LABEL_ON_ERROR(func, bool_var, ret, label) \ + do { \ + if (!bool_var) { \ + fprintf(stderr, "%s : returned error (%s)\n", func, \ + strerror(errno)); \ + ret = -1; \ + goto label; \ + } \ + } while (0) + +#define MAX_FILES_CREATE 10 +#define MAXPATHNAME 512 + +void +assimilatetime(struct timespec *ts, struct timespec ts_st, + struct timespec ts_ed) +{ + if ((ts_ed.tv_nsec - ts_st.tv_nsec) < 0) { + ts->tv_sec += ts_ed.tv_sec - ts_st.tv_sec - 1; + ts->tv_nsec += 1000000000 + ts_ed.tv_nsec - ts_st.tv_nsec; + } else { + ts->tv_sec += ts_ed.tv_sec - ts_st.tv_sec; + ts->tv_nsec += ts_ed.tv_nsec - ts_st.tv_nsec; + } + + if (ts->tv_nsec > 1000000000) { + ts->tv_nsec = ts->tv_nsec - 1000000000; + ts->tv_sec += 1; + } + + return; +} + +/* + * Returns '%' difference between ts1 & ts2 + */ +int +comparetime(struct timespec ts1, struct timespec ts2) +{ + uint64_t ts1_n, ts2_n; + int pct = 0; + + ts1_n = (ts1.tv_sec * 1000000000) + ts1.tv_nsec; + ts2_n = (ts2.tv_sec * 1000000000) + ts2.tv_nsec; + + pct = ((ts1_n - ts2_n) * 100) / ts1_n; + + return pct; +} + +int +old_readdir(glfs_t *fs) +{ + struct glfs_object *root = NULL; + struct glfs_fd *fd = NULL; + struct stat *sb = NULL; + char buf[512]; + struct dirent *entry = NULL; + int ret = -1; + struct glfs_object *glhandle = NULL; + + if (!fs) + return -1; + + root = glfs_h_lookupat(fs, NULL, "/", sb, 0); + VALIDATE_BOOL_AND_GOTO_LABEL_ON_ERROR("glfs_h_lookupat", !!root, ret, out); + + fd = glfs_opendir(fs, "/"); + VALIDATE_BOOL_AND_GOTO_LABEL_ON_ERROR("glfs_opendir", !!fd, ret, out); + + while (glfs_readdir_r(fd, (struct dirent *)buf, &entry), entry) { + if (strcmp(entry->d_name, ".") && strcmp(entry->d_name, "..")) { + glhandle = glfs_h_lookupat(fs, root, "/", sb, 0); + VALIDATE_BOOL_AND_GOTO_LABEL_ON_ERROR("glfs_h_lookupat", !!glhandle, + ret, out); + } + } + + glfs_closedir(fd); + + ret = 0; +out: + return ret; +} + +int +new_xreaddirplus(glfs_t *fs) +{ + struct glfs_fd *fd = NULL; + struct stat *sb = NULL; + int ret = -1; + uint32_t rflags = (GFAPI_XREADDIRP_STAT | GFAPI_XREADDIRP_HANDLE); + struct glfs_xreaddirp_stat *xstat = NULL; + struct dirent de; + struct dirent *pde = NULL; + struct glfs_object *glhandle = NULL; + + if (!fs) + return -1; + + fd = glfs_opendir(fs, "/"); + VALIDATE_BOOL_AND_GOTO_LABEL_ON_ERROR("glfs_opendir", !!fd, ret, out); + + ret = glfs_xreaddirplus_r(fd, rflags, &xstat, &de, &pde); + while (ret > 0 && pde != NULL) { + if (xstat) { + sb = glfs_xreaddirplus_get_stat(xstat); + VALIDATE_BOOL_AND_GOTO_LABEL_ON_ERROR("glfs_xreaddirplus_get_stat", + !!sb, ret, out); + + if (strcmp(de.d_name, ".") && strcmp(de.d_name, "..")) { + glhandle = glfs_xreaddirplus_get_object(xstat); + VALIDATE_BOOL_AND_GOTO_LABEL_ON_ERROR( + "glfs_xreaddirplus_get_object", !!glhandle, ret, out); + } + } + + if (xstat) { + glfs_free(xstat); + xstat = NULL; + } + + ret = glfs_xreaddirplus_r(fd, rflags, &xstat, &de, &pde); + + VALIDATE_AND_GOTO_LABEL_ON_ERROR("glfs_xreaddirp_r", ret, out); + } + + if (xstat) + glfs_free(xstat); + + ret = 0; +out: + return ret; +} + +int +main(int argc, char *argv[]) +{ + int ret = -1; + glfs_t *fs = NULL; + char *volname = NULL; + char *logfile = NULL; + char *hostname = NULL; + char *my_file = "file_"; + char my_file_name[MAXPATHNAME]; + uint32_t flags = O_RDWR | O_SYNC; + struct glfs_fd *fd = NULL; + int i = 0; + int pct = 0; + struct timespec timestamp = {0, 0}, st_timestamp, ed_timestamp; + struct timespec otimestamp = {0, 0}, ost_timestamp, oed_timestamp; + + if (argc != 4) { + fprintf(stderr, "Invalid argument\n"); + return 1; + } + + hostname = argv[1]; + volname = argv[2]; + logfile = argv[3]; + + fs = glfs_new(volname); + VALIDATE_BOOL_AND_GOTO_LABEL_ON_ERROR("glfs_new", !!fs, ret, out); + + ret = glfs_set_volfile_server(fs, "tcp", hostname, 24007); + VALIDATE_AND_GOTO_LABEL_ON_ERROR("glfs_set_volfile_server", ret, out); + + ret = glfs_set_logging(fs, logfile, 7); + VALIDATE_AND_GOTO_LABEL_ON_ERROR("glfs_set_logging", ret, out); + + ret = glfs_init(fs); + VALIDATE_AND_GOTO_LABEL_ON_ERROR("glfs_init", ret, out); + + for (i = 0; i < MAX_FILES_CREATE; i++) { + sprintf(my_file_name, "%s%d", my_file, i); + + fd = glfs_creat(fs, my_file_name, flags, 0644); + VALIDATE_BOOL_AND_GOTO_LABEL_ON_ERROR("glfs_creat", !!fd, ret, out); + + glfs_close(fd); + } + + /* measure performance using old readdir call and new xreaddirplus call and + * compare */ + ret = clock_gettime(CLOCK_REALTIME, &ost_timestamp); + VALIDATE_AND_GOTO_LABEL_ON_ERROR("clock_gettime", ret, out); + + ret = old_readdir(fs); + VALIDATE_AND_GOTO_LABEL_ON_ERROR("old_readdir", ret, out); + + ret = clock_gettime(CLOCK_REALTIME, &oed_timestamp); + VALIDATE_AND_GOTO_LABEL_ON_ERROR("clock_gettime", ret, out); + + assimilatetime(&otimestamp, ost_timestamp, oed_timestamp); + + printf("\tOverall time using readdir:\n\t\tSecs:%ld\n\t\tnSecs:%ld\n", + otimestamp.tv_sec, otimestamp.tv_nsec); + + ret = clock_gettime(CLOCK_REALTIME, &st_timestamp); + VALIDATE_AND_GOTO_LABEL_ON_ERROR("clock_gettime", ret, out); + + ret = new_xreaddirplus(fs); + VALIDATE_AND_GOTO_LABEL_ON_ERROR("new_xreaddirplus", ret, out); + + ret = clock_gettime(CLOCK_REALTIME, &ed_timestamp); + VALIDATE_AND_GOTO_LABEL_ON_ERROR("clock_gettime", ret, out); + + assimilatetime(×tamp, st_timestamp, ed_timestamp); + + printf("\tOverall time using xreaddirplus:\n\t\tSecs:%ld\n\t\tnSecs:%ld\n", + timestamp.tv_sec, timestamp.tv_nsec); + + pct = comparetime(otimestamp, timestamp); + printf("There is improvement by %d%%\n", pct); + + ret = 0; +out: + if (fs) { + ret = glfs_fini(fs); + if (ret) + fprintf(stderr, "glfs_fini(fs) returned %d\n", ret); + } + + return ret; +} diff --git a/tests/basic/gfapi/glfs_xreaddirplus_r.t b/tests/basic/gfapi/glfs_xreaddirplus_r.t new file mode 100755 index 00000000000..d21a00c66f2 --- /dev/null +++ b/tests/basic/gfapi/glfs_xreaddirplus_r.t @@ -0,0 +1,28 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +cleanup; + +TEST glusterd + +TEST $CLI volume create $V0 $H0:$B0/brick1; +EXPECT 'Created' volinfo_field $V0 'Status'; + +TEST $CLI volume start $V0; +EXPECT 'Started' volinfo_field $V0 'Status'; + +logdir=`gluster --print-logdir` + +TEST build_tester $(dirname $0)/glfs_xreaddirplus_r.c -lgfapi + +TEST $(dirname $0)/glfs_xreaddirplus_r $H0 $V0 $logdir/glfs_xreaddirplus_r.log + +cleanup_tester $(dirname $0)/glfs_xreaddirplus_r + +TEST $CLI volume stop $V0 +TEST $CLI volume delete $V0 + +cleanup; +#G_TESTDEF_TEST_STATUS_NETBSD7=BAD_TEST,BUG=000000 diff --git a/tests/basic/gfapi/glfsxmp-coverage.c b/tests/basic/gfapi/glfsxmp-coverage.c new file mode 100644 index 00000000000..51650023efd --- /dev/null +++ b/tests/basic/gfapi/glfsxmp-coverage.c @@ -0,0 +1,1900 @@ +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <glusterfs/api/glfs.h> +#include <glusterfs/api/glfs-handles.h> +#include <string.h> +#include <time.h> + +#define TEST_STR_LEN 2048 + +int +test_dirops(glfs_t *fs) +{ + glfs_fd_t *fd = NULL; + char buf[2048]; + struct dirent *entry = NULL; + + fd = glfs_opendir(fs, "/"); + if (!fd) { + fprintf(stderr, "/: %s\n", strerror(errno)); + return -1; + } + + fprintf(stderr, "Entries:\n"); + while (glfs_readdir_r(fd, (struct dirent *)buf, &entry), entry) { + fprintf(stderr, "%s: %lu\n", entry->d_name, glfs_telldir(fd)); + } + + /* Should internally call fsyncdir(), hopefully */ + glfs_fsync(fd, NULL, NULL); + + glfs_closedir(fd); + return 0; +} + +int +test_xattr(glfs_t *fs) +{ + char *filename = "/filename2"; + char *linkfile = "/linkfile"; + glfs_fd_t *fd = NULL; + char buf[512]; + char *ptr; + int ret; + + ret = glfs_setxattr(fs, filename, "user.testkey", "testval", 8, 0); + fprintf(stderr, "setxattr(%s): %d (%s)\n", filename, ret, strerror(errno)); + + ret = glfs_setxattr(fs, filename, "user.testkey2", "testval", 8, 0); + fprintf(stderr, "setxattr(%s): %d (%s)\n", filename, ret, strerror(errno)); + + ret = glfs_getxattr(fs, filename, "user.testkey", buf, 512); + fprintf(stderr, "getxattr(%s): %d (%s)\n", filename, ret, strerror(errno)); + if (ret < 0) + return -1; + + ret = glfs_listxattr(fs, filename, buf, 512); + fprintf(stderr, "listxattr(%s): %d (%s)\n", filename, ret, strerror(errno)); + if (ret < 0) + return -1; + + ret = glfs_symlink(fs, "filename", linkfile); + fprintf(stderr, "symlink(%s %s): %s\n", filename, linkfile, + strerror(errno)); + if (ret < 0) + return -1; + + ret = glfs_readlink(fs, linkfile, buf, 512); + fprintf(stderr, "readlink(%s) : %d (%s)\n", filename, ret, strerror(errno)); + if (ret < 0) + return -1; + + ret = glfs_lsetxattr(fs, filename, "user.testkey3", "testval", 8, 0); + fprintf(stderr, "lsetxattr(%s) : %d (%s)\n", linkfile, ret, + strerror(errno)); + if (ret < 0) + return -1; + + ret = glfs_llistxattr(fs, linkfile, buf, 512); + fprintf(stderr, "llistxattr(%s): %d (%s)\n", filename, ret, + strerror(errno)); + if (ret < 0) + return -1; + + ret = glfs_lgetxattr(fs, filename, "user.testkey3", buf, 512); + fprintf(stderr, "lgetxattr(%s): %d (%s)\n", linkfile, ret, strerror(errno)); + if (ret < 0) + return -1; + + for (ptr = buf; ptr < buf + ret; ptr++) { + printf("key=%s\n", ptr); + ptr += strlen(ptr); + } + + ret = glfs_removexattr(fs, filename, "user.testkey2"); + fprintf(stderr, "removexattr(%s): %d (%s)\n", filename, ret, + strerror(errno)); + + fd = glfs_open(fs, filename, O_RDWR); + fprintf(stderr, "open(%s): (%p) %s\n", filename, fd, strerror(errno)); + + ret = glfs_fsetxattr(fd, "user.testkey2", "testval", 8, 0); + fprintf(stderr, "fsetxattr(%s): %d (%s)\n", filename, ret, strerror(errno)); + + ret = glfs_fgetxattr(fd, "user.testkey2", buf, 512); + fprintf(stderr, "fgetxattr(%s): %d (%s)\n", filename, ret, strerror(errno)); + + ret = glfs_flistxattr(fd, buf, 512); + fprintf(stderr, "flistxattr(%s): %d (%s)\n", filename, ret, + strerror(errno)); + if (ret < 0) + return -1; + + for (ptr = buf; ptr < buf + ret; ptr++) { + printf("key=%s\n", ptr); + ptr += strlen(ptr); + } + + ret = glfs_fremovexattr(fd, "user.testkey2"); + fprintf(stderr, "fremovexattr(%s): %d (%s)\n", filename, ret, + strerror(errno)); + + glfs_close(fd); + + return 0; +} + +int +test_chdir(glfs_t *fs) +{ + int ret = -1; + char *dir = "/dir"; + char *topdir = "/topdir"; + char *linkdir = "/linkdir"; + char *linkdir2 = "/linkdir2"; + char *subdir = "./subdir"; + char *respath = NULL; + char pathbuf[4096]; + + ret = glfs_mkdir(fs, topdir, 0755); + fprintf(stderr, "mkdir(%s): %s\n", topdir, strerror(errno)); + if (ret) + return -1; + + ret = glfs_mkdir(fs, dir, 0755); + fprintf(stderr, "mkdir(%s): %s\n", dir, strerror(errno)); + if (ret) + return -1; + + respath = glfs_getcwd(fs, pathbuf, 4096); + fprintf(stdout, "getcwd() = %s\n", respath); + + ret = glfs_symlink(fs, "topdir", linkdir); + if (ret) { + fprintf(stderr, "symlink(%s, %s): %s\n", topdir, linkdir, + strerror(errno)); + return -1; + } + + ret = glfs_chdir(fs, linkdir); + if (ret) { + fprintf(stderr, "chdir(%s): %s\n", linkdir, strerror(errno)); + return -1; + } + + respath = glfs_getcwd(fs, pathbuf, 4096); + fprintf(stdout, "getcwd() = %s\n", respath); + + respath = glfs_realpath(fs, subdir, pathbuf); + if (respath) { + fprintf(stderr, "realpath(%s) worked unexpectedly: %s\n", subdir, + respath); + return -1; + } + + ret = glfs_mkdir(fs, subdir, 0755); + if (ret) { + fprintf(stderr, "mkdir(%s): %s\n", subdir, strerror(errno)); + return -1; + } + + respath = glfs_realpath(fs, subdir, pathbuf); + if (!respath) { + fprintf(stderr, "realpath(%s): %s\n", subdir, strerror(errno)); + } else { + fprintf(stdout, "realpath(%s) = %s\n", subdir, respath); + } + + ret = glfs_chdir(fs, subdir); + if (ret) { + fprintf(stderr, "chdir(%s): %s\n", subdir, strerror(errno)); + return -1; + } + + respath = glfs_getcwd(fs, pathbuf, 4096); + fprintf(stdout, "getcwd() = %s\n", respath); + + respath = glfs_realpath(fs, "/linkdir/subdir", pathbuf); + if (!respath) { + fprintf(stderr, "realpath(/linkdir/subdir): %s\n", strerror(errno)); + } else { + fprintf(stdout, "realpath(/linkdir/subdir) = %s\n", respath); + } + + return 0; +} + +#ifdef DEBUG +static void +peek_stat(struct stat *sb) +{ + printf("Dumping stat information:\n"); + printf("File type: "); + + switch (sb->st_mode & S_IFMT) { + case S_IFBLK: + printf("block device\n"); + break; + case S_IFCHR: + printf("character device\n"); + break; + case S_IFDIR: + printf("directory\n"); + break; + case S_IFIFO: + printf("FIFO/pipe\n"); + break; + case S_IFLNK: + printf("symlink\n"); + break; + case S_IFREG: + printf("regular file\n"); + break; + case S_IFSOCK: + printf("socket\n"); + break; + default: + printf("unknown?\n"); + break; + } + + printf("I-node number: %ld\n", (long)sb->st_ino); + + printf("Mode: %lo (octal)\n", + (unsigned long)sb->st_mode); + + printf("Link count: %ld\n", (long)sb->st_nlink); + printf("Ownership: UID=%ld GID=%ld\n", (long)sb->st_uid, + (long)sb->st_gid); + + printf("Preferred I/O block size: %ld bytes\n", (long)sb->st_blksize); + printf("File size: %lld bytes\n", (long long)sb->st_size); + printf("Blocks allocated: %lld\n", (long long)sb->st_blocks); + + printf("Last status change: %s", ctime(&sb->st_ctime)); + printf("Last file access: %s", ctime(&sb->st_atime)); + printf("Last file modification: %s", ctime(&sb->st_mtime)); + + return; +} + +static void +peek_handle(unsigned char *glid) +{ + int i; + + for (i = 0; i < GFAPI_HANDLE_LENGTH; i++) { + printf(":%02x:", glid[i]); + } + printf("\n"); +} +#else /* DEBUG */ +static void +peek_stat(struct stat *sb) +{ + return; +} + +static void +peek_handle(unsigned char *id) +{ + return; +} +#endif /* DEBUG */ + +glfs_t *fs = NULL; +char *full_parent_name = "/testdir", *parent_name = "testdir"; + +void +test_h_unlink(void) +{ + char *my_dir = "unlinkdir"; + char *my_file = "file.txt"; + char *my_subdir = "dir1"; + struct glfs_object *parent = NULL, *leaf = NULL, *dir = NULL, + *subdir = NULL, *subleaf = NULL; + struct stat sb; + int ret; + + printf("glfs_h_unlink tests: In Progress\n"); + + /* Prepare tests */ + parent = glfs_h_lookupat(fs, NULL, full_parent_name, &sb, 0); + if (parent == NULL) { + fprintf(stderr, + "glfs_h_lookupat: error on lookup of %s: from (%p),%s\n", + full_parent_name, NULL, strerror(errno)); + printf("glfs_h_lookupat tests: FAILED\n"); + goto out; + } + peek_stat(&sb); + + dir = glfs_h_mkdir(fs, parent, my_dir, 0755, &sb); + if (dir == NULL) { + fprintf(stderr, "glfs_h_mkdir: error creating %s: from (%p),%s\n", + my_dir, parent, strerror(errno)); + printf("glfs_h_unlink tests: FAILED\n"); + goto out; + } + + leaf = glfs_h_creat(fs, dir, my_file, O_CREAT, 0644, &sb); + if (leaf == NULL) { + fprintf(stderr, "glfs_h_creat: error creating %s: from (%p),%s\n", + my_file, dir, strerror(errno)); + printf("glfs_h_unlink tests: FAILED\n"); + goto out; + } + + subdir = glfs_h_mkdir(fs, dir, my_subdir, 0755, &sb); + if (subdir == NULL) { + fprintf(stderr, "glfs_h_mkdir: error creating %s: from (%p),%s\n", + my_subdir, dir, strerror(errno)); + printf("glfs_h_unlink tests: FAILED\n"); + goto out; + } + + subleaf = glfs_h_creat(fs, subdir, my_file, O_CREAT, 0644, &sb); + if (subleaf == NULL) { + fprintf(stderr, "glfs_h_creat: error creating %s: from (%p),%s\n", + my_file, subdir, strerror(errno)); + printf("glfs_h_unlink tests: FAILED\n"); + goto out; + } + + /* unlink non empty directory */ + ret = glfs_h_unlink(fs, dir, my_subdir); + if ((ret && errno != ENOTEMPTY) || (ret == 0)) { + fprintf(stderr, + "glfs_h_unlink: error unlinking %s: it is non empty: %s\n", + my_subdir, strerror(errno)); + printf("glfs_h_unlink tests: FAILED\n"); + goto out; + } + + /* unlink regular file */ + ret = glfs_h_unlink(fs, subdir, my_file); + if (ret) { + fprintf(stderr, "glfs_h_unlink: error unlinking %s: from (%p),%s\n", + my_file, subdir, strerror(errno)); + printf("glfs_h_unlink tests: FAILED\n"); + goto out; + } + + /* unlink directory */ + ret = glfs_h_unlink(fs, dir, my_subdir); + if (ret) { + fprintf(stderr, "glfs_h_unlink: error unlinking %s: from (%p),%s\n", + my_subdir, dir, strerror(errno)); + printf("glfs_h_unlink tests: FAILED\n"); + goto out; + } + + /* unlink regular file */ + ret = glfs_h_unlink(fs, dir, my_file); + if (ret) { + fprintf(stderr, "glfs_h_unlink: error unlinking %s: from (%p),%s\n", + my_file, dir, strerror(errno)); + printf("glfs_h_unlink tests: FAILED\n"); + goto out; + } + + /* unlink non-existent regular file */ + ret = glfs_h_unlink(fs, dir, my_file); + if ((ret && errno != ENOENT) || (ret == 0)) { + fprintf(stderr, + "glfs_h_unlink: error unlinking non-existent %s: invalid errno " + ",%d, %s\n", + my_file, ret, strerror(errno)); + printf("glfs_h_unlink tests: FAILED\n"); + goto out; + } + + /* unlink non-existent directory */ + ret = glfs_h_unlink(fs, dir, my_subdir); + if ((ret && errno != ENOENT) || (ret == 0)) { + fprintf(stderr, + "glfs_h_unlink: error unlinking non-existent %s: invalid " + "errno ,%d, %s\n", + my_subdir, ret, strerror(errno)); + printf("glfs_h_unlink tests: FAILED\n"); + goto out; + } + + /* unlink directory */ + ret = glfs_h_unlink(fs, parent, my_dir); + if (ret) { + fprintf(stderr, "glfs_h_unlink: error unlinking %s: from (%p),%s\n", + my_dir, dir, strerror(errno)); + printf("glfs_h_unlink tests: FAILED\n"); + goto out; + } + + printf("glfs_h_unlink tests: PASSED\n"); + +out: + if (dir) + glfs_h_close(dir); + if (leaf) + glfs_h_close(leaf); + if (subdir) + glfs_h_close(subdir); + if (subleaf) + glfs_h_close(subleaf); + if (parent) + glfs_h_close(parent); + + return; +} + +void +test_h_getsetattrs(void) +{ + char *my_dir = "attrdir"; + char *my_file = "attrfile.txt"; + struct glfs_object *parent = NULL, *leaf = NULL, *dir = NULL; + struct stat sb, retsb; + int ret, valid; + struct timespec timestamp; + + printf("glfs_h_getattrs and setattrs tests: In Progress\n"); + + /* Prepare tests */ + parent = glfs_h_lookupat(fs, NULL, full_parent_name, &sb, 0); + if (parent == NULL) { + fprintf(stderr, + "glfs_h_lookupat: error on lookup of %s: from (%p),%s\n", + full_parent_name, NULL, strerror(errno)); + printf("glfs_h_lookupat tests: FAILED\n"); + goto out; + } + peek_stat(&sb); + + dir = glfs_h_mkdir(fs, parent, my_dir, 0755, &sb); + if (dir == NULL) { + fprintf(stderr, "glfs_h_mkdir: error creating %s: from (%p),%s\n", + my_dir, parent, strerror(errno)); + printf("glfs_h_unlink tests: FAILED\n"); + goto out; + } + peek_stat(&sb); + + leaf = glfs_h_creat(fs, dir, my_file, O_CREAT, 0644, &sb); + if (leaf == NULL) { + fprintf(stderr, "glfs_h_creat: error creating %s: from (%p),%s\n", + my_file, dir, strerror(errno)); + printf("glfs_h_unlink tests: FAILED\n"); + goto out; + } + peek_stat(&sb); + + ret = glfs_h_getattrs(fs, dir, &retsb); + if (ret != 0) { + fprintf(stderr, "glfs_h_getattrs: error %s: from (%p),%s\n", my_dir, + dir, strerror(errno)); + printf("glfs_h_getattrs and setattrs tests: FAILED\n"); + goto out; + } + peek_stat(&retsb); + /* TODO: Compare stat information */ + + retsb.st_mode = 00666; + retsb.st_uid = 1000; + retsb.st_gid = 1001; + ret = clock_gettime(CLOCK_REALTIME, ×tamp); + if (ret != 0) { + fprintf(stderr, "clock_gettime: error %s\n", strerror(errno)); + printf("glfs_h_getattrs and setattrs tests: FAILED\n"); + goto out; + } + retsb.st_atim = timestamp; + retsb.st_mtim = timestamp; + valid = GFAPI_SET_ATTR_MODE | GFAPI_SET_ATTR_UID | GFAPI_SET_ATTR_GID | + GFAPI_SET_ATTR_ATIME | GFAPI_SET_ATTR_MTIME; + peek_stat(&retsb); + + ret = glfs_h_setattrs(fs, dir, &retsb, valid); + if (ret != 0) { + fprintf(stderr, "glfs_h_setattrs: error %s: from (%p),%s\n", my_dir, + dir, strerror(errno)); + printf("glfs_h_getattrs and setattrs tests: FAILED\n"); + goto out; + } + + memset(&retsb, 0, sizeof(struct stat)); + ret = glfs_h_stat(fs, dir, &retsb); + if (ret != 0) { + fprintf(stderr, "glfs_h_stat: error %s: from (%p),%s\n", my_dir, dir, + strerror(errno)); + printf("glfs_h_getattrs and setattrs tests: FAILED\n"); + goto out; + } + peek_stat(&retsb); + + printf("glfs_h_getattrs and setattrs tests: PASSED\n"); +out: + if (parent) + glfs_h_close(parent); + if (leaf) + glfs_h_close(leaf); + if (dir) + glfs_h_close(dir); + + return; +} + +void +test_h_truncate(void) +{ + char *my_dir = "truncatedir"; + char *my_file = "file.txt"; + struct glfs_object *root = NULL, *parent = NULL, *leaf = NULL; + struct stat sb; + glfs_fd_t *fd = NULL; + char buf[32]; + off_t offset = 0; + int ret = 0; + + printf("glfs_h_truncate tests: In Progress\n"); + + /* Prepare tests */ + root = glfs_h_lookupat(fs, NULL, full_parent_name, &sb, 0); + if (root == NULL) { + fprintf(stderr, + "glfs_h_lookupat: error on lookup of %s: from (%p),%s\n", + full_parent_name, NULL, strerror(errno)); + printf("glfs_h_truncate tests: FAILED\n"); + goto out; + } + peek_stat(&sb); + + parent = glfs_h_mkdir(fs, root, my_dir, 0755, &sb); + if (parent == NULL) { + fprintf(stderr, "glfs_h_mkdir: error creating %s: from (%p),%s\n", + my_dir, root, strerror(errno)); + printf("glfs_h_truncate tests: FAILED\n"); + goto out; + } + peek_stat(&sb); + + leaf = glfs_h_creat(fs, parent, my_file, O_CREAT, 0644, &sb); + if (leaf == NULL) { + fprintf(stderr, "glfs_h_creat: error creating %s: from (%p),%s\n", + my_file, parent, strerror(errno)); + printf("glfs_h_truncate tests: FAILED\n"); + goto out; + } + peek_stat(&sb); + + fd = glfs_h_open(fs, leaf, O_RDWR); + if (fd == NULL) { + fprintf(stderr, "glfs_h_open: error on open of %s: %s\n", my_file, + strerror(errno)); + printf("glfs_h_truncate tests: FAILED\n"); + goto out; + } + + memcpy(buf, "abcdefghijklmnopqrstuvwxyz012345", 32); + ret = glfs_write(fd, buf, 32, 0); + + /* run tests */ + /* truncate lower */ + offset = 30; + ret = glfs_h_truncate(fs, leaf, offset); + if (ret != 0) { + fprintf(stderr, "glfs_h_truncate: error creating %s: from (%p),%s\n", + my_file, parent, strerror(errno)); + printf("glfs_h_truncate tests: FAILED\n"); + goto out; + } + ret = glfs_h_getattrs(fs, leaf, &sb); + if (ret != 0) { + fprintf(stderr, "glfs_h_getattrs: error for %s (%p),%s\n", my_file, + leaf, strerror(errno)); + printf("glfs_h_truncate tests: FAILED\n"); + goto out; + } + if (sb.st_size != offset) { + fprintf(stderr, "glfs_h_truncate: post size mismatch\n"); + printf("glfs_h_truncate tests: FAILED\n"); + goto out; + } + + /* truncate higher */ + offset = 32; + ret = glfs_h_truncate(fs, leaf, offset); + if (ret != 0) { + fprintf(stderr, "glfs_h_truncate: error creating %s: from (%p),%s\n", + my_file, parent, strerror(errno)); + printf("glfs_h_truncate tests: FAILED\n"); + goto out; + } + ret = glfs_h_getattrs(fs, leaf, &sb); + if (ret != 0) { + fprintf(stderr, "glfs_h_getattrs: error for %s (%p),%s\n", my_file, + leaf, strerror(errno)); + printf("glfs_h_truncate tests: FAILED\n"); + goto out; + } + if (sb.st_size != offset) { + fprintf(stderr, "glfs_h_truncate: post size mismatch\n"); + printf("glfs_h_truncate tests: FAILED\n"); + goto out; + } + + /* truncate equal */ + offset = 30; + ret = glfs_h_truncate(fs, leaf, offset); + if (ret != 0) { + fprintf(stderr, "glfs_h_truncate: error creating %s: from (%p),%s\n", + my_file, parent, strerror(errno)); + printf("glfs_h_truncate tests: FAILED\n"); + goto out; + } + ret = glfs_h_getattrs(fs, leaf, &sb); + if (ret != 0) { + fprintf(stderr, "glfs_h_getattrs: error for %s (%p),%s\n", my_file, + leaf, strerror(errno)); + printf("glfs_h_truncate tests: FAILED\n"); + goto out; + } + if (sb.st_size != offset) { + fprintf(stderr, "glfs_h_truncate: post size mismatch\n"); + printf("glfs_h_truncate tests: FAILED\n"); + goto out; + } + + printf("glfs_h_truncate tests: PASSED\n"); +out: + if (fd) + glfs_close(fd); + if (root) + glfs_h_close(root); + if (parent) + glfs_h_close(parent); + if (leaf) + glfs_h_close(leaf); + + return; +} + +void +test_h_links(void) +{ + char *my_dir = "linkdir"; + char *my_file = "file.txt"; + char *my_symlnk = "slnk.txt"; + char *my_lnk = "lnk.txt"; + char *linksrc_dir = "dir1"; + char *linktgt_dir = "dir2"; + struct glfs_object *root = NULL, *parent = NULL, *leaf = NULL, + *dirsrc = NULL, *dirtgt = NULL, *dleaf = NULL; + struct glfs_object *ln1 = NULL; + struct stat sb; + int ret; + char *buf = NULL; + + printf("glfs_h_link(s) tests: In Progress\n"); + + /* Prepare tests */ + root = glfs_h_lookupat(fs, NULL, full_parent_name, &sb, 0); + if (root == NULL) { + fprintf(stderr, + "glfs_h_lookupat: error on lookup of %s: from (%p),%s\n", + full_parent_name, NULL, strerror(errno)); + printf("glfs_h_link(s) tests: FAILED\n"); + goto out; + } + peek_stat(&sb); + + parent = glfs_h_mkdir(fs, root, my_dir, 0755, &sb); + if (parent == NULL) { + fprintf(stderr, "glfs_h_mkdir: error creating %s: from (%p),%s\n", + my_dir, root, strerror(errno)); + printf("glfs_h_link(s) tests: FAILED\n"); + goto out; + } + peek_stat(&sb); + + leaf = glfs_h_creat(fs, parent, my_file, O_CREAT, 0644, &sb); + if (leaf == NULL) { + fprintf(stderr, "glfs_h_creat: error creating %s: from (%p),%s\n", + my_file, parent, strerror(errno)); + printf("glfs_h_link(s) tests: FAILED\n"); + goto out; + } + peek_stat(&sb); + + dirsrc = glfs_h_mkdir(fs, parent, linksrc_dir, 0755, &sb); + if (dirsrc == NULL) { + fprintf(stderr, "glfs_h_mkdir: error creating %s: from (%p),%s\n", + linksrc_dir, parent, strerror(errno)); + printf("glfs_h_link(s) tests: FAILED\n"); + goto out; + } + peek_stat(&sb); + + dirtgt = glfs_h_mkdir(fs, parent, linktgt_dir, 0755, &sb); + if (dirtgt == NULL) { + fprintf(stderr, "glfs_h_mkdir: error creating %s: from (%p),%s\n", + linktgt_dir, parent, strerror(errno)); + printf("glfs_h_link(s) tests: FAILED\n"); + goto out; + } + peek_stat(&sb); + + dleaf = glfs_h_creat(fs, dirsrc, my_file, O_CREAT, 0644, &sb); + if (dleaf == NULL) { + fprintf(stderr, "glfs_h_creat: error creating %s: from (%p),%s\n", + my_file, dirsrc, strerror(errno)); + printf("glfs_h_link(s) tests: FAILED\n"); + goto out; + } + peek_stat(&sb); + + /* run tests */ + /* sym link: /testdir/linkdir/file.txt to ./slnk.txt */ + ln1 = glfs_h_symlink(fs, parent, my_symlnk, "./file.txt", &sb); + if (ln1 == NULL) { + fprintf(stderr, "glfs_h_symlink: error creating %s: from (%p),%s\n", + my_symlnk, parent, strerror(errno)); + printf("glfs_h_link(s) tests: FAILED\n"); + goto out; + } + peek_stat(&sb); + + buf = calloc(1024, sizeof(char)); + if (buf == NULL) { + fprintf(stderr, "Error allocating memory\n"); + printf("glfs_h_link(s) tests: FAILED\n"); + goto out; + } + + ret = glfs_h_readlink(fs, ln1, buf, 1024); + if (ret <= 0) { + fprintf(stderr, "glfs_h_readlink: error reading %s: from (%p),%s\n", + my_symlnk, ln1, strerror(errno)); + printf("glfs_h_link(s) tests: FAILED\n"); + goto out; + } + if (!(strncmp(buf, my_symlnk, strlen(my_symlnk)))) { + fprintf(stderr, + "glfs_h_readlink: error mismatch in link name: actual %s: " + "retrieved %s\n", + my_symlnk, buf); + printf("glfs_h_link(s) tests: FAILED\n"); + goto out; + } + + /* link: /testdir/linkdir/file.txt to ./lnk.txt */ + ret = glfs_h_link(fs, leaf, parent, my_lnk); + if (ret != 0) { + fprintf(stderr, "glfs_h_link: error creating %s: from (%p),%s\n", + my_lnk, parent, strerror(errno)); + printf("glfs_h_link(s) tests: FAILED\n"); + goto out; + } + /* TODO: Should write content to a file and read from the link */ + + /* link: /testdir/linkdir/dir1/file.txt to ../dir2/slnk.txt */ + ret = glfs_h_link(fs, dleaf, dirtgt, my_lnk); + if (ret != 0) { + fprintf(stderr, "glfs_h_link: error creating %s: from (%p),%s\n", + my_lnk, dirtgt, strerror(errno)); + printf("glfs_h_link(s) tests: FAILED\n"); + goto out; + } + /* TODO: Should write content to a file and read from the link */ + + printf("glfs_h_link(s) tests: PASSED\n"); + +out: + if (root) + glfs_h_close(root); + if (parent) + glfs_h_close(parent); + if (leaf) + glfs_h_close(leaf); + if (dirsrc) + glfs_h_close(dirsrc); + if (dirtgt) + glfs_h_close(dirtgt); + if (dleaf) + glfs_h_close(dleaf); + if (ln1) + glfs_h_close(ln1); + if (buf) + free(buf); + + return; +} + +void +test_h_rename(void) +{ + char *my_dir = "renamedir"; + char *my_file = "file.txt"; + char *src_dir = "dir1"; + char *tgt_dir = "dir2"; + struct glfs_object *root = NULL, *parent = NULL, *leaf = NULL, + *dirsrc = NULL, *dirtgt = NULL, *dleaf = NULL; + struct stat sb; + int ret; + + printf("glfs_h_rename tests: In Progress\n"); + + /* Prepare tests */ + root = glfs_h_lookupat(fs, NULL, full_parent_name, &sb, 0); + if (root == NULL) { + fprintf(stderr, + "glfs_h_lookupat: error on lookup of %s: from (%p),%s\n", + full_parent_name, NULL, strerror(errno)); + printf("glfs_h_rename tests: FAILED\n"); + goto out; + } + peek_stat(&sb); + + parent = glfs_h_mkdir(fs, root, my_dir, 0755, &sb); + if (parent == NULL) { + fprintf(stderr, "glfs_h_mkdir: error creating %s: from (%p),%s\n", + my_dir, root, strerror(errno)); + printf("glfs_h_rename tests: FAILED\n"); + goto out; + } + peek_stat(&sb); + + leaf = glfs_h_creat(fs, parent, my_file, O_CREAT, 0644, &sb); + if (leaf == NULL) { + fprintf(stderr, "glfs_h_creat: error creating %s: from (%p),%s\n", + my_file, parent, strerror(errno)); + printf("glfs_h_rename tests: FAILED\n"); + goto out; + } + peek_stat(&sb); + + dirsrc = glfs_h_mkdir(fs, parent, src_dir, 0755, &sb); + if (dirsrc == NULL) { + fprintf(stderr, "glfs_h_mkdir: error creating %s: from (%p),%s\n", + src_dir, parent, strerror(errno)); + printf("glfs_h_rename tests: FAILED\n"); + goto out; + } + peek_stat(&sb); + + dirtgt = glfs_h_mkdir(fs, parent, tgt_dir, 0755, &sb); + if (dirtgt == NULL) { + fprintf(stderr, "glfs_h_mkdir: error creating %s: from (%p),%s\n", + tgt_dir, parent, strerror(errno)); + printf("glfs_h_rename tests: FAILED\n"); + goto out; + } + peek_stat(&sb); + + dleaf = glfs_h_creat(fs, dirsrc, my_file, O_CREAT, 0644, &sb); + if (dleaf == NULL) { + fprintf(stderr, "glfs_h_creat: error creating %s: from (%p),%s\n", + my_file, dirsrc, strerror(errno)); + printf("glfs_h_rename tests: FAILED\n"); + goto out; + } + peek_stat(&sb); + + /* run tests */ + /* Rename file.txt -> file1.txt */ + ret = glfs_h_rename(fs, parent, "file.txt", parent, "file1.txt"); + if (ret != 0) { + fprintf(stderr, "glfs_h_rename: error renaming %s to %s (%s)\n", + "file.txt", "file1.txt", strerror(errno)); + printf("glfs_h_rename tests: FAILED\n"); + goto out; + } + + /* rename dir1/file.txt -> file.txt */ + ret = glfs_h_rename(fs, dirsrc, "file.txt", parent, "file.txt"); + if (ret != 0) { + fprintf(stderr, "glfs_h_rename: error renaming %s/%s to %s (%s)\n", + src_dir, "file.txt", "file.txt", strerror(errno)); + printf("glfs_h_rename tests: FAILED\n"); + goto out; + } + + /* rename file1.txt -> file.txt (exists) */ + ret = glfs_h_rename(fs, parent, "file1.txt", parent, "file.txt"); + if (ret != 0) { + fprintf(stderr, "glfs_h_rename: error renaming %s to %s (%s)\n", + "file.txt", "file.txt", strerror(errno)); + printf("glfs_h_rename tests: FAILED\n"); + goto out; + } + + /* rename dir1 -> dir3 */ + ret = glfs_h_rename(fs, parent, "dir1", parent, "dir3"); + if (ret != 0) { + fprintf(stderr, "glfs_h_rename: error renaming %s to %s (%s)\n", "dir1", + "dir3", strerror(errno)); + printf("glfs_h_rename tests: FAILED\n"); + goto out; + } + + /* rename dir2 ->dir3 (exists) */ + ret = glfs_h_rename(fs, parent, "dir2", parent, "dir3"); + if (ret != 0) { + fprintf(stderr, "glfs_h_rename: error renaming %s to %s (%s)\n", "dir2", + "dir3", strerror(errno)); + printf("glfs_h_rename tests: FAILED\n"); + goto out; + } + + /* rename file.txt -> dir3 (fail) */ + ret = glfs_h_rename(fs, parent, "file.txt", parent, "dir3"); + if (ret == 0) { + fprintf(stderr, "glfs_h_rename: NO error renaming %s to %s (%s)\n", + "file.txt", "dir3", strerror(errno)); + printf("glfs_h_rename tests: FAILED\n"); + goto out; + } + + /* rename dir3 -> file.txt (fail) */ + ret = glfs_h_rename(fs, parent, "dir3", parent, "file.txt"); + if (ret == 0) { + fprintf(stderr, "glfs_h_rename: NO error renaming %s to %s (%s)\n", + "dir3", "file.txt", strerror(errno)); + printf("glfs_h_rename tests: FAILED\n"); + goto out; + } + + printf("glfs_h_rename tests: PASSED\n"); + +out: + if (root) + glfs_h_close(root); + if (parent) + glfs_h_close(parent); + if (leaf) + glfs_h_close(leaf); + if (dirsrc) + glfs_h_close(dirsrc); + if (dirtgt) + glfs_h_close(dirtgt); + if (dleaf) + glfs_h_close(dleaf); + + return; +} + +void +assimilatetime(struct timespec *ts, struct timespec ts_st, + struct timespec ts_ed) +{ + if ((ts_ed.tv_nsec - ts_st.tv_nsec) < 0) { + ts->tv_sec += ts_ed.tv_sec - ts_st.tv_sec - 1; + ts->tv_nsec += 1000000000 + ts_ed.tv_nsec - ts_st.tv_nsec; + } else { + ts->tv_sec += ts_ed.tv_sec - ts_st.tv_sec; + ts->tv_nsec += ts_ed.tv_nsec - ts_st.tv_nsec; + } + + if (ts->tv_nsec > 1000000000) { + ts->tv_nsec = ts->tv_nsec - 1000000000; + ts->tv_sec += 1; + } + + return; +} + +#define MAX_FILES_CREATE 10 +#define MAXPATHNAME 512 +void +test_h_performance(void) +{ + char *my_dir = "perftest", *full_dir_path = "/testdir/perftest"; + char *my_file = "file_", my_file_name[MAXPATHNAME]; + struct glfs_object *parent = NULL, *leaf = NULL, *dir = NULL; + struct stat sb; + int ret, i; + struct glfs_fd *fd; + struct timespec c_ts = {0, 0}, c_ts_st, c_ts_ed; + struct timespec o_ts = {0, 0}, o_ts_st, o_ts_ed; + + printf("glfs_h_performance tests: In Progress\n"); + + /* Prepare tests */ + parent = glfs_h_lookupat(fs, NULL, full_parent_name, &sb, 0); + if (parent == NULL) { + fprintf(stderr, + "glfs_h_lookupat: error on lookup of %s: from (%p),%s\n", + full_parent_name, NULL, strerror(errno)); + printf("glfs_h_performance tests: FAILED\n"); + goto out; + } + + dir = glfs_h_mkdir(fs, parent, my_dir, 0755, &sb); + if (dir == NULL) { + fprintf(stderr, "glfs_h_mkdir: error creating %s: from (%p),%s\n", + my_dir, parent, strerror(errno)); + printf("glfs_h_performance tests: FAILED\n"); + goto out; + } + peek_stat(&sb); + + /* create performance */ + ret = clock_gettime(CLOCK_REALTIME, &o_ts_st); + if (ret != 0) { + fprintf(stderr, "clock_gettime: error %s\n", strerror(errno)); + printf("glfs_h_getattrs and setattrs tests: FAILED\n"); + goto out; + } + + for (i = 0; i < MAX_FILES_CREATE; i++) { + sprintf(my_file_name, "%s%d", my_file, i); + + ret = clock_gettime(CLOCK_REALTIME, &c_ts_st); + if (ret != 0) { + fprintf(stderr, "clock_gettime: error %s\n", strerror(errno)); + printf("glfs_h_getattrs and setattrs tests: FAILED\n"); + goto out; + } + + leaf = glfs_h_lookupat(fs, dir, my_file_name, &sb, 0); + if (leaf != NULL) { + fprintf(stderr, "glfs_h_lookup: exists %s\n", my_file_name); + printf("glfs_h_performance tests: FAILED\n"); + goto out; + } + + leaf = glfs_h_creat(fs, dir, my_file_name, O_CREAT, 0644, &sb); + if (leaf == NULL) { + fprintf(stderr, "glfs_h_creat: error creating %s: from (%p),%s\n", + my_file, dir, strerror(errno)); + printf("glfs_h_performance tests: FAILED\n"); + goto out; + } + + ret = clock_gettime(CLOCK_REALTIME, &c_ts_ed); + if (ret != 0) { + fprintf(stderr, "clock_gettime: error %s\n", strerror(errno)); + printf("glfs_h_getattrs and setattrs tests: FAILED\n"); + goto out; + } + + assimilatetime(&c_ts, c_ts_st, c_ts_ed); + glfs_h_close(leaf); + leaf = NULL; + } + + ret = clock_gettime(CLOCK_REALTIME, &o_ts_ed); + if (ret != 0) { + fprintf(stderr, "clock_gettime: error %s\n", strerror(errno)); + printf("glfs_h_getattrs and setattrs tests: FAILED\n"); + goto out; + } + + assimilatetime(&o_ts, o_ts_st, o_ts_ed); + + printf("Creation performance (handle based):\n\t# empty files:%d\n", + MAX_FILES_CREATE); + printf("\tOverall time:\n\t\tSecs:%ld\n\t\tnSecs:%ld\n", o_ts.tv_sec, + o_ts.tv_nsec); + printf("\tcreate call time time:\n\t\tSecs:%ld\n\t\tnSecs:%ld\n", + c_ts.tv_sec, c_ts.tv_nsec); + + /* create using path */ + c_ts.tv_sec = o_ts.tv_sec = 0; + c_ts.tv_nsec = o_ts.tv_nsec = 0; + + sprintf(my_file_name, "%s1", full_dir_path); + ret = glfs_mkdir(fs, my_file_name, 0755); + if (ret != 0) { + fprintf(stderr, "glfs_mkdir: error creating %s: from (%p),%s\n", my_dir, + parent, strerror(errno)); + printf("glfs_h_performance tests: FAILED\n"); + goto out; + } + peek_stat(&sb); + + ret = clock_gettime(CLOCK_REALTIME, &o_ts_st); + if (ret != 0) { + fprintf(stderr, "clock_gettime: error %s\n", strerror(errno)); + printf("glfs_h_getattrs and setattrs tests: FAILED\n"); + goto out; + } + + for (i = 0; i < MAX_FILES_CREATE; i++) { + sprintf(my_file_name, "%s1/%sn%d", full_dir_path, my_file, i); + + ret = clock_gettime(CLOCK_REALTIME, &c_ts_st); + if (ret != 0) { + fprintf(stderr, "clock_gettime: error %s\n", strerror(errno)); + printf("glfs_h_getattrs and setattrs tests: FAILED\n"); + goto out; + } + + ret = glfs_stat(fs, my_file_name, &sb); + if (ret == 0) { + fprintf(stderr, "glfs_stat: exists %s\n", my_file_name); + printf("glfs_h_performance tests: FAILED\n"); + goto out; + } + + fd = glfs_creat(fs, my_file_name, O_CREAT, 0644); + if (fd == NULL) { + fprintf(stderr, "glfs_creat: error creating %s: from (%p),%s\n", + my_file, dir, strerror(errno)); + printf("glfs_h_performance tests: FAILED\n"); + goto out; + } + + ret = clock_gettime(CLOCK_REALTIME, &c_ts_ed); + if (ret != 0) { + fprintf(stderr, "clock_gettime: error %s\n", strerror(errno)); + printf("glfs_h_getattrs and setattrs tests: FAILED\n"); + goto out; + } + + assimilatetime(&c_ts, c_ts_st, c_ts_ed); + glfs_close(fd); + } + + ret = clock_gettime(CLOCK_REALTIME, &o_ts_ed); + if (ret != 0) { + fprintf(stderr, "clock_gettime: error %s\n", strerror(errno)); + printf("glfs_h_getattrs and setattrs tests: FAILED\n"); + goto out; + } + + assimilatetime(&o_ts, o_ts_st, o_ts_ed); + + printf("Creation performance (path based):\n\t# empty files:%d\n", + MAX_FILES_CREATE); + printf("\tOverall time:\n\t\tSecs:%ld\n\t\tnSecs:%ld\n", o_ts.tv_sec, + o_ts.tv_nsec); + printf("\tcreate call time time:\n\t\tSecs:%ld\n\t\tnSecs:%ld\n", + c_ts.tv_sec, c_ts.tv_nsec); +out: + return; +} + +int +test_handleops(int argc, char *argv[]) +{ + int ret = 0; + glfs_fd_t *fd = NULL; + struct stat sb = { + 0, + }; + struct glfs_object *root = NULL, *parent = NULL, *leaf = NULL, *tmp = NULL; + char readbuf[32], writebuf[32]; + unsigned char leaf_handle[GFAPI_HANDLE_LENGTH]; + + char *full_leaf_name = "/testdir/testfile.txt", *leaf_name = "testfile.txt", + *relative_leaf_name = "testdir/testfile.txt"; + char *leaf_name1 = "testfile1.txt"; + char *full_newparent_name = "/testdir/dir1", *newparent_name = "dir1"; + char *full_newnod_name = "/testdir/nod1", *newnod_name = "nod1"; + + /* Initialize test area */ + ret = glfs_mkdir(fs, full_parent_name, 0755); + if (ret != 0 && errno != EEXIST) { + fprintf(stderr, "%s: (%p) %s\n", full_parent_name, fd, strerror(errno)); + printf("Test initialization failed on volume %s\n", argv[1]); + goto out; + } else if (ret != 0) { + printf("Found test directory %s to be existing\n", full_parent_name); + printf("Cleanup test directory and restart tests\n"); + goto out; + } + + fd = glfs_creat(fs, full_leaf_name, O_CREAT, 0644); + if (fd == NULL) { + fprintf(stderr, "%s: (%p) %s\n", full_leaf_name, fd, strerror(errno)); + printf("Test initialization failed on volume %s\n", argv[1]); + goto out; + } + glfs_close(fd); + + printf("Initialized the test area, within volume %s\n", argv[1]); + + /* Handle based APIs test area */ + + /* glfs_lookupat test */ + printf("glfs_h_lookupat tests: In Progress\n"); + /* start at root of the volume */ + root = glfs_h_lookupat(fs, NULL, "/", &sb, 0); + if (root == NULL) { + fprintf(stderr, + "glfs_h_lookupat: error on lookup of %s: from (%p),%s\n", "/", + NULL, strerror(errno)); + printf("glfs_h_lookupat tests: FAILED\n"); + goto out; + } + peek_stat(&sb); + + /* lookup a parent within root */ + parent = glfs_h_lookupat(fs, root, parent_name, &sb, 0); + if (parent == NULL) { + fprintf(stderr, + "glfs_h_lookupat: error on lookup of %s: from (%p),%s\n", + parent_name, root, strerror(errno)); + printf("glfs_h_lookupat tests: FAILED\n"); + goto out; + } + peek_stat(&sb); + + /* lookup a leaf/child within the parent */ + leaf = glfs_h_lookupat(fs, parent, leaf_name, &sb, 0); + if (leaf == NULL) { + fprintf(stderr, + "glfs_h_lookupat: error on lookup of %s: from (%p),%s\n", + leaf_name, parent, strerror(errno)); + printf("glfs_h_lookupat tests: FAILED\n"); + goto out; + } + peek_stat(&sb); + + /* reset */ + glfs_h_close(root); + root = NULL; + glfs_h_close(leaf); + leaf = NULL; + glfs_h_close(parent); + parent = NULL; + + /* check absolute paths */ + root = glfs_h_lookupat(fs, NULL, "/", &sb, 0); + if (root == NULL) { + fprintf(stderr, + "glfs_h_lookupat: error on lookup of %s: from (%p),%s\n", "/", + NULL, strerror(errno)); + printf("glfs_h_lookupat tests: FAILED\n"); + goto out; + } + peek_stat(&sb); + + parent = glfs_h_lookupat(fs, NULL, full_parent_name, &sb, 0); + if (parent == NULL) { + fprintf(stderr, + "glfs_h_lookupat: error on lookup of %s: from (%p),%s\n", + full_parent_name, root, strerror(errno)); + printf("glfs_h_lookupat tests: FAILED\n"); + goto out; + } + peek_stat(&sb); + + leaf = glfs_h_lookupat(fs, NULL, full_leaf_name, &sb, 0); + if (leaf == NULL) { + fprintf(stderr, + "glfs_h_lookupat: error on lookup of %s: from (%p),%s\n", + full_leaf_name, parent, strerror(errno)); + printf("glfs_h_lookupat tests: FAILED\n"); + goto out; + } + peek_stat(&sb); + + /* reset */ + glfs_h_close(leaf); + leaf = NULL; + + /* check multiple component paths */ + leaf = glfs_h_lookupat(fs, root, relative_leaf_name, &sb, 0); + if (leaf == NULL) { + fprintf(stderr, + "glfs_h_lookupat: error on lookup of %s: from (%p),%s\n", + relative_leaf_name, parent, strerror(errno)); + goto out; + } + peek_stat(&sb); + + /* reset */ + glfs_h_close(root); + root = NULL; + glfs_h_close(parent); + parent = NULL; + + /* check symlinks in path */ + + /* TODO: -ve test cases */ + /* parent invalid + * path invalid + * path does not exist after some components + * no parent, but relative path + * parent and full path? -ve? + */ + + printf("glfs_h_lookupat tests: PASSED\n"); + + /* glfs_openat test */ + printf("glfs_h_open tests: In Progress\n"); + fd = glfs_h_open(fs, leaf, O_RDWR); + if (fd == NULL) { + fprintf(stderr, "glfs_h_open: error on open of %s: %s\n", + full_leaf_name, strerror(errno)); + printf("glfs_h_open tests: FAILED\n"); + goto out; + } + + /* test read/write based on fd */ + memcpy(writebuf, "abcdefghijklmnopqrstuvwxyz012345", 32); + ret = glfs_write(fd, writebuf, 32, 0); + + glfs_lseek(fd, 10, SEEK_SET); + + ret = glfs_read(fd, readbuf, 32, 0); + if (memcmp(readbuf, writebuf, 32)) { + printf("Failed to read what I wrote: %s %s\n", readbuf, writebuf); + glfs_close(fd); + printf("glfs_h_open tests: FAILED\n"); + goto out; + } + + glfs_h_close(leaf); + leaf = NULL; + glfs_close(fd); + + printf("glfs_h_open tests: PASSED\n"); + + /* Create tests */ + printf("glfs_h_creat tests: In Progress\n"); + parent = glfs_h_lookupat(fs, NULL, full_parent_name, &sb, 0); + if (parent == NULL) { + fprintf(stderr, + "glfs_h_lookupat: error on lookup of %s: from (%p),%s\n", + full_parent_name, root, strerror(errno)); + printf("glfs_h_creat tests: FAILED\n"); + goto out; + } + peek_stat(&sb); + + leaf = glfs_h_creat(fs, parent, leaf_name1, O_CREAT, 0644, &sb); + if (leaf == NULL) { + fprintf(stderr, "glfs_h_creat: error on create of %s: from (%p),%s\n", + leaf_name1, parent, strerror(errno)); + printf("glfs_h_creat tests: FAILED\n"); + goto out; + } + peek_stat(&sb); + + glfs_h_close(leaf); + leaf = NULL; + + leaf = glfs_h_creat(fs, parent, leaf_name1, O_CREAT | O_EXCL, 0644, &sb); + if (leaf != NULL || errno != EEXIST) { + fprintf(stderr, + "glfs_h_creat: existing file, leaf = (%p), errno = %s\n", leaf, + strerror(errno)); + printf("glfs_h_creat tests: FAILED\n"); + if (leaf != NULL) { + glfs_h_close(leaf); + leaf = NULL; + } + } + + tmp = glfs_h_creat(fs, root, parent_name, O_CREAT, 0644, &sb); + if (tmp != NULL || !(errno == EISDIR || errno == EINVAL)) { + fprintf(stderr, "glfs_h_creat: dir create, tmp = (%p), errno = %s\n", + leaf, strerror(errno)); + printf("glfs_h_creat tests: FAILED\n"); + if (tmp != NULL) { + glfs_h_close(tmp); + tmp = NULL; + } + } + + /* TODO: Other combinations and -ve cases as applicable */ + printf("glfs_h_creat tests: PASSED\n"); + + /* extract handle and create from handle test */ + printf( + "glfs_h_extract_handle and glfs_h_create_from_handle tests: In " + "Progress\n"); + /* TODO: Change the lookup to create below for a GIFD recovery failure, + * that needs to be fixed */ + leaf = glfs_h_lookupat(fs, parent, leaf_name1, &sb, 0); + if (leaf == NULL) { + fprintf(stderr, + "glfs_h_lookupat: error on lookup of %s: from (%p),%s\n", + leaf_name1, parent, strerror(errno)); + printf("glfs_h_extract_handle tests: FAILED\n"); + goto out; + } + peek_stat(&sb); + + ret = glfs_h_extract_handle(leaf, leaf_handle, GFAPI_HANDLE_LENGTH); + if (ret < 0) { + fprintf(stderr, + "glfs_h_extract_handle: error extracting handle of %s: %s\n", + full_leaf_name, strerror(errno)); + printf("glfs_h_extract_handle tests: FAILED\n"); + goto out; + } + peek_handle(leaf_handle); + + glfs_h_close(leaf); + leaf = NULL; + + leaf = glfs_h_create_from_handle(fs, leaf_handle, GFAPI_HANDLE_LENGTH, &sb); + if (leaf == NULL) { + fprintf( + stderr, + "glfs_h_create_from_handle: error on create of %s: from (%p),%s\n", + leaf_name1, leaf_handle, strerror(errno)); + printf("glfs_h_create_from_handle tests: FAILED\n"); + goto out; + } + peek_stat(&sb); + + fd = glfs_h_open(fs, leaf, O_RDWR); + if (fd == NULL) { + fprintf(stderr, "glfs_h_open: error on open of %s: %s\n", + full_leaf_name, strerror(errno)); + printf("glfs_h_create_from_handle tests: FAILED\n"); + goto out; + } + + /* test read/write based on fd */ + memcpy(writebuf, "abcdefghijklmnopqrstuvwxyz012345", 32); + ret = glfs_write(fd, writebuf, 32, 0); + + glfs_lseek(fd, 0, SEEK_SET); + + ret = glfs_read(fd, readbuf, 32, 0); + if (memcmp(readbuf, writebuf, 32)) { + printf("Failed to read what I wrote: %s %s\n", writebuf, writebuf); + printf("glfs_h_create_from_handle tests: FAILED\n"); + glfs_close(fd); + goto out; + } + + glfs_close(fd); + glfs_h_close(leaf); + leaf = NULL; + glfs_h_close(parent); + parent = NULL; + + printf( + "glfs_h_extract_handle and glfs_h_create_from_handle tests: PASSED\n"); + + /* Mkdir tests */ + printf("glfs_h_mkdir tests: In Progress\n"); + + ret = glfs_rmdir(fs, full_newparent_name); + if (ret && errno != ENOENT) { + fprintf(stderr, "glfs_rmdir: Failed for %s: %s\n", full_newparent_name, + strerror(errno)); + printf("glfs_h_mkdir tests: FAILED\n"); + goto out; + } + + parent = glfs_h_lookupat(fs, NULL, full_parent_name, &sb, 0); + if (parent == NULL) { + fprintf(stderr, + "glfs_h_lookupat: error on lookup of %s: from (%p),%s\n", + full_parent_name, root, strerror(errno)); + printf("glfs_h_mkdir tests: FAILED\n"); + goto out; + } + peek_stat(&sb); + + leaf = glfs_h_mkdir(fs, parent, newparent_name, 0755, &sb); + if (leaf == NULL) { + fprintf(stderr, "glfs_h_mkdir: error on mkdir of %s: from (%p),%s\n", + newparent_name, parent, strerror(errno)); + printf("glfs_h_mkdir tests: FAILED\n"); + goto out; + } + peek_stat(&sb); + + glfs_h_close(leaf); + leaf = NULL; + + leaf = glfs_h_mkdir(fs, parent, newparent_name, 0755, &sb); + if (leaf != NULL || errno != EEXIST) { + fprintf(stderr, + "glfs_h_mkdir: existing directory, leaf = (%p), errno = %s\n", + leaf, strerror(errno)); + printf("glfs_h_mkdir tests: FAILED\n"); + if (leaf != NULL) { + glfs_h_close(leaf); + leaf = NULL; + } + } + + glfs_h_close(parent); + parent = NULL; + + printf("glfs_h_mkdir tests: PASSED\n"); + + /* Mknod tests */ + printf("glfs_h_mknod tests: In Progress\n"); + ret = glfs_unlink(fs, full_newnod_name); + if (ret && errno != ENOENT) { + fprintf(stderr, "glfs_unlink: Failed for %s: %s\n", full_newnod_name, + strerror(errno)); + printf("glfs_h_mknod tests: FAILED\n"); + goto out; + } + + parent = glfs_h_lookupat(fs, NULL, full_parent_name, &sb, 0); + if (parent == NULL) { + fprintf(stderr, + "glfs_h_lookupat: error on lookup of %s: from (%p),%s\n", + full_parent_name, root, strerror(errno)); + printf("glfs_h_mknod tests: FAILED\n"); + goto out; + } + peek_stat(&sb); + + leaf = glfs_h_mknod(fs, parent, newnod_name, S_IFIFO, 0, &sb); + if (leaf == NULL) { + fprintf(stderr, "glfs_h_mkdir: error on mkdir of %s: from (%p),%s\n", + newnod_name, parent, strerror(errno)); + printf("glfs_h_mknod tests: FAILED\n"); + goto out; + } + peek_stat(&sb); + + /* TODO: create op on a FIFO node hangs, need to check and fix + tmp = glfs_h_creat (fs, parent, newnod_name, O_CREAT, 0644, &sb); + if (tmp != NULL || errno != EINVAL) { + fprintf (stderr, "glfs_h_creat: node create, tmp = (%p), errno = + %s\n", tmp, strerror (errno)); printf ("glfs_h_creat/mknod tests: + FAILED\n"); if (tmp != NULL) { glfs_h_close(tmp); tmp = NULL; + } + } */ + + glfs_h_close(leaf); + leaf = NULL; + + leaf = glfs_h_mknod(fs, parent, newnod_name, 0644, 0, &sb); + if (leaf != NULL || errno != EEXIST) { + fprintf(stderr, + "glfs_h_mknod: existing node, leaf = (%p), errno = %s\n", leaf, + strerror(errno)); + printf("glfs_h_mknod tests: FAILED\n"); + if (leaf != NULL) { + glfs_h_close(leaf); + leaf = NULL; + } + } + + glfs_h_close(parent); + parent = NULL; + + printf("glfs_h_mknod tests: PASSED\n"); + + /* unlink tests */ + test_h_unlink(); + + /* TODO: opendir tests */ + + /* getattr tests */ + test_h_getsetattrs(); + + /* TODO: setattr tests */ + + /* truncate tests */ + test_h_truncate(); + + /* link tests */ + test_h_links(); + + /* rename tests */ + test_h_rename(); + + /* performance tests */ + test_h_performance(); + + /* END: New APIs test area */ + +out: + /* Cleanup glfs handles */ + if (root) + glfs_h_close(root); + if (parent) + glfs_h_close(parent); + if (leaf) + glfs_h_close(leaf); + + return ret; +} + +int +test_write_apis(glfs_t *fs) +{ + /* Add more content here */ + /* Some apis we can get are */ + /* + 0. glfs_set_xlator_option() + + Read/Write combinations: + . glfs_{p,}readv/{p,}writev + . glfs_pread/pwrite + + tests/basic/gfapi/gfapi-async-calls-test.c + . glfs_read_async/write_async + . glfs_pread_async/pwrite_async + . glfs_readv_async/writev_async + . glfs_preadv_async/pwritev_async + + . ftruncate/ftruncate_async + . fsync/fsync_async + . fdatasync/fdatasync_async + + */ + + glfs_fd_t *fd = NULL; + char *filename = "/filename2"; + int flags = O_RDWR; + char *buf = "some bytes!"; + char writestr[TEST_STR_LEN]; + struct iovec iov = {&writestr, TEST_STR_LEN}; + int ret, i; + + for (i = 0; i < TEST_STR_LEN; i++) + writestr[i] = 0x11; + + fd = glfs_open(fs, filename, flags); + if (!fd) + fprintf(stderr, "open(%s): (%p) %s\n", filename, fd, strerror(errno)); + + ret = glfs_writev(fd, &iov, 1, flags); + if (ret < 0) { + fprintf(stderr, "writev(%s): %d (%s)\n", filename, ret, + strerror(errno)); + } + + ret = glfs_pwrite(fd, buf, 10, 4, flags, NULL, NULL); + if (ret < 0) { + fprintf(stderr, "pwrite(%s): %d (%s)\n", filename, ret, + strerror(errno)); + } + + ret = glfs_pwritev(fd, &iov, 1, 4, flags); + if (ret < 0) { + fprintf(stderr, "pwritev(%s): %d (%s)\n", filename, ret, + strerror(errno)); + } + + ret = glfs_fsync(fd, NULL, NULL); + if (ret < 0) { + fprintf(stderr, "fsync(%s): %d (%s)\n", filename, ret, strerror(errno)); + } + + glfs_close(fd); + + return 0; +} + +int +test_metadata_ops(glfs_t *fs, glfs_t *fs2) +{ + glfs_fd_t *fd = NULL; + glfs_fd_t *fd2 = NULL; + struct stat sb = { + 0, + }; + struct glfs_stat gsb = { + 0, + }; + struct statvfs sfs; + char readbuf[32]; + char writebuf[11] = "helloworld"; + + char *filename = "/filename2"; + int ret; + + ret = glfs_lstat(fs, filename, &sb); + fprintf(stderr, "lstat(%s): (%d) %s\n", filename, ret, strerror(errno)); + + fd = glfs_creat(fs, filename, O_RDWR, 0644); + if (!fd) + fprintf(stderr, "creat(%s): (%p) %s\n", filename, fd, strerror(errno)); + + fd2 = glfs_open(fs2, filename, O_RDWR); + if (!fd2) + fprintf(stderr, "open(%s): (%p) %s\n", filename, fd, strerror(errno)); + + ret = glfs_lstat(fs, filename, &sb); + if (ret) + fprintf(stderr, "lstat(%s): (%d) %s\n", filename, ret, strerror(errno)); + + ret = glfs_write(fd, writebuf, 11, 0); + if (ret < 0) { + fprintf(stderr, "writev(%s): %d (%s)\n", filename, ret, + strerror(errno)); + } + + glfs_fsync(fd, NULL, NULL); + + glfs_lseek(fd2, 5, SEEK_SET); + + ret = glfs_read(fd2, readbuf, 32, 0); + + printf("read %d, %s", ret, readbuf); + + /* get stat */ + ret = glfs_fstat(fd2, &sb); + if (ret) + fprintf(stderr, "fstat(%s): %d (%s)\n", filename, ret, strerror(errno)); + + ret = glfs_access(fs, filename, R_OK); + if (ret) + fprintf(stderr, "access(%s): %d (%s)\n", filename, ret, + strerror(errno)); + + ret = glfs_fallocate(fd2, 1024, 1024, 1024); + if (ret) + fprintf(stderr, "fallocate(%s): %d (%s)\n", filename, ret, + strerror(errno)); + + ret = glfs_discard(fd2, 1024, 512); + if (ret) + fprintf(stderr, "discard(%s): %d (%s)\n", filename, ret, + strerror(errno)); + + ret = glfs_zerofill(fd2, 2048, 1024); + if (ret) + fprintf(stderr, "zerofill(%s): %d (%s)\n", filename, ret, + strerror(errno)); + + /* set stat */ + /* TODO: got some errors, need to fix */ + ret = glfs_fsetattr(fd2, &gsb); + + glfs_close(fd); + glfs_close(fd2); + + filename = "/filename3"; + ret = glfs_mknod(fs, filename, S_IFIFO, 0); + if (ret) + fprintf(stderr, "%s: (%d) %s\n", filename, ret, strerror(errno)); + + ret = glfs_lstat(fs, filename, &sb); + if (ret) + fprintf(stderr, "%s: (%d) %s\n", filename, ret, strerror(errno)); + + ret = glfs_rename(fs, filename, "/filename4"); + if (ret) + fprintf(stderr, "rename(%s): (%d) %s\n", filename, ret, + strerror(errno)); + + ret = glfs_unlink(fs, "/filename4"); + if (ret) + fprintf(stderr, "unlink(%s): (%d) %s\n", "/filename4", ret, + strerror(errno)); + + filename = "/dirname2"; + ret = glfs_mkdir(fs, filename, 0); + if (ret) + fprintf(stderr, "%s: (%d) %s\n", filename, ret, strerror(errno)); + + ret = glfs_lstat(fs, filename, &sb); + if (ret) + fprintf(stderr, "lstat(%s): (%d) %s\n", filename, ret, strerror(errno)); + + ret = glfs_rmdir(fs, filename); + if (ret) + fprintf(stderr, "rmdir(%s): (%d) %s\n", filename, ret, strerror(errno)); +} +int +main(int argc, char *argv[]) +{ + glfs_t *fs2 = NULL; + int ret = 0; + glfs_fd_t *fd = NULL; + glfs_fd_t *fd2 = NULL; + struct stat sb = { + 0, + }; + struct glfs_stat gsb = { + 0, + }; + struct statvfs sfs; + char readbuf[32]; + char writebuf[32]; + char volumeid[64]; + + char *filename = "/filename2"; + + if ((argc < 2) || (argc > 3)) { + printf("Usage:\n\t%s <volname> <hostname>\n\t%s <volfile-path>", + argv[0], argv[0]); + return -1; + } + + if (argc == 2) { + /* Generally glfs_new() requires volume name as an argument */ + fs = glfs_new("test-only"); + if (!fs) { + fprintf(stderr, "glfs_new: returned NULL\n"); + return 1; + } + ret = glfs_set_volfile(fs, argv[1]); + if (ret) + fprintf(stderr, "glfs_set_volfile failed\n"); + } else { + fs = glfs_new(argv[1]); + if (!fs) { + fprintf(stderr, "glfs_new: returned NULL\n"); + return 1; + } + // ret = glfs_set_volfile_server (fs, "unix", "/tmp/gluster.sock", 0); + ret = glfs_set_volfile_server(fs, "tcp", argv[2], 24007); + if (ret) + fprintf(stderr, "glfs_set_volfile_server failed\n"); + } + + /* Change this to relevant file when running locally */ + ret = glfs_set_logging(fs, "/dev/stderr", 5); + if (ret) + fprintf(stderr, "glfs_set_logging failed\n"); + + ret = glfs_init(fs); + if (ret) + fprintf(stderr, "glfs_init: returned %d\n", ret); + + if (ret) + goto out; + + /* no major use for getting the volume id in this test, done for coverage */ + ret = glfs_get_volumeid(fs, volumeid, 64); + if (ret) { + fprintf(stderr, "glfs_get_volumeid: returned %d\n", ret); + } + + sleep(2); + + if (argc == 2) { + /* Generally glfs_new() requires volume name as an argument */ + fs2 = glfs_new("test_only_volume"); + if (!fs2) { + fprintf(stderr, "glfs_new(fs2): returned NULL\n"); + return 1; + } + ret = glfs_set_volfile(fs2, argv[1]); + if (ret) + fprintf(stderr, "glfs_set_volfile failed(fs2)\n"); + } else { + fs2 = glfs_new(argv[1]); + if (!fs2) { + fprintf(stderr, "glfs_new(fs2): returned NULL\n"); + return 1; + } + ret = glfs_set_volfile_server(fs2, "tcp", argv[2], 24007); + if (ret) + fprintf(stderr, "glfs_set_volfile_server failed(fs2)\n"); + } + + ret = glfs_set_statedump_path(fs2, "/tmp"); + if (ret) { + fprintf(stderr, "glfs_set_statedump_path: %s\n", strerror(errno)); + } + + ret = glfs_init(fs2); + if (ret) + fprintf(stderr, "glfs_init: returned %d\n", ret); + + test_metadata_ops(fs, fs2); + + test_dirops(fs); + + test_xattr(fs); + + test_chdir(fs); + + test_handleops(argc, argv); + // done + + /* Test some extra apis */ + test_write_apis(fs); + + glfs_statvfs(fs, "/", &sfs); + + glfs_unset_volfile_server(fs, "tcp", argv[2], 24007); + + glfs_fini(fs); + glfs_fini(fs2); + + ret = 0; +out: + return ret; +} diff --git a/tests/basic/gfapi/glfsxmp.t b/tests/basic/gfapi/glfsxmp.t new file mode 100644 index 00000000000..b3e6645c0f5 --- /dev/null +++ b/tests/basic/gfapi/glfsxmp.t @@ -0,0 +1,30 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +cleanup + +TEST glusterd + +TEST $CLI volume create $V0 replica 3 $H0:$B0/brick{0,1,2} +EXPECT 'Created' volinfo_field $V0 'Status' + +TEST $CLI volume start $V0 +EXPECT 'Started' volinfo_field $V0 'Status' + +$CLI system getspec $V0 > fubar.vol + +TEST cp $(dirname $0)/glfsxmp-coverage.c ./glfsxmp.c +TEST build_tester ./glfsxmp.c -lgfapi +TEST ./glfsxmp $V0 $H0 + +TEST ./glfsxmp fubar.vol + +TEST cleanup_tester ./glfsxmp +TEST rm ./glfsxmp.c + +TEST $CLI volume stop $V0 +TEST $CLI volume delete $V0 + +cleanup diff --git a/tests/basic/gfapi/libgfapi-fini-hang.c b/tests/basic/gfapi/libgfapi-fini-hang.c new file mode 100644 index 00000000000..37800e3188b --- /dev/null +++ b/tests/basic/gfapi/libgfapi-fini-hang.c @@ -0,0 +1,62 @@ +#include <fcntl.h> +#include <unistd.h> +#include <time.h> +#include <limits.h> +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <glusterfs/api/glfs.h> +#include <glusterfs/api/glfs-handles.h> + +#define LOG_ERR(func, ret) \ + do { \ + if (ret != 0) { \ + fprintf(stderr, "%s : returned error %d\n", func, ret); \ + exit(1); \ + } else { \ + fprintf(stderr, "%s : returned %d\n", func, ret); \ + } \ + } while (0) + +int +main(int argc, char *argv[]) +{ + glfs_t *fs = NULL; + int ret = 0, i; + glfs_fd_t *fd = NULL; + char readbuf[32]; + char *logname = NULL; + char *hostname = NULL; + char *volname = NULL; + + fprintf(stderr, "Starting libgfapi_fini\n"); + + if (argc < 4) { + fprintf(stderr, "Invalid argument\n"); + exit(1); + } + + hostname = argv[1]; + volname = argv[2]; + logname = argv[3]; + + fs = glfs_new(volname); + if (!fs) { + fprintf(stderr, "glfs_new: returned NULL\n"); + exit(1); + } + + ret = glfs_set_volfile_server(fs, "tcp", hostname, 0); + LOG_ERR("glfs_set_volfile_server", ret); + + ret = glfs_set_logging(fs, logname, 7); + LOG_ERR("glfs_set_logging", ret); + + /* Do not call glfs_init. + * glfs_fini() shouldn't hang in that case*/ + ret = glfs_fini(fs); + LOG_ERR("glfs_fini", ret); + fprintf(stderr, "End of libgfapi_fini\n"); + + exit(0); +} diff --git a/tests/basic/gfapi/libgfapi-fini-hang.t b/tests/basic/gfapi/libgfapi-fini-hang.t new file mode 100755 index 00000000000..ba262a943ee --- /dev/null +++ b/tests/basic/gfapi/libgfapi-fini-hang.t @@ -0,0 +1,42 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc + +function check_process () { + ps -p $1 + if [ $? -eq 1 ] ; then + echo "Y" + else + echo "N" + fi +} + +cleanup; + +TEST glusterd + +TEST $CLI volume create $V0 $H0:$B0/brick1; +EXPECT 'Created' volinfo_field $V0 'Status'; + +TEST $CLI volume start $V0; +EXPECT 'Started' volinfo_field $V0 'Status'; + +logdir=$(gluster --print-logdir) + +TEST build_tester $(dirname $0)/libgfapi-fini-hang.c -o $M0/libgfapi-fini-hang -lgfapi +TEST cd $M0 + ./libgfapi-fini-hang $H0 $V0 $logdir/libgfapi-fini-hang.log & +PID=$! + +# check if the process "libgfapi-fini-hang" exits with in $PROCESS_UP_TIMEOUT +EXPECT_WITHIN $PROCESS_UP_TIMEOUT 'Y' check_process $PID + +# Kill the process if present +TEST ! kill -9 $PID + +TEST rm -f $M0/libgfapi-fini-hang + +TEST $CLI volume stop $V0 +TEST $CLI volume delete $V0 + +cleanup; diff --git a/tests/basic/gfapi/mandatory-lock-optimal.c b/tests/basic/gfapi/mandatory-lock-optimal.c new file mode 100644 index 00000000000..34fef8d0b80 --- /dev/null +++ b/tests/basic/gfapi/mandatory-lock-optimal.c @@ -0,0 +1,532 @@ +/* Pre-requisites:- + * + * 1. Make sure that performance translators are switched off while running this + * test. + * 2. Perform the following volume set operation: + * # gluster volume set <VOLNAME> locks.mandatory-locking optimal + * 3. For installation under non-standard paths, export LD_LIBRARY_PATH to + * automatically load exact libgfapi.so and compile this C file as follows: + * $ gcc mandatory-lock-optimal.c -lgfapi -I <include path for api/glfs.h> -L + * <include path for libgfapi shared library> + */ + +#include <errno.h> +#include <stdio.h> +#include <fcntl.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <glusterfs/api/glfs.h> + +#define TOTAL_TEST_COUNT 8 + +/* C1 = Client 1 : C2 = Client 2 : C3 = Client 3 : + * fs1, fd1 are associated with C1. Similarly fs2, fd2 for C2 + * and fs3, fd3 for C3 */ + +FILE *fp; +glfs_t *fs1, *fs2, *fs3; +glfs_fd_t *fd, *fd1, *fd2, *fd3; +struct flock lock; +char buf1[10], *buf2 = "ten bytes!", *fname = "/mand.lock"; +int ret, test_count; +off_t offset; + +/* run_test_1 () : C1 takes byte range mandatory read lock. + C2 attempts to read from a conflicting range. + Expected result : Read from C2 should pass. + + * run_test_2 () : C1 takes byte range mandatory read lock. + C2 attempts write to a conflicting range. + Expected result : Write from C2 should fail with EAGAIN. + + * run_test_3 () : C1 takes byte range advisory write lock. + C2 attempts to read from a conflicting range. + Expected result : Read from C2 should pass. + + * run_test_4 () : C1 takes byte range advisory write lock. + C2 attempts write to a conflicting range. + Expected result : Write from C2 should pass. + + * run_test_5 () : C1 takes byte range advisory read lock. + C2 attempts to open the same file with O_TRUNC. + Expected result : Open from C2 should pass. + + * run_test_6 () : C1 takes byte range mandatory read lock. + C2 attempts to open the same file with O_TRUNC. + Expected result : Open from C2 should fail with EAGAIN. + + * run_test_7 () : C1 takes byte range mandatory read lock. + C2 attempts ftruncate on a conflicting range. + Expected result : Write from C2 should fail with EAGAIN. + + * run_test_8 () : C1 takes byte range advisory read lock. + C2 takes byte range mandatory read lock + within the byte range for which C1 already + holds an advisory lock so as to perform a + basic split/merge. C3 repositions fd3 to + start of C2's byte range mandatory lock + offset and attempts a write. Then it again + repositions fd3 to one byte past C2's byte + range mandatoy lock and again attempts a write. + Expected result : First write should fail with EAGAIN. + Second write should pass. */ + +#define LOG_ERR(func, err) \ + do { \ + if (!fp) \ + fprintf(stderr, "\n%s : returned error (%s)\n", func, \ + strerror(err)); \ + else \ + fprintf(fp, "\n%s : returned error (%s)\n", func, strerror(err)); \ + cleanup_and_exit(err); \ + } while (0) + +void +cleanup_and_exit(int exit_status) +{ + if (exit_status || test_count != TOTAL_TEST_COUNT) { + fprintf(fp, "\nAborting due to some test failures.\n"); + exit_status = 1; + } else + fprintf(fp, "\nAll tests ran successfully.\n"); + if (fp) + fclose(fp); + if (fd) + glfs_close(fd); + if (fd1) + glfs_close(fd1); + if (fd2) + glfs_close(fd2); + + glfs_unlink(fs1, fname); + + if (fs1) + glfs_fini(fs1); + if (fs2) + glfs_fini(fs2); + + exit(exit_status); +} + +glfs_t * +new_client_create(char *hostname, char *volname, char *logfile_name) +{ + glfs_t *fs = NULL; + + fs = glfs_new(volname); + if (!fs) + LOG_ERR("glfs_new", errno); + + ret = glfs_set_volfile_server(fs, "tcp", hostname, 24007); + if (ret) + LOG_ERR("glfs_set_volfile_server", errno); + + ret = glfs_set_logging(fs, logfile_name, 7); + if (ret) + LOG_ERR("glfs_set_logging", errno); + + ret = glfs_init(fs); + if (ret) + LOG_ERR("glfs_init", errno); + + return fs; +} + +void +run_test_1(int i) +{ + fprintf(fp, "\nRunning Test-%d . . . ", i); + + fd1 = glfs_open(fs1, fname, O_RDONLY | O_NONBLOCK); + if (!fd1) + LOG_ERR("glfs_open", errno); + + lock.l_type = F_RDLCK; + lock.l_whence = SEEK_SET; + lock.l_start = 0L; + lock.l_len = 5L; + + ret = glfs_file_lock(fd1, F_SETLK, &lock, GLFS_LK_MANDATORY); + if (ret) + LOG_ERR("glfs_file_lock", errno); + + fd2 = glfs_open(fs2, fname, O_RDONLY | O_NONBLOCK); + if (!fd2) + LOG_ERR("glfs_open", errno); + + /* On successful read, 0 is returned as there is no content inside the + * file + */ + ret = glfs_read(fd2, buf1, 10, 0); + if (ret) + LOG_ERR("glfs_read", errno); + + ret = glfs_close(fd1); + if (ret) + LOG_ERR("glfs_close", errno); + fd1 = NULL; + + ret = glfs_close(fd2); + if (ret) + LOG_ERR("glfs_close", errno); + fd2 = NULL; + + test_count++; + fprintf(fp, "OK\n", i); +} + +void +run_test_2(int i) +{ + fprintf(fp, "\nRunning Test-%d . . . ", i); + + fd1 = glfs_open(fs1, fname, O_RDONLY | O_NONBLOCK); + if (!fd1) + LOG_ERR("glfs_open", errno); + + lock.l_type = F_RDLCK; + lock.l_whence = SEEK_SET; + lock.l_start = 0L; + lock.l_len = 5L; + + ret = glfs_file_lock(fd1, F_SETLK, &lock, GLFS_LK_MANDATORY); + if (ret) + LOG_ERR("glfs_file_lock", errno); + + fd2 = glfs_open(fs2, fname, O_WRONLY | O_NONBLOCK); + if (!fd2) + LOG_ERR("glfs_open", errno); + + ret = glfs_write(fd2, buf2, 10, 0); + if (ret == 10 || errno != EAGAIN) + LOG_ERR("glfs_write", errno); + + ret = glfs_close(fd1); + if (ret) + LOG_ERR("glfs_close", errno); + fd1 = NULL; + + ret = glfs_close(fd2); + if (ret) + LOG_ERR("glfs_close", errno); + fd2 = NULL; + + test_count++; + fprintf(fp, "OK\n", i); +} + +void +run_test_3(int i) +{ + fprintf(fp, "\nRunning Test-%d . . . ", i); + + fd1 = glfs_open(fs1, fname, O_WRONLY | O_NONBLOCK); + if (!fd1) + LOG_ERR("glfs_open", errno); + + lock.l_type = F_WRLCK; + lock.l_whence = SEEK_SET; + lock.l_start = 0L; + lock.l_len = 5L; + + ret = glfs_file_lock(fd1, F_SETLK, &lock, GLFS_LK_ADVISORY); + if (ret) + LOG_ERR("glfs_file_lock", errno); + + fd2 = glfs_open(fs2, fname, O_RDONLY | O_NONBLOCK); + if (!fd2) + LOG_ERR("glfs_open", errno); + + /* Still there is no content inside file. So following read should + * return 0 + */ + ret = glfs_read(fd2, buf1, 10, 0); + if (ret) + LOG_ERR("glfs_read", errno); + + ret = glfs_close(fd1); + if (ret) + LOG_ERR("glfs_close", errno); + fd1 = NULL; + + ret = glfs_close(fd2); + if (ret) + LOG_ERR("glfs_close", errno); + fd2 = NULL; + + test_count++; + fprintf(fp, "OK\n", i); +} + +void +run_test_4(int i) +{ + fprintf(fp, "\nRunning Test-%d . . . ", i); + + fd1 = glfs_open(fs1, fname, O_WRONLY | O_NONBLOCK); + if (!fd1) + LOG_ERR("glfs_open", errno); + + lock.l_type = F_WRLCK; + lock.l_whence = SEEK_SET; + lock.l_start = 0L; + lock.l_len = 5L; + + ret = glfs_file_lock(fd1, F_SETLK, &lock, GLFS_LK_ADVISORY); + if (ret) + LOG_ERR("glfs_file_lock", errno); + + fd2 = glfs_open(fs2, fname, O_WRONLY | O_NONBLOCK); + if (!fd2) + LOG_ERR("glfs_open", errno); + + ret = glfs_write(fd2, buf2, 10, 0); + if (ret != 10) + LOG_ERR("glfs_write", errno); + + ret = glfs_close(fd1); + if (ret) + LOG_ERR("glfs_close", errno); + fd1 = NULL; + + ret = glfs_close(fd2); + if (ret) + LOG_ERR("glfs_close", errno); + fd2 = NULL; + + test_count++; + fprintf(fp, "OK\n", i); +} + +void +run_test_5(int i) +{ + fprintf(fp, "\nRunning Test-%d . . . ", i); + + fd1 = glfs_open(fs1, fname, O_RDONLY | O_NONBLOCK); + if (!fd1) + LOG_ERR("glfs_open", errno); + + lock.l_type = F_RDLCK; + lock.l_whence = SEEK_SET; + lock.l_start = 0L; + lock.l_len = 5L; + + ret = glfs_file_lock(fd1, F_SETLK, &lock, GLFS_LK_ADVISORY); + if (ret) + LOG_ERR("glfs_file_lock", errno); + + fd2 = glfs_open(fs2, fname, O_RDONLY | O_NONBLOCK | O_TRUNC); + if (!fd2) + LOG_ERR("glfs_open", errno); + + ret = glfs_close(fd1); + if (ret) + LOG_ERR("glfs_close", errno); + fd1 = NULL; + + ret = glfs_close(fd2); + if (ret) + LOG_ERR("glfs_close", errno); + fd2 = NULL; + + test_count++; + fprintf(fp, "OK\n", i); +} + +void +run_test_6(int i) +{ + fprintf(fp, "\nRunning Test-%d . . . ", i); + + fd1 = glfs_open(fs1, fname, O_RDONLY | O_NONBLOCK); + if (!fd1) + LOG_ERR("glfs_open", errno); + + lock.l_type = F_RDLCK; + lock.l_whence = SEEK_SET; + lock.l_start = 0L; + lock.l_len = 5L; + + ret = glfs_file_lock(fd1, F_SETLK, &lock, GLFS_LK_MANDATORY); + if (ret) + LOG_ERR("glfs_file_lock", errno); + + fd2 = glfs_open(fs2, fname, O_RDONLY | O_NONBLOCK | O_TRUNC); + if (fd2) + LOG_ERR("glfs_open", errno); + + ret = glfs_close(fd1); + if (ret) + LOG_ERR("glfs_close", errno); + fd1 = NULL; + + test_count++; + fprintf(fp, "OK\n", i); +} + +void +run_test_7(int i) +{ + fprintf(fp, "\nRunning Test-%d . . . ", i); + + fd1 = glfs_open(fs1, fname, O_RDONLY | O_NONBLOCK); + if (!fd1) + LOG_ERR("glfs_open", errno); + + lock.l_type = F_RDLCK; + lock.l_whence = SEEK_SET; + lock.l_start = 0L; + lock.l_len = 5L; + + ret = glfs_file_lock(fd1, F_SETLK, &lock, GLFS_LK_MANDATORY); + if (ret) + LOG_ERR("glfs_file_lock", errno); + + fd2 = glfs_open(fs2, fname, O_RDWR | O_NONBLOCK); + if (!fd2) + LOG_ERR("glfs_open", errno); + + ret = glfs_ftruncate(fd2, 4, NULL, NULL); + if (ret == 0 || errno != EAGAIN) + LOG_ERR("glfs_ftruncate", errno); + + ret = glfs_close(fd1); + if (ret) + LOG_ERR("glfs_close", errno); + fd1 = NULL; + + ret = glfs_close(fd2); + if (ret) + LOG_ERR("glfs_close", errno); + fd2 = NULL; + + test_count++; + fprintf(fp, "OK\n", i); +} + +void +run_test_8(int i) +{ + fprintf(fp, "\nRunning Test-%d . . . ", i); + + fd1 = glfs_open(fs1, fname, O_RDONLY | O_NONBLOCK); + if (!fd1) + LOG_ERR("glfs_open", errno); + + lock.l_type = F_RDLCK; + lock.l_whence = SEEK_SET; + lock.l_start = 0L; + lock.l_len = 10L; + + ret = glfs_file_lock(fd1, F_SETLK, &lock, GLFS_LK_ADVISORY); + if (ret) + LOG_ERR("glfs_file_lock", errno); + + fd2 = glfs_open(fs2, fname, O_RDONLY | O_NONBLOCK); + if (!fd2) + LOG_ERR("glfs_open", errno); + + lock.l_type = F_RDLCK; + lock.l_whence = SEEK_SET; + lock.l_start = 5L; + lock.l_len = 2L; + + ret = glfs_file_lock(fd2, F_SETLK, &lock, GLFS_LK_MANDATORY); + if (ret) + LOG_ERR("glfs_file_lock", errno); + + fd3 = glfs_open(fs3, fname, O_RDWR | O_NONBLOCK); + if (!fd3) + LOG_ERR("glfs_open", errno); + + offset = glfs_lseek(fd3, 5L, SEEK_SET); + if (offset != 5) + LOG_ERR("glfs_lseek", errno); + + ret = glfs_write(fd3, buf2, 10, 0); + if (ret == 10 || errno != EAGAIN) + LOG_ERR("glfs_write", errno); + + offset = glfs_lseek(fd3, 8L, SEEK_SET); + if (offset != 8) + LOG_ERR("glfs_lseek", errno); + + ret = glfs_write(fd3, buf2, 10, 0); + if (ret != 10) + LOG_ERR("glfs_write", errno); + + ret = glfs_close(fd1); + if (ret) + LOG_ERR("glfs_close", errno); + fd1 = NULL; + + ret = glfs_close(fd2); + if (ret) + LOG_ERR("glfs_close", errno); + fd2 = NULL; + + ret = glfs_close(fd3); + if (ret) + LOG_ERR("glfs_close", errno); + fd3 = NULL; + + test_count++; + fprintf(fp, "OK\n", i); +} + +int +main(int argc, char *argv[]) +{ + char logfile[50]; + + if (argc != 4) { + fprintf(stderr, + "Usage: %s <server ip/hostname> <volume name> <test log " + "directory>\n", + argv[0]); + return 0; + } + + sprintf(logfile, "%s/%s", argv[3], "mandatory-lock-optimal-test.log"); + fp = fopen(logfile, "w"); + if (!fp) { + fprintf(stderr, "\n%s\n", logfile); + LOG_ERR("Log file creation", errno); + } + + sprintf(logfile, "%s/%s", argv[3], "glfs-client-1.log"); + fs1 = new_client_create(argv[1], argv[2], logfile); + if (!fs1) + LOG_ERR("client-1 creation", EINVAL); + + sprintf(logfile, "%s/%s", argv[3], "glfs-client-2.log"); + fs2 = new_client_create(argv[1], argv[2], logfile); + if (!fs2) + LOG_ERR("client-2 creation", EINVAL); + + sprintf(logfile, "%s/%s", argv[3], "glfs-client-3.log"); + fs3 = new_client_create(argv[1], argv[2], logfile); + if (!fs3) + LOG_ERR("client-3 creation", EINVAL); + + fd = glfs_creat(fs1, fname, O_RDWR, 0644); + if (!fd) + LOG_ERR("glfs_creat", errno); + + test_count = 0; + + run_test_1(1); + run_test_2(2); + run_test_3(3); + run_test_4(4); + run_test_5(5); + run_test_6(6); + run_test_7(7); + run_test_8(8); + + cleanup_and_exit(0); + + return 0; +} diff --git a/tests/basic/gfapi/mandatory-lock-optimal.t b/tests/basic/gfapi/mandatory-lock-optimal.t new file mode 100644 index 00000000000..27062e1f6c2 --- /dev/null +++ b/tests/basic/gfapi/mandatory-lock-optimal.t @@ -0,0 +1,38 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +cleanup + +TEST glusterd + +# Create and start the volume +TEST $CLI volume create $V0 $H0:$B0/${V0}1 +TEST $CLI volume start $V0 + +logdir=`gluster --print-logdir` + +# Switch off performance translators +TEST $CLI volume set $V0 performance.open-behind off +TEST $CLI volume set $V0 performance.write-behind off +TEST $CLI volume set $V0 performance.quick-read off +TEST $CLI volume set $V0 performance.io-cache off +TEST $CLI volume set $V0 performance.read-ahead off +TEST $CLI volume set $V0 performance.readdir-ahead off + +# Enable optimal mandatory-locking mode and restart the volume +TEST $CLI volume set $V0 locks.mandatory-locking optimal +TEST $CLI volume stop $V0 +TEST $CLI volume start $V0 + +# Compile and run the test program +TEST build_tester $(dirname $0)/mandatory-lock-optimal.c -lgfapi +TEST ./$(dirname $0)/mandatory-lock-optimal $H0 $V0 $logdir + +# Cleanup the environment +cleanup_tester $(dirname $0)/mandatory-lock-optimal +TEST $CLI volume stop $V0 +TEST $CLI volume delete $V0 + +cleanup diff --git a/tests/basic/gfapi/protocol-client-ssl.vol.in b/tests/basic/gfapi/protocol-client-ssl.vol.in new file mode 100644 index 00000000000..cdc0c9d0671 --- /dev/null +++ b/tests/basic/gfapi/protocol-client-ssl.vol.in @@ -0,0 +1,15 @@ +# +# This .vol file expects that there is +# +# 1. GlusterD listening on @@HOSTNAME@@ +# 2. a volume that provides a brick on @@BRICKPATH@@ +# 3. the volume with the brick has been started +# +volume test + type protocol/client + option remote-host @@HOSTNAME@@ + option remote-subvolume @@BRICKPATH@@ + option transport-type socket + option transport.socket.ssl-enabled @@SSL@@ +end-volume + diff --git a/tests/basic/gfapi/protocol-client.vol.in b/tests/basic/gfapi/protocol-client.vol.in new file mode 100644 index 00000000000..ef35001e29f --- /dev/null +++ b/tests/basic/gfapi/protocol-client.vol.in @@ -0,0 +1,14 @@ +# +# This .vol file expects that there is +# +# 1. GlusterD listening on @@HOSTNAME@@ +# 2. a volume that provides a brick on @@BRICKPATH@@ +# 3. the volume with the brick has been started +# +volume test + type protocol/client + option remote-host @@HOSTNAME@@ + option remote-subvolume @@BRICKPATH@@ + option transport-type socket +end-volume + diff --git a/tests/basic/gfapi/seek.c b/tests/basic/gfapi/seek.c new file mode 100644 index 00000000000..85ea9b88141 --- /dev/null +++ b/tests/basic/gfapi/seek.c @@ -0,0 +1,99 @@ +/* seek.c - use glfs_lseek() to find holes in a file + * + * Author: Niels de Vos <ndevos@redhat.com> + */ + +/* needed for SEEK_HOLE/SEEK_DATA */ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include <sys/types.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include <glusterfs/api/glfs.h> +#include <glusterfs/api/glfs-handles.h> + +int +main(int argc, char **argv) +{ + glfs_t *fs = NULL; + int ret = 0; + glfs_fd_t *fd = NULL; + char *filename = NULL; + char *volname = NULL; + char *hostname = NULL; + struct stat st = { + 0, + }; + off_t hole_start = 0; + off_t hole_end = 0; + + if (argc != 4) { + fprintf(stderr, "Invalid argument, use %s <hostname> <vol> <file>\n", + argv[0]); + exit(1); + } + + hostname = argv[1]; + volname = argv[2]; + filename = argv[3]; + + fs = glfs_new(volname); + if (!fs) { + perror("glfs_new() returned NULL"); + return 1; + } + + if (glfs_set_volfile_server(fs, "tcp", hostname, 24007)) { + perror("glfs_set_volfile_server"); + return 1; + } + + if (glfs_init(fs)) { + perror("glfs_init"); + return 1; + } + + fd = glfs_open(fs, filename, O_RDONLY); + if (fd <= 0) { + perror("glfs_open"); + return 1; + } + + if (glfs_fstat(fd, &st)) { + perror("glfs_fstat"); + return 1; + } + + while (hole_end < st.st_size) { + hole_start = glfs_lseek(fd, hole_end, SEEK_HOLE); + if (hole_start == -1 && errno == ENXIO) + /* no more holes */ + break; + if (hole_start == -1) { + perror("no more holes"); + break; + } + + hole_end = glfs_lseek(fd, hole_start, SEEK_DATA); + if (hole_end == -1 && errno == ENXIO) { + /* no more data */ + break; + } + + printf("HOLE found: %ld - %ld%s\n", hole_start, hole_end, + (hole_end == st.st_size) ? " (EOF)" : ""); + } + + glfs_close(fd); + + if (fs) { + glfs_fini(fs); + } + + return ret; +} diff --git a/tests/basic/gfapi/sink.t b/tests/basic/gfapi/sink.t new file mode 100644 index 00000000000..53af2ecf62d --- /dev/null +++ b/tests/basic/gfapi/sink.t @@ -0,0 +1,13 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +cleanup + +TEST build_tester $(dirname ${0})/gfapi-load-volfile.c -lgfapi +TEST ./$(dirname ${0})/gfapi-load-volfile $(dirname $0)/sink.vol + +cleanup_tester $(dirname ${0})/gfapi-load-volfile + +cleanup diff --git a/tests/basic/gfapi/sink.vol b/tests/basic/gfapi/sink.vol new file mode 100644 index 00000000000..d1c92261448 --- /dev/null +++ b/tests/basic/gfapi/sink.vol @@ -0,0 +1,24 @@ +# +# The sink xlator does not do any memory allocations. It only passes the FOPs +# through to the next xlator. +# +# For testing, there is no next xlator needed, we are only interested in the +# resource usage of the Gluster core when gfapi is used. +# +# Note: The sink xlator does not handle any calls. Mounting is possible, but +# any I/O needs additional functionality in the sink xlator. +# +volume sink + type debug/sink + # an option is required, otherwise the graph parsing fails + option an-option-is-required yes +end-volume + +# +# It is possible to test the resource usage of other xlators by adding them in +# the graph before the "sink". +# +#volume mdcache-sink +# type performance/md-cache +# subvolumes sink +#end-volume diff --git a/tests/basic/gfapi/upcall-cache-invalidate.c b/tests/basic/gfapi/upcall-cache-invalidate.c new file mode 100644 index 00000000000..078286a8956 --- /dev/null +++ b/tests/basic/gfapi/upcall-cache-invalidate.c @@ -0,0 +1,209 @@ +#include <fcntl.h> +#include <unistd.h> +#include <time.h> +#include <limits.h> +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <glusterfs/api/glfs.h> +#include <glusterfs/api/glfs-handles.h> + +#define LOG_ERR(func, ret) \ + do { \ + if (ret != 0) { \ + fprintf(stderr, "%s : returned error %d (%s)\n", func, ret, \ + strerror(errno)); \ + goto out; \ + } else { \ + fprintf(stderr, "%s : returned %d\n", func, ret); \ + } \ + } while (0) + +int +main(int argc, char *argv[]) +{ + glfs_t *fs = NULL; + glfs_t *fs2 = NULL; + glfs_t *fs_tmp = NULL; + glfs_t *fs_tmp2 = NULL; + int ret = 0, i; + glfs_fd_t *fd = NULL; + glfs_fd_t *fd2 = NULL; + glfs_fd_t *fd_tmp = NULL; + glfs_fd_t *fd_tmp2 = NULL; + char readbuf[32]; + char *filename = "file_tmp"; + char *writebuf = NULL; + char *vol_id = NULL; + unsigned int cnt = 1; + struct glfs_upcall *cbk = NULL; + char *logfile = NULL; + char *volname = NULL; + char *hostname = NULL; + + if (argc != 4) { + fprintf(stderr, "Invalid argument\n"); + exit(1); + } + + hostname = argv[1]; + volname = argv[2]; + logfile = argv[3]; + + fs = glfs_new(volname); + if (!fs) { + fprintf(stderr, "glfs_new: returned NULL\n"); + return -1; + } + + ret = glfs_set_volfile_server(fs, "tcp", hostname, 24007); + LOG_ERR("glfs_set_volfile_server", ret); + + ret = glfs_set_logging(fs, logfile, 7); + LOG_ERR("glfs_set_logging", ret); + + ret = glfs_init(fs); + LOG_ERR("glfs_init", ret); + + /* This does not block, but enables caching of events. Real + * applications like NFS-Ganesha run this in a thread before activity + * on the fs (through this instance) happens. */ + ret = glfs_h_poll_upcall(fs_tmp, &cbk); + LOG_ERR("glfs_h_poll_upcall", ret); + + fs2 = glfs_new(volname); + if (!fs2) { + fprintf(stderr, "glfs_new fs2: returned NULL\n"); + return 1; + } + + ret = glfs_set_volfile_server(fs2, "tcp", hostname, 24007); + LOG_ERR("glfs_set_volfile_server-fs2", ret); + + ret = glfs_set_logging(fs2, logfile, 7); + LOG_ERR("glfs_set_logging-fs2", ret); + + ret = glfs_init(fs2); + LOG_ERR("glfs_init-fs2", ret); + + fd = glfs_creat(fs, filename, O_RDWR | O_SYNC, 0644); + if (fd <= 0) { + ret = -1; + LOG_ERR("glfs_creat", ret); + } + fprintf(stderr, "glfs-create fd - %d\n", fd); + + fd2 = glfs_open(fs2, filename, O_SYNC | O_RDWR | O_CREAT); + if (fd2 <= 0) { + ret = -1; + LOG_ERR("glfs_open-fs2", ret); + } + fprintf(stderr, "glfs-open fd2 - %d\n", fd2); + + do { + if (cnt % 2) { + fd_tmp = fd; + fs_tmp = fs; + fd_tmp2 = fd2; + fs_tmp2 = fs2; + } else { + fd_tmp = fd2; + fs_tmp = fs2; + fd_tmp2 = fd; + fs_tmp2 = fs; + } + + /* WRITE on fd_tmp */ + writebuf = malloc(10); + if (writebuf) { + memcpy(writebuf, "abcd", 4); + ret = glfs_write(fd_tmp, writebuf, 4, 0); + if (ret <= 0) { + ret = -1; + LOG_ERR("glfs_write", ret); + } else { + fprintf(stderr, "glfs_write succeeded\n"); + } + free(writebuf); + } else { + fprintf(stderr, "Could not allocate writebuf\n"); + return -1; + } + + /* READ on fd_tmp2 */ + ret = glfs_lseek(fd_tmp2, 0, SEEK_SET); + LOG_ERR("glfs_lseek", ret); + + memset(readbuf, 0, sizeof(readbuf)); + ret = glfs_pread(fd_tmp2, readbuf, 4, 0, 0, NULL); + + if (ret <= 0) { + ret = -1; + LOG_ERR("glfs_pread", ret); + } else { + fprintf(stderr, "glfs_read: %s\n", readbuf); + } + + /* Open() fops seem to be not performed on server side until + * there are I/Os on that fd + */ + if (cnt > 2) { + struct glfs_upcall_inode *in_arg = NULL; + enum glfs_upcall_reason reason = 0; + struct glfs_object *object = NULL; + uint64_t flags = 0; + uint64_t expire = 0; + + ret = glfs_h_poll_upcall(fs_tmp, &cbk); + LOG_ERR("glfs_h_poll_upcall", ret); + + reason = glfs_upcall_get_reason(cbk); + + /* Expect 'GLFS_INODE_INVALIDATE' upcall event. */ + if (reason == GLFS_UPCALL_INODE_INVALIDATE) { + in_arg = glfs_upcall_get_event(cbk); + + object = glfs_upcall_inode_get_object(in_arg); + flags = glfs_upcall_inode_get_flags(in_arg); + expire = glfs_upcall_inode_get_expire(in_arg); + + fprintf(stderr, + " upcall event type - %d," + " object(%p), flags(%d), " + " expire_time_attr(%d)\n", + reason, object, flags, expire); + } else { + fprintf(stderr, "Didn't receive upcall notify event"); + ret = -1; + goto err; + } + + glfs_free(cbk); + } + + sleep(5); + } while (++cnt < 5); + +err: + glfs_close(fd); + LOG_ERR("glfs_close", ret); + + glfs_close(fd2); + LOG_ERR("glfs_close-fd2", ret); + +out: + if (fs) { + ret = glfs_fini(fs); + fprintf(stderr, "glfs_fini(fs) returned %d \n", ret); + } + + if (fs2) { + ret = glfs_fini(fs2); + fprintf(stderr, "glfs_fini(fs2) returned %d \n", ret); + } + + if (ret) + exit(1); + exit(0); +} diff --git a/tests/basic/gfapi/upcall-cache-invalidate.t b/tests/basic/gfapi/upcall-cache-invalidate.t new file mode 100755 index 00000000000..5fd6a3332e7 --- /dev/null +++ b/tests/basic/gfapi/upcall-cache-invalidate.t @@ -0,0 +1,30 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +cleanup; + +TEST glusterd + +TEST $CLI volume create $V0 $H0:$B0/brick1; +EXPECT 'Created' volinfo_field $V0 'Status'; + +TEST $CLI volume start $V0; +EXPECT 'Started' volinfo_field $V0 'Status'; + +logdir=`gluster --print-logdir` + +## Enable Upcall cache-invalidation feature +TEST $CLI volume set $V0 features.cache-invalidation on; + +TEST build_tester $(dirname $0)/upcall-cache-invalidate.c -lgfapi + +TEST ./$(dirname $0)/upcall-cache-invalidate $H0 $V0 $logdir/upcall-cache-invalidate.log + +cleanup_tester $(dirname $0)/upcall-cache-invalidate + +TEST $CLI volume stop $V0 +TEST $CLI volume delete $V0 + +cleanup; diff --git a/tests/basic/gfapi/upcall-register-api.c b/tests/basic/gfapi/upcall-register-api.c new file mode 100644 index 00000000000..53ce0ecdb68 --- /dev/null +++ b/tests/basic/gfapi/upcall-register-api.c @@ -0,0 +1,286 @@ +#include <fcntl.h> +#include <unistd.h> +#include <time.h> +#include <limits.h> +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <glusterfs/api/glfs.h> +#include <glusterfs/api/glfs-handles.h> + +#define LOG_ERR(func, ret) \ + do { \ + if (ret != 0) { \ + fprintf(stderr, "%s : returned error %d (%s)\n", func, ret, \ + strerror(errno)); \ + goto out; \ + } else { \ + fprintf(stderr, "%s : returned %d\n", func, ret); \ + } \ + } while (0) + +int upcall_recv = 0; + +void +up_async_invalidate(struct glfs_upcall *up_arg, void *data) +{ + struct glfs_upcall_inode *in_arg = NULL; + enum glfs_upcall_reason reason = 0; + struct glfs_object *object = NULL; + uint64_t flags = 0; + uint64_t expire = 0; + + if (!up_arg) + return; + + reason = glfs_upcall_get_reason(up_arg); + + /* Expect 'GLFS_INODE_INVALIDATE' upcall event. */ + + if (reason == GLFS_UPCALL_INODE_INVALIDATE) { + in_arg = glfs_upcall_get_event(up_arg); + + object = glfs_upcall_inode_get_object(in_arg); + flags = glfs_upcall_inode_get_flags(in_arg); + expire = glfs_upcall_inode_get_expire(in_arg); + + fprintf(stderr, + " upcall event type - %d," + " object(%p), flags(%d), " + " expire_time_attr(%d)\n", + reason, object, flags, expire); + upcall_recv++; + } + + glfs_free(up_arg); + return; +} + +int +perform_io(glfs_t *fs, glfs_t *fs2, int cnt) +{ + glfs_t *fs_tmp = NULL; + glfs_t *fs_tmp2 = NULL; + glfs_fd_t *fd_tmp = NULL; + glfs_fd_t *fd_tmp2 = NULL; + char readbuf[32]; + char *writebuf = NULL; + glfs_fd_t *fd = NULL; + glfs_fd_t *fd2 = NULL; + char *filename = "file_tmp"; + int ret = -1; + + if (!fs || !fs2) + return -1; + + /* Create file from fs and open it from fs2 */ + fd = glfs_creat(fs, filename, O_RDWR | O_SYNC, 0644); + if (fd <= 0) { + ret = -1; + LOG_ERR("glfs_creat", ret); + } + + fd2 = glfs_open(fs2, filename, O_SYNC | O_RDWR | O_CREAT); + if (fd2 <= 0) { + ret = -1; + LOG_ERR("glfs_open-fs2", ret); + } + + do { + if (cnt % 2) { + fd_tmp = fd; + fs_tmp = fs; + fd_tmp2 = fd2; + fs_tmp2 = fs2; + } else { + fd_tmp = fd2; + fs_tmp = fs2; + fd_tmp2 = fd; + fs_tmp2 = fs; + } + + /* WRITE on fd_tmp */ + writebuf = malloc(10); + if (writebuf) { + memcpy(writebuf, "abcd", 4); + ret = glfs_write(fd_tmp, writebuf, 4, 0); + if (ret <= 0) { + ret = -1; + LOG_ERR("glfs_write", ret); + } + free(writebuf); + } else { + fprintf(stderr, "Could not allocate writebuf\n"); + return -1; + } + + /* READ on fd_tmp2 */ + ret = glfs_lseek(fd_tmp2, 0, SEEK_SET); + LOG_ERR("glfs_lseek", ret); + + memset(readbuf, 0, sizeof(readbuf)); + ret = glfs_pread(fd_tmp2, readbuf, 4, 0, 0, NULL); + + if (ret <= 0) { + ret = -1; + LOG_ERR("glfs_pread", ret); + } + + sleep(2); + } while (--cnt > 0); + + sleep(2); + + ret = 0; +err: + glfs_close(fd); + + glfs_close(fd2); + +out: + return ret; +} + +int +main(int argc, char *argv[]) +{ + glfs_t *fs = NULL; + glfs_t *fs2 = NULL; + int ret = 0, i; + char *vol_id = NULL; + unsigned int cnt = 5; + struct glfs_upcall *cbk = NULL; + char *logfile = NULL; + char *volname = NULL; + char *hostname = NULL; + int up_events = GLFS_EVENT_ANY; + + if (argc != 4) { + fprintf(stderr, "Invalid argument\n"); + exit(1); + } + + hostname = argv[1]; + volname = argv[2]; + logfile = argv[3]; + + /* Initialize fs */ + fs = glfs_new(volname); + if (!fs) { + fprintf(stderr, "glfs_new: returned NULL\n"); + return -1; + } + + ret = glfs_set_volfile_server(fs, "tcp", hostname, 24007); + LOG_ERR("glfs_set_volfile_server", ret); + + ret = glfs_set_logging(fs, logfile, 7); + LOG_ERR("glfs_set_logging", ret); + + ret = glfs_init(fs); + LOG_ERR("glfs_init", ret); + + /* Initialize fs2 */ + fs2 = glfs_new(volname); + if (!fs2) { + fprintf(stderr, "glfs_new fs2: returned NULL\n"); + return 1; + } + + ret = glfs_set_volfile_server(fs2, "tcp", hostname, 24007); + LOG_ERR("glfs_set_volfile_server-fs2", ret); + + ret = glfs_set_logging(fs2, logfile, 7); + LOG_ERR("glfs_set_logging-fs2", ret); + + ret = glfs_init(fs2); + LOG_ERR("glfs_init-fs2", ret); + + /* Register Upcalls */ + ret = glfs_upcall_register(fs, up_events, up_async_invalidate, NULL); + + /* Check if the return mask contains the event */ + if (!(ret & GLFS_EVENT_INODE_INVALIDATE)) { + fprintf(stderr, + "glfs_upcall_register return doesn't contain" + " upcall event\n"); + return -1; + } + + ret = glfs_upcall_register(fs2, up_events, up_async_invalidate, NULL); + + /* Check if the return mask contains the event */ + if ((ret < 0) || !(ret & GLFS_EVENT_INODE_INVALIDATE)) { + fprintf(stderr, + "glfs_upcall_register return doesn't contain" + " upcall event\n"); + return -1; + } + + /* Perform I/O */ + ret = perform_io(fs, fs2, cnt); + LOG_ERR("perform_io", ret); + + if (upcall_recv == 0) { + fprintf(stderr, "Upcalls are not received.\n"); + ret = -1; + } else { + fprintf(stderr, "Received %d upcalls as expected\n", upcall_recv); + ret = 0; + } + + sleep(5); /* to flush out previous upcalls if any */ + + /* Now unregister and check there are no upcall events received */ + ret = glfs_upcall_unregister(fs, up_events); + + /* Check if the return mask contains the event */ + if ((ret < 0) || !(ret & GLFS_EVENT_INODE_INVALIDATE)) { + fprintf(stderr, + "glfs_upcall_unregister return doesn't contain" + " upcall event\n"); + return -1; + } + + ret = glfs_upcall_unregister(fs2, up_events); + + /* Check if the return mask contains the event */ + if ((ret < 0) || !(ret & GLFS_EVENT_INODE_INVALIDATE)) { + fprintf(stderr, + "glfs_upcall_unregister return doesn't contain" + " upcall event\n"); + return -1; + } + + upcall_recv = 0; + + ret = perform_io(fs, fs2, cnt); + LOG_ERR("perform_io", ret); + + if (upcall_recv != 0) { + fprintf(stderr, "%d upcalls received even after unregister.\n", + upcall_recv); + ret = -1; + } else { + fprintf(stderr, + "Post unregister, no upcalls received as" + " expected\n"); + ret = 0; + } + +out: + if (fs) { + ret = glfs_fini(fs); + fprintf(stderr, "glfs_fini(fs) returned %d\n", ret); + } + + if (fs2) { + ret = glfs_fini(fs2); + fprintf(stderr, "glfs_fini(fs2) returned %d\n", ret); + } + + if (ret) + exit(1); + exit(0); +} diff --git a/tests/basic/gfapi/upcall-register-api.t b/tests/basic/gfapi/upcall-register-api.t new file mode 100755 index 00000000000..a46234ed7af --- /dev/null +++ b/tests/basic/gfapi/upcall-register-api.t @@ -0,0 +1,30 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +cleanup; + +TEST glusterd + +TEST $CLI volume create $V0 $H0:$B0/brick1; +EXPECT 'Created' volinfo_field $V0 'Status'; + +TEST $CLI volume start $V0; +EXPECT 'Started' volinfo_field $V0 'Status'; + +logdir=`gluster --print-logdir` + +## Enable Upcall cache-invalidation feature +TEST $CLI volume set $V0 features.cache-invalidation on; + +TEST build_tester $(dirname $0)/upcall-register-api.c -lgfapi + +TEST ./$(dirname $0)/upcall-register-api $H0 $V0 $logdir/upcall-register-api.log + +cleanup_tester $(dirname $0)/upcall-register-api + +TEST $CLI volume stop $V0 +TEST $CLI volume delete $V0 + +cleanup; diff --git a/tests/basic/gfid-access.t b/tests/basic/gfid-access.t new file mode 100644 index 00000000000..19b6564e676 --- /dev/null +++ b/tests/basic/gfid-access.t @@ -0,0 +1,80 @@ +#!/bin/bash + +. $(dirname $0)/../include.rc +. $(dirname $0)/../volume.rc + +cleanup; + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 $H0:$B0/${V0}0 +TEST $CLI volume start $V0 +TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0 --aux-gfid-mount; +TEST mkdir $M0/a +TEST touch $M0/b +a_gfid_str=$(gf_gfid_xattr_to_str $(gf_get_gfid_xattr $B0/${V0}0/a)) +b_gfid_str=$(gf_gfid_xattr_to_str $(gf_get_gfid_xattr $B0/${V0}0/b)) + +#Operations on Directory +TEST setfattr -n trusted.abc -v abc $M0/a +EXPECT "abc" echo $(getfattr -n trusted.abc --only-values $M0/a) +EXPECT "abc" echo $(getfattr -n trusted.abc --only-values $M0/.gfid/$a_gfid_str) +TEST setfattr -x trusted.abc $M0/a +TEST ! getfattr -n trusted.abc $M0/a +TEST ! getfattr -n trusted.abc $M0/.gfid/$a_gfid_str +TEST chmod 0777 $M0/a +EXPECT "777" stat -c "%a" $M0/a +EXPECT "777" stat -c "%a" $M0/.gfid/$a_gfid_str + +TEST setfattr -n trusted.abc -v def $M0/.gfid/$a_gfid_str +EXPECT "def" echo $(getfattr -n trusted.abc --only-values $M0/a) +EXPECT "def" echo $(getfattr -n trusted.abc --only-values $M0/.gfid/$a_gfid_str) +TEST setfattr -x trusted.abc $M0/.gfid/$a_gfid_str +TEST ! getfattr -n trusted.abc $M0/a +TEST ! getfattr -n trusted.abc $M0/.gfid/$a_gfid_str +TEST chmod 0777 $M0/.gfid/$a_gfid_str +EXPECT "777" stat -c "%a" $M0/a +EXPECT "777" stat -c "%a" $M0/.gfid/$a_gfid_str + +#Entry operations on directory +#Test that virtual directories are not allowed to be deleted. +TEST ! mkdir $M0/.gfid +TEST ! rmdir $M0/.gfid +TEST ! touch $M0/.gfid +TEST ! rm -f $M0/.gfid +TEST ! mv $M0/.gfid $M0/dont-rename +TEST ! ln -s $M0/symlink $M0/.gfid +TEST ! ln $M0/.gfid $M0/hlink +TEST ! mknod $M0/.gfid b 0 0 + +#Test that first level directory/file creations inside .gfid are not allowed. +tmpfile=$(mktemp) +TEST ! mkdir $M0/.gfid/a +TEST ! touch $M0/.gfid/a +TEST ! mv $tmpfile $M0/.gfid +TEST ! mv $M0/a $M0/.gfid +TEST ! mknod $M0/.gfid/b b 0 0 +rm -f $tmpfile + +#Operations on File +TEST setfattr -n trusted.abc -v abc $M0/b +EXPECT "abc" echo $(getfattr -n trusted.abc --only-values $M0/b) +EXPECT "abc" echo $(getfattr -n trusted.abc --only-values $M0/.gfid/$b_gfid_str) +TEST setfattr -x trusted.abc $M0/b +TEST ! getfattr -n trusted.abc $M0/b +TEST ! getfattr -n trusted.abc $M0/.gfid/$b_gfid_str +TEST chmod 0777 $M0/b +EXPECT "777" stat -c "%a" $M0/b +EXPECT "777" stat -c "%a" $M0/.gfid/$b_gfid_str + +TEST setfattr -n trusted.abc -v def $M0/.gfid/$b_gfid_str +EXPECT "def" echo $(getfattr -n trusted.abc --only-values $M0/b) +EXPECT "def" echo $(getfattr -n trusted.abc --only-values $M0/.gfid/$b_gfid_str) +TEST setfattr -x trusted.abc $M0/.gfid/$b_gfid_str +TEST ! getfattr -n trusted.abc $M0/b +TEST ! getfattr -n trusted.abc $M0/.gfid/$b_gfid_str +TEST chmod 0777 $M0/.gfid/$b_gfid_str +EXPECT "777" stat -c "%a" $M0/b +EXPECT "777" stat -c "%a" $M0/.gfid/$b_gfid_str + +cleanup diff --git a/tests/basic/gfproxy.t b/tests/basic/gfproxy.t new file mode 100755 index 00000000000..7aa8b70b793 --- /dev/null +++ b/tests/basic/gfproxy.t @@ -0,0 +1,71 @@ +#!/bin/bash + +. $(dirname $0)/../include.rc +. $(dirname $0)/../volume.rc +. $(dirname $0)/../nfs.rc + +function file_exists +{ + if [ -f $1 ]; then echo "Y"; else echo "N"; fi +} + +cleanup; + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 replica 3 $H0:$B0/${V0}{0,1,2} +TEST $CLI volume set $V0 config.gfproxyd enable +TEST $CLI volume set $V0 failover-hosts "127.0.0.1,192.168.122.215,192.168.122.90" +TEST $CLI volume set $V0 client-log-level TRACE +TEST $CLI volume start $V0 + +sleep 2 + +REGULAR_CLIENT_VOLFILE="/var/lib/glusterd/vols/${V0}/trusted-${V0}.tcp-fuse.vol" +GFPROXY_CLIENT_VOLFILE="/var/lib/glusterd/vols/${V0}/trusted-${V0}.tcp-gfproxy-fuse.vol" +GFPROXYD_VOLFILE="/var/lib/glusterd/vols/${V0}/${V0}.gfproxyd.vol" + +# Client volfile must exist +TEST [ -f $GFPROXY_CLIENT_VOLFILE ] + +# write-behind translators must exist +TEST grep "performance/write-behind" $GFPROXY_CLIENT_VOLFILE + +# Make sure we didn't screw up the existing client +TEST grep "performance/write-behind" $REGULAR_CLIENT_VOLFILE +TEST grep "cluster/replicate" $REGULAR_CLIENT_VOLFILE +TEST grep "cluster/distribute" $REGULAR_CLIENT_VOLFILE + +TEST [ -f $GFPROXYD_VOLFILE ] + +TEST grep "cluster/replicate" $GFPROXYD_VOLFILE +TEST grep "cluster/distribute" $GFPROXYD_VOLFILE + +# write-behind must *not* exist +TEST ! grep "performance/write-behind" $GFPROXYD_VOLFILE + +# Test that we can start the server and the client +TEST glusterfs --thin-client --volfile-id=patchy --volfile-server=$H0 -l /var/log/glusterfs/${V0}-gfproxy-client.log $M0 +sleep 2 +TEST grep gfproxy-client/${V0} /proc/mounts + +# Write data to the mount and checksum it +TEST dd if=/dev/urandom bs=1M count=10 of=/tmp/testfile1 +md5=$(md5sum /tmp/testfile1 | awk '{print $1}') +TEST cp -v /tmp/testfile1 $M0/testfile1 +TEST [ "$(md5sum $M0/testfile1 | awk '{print $1}')" == "$md5" ] + +rm /tmp/testfile1 + +dd if=/dev/zero of=$M0/bigfile bs=1K count=10240 & +BG_STRESS_PID=$! + +TEST wait $BG_STRESS_PID + +# Perform graph change and make sure the gfproxyd restarts +TEST $CLI volume set $V0 stat-prefetch off + +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "Y" file_exists $M0/bigfile + +cleanup; +#G_TESTDEF_TEST_STATUS_NETBSD7=1501392 diff --git a/tests/basic/global-threading.t b/tests/basic/global-threading.t new file mode 100644 index 00000000000..f7d34044b09 --- /dev/null +++ b/tests/basic/global-threading.t @@ -0,0 +1,104 @@ +#!/bin/bash + +. $(dirname $0)/../include.rc +. $(dirname $0)/../volume.rc + +# Test if the given process has a number of threads of a given type between +# min and max. +function check_threads() { + local pid="${1}" + local pattern="${2}" + local min="${3}" + local max="${4-}" + local count + + count="$(ps hH -o comm ${pid} | grep "${pattern}" | wc -l)" + if [[ ${min} -gt ${count} ]]; then + return 1 + fi + if [[ ! -z "${max}" && ${max} -lt ${count} ]]; then + return 1 + fi + + return 0 +} + +cleanup + +TEST glusterd + +# Glusterd shouldn't use any thread +TEST check_threads $(get_glusterd_pid) glfs_tpw 0 0 +TEST check_threads $(get_glusterd_pid) glfs_iotwr 0 0 + +TEST pkill -9 glusterd + +TEST glusterd --global-threading + +# Glusterd shouldn't use global threads, even if enabled +TEST check_threads $(get_glusterd_pid) glfs_tpw 0 0 +TEST check_threads $(get_glusterd_pid) glfs_iotwr 0 0 + +TEST $CLI volume create $V0 replica 2 $H0:$B0/b{0,1} + +# Normal configuration using io-threads on bricks +TEST $CLI volume set $V0 config.global-threading off +TEST $CLI volume set $V0 performance.iot-pass-through off +TEST $CLI volume set $V0 performance.client-io-threads off +TEST $CLI volume start $V0 + +# There shouldn't be global threads +TEST check_threads $(get_brick_pid $V0 $H0 $B0/b0) glfs_tpw 0 0 +TEST check_threads $(get_brick_pid $V0 $H0 $B0/b1) glfs_tpw 0 0 + +# There should be at least 1 io-thread +TEST check_threads $(get_brick_pid $V0 $H0 $B0/b0) glfs_iotwr 1 +TEST check_threads $(get_brick_pid $V0 $H0 $B0/b1) glfs_iotwr 1 + +# Self-heal should be using global threads +TEST check_threads $(get_shd_process_pid) glfs_tpw 1 +TEST check_threads $(get_shd_process_pid) glfs_iotwr 0 0 + +TEST $CLI volume stop $V0 + +# Configuration with global threads on bricks +TEST $CLI volume set $V0 config.global-threading on +TEST $CLI volume set $V0 performance.iot-pass-through on +TEST $CLI volume start $V0 + +# There should be at least 1 global thread +TEST check_threads $(get_brick_pid $V0 $H0 $B0/b0) glfs_tpw 1 +TEST check_threads $(get_brick_pid $V0 $H0 $B0/b1) glfs_tpw 1 + +# There shouldn't be any io-thread worker threads +TEST check_threads $(get_brick_pid $V0 $H0 $B0/b0) glfs_iotwr 0 0 +TEST check_threads $(get_brick_pid $V0 $H0 $B0/b1) glfs_iotwr 0 0 + +# Normal configuration using io-threads on clients +TEST $CLI volume set $V0 performance.iot-pass-through off +TEST $CLI volume set $V0 performance.client-io-threads on +TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0 + +# There shouldn't be global threads +TEST check_threads $(get_mount_process_pid $V0 $M0) glfs_tpw 0 0 + +# There should be at least 1 io-thread +TEST check_threads $(get_mount_process_pid $V0 $M0) glfs_iotwr 1 + +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 + +# Configuration with global threads on clients +TEST $CLI volume set $V0 performance.client-io-threads off +TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 --global-threading $M0 + +# There should be at least 1 global thread +TEST check_threads $(get_mount_process_pid $V0 $M0) glfs_tpw 1 + +# There shouldn't be io-threads +TEST check_threads $(get_mount_process_pid $V0 $M0) glfs_iotwr 0 0 + +# Some basic volume access checks with global-threading enabled everywhere +TEST mkdir ${M0}/dir +TEST dd if=/dev/zero of=${M0}/dir/file bs=128k count=8 + +cleanup diff --git a/tests/basic/glusterd-restart-shd-mux.t b/tests/basic/glusterd-restart-shd-mux.t new file mode 100644 index 00000000000..46d0dac2fce --- /dev/null +++ b/tests/basic/glusterd-restart-shd-mux.t @@ -0,0 +1,96 @@ +#!/bin/bash + +. $(dirname $0)/../include.rc +. $(dirname $0)/../volume.rc + +cleanup; + +TESTS_EXPECTED_IN_LOOP=20 + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 replica 3 $H0:$B0/${V0}{0,1,2,3,4,5} +TEST $CLI volume set $V0 cluster.background-self-heal-count 0 +TEST $CLI volume set $V0 cluster.eager-lock off +TEST $CLI volume set $V0 performance.flush-behind off +TEST $CLI volume start $V0 + +for i in $(seq 1 3); do + TEST $CLI volume create ${V0}_afr$i replica 3 $H0:$B0/${V0}_afr${i}{0,1,2,3,4,5} + TEST $CLI volume start ${V0}_afr$i + TEST $CLI volume create ${V0}_ec$i disperse 6 redundancy 2 $H0:$B0/${V0}_ec${i}{0,1,2,3,4,5} + TEST $CLI volume start ${V0}_ec$i +done + +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "^1$" shd_count + +#Stop the glusterd +TEST pkill glusterd +#Only stopping glusterd, so there will be one shd +EXPECT_WITHIN $PROCESS_DOWN_TIMEOUT "^1$" shd_count +TEST glusterd +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "^1$" shd_count +#Check the thread count become to number of volumes*number of ec subvolume (3*6=18) +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "^18$" number_healer_threads_shd $V0 "ec_shd_index_healer" +#Check the thread count become to number of volumes*number of afr subvolume (4*6=24) +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "^24$" number_healer_threads_shd $V0 "afr_shd_index_healer" + +shd_pid=$(get_shd_mux_pid $V0) +for i in $(seq 1 3); do + afr_path="/var/run/gluster/shd/${V0}_afr$i/${V0}_afr$i-shd.pid" + EXPECT_WITHIN $PROCESS_UP_TIMEOUT "^${shd_pid}$" cat $afr_path + ec_path="/var/run/gluster/shd/${V0}_ec$i/${V0}_ec${i}-shd.pid" + EXPECT_WITHIN $PROCESS_UP_TIMEOUT "^${shd_pid}$" cat $ec_path +done + +#Reboot a node scenario +TEST pkill gluster +#Only stopped glusterd, so there will be one shd +EXPECT_WITHIN $PROCESS_DOWN_TIMEOUT "^0$" shd_count + +TEST glusterd +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "^1$" shd_count + +#Check the thread count become to number of volumes*number of ec subvolume (3*6=18) +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "^18$" number_healer_threads_shd $V0 "ec_shd_index_healer" +#Check the thread count become to number of volumes*number of afr subvolume (4*6=24) +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "^24$" number_healer_threads_shd $V0 "afr_shd_index_healer" + +shd_pid=$(get_shd_mux_pid $V0) +for i in $(seq 1 3); do + afr_path="/var/run/gluster/shd/${V0}_afr$i/${V0}_afr$i-shd.pid" + EXPECT_WITHIN $PROCESS_UP_TIMEOUT "^${shd_pid}$" cat $afr_path + ec_path="/var/run/gluster/shd/${V0}_ec$i/${V0}_ec${i}-shd.pid" + EXPECT_WITHIN $PROCESS_UP_TIMEOUT "^${shd_pid}$" cat $ec_path +done + +for i in $(seq 1 3); do + TEST $CLI volume stop ${V0}_afr$i + TEST $CLI volume stop ${V0}_ec$i +done + +EXPECT_WITHIN $PROCESS_DOWN_TIMEOUT "^6$" number_healer_threads_shd $V0 "afr_shd_index_healer" + +TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0 + +TEST kill_brick $V0 $H0 $B0/${V0}0 +TEST kill_brick $V0 $H0 $B0/${V0}3 + +TEST touch $M0/foo{1..100} + +EXPECT_WITHIN $HEAL_TIMEOUT "^204$" get_pending_heal_count $V0 + +TEST $CLI volume start ${V0} force + +EXPECT_WITHIN $HEAL_TIMEOUT "^0$" get_pending_heal_count $V0 + +TEST rm -rf $M0/* +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 + + +TEST $CLI volume stop ${V0} +TEST $CLI volume delete ${V0} + +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "^0$" shd_count + +cleanup diff --git a/tests/basic/glusterd/arbiter-volume-probe.t b/tests/basic/glusterd/arbiter-volume-probe.t new file mode 100644 index 00000000000..cb05f4ada42 --- /dev/null +++ b/tests/basic/glusterd/arbiter-volume-probe.t @@ -0,0 +1,25 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../cluster.rc + +#This tests if the arbiter-count is transferred to the other peer. +function check_peers { + $CLI_1 peer status | grep 'Peer in Cluster (Connected)' | wc -l +} + +cleanup; + +TEST launch_cluster 2; +TEST $CLI_1 peer probe $H2; + +EXPECT_WITHIN $PROBE_TIMEOUT 1 check_peers + +kill_glusterd 2 +$CLI_1 volume create $V0 replica 3 arbiter 1 $H0:$B0/b{1..3} +TEST $glusterd_2 +EXPECT_WITHIN $PROBE_TIMEOUT 1 check_peers +EXPECT "1 x \(2 \+ 1\) = 3" volinfo_field_1 $V0 "Number of Bricks" +EXPECT "1 x \(2 \+ 1\) = 3" volinfo_field_2 $V0 "Number of Bricks" + +cleanup; diff --git a/tests/basic/glusterd/check-cloudsync-ancestry.t b/tests/basic/glusterd/check-cloudsync-ancestry.t new file mode 100644 index 00000000000..ff6ffee8db7 --- /dev/null +++ b/tests/basic/glusterd/check-cloudsync-ancestry.t @@ -0,0 +1,48 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +# When shard and cloudsync xlators enabled on a volume, shard xlator +# should be an ancestor of cloudsync. This testcase is to check this condition. + +cleanup; +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 $H0:$B0/b1 $H0:$B0/b2 $H0:$B0/b3 + +volfile=$(gluster system:: getwd)"/vols/$V0/trusted-$V0.tcp-fuse.vol" + +#Test that both shard and cloudsync are not loaded +EXPECT "N" volgen_volume_exists $volfile $V0-shard features shard +EXPECT "N" volgen_volume_exists $volfile $V0-cloudsync features cloudsync + +#Enable shard and cloudsync in that order and check if volfile is correct +TEST $CLI volume set $V0 shard on +TEST $CLI volume set $V0 cloudsync on + +#Test that both shard and cloudsync are loaded +EXPECT "Y" volgen_volume_exists $volfile $V0-shard features shard +EXPECT "Y" volgen_volume_exists $volfile $V0-cloudsync features cloudsync + +EXPECT "Y" volgen_check_ancestry $volfile features shard features cloudsync + +#Disable shard and cloudsync +TEST $CLI volume set $V0 shard off +TEST $CLI volume set $V0 cloudsync off + +#Test that both shard and cloudsync are not loaded +EXPECT "N" volgen_volume_exists $volfile $V0-shard features shard +EXPECT "N" volgen_volume_exists $volfile $V0-cloudsync features cloudsync + +#Enable cloudsync and shard in that order and check if volfile is correct +TEST $CLI volume set $V0 cloudsync on +TEST $CLI volume set $V0 shard on + +#Test that both shard and cloudsync are loaded +EXPECT "Y" volgen_volume_exists $volfile $V0-shard features shard +EXPECT "Y" volgen_volume_exists $volfile $V0-cloudsync features cloudsync + +EXPECT "Y" volgen_check_ancestry $volfile features shard features cloudsync + +cleanup; diff --git a/tests/basic/glusterd/disperse-create.t b/tests/basic/glusterd/disperse-create.t new file mode 100644 index 00000000000..db8a621d48e --- /dev/null +++ b/tests/basic/glusterd/disperse-create.t @@ -0,0 +1,73 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +# This command tests the volume create command validation for disperse volumes. + +cleanup; +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 disperse $H0:$B0/b1 $H0:$B0/b2 $H0:$B0/b3 +EXPECT "1 x \(2 \+ 1\) = 3" volinfo_field $V0 "Number of Bricks" + +TEST $CLI volume delete $V0 +TEST $CLI volume create $V0 disperse 3 $H0:$B0/b4 $H0:$B0/b5 $H0:$B0/b6 +EXPECT "1 x \(2 \+ 1\) = 3" volinfo_field $V0 "Number of Bricks" + +TEST $CLI volume delete $V0 +TEST $CLI volume create $V0 disperse 3 redundancy 1 $H0:$B0/b7 $H0:$B0/b8 $H0:$B0/b9 +EXPECT "1 x \(2 \+ 1\) = 3" volinfo_field $V0 "Number of Bricks" + +TEST $CLI volume delete $V0 +TEST $CLI volume create $V0 disperse-data 2 $H0:$B0/b10 $H0:$B0/b11 $H0:$B0/b12 +EXPECT "1 x \(2 \+ 1\) = 3" volinfo_field $V0 "Number of Bricks" + +TEST $CLI volume delete $V0 +TEST $CLI volume create $V0 redundancy 1 $H0:$B0/b10 $H0:$B0/b11 $H0:$B0/b12 +EXPECT "1 x \(2 \+ 1\) = 3" volinfo_field $V0 "Number of Bricks" + +TEST $CLI volume delete $V0 +TEST $CLI volume create $V0 disperse-data 2 redundancy 1 $H0:$B0/b11 $H0:$B0/b12 $H0:$B0/b13 +EXPECT "1 x \(2 \+ 1\) = 3" volinfo_field $V0 "Number of Bricks" + +TEST $CLI volume delete $V0 +TEST $CLI volume create $V0 disperse-data 2 redundancy 1 $H0:$B0/b11 $H0:$B0/b12 $H0:$B0/b13 +EXPECT "1 x \(2 \+ 1\) = 3" volinfo_field $V0 "Number of Bricks" + +TEST $CLI volume delete $V0 +TEST $CLI volume create $V0 disperse 3 disperse-data 2 $H0:$B0/b14 $H0:$B0/b15 $H0:$B0/b16 +EXPECT "1 x \(2 \+ 1\) = 3" volinfo_field $V0 "Number of Bricks" + +TEST $CLI volume delete $V0 +TEST $CLI volume create $V0 disperse 3 disperse-data 2 redundancy 1 $H0:$B0/b17 $H0:$B0/b18 $H0:$B0/b19 +EXPECT "1 x \(2 \+ 1\) = 3" volinfo_field $V0 "Number of Bricks" + +# -ve test cases +#Key-words appearing more than once +TEST ! $CLI volume create $V0 disperse 3 disperse 3 $H0:$B0/b20 $H0:$B0/b21 $H0:$B0/b22 +TEST ! $CLI volume create $V0 disperse-data 2 disperse-data 2 $H0:$B0/b20 $H0:$B0/b21 $H0:$B0/b22 +TEST ! $CLI volume create $V0 redundancy 1 redundancy 1 $H0:$B0/b20 $H0:$B0/b21 $H0:$B0/b22 + +#Minimum counts test +TEST ! $CLI volume create $V0 disperse 2 $H0:$B0/b20 $H0:$B0/b22 +TEST ! $CLI volume create $V0 disperse-data 1 redundancy 0 $H0:$B0/b20 $H0:$B0/b22 +TEST ! $CLI volume create $V0 disperse 4 disperse-data 4 $H0:$B0/b20 $H0:$B0/b21 $H0:$B0/b23 $H0:$B0/b24 +TEST ! $CLI volume create $V0 redundancy 0 $H0:$B0/b20 $H0:$B0/b22 + +#Wrong count n != k+m +TEST ! $CLI volume create $V0 disperse 4 disperse-data 4 redundancy 2 $H0:$B0/b20 $H0:$B0/b21 $H0:$B0/b22 +#Num bricks is not multiple of disperse count +TEST ! $CLI volume create $V0 disperse 6 disperse-data 4 $H0:$B0/b20 $H0:$B0/b21 $H0:$B0/b22 +#Redundancy > data +TEST ! $CLI volume create $V0 disperse 6 disperse-data 2 redundancy 4 $H0:$B0/b20 $H0:$B0/b21 $H0:$B0/b22 +TEST ! $CLI volume create $V0 disperse 4 disperse-data 2 redundancy 2 $H0:$B0/b20 $H0:$B0/b21 $H0:$B0/b22 +#Replica + Disperse +TEST ! $CLI volume create $V0 disperse 4 replica 2 $H0:$B0/b20 $H0:$B0/b21 $H0:$B0/b22 +TEST ! $CLI volume create $V0 disperse-data 2 replica 2 $H0:$B0/b20 $H0:$B0/b21 $H0:$B0/b22 $H0:$B0/b23 +TEST ! $CLI volume create $V0 redundancy 2 replica 2 $H0:$B0/b20 $H0:$B0/b21 $H0:$B0/b22 +TEST ! $CLI volume create $V0 replica 2 disperse 4 $H0:$B0/b20 $H0:$B0/b21 $H0:$B0/b22 +TEST ! $CLI volume create $V0 replica 2 disperse-data 2 $H0:$B0/b20 $H0:$B0/b21 $H0:$B0/b22 $H0:$B0/b23 +TEST ! $CLI volume create $V0 replica 2 redundancy 2 $H0:$B0/b20 $H0:$B0/b21 $H0:$B0/b22 + +cleanup diff --git a/tests/basic/glusterd/heald.t b/tests/basic/glusterd/heald.t new file mode 100644 index 00000000000..7dae3c3f0fb --- /dev/null +++ b/tests/basic/glusterd/heald.t @@ -0,0 +1,92 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +# This test contains volume heal commands handled by glusterd. +# Covers enable/disable at the moment. Will be enhanced later to include +# the other commands as well. + +function is_pid_running { + local pid=$1 + num=`ps auxww | grep glustershd | grep $pid | grep -v grep | wc -l` + echo $num +} + +cleanup; +TEST glusterd +TEST pidof glusterd + +#Commands should fail when volume doesn't exist +TEST ! $CLI volume heal non-existent-volume enable +TEST ! $CLI volume heal non-existent-volume disable + +# Glustershd shouldn't be running as long as there are no replicate/disperse +# volumes +TEST $CLI volume create dist $H0:$B0/dist +TEST $CLI volume start dist +TEST "[ -z $(get_shd_process_pid dist)]" +TEST ! $CLI volume heal dist enable +TEST ! $CLI volume heal dist disable + +# Commands should work on replicate/disperse volume. +TEST $CLI volume create r2 replica 2 $H0:$B0/r2_0 $H0:$B0/r2_1 +TEST "[ -z $(get_shd_process_pid r2)]" +TEST $CLI volume start r2 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "[0-9][0-9]*" get_shd_process_pid r2 +TEST $CLI volume heal r2 enable +EXPECT "enable" volume_option r2 "cluster.self-heal-daemon" +volfiler2=$(gluster system:: getwd)"/vols/r2/r2-shd.vol" +EXPECT "enable" volgen_volume_option $volfiler2 r2-replicate-0 cluster replicate self-heal-daemon +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "[0-9][0-9]*" get_shd_process_pid r2 +pid=$( get_shd_process_pid r2 ) +TEST $CLI volume heal r2 disable +EXPECT "disable" volume_option r2 "cluster.self-heal-daemon" +EXPECT "disable" volgen_volume_option $volfiler2 r2-replicate-0 cluster replicate self-heal-daemon +EXPECT "1" is_pid_running $pid + +# Commands should work on disperse volume. +TEST $CLI volume create ec2 disperse 3 redundancy 1 $H0:$B0/ec2_0 $H0:$B0/ec2_1 $H0:$B0/ec2_2 +TEST $CLI volume start ec2 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "[0-9][0-9]*" get_shd_process_pid ec2 +TEST $CLI volume heal ec2 enable +EXPECT "enable" volume_option ec2 "cluster.disperse-self-heal-daemon" +volfileec2=$(gluster system:: getwd)"/vols/ec2/ec2-shd.vol" +EXPECT "enable" volgen_volume_option $volfileec2 ec2-disperse-0 cluster disperse self-heal-daemon +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "[0-9][0-9]*" get_shd_process_pid ec2 +pid=$(get_shd_process_pid ec2) +TEST $CLI volume heal ec2 disable +EXPECT "disable" volume_option ec2 "cluster.disperse-self-heal-daemon" +EXPECT "disable" volgen_volume_option $volfileec2 ec2-disperse-0 cluster disperse self-heal-daemon +EXPECT "1" is_pid_running $pid + +#Check that shd graph is rewritten correctly on volume stop/start +EXPECT "Y" volgen_volume_exists $volfileec2 ec2-disperse-0 cluster disperse + +EXPECT "Y" volgen_volume_exists $volfiler2 r2-replicate-0 cluster replicate +TEST $CLI volume stop r2 +EXPECT "Y" volgen_volume_exists $volfileec2 ec2-disperse-0 cluster disperse +TEST $CLI volume stop ec2 +# When both the volumes are stopped glustershd volfile is not modified just the +# process is stopped +TEST "[ -z $(get_shd_process_pid dist) ]" +TEST "[ -z $(get_shd_process_pid ec2) ]" + +TEST $CLI volume start r2 +EXPECT "Y" volgen_volume_exists $volfiler2 r2-replicate-0 cluster replicate + +TEST $CLI volume set r2 self-heal-daemon on +TEST $CLI volume set r2 cluster.self-heal-daemon off +TEST ! $CLI volume set ec2 self-heal-daemon off +TEST ! $CLI volume set ec2 cluster.self-heal-daemon on +TEST ! $CLI volume set dist self-heal-daemon off +TEST ! $CLI volume set dist cluster.self-heal-daemon on + +TEST $CLI volume set ec2 disperse-self-heal-daemon off +TEST $CLI volume set ec2 cluster.disperse-self-heal-daemon on +TEST ! $CLI volume set r2 disperse-self-heal-daemon on +TEST ! $CLI volume set r2 cluster.disperse-self-heal-daemon off +TEST ! $CLI volume set dist disperse-self-heal-daemon off +TEST ! $CLI volume set dist cluster.disperse-self-heal-daemon on + +cleanup diff --git a/tests/basic/glusterd/thin-arbiter-volume-probe.t b/tests/basic/glusterd/thin-arbiter-volume-probe.t new file mode 100644 index 00000000000..acc6943806d --- /dev/null +++ b/tests/basic/glusterd/thin-arbiter-volume-probe.t @@ -0,0 +1,25 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../cluster.rc + +#This tests if the thin-arbiter-count is transferred to the other peer. +function check_peers { + $CLI_1 peer status | grep 'Peer in Cluster (Connected)' | wc -l +} + +cleanup; + +TEST launch_cluster 2; +TEST $CLI_1 peer probe $H2; + +EXPECT_WITHIN $PROBE_TIMEOUT 1 check_peers + +kill_glusterd 2 +$CLI_1 volume create $V0 replica 2 thin-arbiter 1 $H0:$B0/b{1..3} +TEST $glusterd_2 +EXPECT_WITHIN $PROBE_TIMEOUT 1 check_peers +EXPECT "1 x 2 = 2" volinfo_field_1 $V0 "Number of Bricks" +EXPECT "1 x 2 = 2" volinfo_field_2 $V0 "Number of Bricks" + +cleanup; diff --git a/tests/basic/glusterd/thin-arbiter-volume.t b/tests/basic/glusterd/thin-arbiter-volume.t new file mode 100644 index 00000000000..4e813890a45 --- /dev/null +++ b/tests/basic/glusterd/thin-arbiter-volume.t @@ -0,0 +1,45 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../ volume.rc +. $(dirname $0)/../../thin-arbiter.rc + +#This command tests the volume create command validation for thin-arbiter volumes. + +cleanup; + +TEST glusterd +TEST pidof glusterd + +TEST $CLI volume create $V0 replica 2 thin-arbiter 1 $H0:$B0/b1 $H0:$B0/b2 $H0:$B0/b3 +EXPECT "1 x 2 = 2" volinfo_field $V0 "Number of Bricks" +TEST $CLI volume start $V0 + +TEST $GFS --volfile-id=$V0 --volfile-server=$H0 $M0; + +TEST touch $M0/a.txt +TEST ls $B0/b1/a.txt +TEST ls $B0/b2/a.txt +TEST ! ls $B0/b3/a.txt + +TEST umount $M0 +TEST $CLI volume stop $V0 +TEST $CLI volume delete $V0 + +TEST $CLI volume create $V0 replica 2 thin-arbiter 1 $H0:$B0/b{4..8} +EXPECT "2 x 2 = 4" volinfo_field $V0 "Number of Bricks" + +TEST $CLI volume delete $V0 + +TEST rm -rf $B0/b{1..3} + +TEST $CLI volume create $V0 replica 2 thin-arbiter 1 $H0:$B0/b1 $H0:$B0/b2 $H0:$B0/b3 +EXPECT "1 x 2 = 2" volinfo_field $V0 "Number of Bricks" + +TEST killall -15 glusterd +TEST glusterd +TEST pidof glusterd +EXPECT "1 x 2 = 2" volinfo_field $V0 "Number of Bricks" + +cleanup + diff --git a/tests/basic/glusterd/volfile_server_switch.t b/tests/basic/glusterd/volfile_server_switch.t new file mode 100644 index 00000000000..e11cfed509a --- /dev/null +++ b/tests/basic/glusterd/volfile_server_switch.t @@ -0,0 +1,46 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc +. $(dirname $0)/../../cluster.rc + + +cleanup; + +# * How this test works ? +# 1. create a 3 node cluster +# 2. add them to trusted pool +# 3. create a volume and start +# 4. mount the volume with all 3 backup-volfile servers +# 5. kill glusterd in node 1 +# 6. make changes to volume using node 2, using 'volume set' here +# 7. check whether those notifications are received by client + +TEST launch_cluster 3; + +TEST $CLI_1 peer probe $H2; +EXPECT_WITHIN $PROBE_TIMEOUT 1 peer_count + +TEST $CLI_1 peer probe $H3; +EXPECT_WITHIN $PROBE_TIMEOUT 2 peer_count + +TEST $CLI_1 volume create $V0 $H1:$B1/$V0 $H2:$B2/$V0 $H3:$B3/$V0 + +TEST $CLI_1 volume start $V0 + +TEST $CLI_1 volume status $V0; + +TEST glusterfs --volfile-id=/$V0 --volfile-server=$H1 --volfile-server=$H2 --volfile-server=$H3 $M0 + +TEST kill_glusterd 1 + +TEST $CLI_2 volume set $V0 performance.write-behind off + +# make sure by this time directory will be created +# TODO: suggest ideal time to wait +sleep 5 + +count=$(find $M0/.meta/graphs/* -maxdepth 0 -type d -iname "*" | wc -l) +TEST [ "$count" -gt "1" ] + +cleanup; diff --git a/tests/basic/glusterd/volume-brick-count.t b/tests/basic/glusterd/volume-brick-count.t new file mode 100644 index 00000000000..dc1a5278f4f --- /dev/null +++ b/tests/basic/glusterd/volume-brick-count.t @@ -0,0 +1,61 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +function test_volume_config() +{ + volname=$1 + type_string=$2 + brickCount=$3 + distCount=$4 + replicaCount=$5 + arbiterCount=$6 + disperseCount=$7 + redundancyCount=$8 + + EXPECT "$type_string" volinfo_field $volname "Number of Bricks" + EXPECT "$brickCount" get-xml "volume info $volname" "brickCount" + EXPECT "$distCount" get-xml "volume info $volname" "distCount" + EXPECT "$replicaCount" get-xml "volume info $volname" "replicaCount" + EXPECT "$arbiterCount" get-xml "volume info $volname" "arbiterCount" + EXPECT "$disperseCount" get-xml "volume info $volname" "disperseCount" + EXPECT "$redundancyCount" get-xml "volume info $volname" "redundancyCount" +} + +# This command tests the volume create command and number of bricks for different volume types. +cleanup; +TESTS_EXPECTED_IN_LOOP=56 +TEST glusterd +TEST pidof glusterd + +TEST $CLI volume create ${V0}_1 replica 3 arbiter 1 $H0:$B0/b1 $H0:$B0/b2 $H0:$B0/b3 +test_volume_config "${V0}_1" "1 x \(2 \+ 1\) = 3" "3" "1" "3" "1" "0" "0" + +TEST $CLI volume create ${V0}_2 replica 3 arbiter 1 $H0:$B0/b{4..9} +test_volume_config "${V0}_2" "2 x \(2 \+ 1\) = 6" "6" "2" "3" "1" "0" "0" + + +TEST $CLI volume create ${V0}_3 replica 3 arbiter 1 $H0:$B0/b{10..12} +test_volume_config "${V0}_3" "1 x \(2 \+ 1\) = 3" "3" "1" "3" "1" "0" "0" +TEST killall -15 glusterd +TEST glusterd +TEST pidof glusterd +test_volume_config "${V0}_3" "1 x \(2 \+ 1\) = 3" "3" "1" "3" "1" "0" "0" + +TEST $CLI volume create ${V0}_4 replica 3 $H0:$B0/b{13..15} +test_volume_config "${V0}_4" "1 x 3 = 3" "3" "1" "3" "0" "0" "0" + +TEST $CLI volume create ${V0}_5 replica 3 $H0:$B0/b{16..21} +test_volume_config "${V0}_5" "2 x 3 = 6" "6" "2" "3" "0" "0" "0" + +TEST $CLI volume create ${V0}_6 disperse 3 redundancy 1 $H0:$B0/b{22..24} +test_volume_config "${V0}_6" "1 x \(2 \+ 1\) = 3" "3" "1" "1" "0" "3" "1" + +TEST $CLI volume create ${V0}_7 disperse 3 redundancy 1 $H0:$B0/b{25..30} +test_volume_config "${V0}_7" "2 x \(2 \+ 1\) = 6" "6" "2" "1" "0" "3" "1" + +TEST $CLI volume create ${V0}_8 $H0:$B0/b{31..33} +test_volume_config "${V0}_8" "3" "3" "3" "1" "0" "0" "0" + +cleanup diff --git a/tests/basic/glusterfsd-args.t b/tests/basic/glusterfsd-args.t new file mode 100644 index 00000000000..2dd84b8c29e --- /dev/null +++ b/tests/basic/glusterfsd-args.t @@ -0,0 +1,5 @@ +#!/bin/bash + +. $(dirname $0)/../include.rc + +EXPECT $GLUSTER_LIBEXECDIR glusterfsd --print-libexecdir diff --git a/tests/basic/graph-cleanup-brick-down-shd-mux.t b/tests/basic/graph-cleanup-brick-down-shd-mux.t new file mode 100644 index 00000000000..3c621cdcc26 --- /dev/null +++ b/tests/basic/graph-cleanup-brick-down-shd-mux.t @@ -0,0 +1,64 @@ +#!/bin/bash + +. $(dirname $0)/../include.rc +. $(dirname $0)/../volume.rc + +cleanup; + +TESTS_EXPECTED_IN_LOOP=4 + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 replica 3 $H0:$B0/${V0}{0,1,2,3,4,5} +TEST $CLI volume set $V0 cluster.background-self-heal-count 0 +TEST $CLI volume set $V0 cluster.eager-lock off +TEST $CLI volume set $V0 performance.flush-behind off +TEST $CLI volume start $V0 + +for i in $(seq 1 2); do + TEST $CLI volume create ${V0}_afr$i replica 3 $H0:$B0/${V0}_afr${i}{0,1,2,3,4,5} + TEST $CLI volume start ${V0}_afr$i + TEST $CLI volume create ${V0}_ec$i disperse 6 redundancy 2 $H0:$B0/${V0}_ec${i}{0,1,2,3,4,5} + TEST $CLI volume start ${V0}_ec$i +done + +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "^1$" shd_count +#Check the thread count become to number of volumes*number of ec subvolume (2*6=12) +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "^12$" number_healer_threads_shd $V0 "ec_shd_index_healer" +#Check the thread count become to number of volumes*number of afr subvolume (3*6=18) +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "^18$" number_healer_threads_shd $V0 "afr_shd_index_healer" + +#kill one brick and test cleanup +TEST kill_brick $V0 $H0 $B0/${V0}0 +TEST $CLI volume stop $V0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "^12$" number_healer_threads_shd ${V0}_afr1 "afr_shd_index_healer" +TEST $CLI volume start $V0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "^18$" number_healer_threads_shd ${V0}_afr1 "afr_shd_index_healer" + +#kill an entire subvol and test cleanup +TEST kill_brick $V0 $H0 $B0/${V0}0 +TEST kill_brick $V0 $H0 $B0/${V0}1 +TEST kill_brick $V0 $H0 $B0/${V0}2 +#wait for some time to create a race sceanrio +sleep 1 +TEST $CLI volume stop $V0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "^12$" number_healer_threads_shd ${V0}_afr1 "afr_shd_index_healer" +TEST $CLI volume start $V0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "^18$" number_healer_threads_shd ${V0}_afr1 "afr_shd_index_healer" + +#kill all bricks and test cleanup +TEST kill_brick $V0 $H0 $B0/${V0}0 +TEST kill_brick $V0 $H0 $B0/${V0}1 +TEST kill_brick $V0 $H0 $B0/${V0}2 +TEST kill_brick $V0 $H0 $B0/${V0}3 +TEST kill_brick $V0 $H0 $B0/${V0}4 +TEST kill_brick $V0 $H0 $B0/${V0}5 +#wait for some time to create a race sceanrio +sleep 2 + +TEST $CLI volume stop $V0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "^12$" number_healer_threads_shd ${V0}_afr1 "afr_shd_index_healer" +TEST $CLI volume start $V0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "^18$" number_healer_threads_shd ${V0}_afr1 "afr_shd_index_healer" + +cleanup diff --git a/tests/basic/hardlink-limit.t b/tests/basic/hardlink-limit.t new file mode 100644 index 00000000000..ee65c650b59 --- /dev/null +++ b/tests/basic/hardlink-limit.t @@ -0,0 +1,44 @@ +#!/bin/bash + +. $(dirname $0)/../include.rc +. $(dirname $0)/../volume.rc +. $(dirname $0)/../dht.rc + +cleanup; + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume info; + +TEST $CLI volume create $V0 replica 3 $H0:$B0/${V0}{1,2,3,4,5,6}; + +EXPECT "$V0" volinfo_field $V0 'Volume Name'; +EXPECT 'Created' volinfo_field $V0 'Status'; +EXPECT '6' brick_count $V0 + +TEST $CLI volume start $V0; +EXPECT 'Started' volinfo_field $V0 'Status'; +TEST $CLI volume set $V0 storage.max-hardlinks 3 +TEST glusterfs -s $H0 --volfile-id $V0 $M0; + +TEST dd if=/dev/zero of=$M0/testfile count=1 + +# max-hardlinks is 3, should be able to create 2 links. +TEST link $M0/testfile $M0/testfile.link1 +TEST link $M0/testfile $M0/testfile.link2 + +# But not 3. +TEST ! link $M0/testfile $M0/testfile.link3 +# If we remove one... +TEST rm $M0/testfile.link1 +# Now we can add one. +TEST link $M0/testfile $M0/testfile.link3 + +# But not another +TEST ! link $M0/testfile $M0/testfile.link4 + +# Unless we disable the limit... +TEST $CLI volume set $V0 storage.max-hardlinks 0 +TEST link $M0/testfile $M0/testfile.link4 + +cleanup; diff --git a/tests/basic/inode-leak.t b/tests/basic/inode-leak.t new file mode 100644 index 00000000000..e112fdddf8a --- /dev/null +++ b/tests/basic/inode-leak.t @@ -0,0 +1,31 @@ +#!/bin/bash + +. $(dirname $0)/../include.rc +. $(dirname $0)/../volume.rc + +cleanup + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 replica 2 $H0:$B0/${V0}{0,1,2,3} +TEST $CLI volume start $V0 +TEST glusterfs -s $H0 --volfile-id $V0 $M0 + +EXPECT "1" get_mount_active_size_value $V0 $M0 +EXPECT "0" get_mount_lru_size_value $V0 $M0 + +TEST cp -rf /etc $M0 +TEST find $M0 +TEST rm -rf $M0/* + +EXPECT "1" get_mount_active_size_value $V0 $M0 +EXPECT "0" get_mount_lru_size_value $V0 $M0 + +cleanup + +# Mainly marking it as known-issue as it is taking a *lot* of time. +# Revert back if we are below an hour in regression runs. +# Or consider running only in nightly regressions. + +#G_TESTDEF_TEST_STATUS_NETBSD7=KNOWN_ISSUE,BUG=000000 +#G_TESTDEF_TEST_STATUS_CENTOS6=KNOWN_ISSUE,BUG=000000 diff --git a/tests/basic/inode-quota-enforcing.t b/tests/basic/inode-quota-enforcing.t new file mode 100644 index 00000000000..d666395dab1 --- /dev/null +++ b/tests/basic/inode-quota-enforcing.t @@ -0,0 +1,100 @@ +#!/bin/bash + +. $(dirname $0)/../include.rc +. $(dirname $0)/../volume.rc +. $(dirname $0)/../nfs.rc + +cleanup; + +QDD=$(dirname $0)/quota +# compile the test write program and run it +build_tester $(dirname $0)/quota.c -o $QDD + +TESTS_EXPECTED_IN_LOOP=9 + +TEST glusterd + +# -------------------------------------------------- +# Create, start and mount a volume with single brick +# -------------------------------------------------- + +TEST $CLI volume create $V0 replica 2 $H0:$B0/${V0}{1,2}; + +TEST $CLI volume start $V0 + +TEST $GFS -s $H0 --volfile-id $V0 $M0 +TEST mkdir -p $M0/test_dir + +#-------------------------------------------------------- +# Enable quota of the volume and set hard and soft timeout +#------------------------------------------------------ + +TEST $CLI volume quota $V0 enable +EXPECT 'on' volinfo_field $V0 'features.quota' +TEST $CLI volume quota $V0 soft-timeout 0 +EXPECT '0' volinfo_field $V0 'features.soft-timeout' +TEST $CLI volume quota $V0 hard-timeout 0 +EXPECT '0' volinfo_field $V0 'features.hard-timeout' + +#------------------------------------------------------- +# Set quota limits on the directory and +# verify if the limits are being reflected properly +#------------------------------------------------------ + +TEST $CLI volume quota $V0 limit-objects /test_dir 10 +EXPECT "10" quota_object_list_field "/test_dir" 2 + +TEST $CLI volume quota $V0 limit-usage /test_dir 100MB +EXPECT "100.0MB" quota_list_field "/test_dir" 2 + +#------------------------------------------------------ +# Check the quota enforcement mechanism for object count +#------------------------------------------------------- + +# Try creating 9 files and it should succeed as object limit +# is set to 10, since directory where limit is set is accounted +# as well. + +for i in {1..9}; do + #TEST_IN_LOOP touch $M0/test_dir/test$i.txt + TEST_IN_LOOP $QDD $M0/test_dir/test$i.txt 256 4 +done +EXPECT_WITHIN $MARKER_UPDATE_TIMEOUT "9" quota_object_list_field "/test_dir" 4 +EXPECT_WITHIN $MARKER_UPDATE_TIMEOUT "9.0MB" quotausage "/test_dir" + +# Check available limit +EXPECT_WITHIN $MARKER_UPDATE_TIMEOUT "0" quota_object_list_field "/test_dir" 6 +EXPECT_WITHIN $MARKER_UPDATE_TIMEOUT "91.0MB" quota_list_field "/test_dir" 5 + +# Check if hard-limit exceeded +EXPECT "Yes" quota_object_list_field "/test_dir" 8 + +# Check if soft-limit exceeded +EXPECT "Yes" quota_object_list_field "/test_dir" 7 + +# Creation of 11th file should throw out an error +TEST ! touch $M0/test_dir/test11.txt + +#------------------------------------------------------- +# remove quota limits on the directory and +# verify if the limit show 'N/A' and displayes only the usage +#------------------------------------------------------ +TEST $CLI volume quota $V0 remove-objects /test_dir +EXPECT "N/A" quota_object_list_field "/test_dir" 2 +EXPECT "9" quota_object_list_field "/test_dir" 4 + +TEST $CLI volume quota $V0 remove /test_dir +EXPECT "N/A" quota_list_field "/test_dir" 2 +EXPECT "9.0MB" quotausage "/test_dir" 4 + +# Set back the limits +TEST $CLI volume quota $V0 limit-objects /test_dir 10 +EXPECT "10" quota_object_list_field "/test_dir" 2 + +# Remove all files and verify the file count +TEST rm -rf $M0/test_dir/test* +EXPECT_WITHIN $MARKER_UPDATE_TIMEOUT "0" quota_object_list_field "/test_dir" 4 + +rm -f $QDD +cleanup; +#G_TESTDEF_TEST_STATUS_NETBSD7=BAD_TEST,BUG=1332021 diff --git a/tests/basic/ios-dump.t b/tests/basic/ios-dump.t new file mode 100644 index 00000000000..0cfbdc6ae7c --- /dev/null +++ b/tests/basic/ios-dump.t @@ -0,0 +1,43 @@ +#!/bin/bash + +. $(dirname $0)/../include.rc +. $(dirname $0)/../volume.rc + +cleanup; + +function check_brick_inter_stats() { + local counter="$1" + local inter_cnt="" + + inter_cnt=$(grep -h "\".*inter.*$counter\"" \ + /var/lib/glusterd/stats/glusterfsd*.dump 2>/dev/null | + grep -v '\"0.0000\"' | wc -l) + if (( $inter_cnt == 3 )); then + echo "Y" + else + echo "N" + fi +} + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 replica 3 $H0:$B0/${V0}{0,1,2} +TEST $CLI volume set $V0 diagnostics.stats-dump-interval 5 +TEST $CLI volume set $V0 diagnostics.count-fop-hits on +TEST $CLI volume set $V0 diagnostics.latency-measurement on +TEST $CLI volume start $V0 +TEST glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0 --attribute-timeout=0 --entry-timeout=0 + +# Generate some FOPs +cd $M0 +for i in {1..10}; do + mkdir a + cd a + for g in {1..10}; do + dd if=/dev/zero of=test$g bs=128k count=1 + done +done + +EXPECT_WITHIN 30 "Y" check_brick_inter_stats fop.weighted_latency_ave_usec + +cleanup diff --git a/tests/basic/jbr/jbr-volgen.t b/tests/basic/jbr/jbr-volgen.t new file mode 100644 index 00000000000..f368710c158 --- /dev/null +++ b/tests/basic/jbr/jbr-volgen.t @@ -0,0 +1,39 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +volfiles=${GLUSTERD_WORKDIR}/vols/${V0}/ +check_brick_volfiles () { + for vf in ${volfiles}${V0}.$(hostname).*.vol; do + grep -qs experimental/jbr $vf || return + # At least for now, nothing else would put a client translator + # in a brick volfile. + grep -qs protocol/client $vf || return + done + echo "OK" +} + +TEST glusterd +TEST pidof glusterd + +TEST $CLI volume create $V0 replica 2 $H0:$B0/${V0}{1,2} +TEST $CLI volume set $V0 cluster.jbr on + +# Check that the client volfile got modified properly. +TEST grep -qs experimental/jbrc ${volfiles}${V0}.tcp-fuse.vol + +# Check that the brick volfiles got modified as well. +EXPECT "OK" check_brick_volfiles + +# Put things back and make sure the "undo" worked. +TEST $CLI volume set $V0 cluster.jbr off +TEST $CLI volume start $V0 +TEST $GFS -s $H0 --volfile-id $V0 $M0 +echo hello > $M0/probe +EXPECT hello cat ${B0}/${V0}1/probe +EXPECT hello cat ${B0}/${V0}2/probe + +cleanup +#G_TESTDEF_TEST_STATUS_CENTOS6=KNOWN_ISSUE,BUG=1385758 +#G_TESTDEF_TEST_STATUS_NETBSD7=KNOWN_ISSUE,BUG=1385758 diff --git a/tests/basic/jbr/jbr.t b/tests/basic/jbr/jbr.t new file mode 100755 index 00000000000..605344b5a7e --- /dev/null +++ b/tests/basic/jbr/jbr.t @@ -0,0 +1,38 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc +. $(dirname $0)/../../cluster.rc +. $(dirname $0)/../../snapshot.rc +. $(dirname $0)/../../fdl.rc + +cleanup; + +TEST verify_lvm_version; +#Create cluster with 3 nodes +TEST launch_cluster 3; +TEST setup_lvm 3 + +TEST $CLI_1 peer probe $H2; +TEST $CLI_1 peer probe $H3; +EXPECT_WITHIN $PROBE_TIMEOUT 2 peer_count; + +TEST $CLI_1 volume create $V0 replica 3 $H1:$L1 $H2:$L2 $H3:$L3 +TEST $CLI_1 volume set $V0 cluster.jbr on +TEST $CLI_1 volume set $V0 cluster.jbr.quorum-percent 100 +TEST $CLI_1 volume set $V0 features.fdl on +#TEST $CLI_1 volume set $V0 diagnostics.brick-log-level DEBUG +TEST $CLI_1 volume start $V0 + +TEST glusterfs --volfile-id=$V0 --volfile-server=$H1 --entry-timeout=0 $M0; + +EXPECT_WITHIN $CHILD_UP_TIMEOUT "3" jbrc_child_up_status $V0 0 + +echo "file" > $M0/file1 +TEST stat $L1/file1 +TEST stat $L2/file1 +TEST stat $L3/file1 + +cleanup; +#G_TESTDEF_TEST_STATUS_CENTOS6=KNOWN_ISSUE,BUG=1385758 +#G_TESTDEF_TEST_STATUS_NETBSD7=KNOWN_ISSUE,BUG=1385758 diff --git a/tests/basic/logchecks-messages.h b/tests/basic/logchecks-messages.h new file mode 100644 index 00000000000..bf364848ec7 --- /dev/null +++ b/tests/basic/logchecks-messages.h @@ -0,0 +1,105 @@ +/* + Copyright (c) 2013 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. + */ + +#ifndef _LOGCHECKS_MESSAGES_H_ +#define _LOGCHECKS_MESSAGES_H_ + +#include <glusterfs/glfs-message-id.h> + +/* NOTE: Rules for message additions + * 1) Each instance of a message is _better_ left with a unique message ID, even + * if the message format is the same. Reasoning is that, if the message + * format needs to change in one instance, the other instances are not + * impacted or the new change does not change the ID of the instance being + * modified. + * 2) Addition of a message, + * - Should increment the GLFS_NUM_MESSAGES + * - Append to the list of messages defined, towards the end + * - Retain macro naming as glfs_msg_X (for redability across developers) + * NOTE: Rules for message format modifications + * 3) Check acorss the code if the message ID macro in question is reused + * anywhere. If reused then then the modifications should ensure correctness + * everywhere, or needs a new message ID as (1) above was not adhered to. If + * not used anywhere, proceed with the required modification. + * NOTE: Rules for message deletion + * 4) Check (3) and if used anywhere else, then cannot be deleted. If not used + * anywhere, then can be deleted, but will leave a hole by design, as + * addition rules specify modification to the end of the list and not filling + * holes. + */ + +#define GLFS_COMP_BASE 1000 +#define GLFS_NUM_MESSAGES 19 +#define GLFS_MSGID_END (GLFS_COMP_BASE + GLFS_NUM_MESSAGES + 1) +/* Messaged with message IDs */ +#define glfs_msg_start_x GLFS_COMP_BASE, "Invalid: Start of messages" +/*------------*/ +#define logchecks_msg_1 \ + (GLFS_COMP_BASE + 1), \ + "Informational: Testing logging" \ + " in gluster" +#define logchecks_msg_2 \ + (GLFS_COMP_BASE + 2), \ + "Informational: Format testing:" \ + " %d:%s:%x" +#define logchecks_msg_3 \ + (GLFS_COMP_BASE + 3), \ + "Critical: Testing logging" \ + " in gluster" +#define logchecks_msg_4 \ + (GLFS_COMP_BASE + 4), \ + "Critical: Format testing:" \ + " %d:%s:%x" +#define logchecks_msg_5 (GLFS_COMP_BASE + 5), "Critical: Rotated the log" +#define logchecks_msg_6 (GLFS_COMP_BASE + 6), "Critical: Flushed the log" +#define logchecks_msg_7 (GLFS_COMP_BASE + 7), "Informational: gf_msg_callingfn" +#define logchecks_msg_8 \ + (GLFS_COMP_BASE + 8), \ + "Informational: " \ + "gf_msg_callingfn: Format testing: %d:%s:%x" +#define logchecks_msg_9 (GLFS_COMP_BASE + 9), "Critical: gf_msg_callingfn" +#define logchecks_msg_10 \ + (GLFS_COMP_BASE + 10), \ + "Critical: " \ + "gf_msg_callingfn: Format testing: %d:%s:%x" +#define logchecks_msg_11 (GLFS_COMP_BASE + 11), "==========================" +#define logchecks_msg_12 \ + (GLFS_COMP_BASE + 12), \ + "Test 1: Only stderr and" \ + " partial syslog" +#define logchecks_msg_13 \ + (GLFS_COMP_BASE + 13), \ + "Test 2: Only checklog and" \ + " partial syslog" +#define logchecks_msg_14 \ + (GLFS_COMP_BASE + 14), \ + "Test 5: Changing to" \ + " traditional format" +#define logchecks_msg_15 \ + (GLFS_COMP_BASE + 15), \ + "Test 6: Changing log level" \ + " to critical and above" +#define logchecks_msg_16 (GLFS_COMP_BASE + 16), "Test 7: Only to syslog" +#define logchecks_msg_17 \ + (GLFS_COMP_BASE + 17), \ + "Test 8: Only to syslog," \ + " traditional format" +#define logchecks_msg_18 \ + (GLFS_COMP_BASE + 18), \ + "Test 9: Only to syslog," \ + " only critical and above" +#define logchecks_msg_19 \ + (GLFS_COMP_BASE + 19), \ + "Pre init message, not to be" \ + " seen in logs" +/*------------*/ +#define glfs_msg_end_x GLFS_MSGID_END, "Invalid: End of messages" + +#endif /* !_component_MESSAGES_H_ */
\ No newline at end of file diff --git a/tests/basic/logchecks.c b/tests/basic/logchecks.c new file mode 100644 index 00000000000..df0be28ace0 --- /dev/null +++ b/tests/basic/logchecks.c @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2013 Red Hat, Inc. <http://www.redhat.com> + * This file is part of GlusterFS. + * + * This file is licensed to you under your choice of the GNU Lesser + * General Public License, version 3 or any later version (LGPLv3 or + * later), or the GNU General Public License, version 2 (GPLv2), in all + * cases as published by the Free Software Foundation. + */ + +#include <stdio.h> +#include <unistd.h> + +#include <glusterfs/glusterfs.h> +#include <glusterfs/globals.h> +#include <glusterfs/logging.h> + +#include "logchecks-messages.h" +#include "../../libglusterfs/src/logging.h" + +glusterfs_ctx_t *ctx = NULL; + +#define TEST_FILENAME "/tmp/logchecks.log" +#define GF_LOG_CONTROL_FILE "/etc/glusterfs/logger.conf" + +int +go_log_vargs(gf_loglevel_t level, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + gf_msg_vplain(level, fmt, ap); + va_end(ap); + + return 0; +} + +int +go_log(void) +{ + /*** gf_msg ***/ + gf_msg("logchecks", GF_LOG_INFO, 0, logchecks_msg_1); + gf_msg("logchecks", GF_LOG_INFO, 22, logchecks_msg_2, 42, "Forty-Two", 42); + /* change criticality */ + gf_msg("logchecks", GF_LOG_CRITICAL, 0, logchecks_msg_3); + gf_msg("logchecks", GF_LOG_CRITICAL, 22, logchecks_msg_4, 42, "Forty-Two", + 42); + + /*** msg_nomem ***/ + gf_msg_nomem("logchecks", GF_LOG_ALERT, 555); + gf_msg_nomem("logchecks", GF_LOG_INFO, 555); + + /*** msg_plain ***/ + gf_msg_plain(GF_LOG_INFO, + "Informational: gf_msg_plain with" + " args %d:%s:%x", + 42, "Forty-Two", 42); + gf_msg_plain(GF_LOG_ALERT, + "Alert: gf_msg_plain with" + " args %d:%s:%x", + 42, "Forty-Two", 42); + + /*** msg_vplain ***/ + go_log_vargs(GF_LOG_INFO, "Informational: gf_msg_vplain: No args!!!"); + go_log_vargs(GF_LOG_INFO, + "Informational: gf_msg_vplain: Some" + " args %d:%s:%x", + 42, "Forty-Two", 42); + go_log_vargs(GF_LOG_INFO, "Critical: gf_msg_vplain: No args!!!"); + go_log_vargs(GF_LOG_INFO, + "Critical: gf_msg_vplain: Some" + " args %d:%s:%x", + 42, "Forty-Two", 42); + + /*** msg_plain_nomem ***/ + gf_msg_plain_nomem(GF_LOG_INFO, "Informational: gf_msg_plain_nomem"); + gf_msg_plain_nomem(GF_LOG_ALERT, "Alert: gf_msg_plain_nomem"); + + /*** msg_backtrace_nomem ***/ + // TODO: Need to create a stack depth and then call + gf_msg_backtrace_nomem(GF_LOG_INFO, 5); + gf_msg_backtrace_nomem(GF_LOG_ALERT, 5); + + /*** gf_msg_callingfn ***/ + // TODO: Need to create a stack depth and then call + gf_msg_callingfn("logchecks", GF_LOG_INFO, 0, logchecks_msg_7); + gf_msg_callingfn("logchecks", GF_LOG_INFO, 0, logchecks_msg_8, 42, + "Forty-Two", 42); + gf_msg_callingfn("logchecks", GF_LOG_CRITICAL, 0, logchecks_msg_9); + gf_msg_callingfn("logchecks", GF_LOG_CRITICAL, 0, logchecks_msg_10, 42, + "Forty-Two", 42); + + /*** gf_msg_debug ***/ + gf_msg_debug("logchecks", 0, "Debug: Hello World!!!"); + gf_msg_debug("logchecks", 22, "Debug: With args %d:%s:%x", 42, "Forty-Two", + 42); + + /*** gf_msg_trace ***/ + gf_msg_trace("logchecks", 0, "Trace: Hello World!!!"); + gf_msg_trace("logchecks", 22, "Trace: With args %d:%s:%x", 42, "Forty-Two", + 42); + + /*** gf_msg_backtrace ***/ + // TODO: Test with lower callstr values to check truncation + + return 0; +} + +int +main(int argc, char *argv[]) +{ + int ret = -1; + + unlink(GF_LOG_CONTROL_FILE); + creat(GF_LOG_CONTROL_FILE, O_RDONLY); + ctx = glusterfs_ctx_new(); + if (!ctx) + return -1; + + ret = glusterfs_globals_init(ctx); + if (ret) { + printf("Error from glusterfs_globals_init [%s]\n", strerror(errno)); + return ret; + } + + /* Pre init test, message should not be printed */ + gf_msg("logchecks", GF_LOG_ALERT, 0, logchecks_msg_19); + + THIS->ctx = ctx; + + /* TEST 1: messages before initializing the log, goes to stderr + * and syslog based on criticality */ + gf_msg("logchecks", GF_LOG_ALERT, 0, logchecks_msg_11); + gf_msg("logchecks", GF_LOG_ALERT, 0, logchecks_msg_12); + go_log(); + gf_msg("logchecks", GF_LOG_ALERT, 0, logchecks_msg_11); + + /* TEST 2: messages post initialization, goes to glusterlog and + * syslog based on severity */ + ret = gf_log_init(ctx, TEST_FILENAME, "logchecks"); + if (ret != 0) { + printf("Error from gf_log_init [%s]\n", strerror(errno)); + return -1; + } + gf_msg("logchecks", GF_LOG_ALERT, 0, logchecks_msg_11); + gf_msg("logchecks", GF_LOG_ALERT, 0, logchecks_msg_13); + go_log(); + gf_msg("logchecks", GF_LOG_ALERT, 0, logchecks_msg_11); + + /* TEST 3: Test rotation */ + gf_msg("logchecks", GF_LOG_ALERT, 0, logchecks_msg_11); + gf_log_logrotate(0); + gf_msg("logchecks", GF_LOG_CRITICAL, 0, logchecks_msg_5); + gf_msg("logchecks", GF_LOG_ALERT, 0, logchecks_msg_11); + + /* TEST 4: Check flush, nothing noticeable should occur :) */ + gf_msg("logchecks", GF_LOG_ALERT, 0, logchecks_msg_11); + gf_log_flush(); + gf_msg("logchecks", GF_LOG_CRITICAL, 0, logchecks_msg_6); + gf_msg("logchecks", GF_LOG_ALERT, 0, logchecks_msg_11); + + /* TEST 5: Change format */ + gf_msg("logchecks", GF_LOG_ALERT, 0, logchecks_msg_11); + gf_log_set_logformat(gf_logformat_traditional); + gf_msg("logchecks", GF_LOG_ALERT, 0, logchecks_msg_14); + go_log(); + gf_msg("logchecks", GF_LOG_ALERT, 0, logchecks_msg_11); + + /* TEST 6: Change level */ + gf_msg("logchecks", GF_LOG_ALERT, 0, logchecks_msg_11); + gf_log_set_loglevel(ctx, GF_LOG_CRITICAL); + gf_msg("logchecks", GF_LOG_ALERT, 0, logchecks_msg_15); + go_log(); + gf_msg("logchecks", GF_LOG_ALERT, 0, logchecks_msg_11); + + /* Reset to run with syslog */ + gf_log_set_logformat(gf_logformat_withmsgid); + gf_log_set_loglevel(ctx, GF_LOG_INFO); + + /* Run tests with logger changed to syslog */ + /* TEST 7: No more gluster logs */ + gf_msg("logchecks", GF_LOG_ALERT, 0, logchecks_msg_11); + gf_log_set_logger(gf_logger_syslog); + gf_msg("logchecks", GF_LOG_ALERT, 0, logchecks_msg_16); + go_log(); + gf_msg("logchecks", GF_LOG_ALERT, 0, logchecks_msg_11); + + /* TEST 8: Change format */ + gf_msg("logchecks", GF_LOG_ALERT, 0, logchecks_msg_11); + gf_log_set_logformat(gf_logformat_traditional); + gf_msg("logchecks", GF_LOG_ALERT, 0, logchecks_msg_14); + go_log(); + gf_msg("logchecks", GF_LOG_ALERT, 0, logchecks_msg_11); + + /* TEST 9: Change level */ + gf_msg("logchecks", GF_LOG_ALERT, 0, logchecks_msg_11); + gf_log_set_loglevel(ctx, GF_LOG_CRITICAL); + gf_msg("logchecks", GF_LOG_ALERT, 0, logchecks_msg_15); + go_log(); + gf_msg("logchecks", GF_LOG_ALERT, 0, logchecks_msg_11); + + // TODO: signal crash prints, but not yet feasible here + // TODO: Graph printing + // TODO: Multi threaded logging + + /* Close out the logging */ + gf_log_fini(ctx); + gf_log_globals_fini(); + + unlink(GF_LOG_CONTROL_FILE); + unlink(TEST_FILENAME); + + return 0; +} diff --git a/tests/basic/md-cache/bug-1317785.t b/tests/basic/md-cache/bug-1317785.t new file mode 100644 index 00000000000..5076e3612ac --- /dev/null +++ b/tests/basic/md-cache/bug-1317785.t @@ -0,0 +1,34 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +cleanup; + +TEST glusterd + +TEST $CLI volume create $V0 $H0:$B0/$V0 +TEST $CLI volume start $V0 + +TEST $CLI volume set $V0 cache-swift-metadata on +EXPECT 'on' volinfo_field $V0 'performance.cache-swift-metadata' + +TEST $CLI volume set $V0 cache-swift-metadata off +EXPECT 'off' volinfo_field $V0 'performance.cache-swift-metadata' + +TEST $CLI volume set $V0 performance.cache-capability-xattrs off +EXPECT 'off' volinfo_field $V0 'performance.cache-capability-xattrs' + +TEST $CLI volume set $V0 performance.cache-capability-xattrs on +EXPECT 'on' volinfo_field $V0 'performance.cache-capability-xattrs' + +TEST $CLI volume set $V0 performance.cache-ima-xattrs off +EXPECT 'off' volinfo_field $V0 'performance.cache-ima-xattrs' + +TEST $CLI volume set $V0 performance.cache-ima-xattrs on +EXPECT 'on' volinfo_field $V0 'performance.cache-ima-xattrs' + +TEST $CLI volume stop $V0 +TEST $CLI volume delete $V0 + +cleanup; diff --git a/tests/basic/md-cache/bug-1418249.t b/tests/basic/md-cache/bug-1418249.t new file mode 100755 index 00000000000..85a4f58ec10 --- /dev/null +++ b/tests/basic/md-cache/bug-1418249.t @@ -0,0 +1,20 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +cleanup; + +TEST glusterd + +TEST $CLI volume create $V0 $H0:$B0/$V0 +TEST $CLI volume start $V0 + +TEST $CLI volume set $V0 group metadata-cache +EXPECT 'on' volinfo_field $V0 'performance.cache-invalidation' +EXPECT '600' volinfo_field $V0 'performance.md-cache-timeout' +EXPECT 'on' volinfo_field $V0 'performance.stat-prefetch' +EXPECT '600' volinfo_field $V0 'features.cache-invalidation-timeout' +EXPECT 'on' volinfo_field $V0 'features.cache-invalidation' +EXPECT '200000' volinfo_field $V0 'network.inode-lru-limit' +cleanup; diff --git a/tests/basic/meta.t b/tests/basic/meta.t new file mode 100755 index 00000000000..0bac3c6797d --- /dev/null +++ b/tests/basic/meta.t @@ -0,0 +1,45 @@ +#!/bin/bash + +. $(dirname $0)/../include.rc +. $(dirname $0)/../volume.rc + +cleanup; + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume info; + +TEST $CLI volume create $V0 replica 3 $H0:$B0/${V0}{1..9}; + +EXPECT "$V0" volinfo_field $V0 'Volume Name'; +EXPECT 'Created' volinfo_field $V0 'Status'; + +TEST $CLI volume start $V0; +EXPECT 'Started' volinfo_field $V0 'Status'; + +TEST $GFS -s $H0 --volfile-id $V0 $M0; + +# verify json validity + +TEST json_verify < $M0/.meta/frames; + +TEST json_verify < $M0/.meta/cmdline; + +TEST json_verify < $M0/.meta/version; + +# default log level (INFO) is 7 +TEST grep -q 7 $M0/.meta/logging/loglevel; + +# check for attribute_timeout exposed through state dump +TEST grep -q attribute_timeout $M0/.meta/master/private; + +# check for mount point specified as an option +TEST grep -q $M0 $M0/.meta/master/options/mountpoint; + +TEST $CLI volume stop $V0; +EXPECT 'Stopped' volinfo_field $V0 'Status'; + +TEST $CLI volume delete $V0; +TEST ! $CLI volume info $V0; + +cleanup; diff --git a/tests/basic/metadisp/fsyncdir.c b/tests/basic/metadisp/fsyncdir.c new file mode 100644 index 00000000000..62b532b9ce4 --- /dev/null +++ b/tests/basic/metadisp/fsyncdir.c @@ -0,0 +1,29 @@ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include <fcntl.h> + +int +main(int argc, char **argv) +{ + int pfd; + + pfd = open(argv[1], O_RDONLY | O_DIRECTORY); + if (pfd == (-1)) { + perror("open"); + return EXIT_FAILURE; + } + + if (rename(argv[2], argv[3]) == (-1)) { + perror("rename"); + return EXIT_FAILURE; + } + + if (fsync(pfd) == (-1)) { + perror("fsync"); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} diff --git a/tests/basic/metadisp/ftruncate.c b/tests/basic/metadisp/ftruncate.c new file mode 100644 index 00000000000..c9185212c31 --- /dev/null +++ b/tests/basic/metadisp/ftruncate.c @@ -0,0 +1,34 @@ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include <fcntl.h> + +int +main(int argc, char **argv) +{ + int pfd; + + pfd = open(argv[1], O_RDWR); + if (pfd == (-1)) { + perror("open"); + return EXIT_FAILURE; + } + + if (ftruncate(pfd, 0) == (-1)) { + perror("ftruncate"); + return EXIT_FAILURE; + } + + if (write(pfd, "hello", 5) == (-1)) { + perror("write"); + return EXIT_FAILURE; + } + + if (fsync(pfd) == (-1)) { + perror("fsync"); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} diff --git a/tests/basic/metadisp/fxattr.c b/tests/basic/metadisp/fxattr.c new file mode 100644 index 00000000000..e552057778a --- /dev/null +++ b/tests/basic/metadisp/fxattr.c @@ -0,0 +1,107 @@ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include <fcntl.h> +#include <string.h> +#include <sys/types.h> +#include <sys/xattr.h> + +static char MY_XATTR[] = "user.fxtest"; +static char *PROGRAM; +#define CONSUME(v) \ + do { \ + if (!argc) { \ + fprintf(stderr, "missing argument\n"); \ + return EXIT_FAILURE; \ + } \ + v = argv[0]; \ + ++argv; \ + --argc; \ + } while (0) + +static int +do_get(int argc, char **argv, int fd) +{ + char *value; + int ret; + char buf[1024]; + + CONSUME(value); + + ret = fgetxattr(fd, MY_XATTR, buf, sizeof(buf)); + if (ret == (-1)) { + perror("fgetxattr"); + return EXIT_FAILURE; + } + + if (strncmp(buf, value, ret) != 0) { + fprintf(stderr, "data mismatch\n"); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} + +static int +do_set(int argc, char **argv, int fd) +{ + char *value; + int ret; + + CONSUME(value); + + ret = fsetxattr(fd, MY_XATTR, value, strlen(value), 0); + if (ret == (-1)) { + perror("fsetxattr"); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} + +static int +do_remove(int argc, char **argv, int fd) +{ + int ret; + + ret = fremovexattr(fd, MY_XATTR); + if (ret == (-1)) { + perror("femovexattr"); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} + +int +main(int argc, char **argv) +{ + int fd; + char *path; + char *cmd; + + CONSUME(PROGRAM); + CONSUME(path); + CONSUME(cmd); + + fd = open(path, O_RDWR); + if (fd == (-1)) { + perror("open"); + return EXIT_FAILURE; + } + + if (strcmp(cmd, "get") == 0) { + return do_get(argc, argv, fd); + } + + if (strcmp(cmd, "set") == 0) { + return do_set(argc, argv, fd); + } + + if (strcmp(cmd, "remove") == 0) { + return do_remove(argc, argv, fd); + } + + return EXIT_SUCCESS; +} diff --git a/tests/basic/metadisp/gfs-fsetxattr.c b/tests/basic/metadisp/gfs-fsetxattr.c new file mode 100644 index 00000000000..63578bc528f --- /dev/null +++ b/tests/basic/metadisp/gfs-fsetxattr.c @@ -0,0 +1,141 @@ +#include <glusterfs/api/glfs.h> +#include <glusterfs/api/glfs-handles.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +int gfapi = 1; + +int +main(int argc, char *argv[]) +{ + glfs_t *fs = NULL; + int ret = 0; + int i = 0; + glfs_fd_t *fd = NULL; + char *topdir = "topdir", *filename = "file1"; + char *buf = NULL; + char *logfile = NULL; + char *hostname = NULL; + char *basename = NULL; + char *dir1 = NULL, *dir2 = NULL, *filename1 = NULL, *filename2 = NULL; + struct stat sb = { + 0, + }; + + if (argc != 5) { + fprintf( + stderr, + "Expect following args %s <hostname> <Vol> <log file> <basename>\n", + argv[0]); + return -1; + } + + hostname = argv[1]; + logfile = argv[3]; + basename = argv[4]; + + fs = glfs_new(argv[2]); + if (!fs) { + fprintf(stderr, "glfs_new: returned NULL (%s)\n", strerror(errno)); + return -1; + } + + ret = glfs_set_volfile_server(fs, "tcp", hostname, 24007); + if (ret < 0) { + fprintf(stderr, "glfs_set_volfile_server failed ret:%d (%s)\n", ret, + strerror(errno)); + return -1; + } + + ret = glfs_set_logging(fs, logfile, 7); + if (ret < 0) { + fprintf(stderr, "glfs_set_logging failed with ret: %d (%s)\n", ret, + strerror(errno)); + return -1; + } + + ret = glfs_init(fs); + if (ret < 0) { + fprintf(stderr, "glfs_init failed with ret: %d (%s)\n", ret, + strerror(errno)); + return -1; + } + + ret = asprintf(&dir1, "%s-dir", basename); + if (ret < 0) { + fprintf(stderr, "cannot construct filename (%s)", strerror(errno)); + return ret; + } + + ret = glfs_mkdir(fs, dir1, 0755); + if (ret < 0) { + fprintf(stderr, "mkdir(%s): %s\n", dir1, strerror(errno)); + return -1; + } + + fd = glfs_opendir(fs, dir1); + if (!fd) { + fprintf(stderr, "/: %s\n", strerror(errno)); + return -1; + } + + ret = glfs_fsetxattr(fd, "user.dirfattr", "fsetxattr", 9, 0); + if (ret < 0) { + fprintf(stderr, "fsetxattr(%s): %d (%s)\n", dir1, ret, strerror(errno)); + return -1; + } + + ret = glfs_closedir(fd); + if (ret < 0) { + fprintf(stderr, "glfs_closedir failed with ret: %d (%s)\n", ret, + strerror(errno)); + return -1; + } + + ret = asprintf(&filename1, "%s-file", basename); + if (ret < 0) { + fprintf(stderr, "cannot construct filename (%s)", strerror(errno)); + return ret; + } + + ret = asprintf(&filename2, "%s-file-renamed", basename); + if (ret < 0) { + fprintf(stderr, "cannot construct filename (%s)", strerror(errno)); + return ret; + } + + fd = glfs_creat(fs, filename1, O_RDWR, 0644); + if (!fd) { + fprintf(stderr, "%s: (%p) %s\n", filename1, fd, strerror(errno)); + return -1; + } + + ret = glfs_rename(fs, filename1, filename2); + if (ret < 0) { + fprintf(stderr, "glfs_rename failed with ret: %d (%s)\n", ret, + strerror(errno)); + return -1; + } + + ret = glfs_lstat(fs, filename2, &sb); + if (ret < 0) { + fprintf(stderr, "glfs_lstat failed with ret: %d (%s)\n", ret, + strerror(errno)); + return -1; + } + + ret = glfs_fsetxattr(fd, "user.filefattr", "fsetxattr", 9, 0); + if (ret < 0) { + fprintf(stderr, "fsetxattr(%s): %d (%s)\n", dir1, ret, strerror(errno)); + return -1; + } + + ret = glfs_close(fd); + if (ret < 0) { + fprintf(stderr, "glfs_close failed with ret: %d (%s)\n", ret, + strerror(errno)); + return -1; + } +} diff --git a/tests/basic/metadisp/metadisp.t b/tests/basic/metadisp/metadisp.t new file mode 100644 index 00000000000..894ffe07226 --- /dev/null +++ b/tests/basic/metadisp/metadisp.t @@ -0,0 +1,316 @@ +#!/usr/bin/env bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + + +# Considering `--enable-metadisp` is an option for `./configure`, +# which is disabled by default, this test will never pass regression. +# But to see the value of this test, run below after configuring +# with above option : +# `prove -vmfe '/bin/bash' tests/basic/metadisp/metadisp.t` + +#G_TESTDEF_TEST_STATUS_CENTOS6=BAD_TEST + +cleanup; + +TEST mkdir -p $B0/b0/{0,1} + +TEST setfattr -n trusted.glusterfs.volume-id -v 0xddab9eece7b64a95b07351a1f748f56f ${B0}/b0/0 +TEST setfattr -n trusted.glusterfs.volume-id -v 0xddab9eece7b64a95b07351a1f748f56f ${B0}/b0/1 + +TEST $GFS --volfile=$(dirname $0)/metadisp.vol --volfile-id=$V0 $M0; + +NUM_FILES=40 +TEST touch $M0/{1..${NUM_FILES}} + +# each drive should get 40 files +TEST [ $(dir -1 $B0/b0/0/ | wc -l) -eq $NUM_FILES ] +TEST [ $(dir -1 $B0/b0/1/ | wc -l) -eq $NUM_FILES ] + +# now write some data to a file +echo "hello" > $M0/3 +filename=$$ +echo "hello" > /tmp/metadisp-write-${filename} +checksum=$(md5sum /tmp/metadisp-write-${filename} | awk '{print $1}') +TEST [ "$(md5sum $M0/3 | awk '{print $1}')" == "$checksum" ] + +# check that the backend file exists on b1 +gfid=$(gf_gfid_xattr_to_str $(gf_get_gfid_xattr $B0/b0/*/3)) +TEST [ $(dir -1 $B0/b0/1/$gfid | wc -l) -eq 1 ] + +# check that the backend file matches the frontend +TEST [ "$(md5sum $B0/b0/1/$gfid | awk '{print $1}')" == "$checksum" ] + +# delete the file +TEST rm $M0/3 + +# ensure the frontend and backend files are cleaned up +TEST ! -e $M0/3 +TEST ! [ stat $B0/b*/*/$gfid ] + +# Test TRUNCATE + WRITE flow +echo "hello" | tee $M0/4 +echo "goo" | tee $M0/4 +filename=$$ +echo "goo" | tee /tmp/metadisp-truncate-${filename} +checksum=$(md5sum /tmp/metadisp-truncate-${filename} | awk '{print $1}') +TEST [ "$(md5sum $M0/4 | awk '{print $1}')" == "$checksum" ] + +# Test mkdir + rmdir. +TEST mkdir $M0/rmdir_me +nfiles=$(ls -d $B0/b*/*/rmdir_me 2> /dev/null | wc -l) +TEST [ "$nfiles" = "1" ] +TEST rmdir $M0/rmdir_me +nfiles=$(ls -d $B0/b*/*/rmdir_me 2> /dev/null | wc -l) +TEST [ "$nfiles" = "0" ] + +# Test rename. +TEST touch $M0/rename_me +nfiles=$(ls $B0/b*/*/rename_me 2> /dev/null | wc -l) +TEST [ "$nfiles" = "1" ] +nfiles=$(ls $B0/b*/*/such_rename 2> /dev/null | wc -l) +TEST [ "$nfiles" = "0" ] +TEST mv $M0/rename_me $M0/such_rename +nfiles=$(ls $B0/b*/*/rename_me 2> /dev/null | wc -l) +TEST [ "$nfiles" = "0" ] +nfiles=$(ls $B0/b*/*/such_rename 2> /dev/null | wc -l) +TEST [ "$nfiles" = "1" ] + +# Test rename of a file that doesn't exist. +TEST ! mv $M0/does-not-exist $M0/neither-does-this + + +# cleanup all the other files. +TEST rm -v $M0/1 $M0/2 $M0/{4..${NUM_FILES}} +TEST rm $M0/such_rename +TEST [ $(ls /d/backends/b0/0/ | wc -l) -eq 0 ] +TEST [ $(ls /d/backends/b0/1/ | wc -l) -eq 0 ] + +# Test CREATE flow +NUM_FILES=40 +TEST touch $M0/{1..${NUM_FILES}} +TEST [ $(ls /d/backends/b0/0/ | wc -l) -eq $NUM_FILES ] +TEST [ $(ls /d/backends/b0/1/ | wc -l) -eq $NUM_FILES ] + +# Test UNLINK flow +# No drives should have any files +TEST rm -v $M0/{1..${NUM_FILES}} +TEST [ $(ls /d/backends/b0/0/ | wc -l) -eq 0 ] +TEST [ $(ls /d/backends/b0/1/ | wc -l) -eq 0 ] + +# Test CREATE + WRITE + READ flow +filename=$$ +dd if=/dev/urandom of=/tmp/${filename} bs=1M count=10 +checksum=$(md5sum /tmp/${filename} | awk '{print $1}') +TEST cp -v /tmp/${filename} $M0/1 +TEST cp -v /tmp/${filename} $M0/2 +TEST cp -v /tmp/${filename} $M0/3 +TEST cp -v /tmp/${filename} $M0/4 +TEST [ "$(md5sum $M0/1 | awk '{print $1}')" == "$checksum" ] +TEST [ "$(md5sum $M0/2 | awk '{print $1}')" == "$checksum" ] +TEST [ "$(md5sum $M0/3 | awk '{print $1}')" == "$checksum" ] +TEST [ "$(md5sum $M0/4 | awk '{print $1}')" == "$checksum" ] + +# Test TRUNCATE + WRITE flow +TEST dd if=/dev/zero of=$M0/1 bs=1M count=20 + +# Check that readdir stats the files properly and we get the correct sizes +TEST [ $(find $M0 -size +9M | wc -l) -eq 4 ]; + +# Test mkdir + rmdir. +TEST mkdir $M0/rmdir_me +nfiles=$(ls -d $B0/b*/*/rmdir_me 2> /dev/null | wc -l) +TEST [ "$nfiles" = "1" ] +TEST rmdir $M0/rmdir_me +nfiles=$(ls -d $B0/b*/*/rmdir_me 2> /dev/null | wc -l) +TEST [ "$nfiles" = "0" ] + +# Test rename. +# Still flaky, so disabled until it can be debugged. +TEST touch $M0/rename_me +nfiles=$(ls $B0/b*/*/rename_me 2> /dev/null | wc -l) +TEST [ "$nfiles" = "1" ] +nfiles=$(ls $B0/b*/*/such_rename 2> /dev/null | wc -l) +TEST [ "$nfiles" = "0" ] +TEST mv $M0/rename_me $M0/such_rename +nfiles=$(ls $B0/b*/*/rename_me 2> /dev/null | wc -l) +TEST [ "$nfiles" = "0" ] +nfiles=$(ls $B0/b*/*/such_rename 2> /dev/null | wc -l) +TEST [ "$nfiles" = "1" ] + +# Test rename of a file that doesn't exist. +TEST ! mv $M0/does-not-exist $M0/neither-does-this + +# Test rename over an existing file. +ok=yes +for i in $(seq 0 9); do + echo foo > $M0/src$i + echo bar > $M0/dst$i +done +for i in $(seq 0 9); do + mv $M0/src$i $M0/dst$i +done +for i in $(seq 0 9); do + nfiles=$(cat $B0/b0/*/dst$i | wc -l) + if [ "$nfiles" = "2" ]; then + echo "COLLISION on dst$i" + (ls -l $B0/b0/*/dst$i; cat $B0/b0/*/dst$i) | sed "/^/s// /" + ok=no + fi +done +EXPECT "yes" echo $ok + +# Test rename of a directory. +count_copies () { + ls -d $B0/b?/?/$1 2> /dev/null | wc -l +} +TEST mkdir $M0/foo_dir +EXPECT 1 count_copies foo_dir +EXPECT 0 count_copies bar_dir +TEST mv $M0/foo_dir $M0/bar_dir +EXPECT 0 count_copies foo_dir +EXPECT 1 count_copies bar_dir + +for x in $(seq 0 99); do + touch $M0/target$x + ln -s $M0/target$x $M0/link$x +done +on_0=$(ls $B0/b*/0/link* | wc -l) +on_1=$(ls $B0/b*/1/link* | wc -l) +TEST [ "$on_0" -eq 100 ] +TEST [ "$on_1" -eq 0 ] +TEST [ "$(ls -l $M0/link* | wc -l)" = 100 ] + +# Test (hard) link. +_test_hardlink () { + local b + local has_src + local has_dst + local src_inum + local dst_inum + touch $M0/hardsrc$1 + ln $M0/hardsrc$1 $M0/harddst$1 + for b in $B0/b{0}/{0,1}; do + [ -f $b/hardsrc$1 ]; has_src=$? + [ -f $b/harddst$1 ]; has_dst=$? + if [ "$has_src" != "$has_dst" ]; then + echo "MISSING $b/hardxxx$1 $has_src $has_dst" + return + fi + if [ "$has_src$has_dst" = "00" ]; then + src_inum=$(stat -c '%i' $b/hardsrc$1) + dst_inum=$(stat -c '%i' $b/harddst$1) + if [ "$dst_inum" != "$src_inum" ]; then + echo "MISMATCH $b/hardxx$i $src_inum $dst_inum" + return + fi + fi + done + echo "OK" +} + +test_hardlink () { + local result=$(_test_hardlink $*) + # [ "$result" = "OK" ] || echo $result > /dev/tty + echo $result +} + +# Do this multiple times to make sure colocation isn't a fluke. +EXPECT "OK" test_hardlink 0 +EXPECT "OK" test_hardlink 1 +EXPECT "OK" test_hardlink 2 +EXPECT "OK" test_hardlink 3 +EXPECT "OK" test_hardlink 4 +EXPECT "OK" test_hardlink 5 +EXPECT "OK" test_hardlink 6 +EXPECT "OK" test_hardlink 7 +EXPECT "OK" test_hardlink 8 +EXPECT "OK" test_hardlink 9 + +# Test remove hardlink source. ensure deleting one file +# doesn't delete the data unless link-count is 1 +TEST mkdir $M0/hardlink +TEST touch $M0/hardlink/fileA +echo "data" >> $M0/hardlink/fileA +checksum=$(md5sum $M0/hardlink/fileA | awk '{print $1}') +TEST ln $M0/hardlink/fileA $M0/hardlink/fileB +TEST [ $(dir -1 $M0/hardlink/ | wc -l) -eq 2 ] +TEST rm $M0/hardlink/fileA +TEST [ $(dir -1 $M0/hardlink/ | wc -l) -eq 1 ] +TEST [ "$(md5sum $M0/hardlink/fileB | awk '{print $1}')" == "$checksum" ] + +# +# FIXME: statfs values look ok but the test is bad +# +# Test statfs. If we're doing it right, the numbers for the mountpoint should be +# double those for the brick filesystem times the number of bricks, +# but unless we're on a completely idle +# system (which never happens) the numbers can change even while this function +# runs and that would trip us up. Do a sloppy comparison to deal with that. +#compare_fields () { +# val1=$(df $1 | grep / | awk "{print \$$3}") +# val2=$(df $2 | grep / | awk "{print \$$3}") +# [ "$val2" -gt "$(((val1/(29/10))*19/10))" -a "$val2" -lt "$(((val1/(31/10))*21/10))" ] +#} + +#brick_df=$(df $B0 | grep /) +#mount_df=$(df $M0 | grep /) +#TEST compare_fields $B0 $M0 2 # Total blocks +#TEST compare_fields $B0 $M0 3 # Used +#TEST compare_fields $B0 $M0 4 # Available + +# Test removexattr. +#RXATTR_FILE=$(get_file_not_on_disk0 rxtest) +#TEST setfattr -n user.foo -v bar $M0/$RXATTR_FILE +#TEST getfattr -n user.foo $B0/b0/1/$RXATTR_FILE +#TEST setfattr -x user.foo $M0/$RXATTR_FILE +#TEST ! getfattr -n user.foo $B0/b0/1/$RXATTR_FILE + +# Test fsyncdir. We can't really test whether it's doing the right thing, +# but we can test that it doesn't fail and we can hand-check that it's calling +# down to all of the disks instead of just one. +# +# P.S. There's no fsyncdir test in the rest of Gluster, so who even knows if +# other translators are handling it correctly? + +#FSYNCDIR_EXE=$(dirname $0)/fsyncdir +#build_tester ${FSYNCDIR_EXE}.c +#TEST touch $M0/fsyncdir_src +#TEST $FSYNCDIR_EXE $M0 $M0/fsyncdir_src $M0/fsyncdir_dst +#TEST rm -f $FSYNCDIR_EXE + +# Test fsetxattr, fgetxattr, fremovexattr (in that order). +FXATTR_FILE=$M0/fxfile1 +TEST touch $FXATTR_FILE +FXATTR_EXE=$(dirname $0)/fxattr +build_tester ${FXATTR_EXE}.c +TEST ! getfattr -n user.fxtest $FXATTR_FILE +TEST $FXATTR_EXE $FXATTR_FILE set value1 +TEST getfattr -n user.fxtest $FXATTR_FILE +TEST setfattr -n user.fxtest -v value2 $FXATTR_FILE +TEST $FXATTR_EXE $FXATTR_FILE get value2 +TEST $FXATTR_EXE $FXATTR_FILE remove +TEST ! getfattr -n user.fxtest $FXATTR_FILE +TEST rm -f $FXATTR_EXE + +# Test ftruncate +FTRUNCATE_EXE=$(dirname $0)/ftruncate +build_tester ${FTRUNCATE_EXE}.c +FTRUNCATE_FILE=$M0/ftfile1 +TEST dd if=/dev/urandom of=$FTRUNCATE_FILE count=1 bs=1MB +TEST $FTRUNCATE_EXE $FTRUNCATE_FILE +#gfid=$(gf_gfid_xattr_to_str $(gf_get_gfid_xattr $B0/b0/*/ftfile1)) + +# Test fallocate, discard, zerofill. Actually we don't so much check that these +# *work* as that they don't throw any errors (especially ENOENT because the +# file's not on disk zero). +FALLOC_FILE=fatest1 +TEST touch $M0/$FALLOC_FILE +TEST fallocate -l $((4096*5)) $M0/$FALLOC_FILE +TEST fallocate -p -o 4096 -l 4096 $M0/$FALLOC_FILE +# This actually fails with "operation not supported" on most filesystems, so +# don't leave it enabled except to test changes. +#TEST fallocate -z -o $((4096*3)) -l 4096 $M0/$FALLOC_FILE + +#cleanup; diff --git a/tests/basic/metadisp/metadisp.vol b/tests/basic/metadisp/metadisp.vol new file mode 100644 index 00000000000..58ae2f6f2a8 --- /dev/null +++ b/tests/basic/metadisp/metadisp.vol @@ -0,0 +1,14 @@ +volume posix-0 + type storage/posix + option directory /d/backends/b0/0 +end-volume + +volume posix-1 + type storage/posix + option directory /d/backends/b0/1 +end-volume + +volume metadisp-0 + type features/metadisp + subvolumes posix-0 posix-1 +end-volume diff --git a/tests/basic/mgmt_v3-locks.t b/tests/basic/mgmt_v3-locks.t new file mode 100644 index 00000000000..9d766f40602 --- /dev/null +++ b/tests/basic/mgmt_v3-locks.t @@ -0,0 +1,120 @@ +#!/bin/bash + +. $(dirname $0)/../include.rc +. $(dirname $0)/../cluster.rc + +function check_peers { + $CLI_1 peer status | grep 'Peer in Cluster (Connected)' | wc -l +} + +function volume_count { + local cli=$1; + if [ $cli -eq '1' ] ; then + $CLI_1 volume info | grep 'Volume Name' | wc -l; + else + $CLI_2 volume info | grep 'Volume Name' | wc -l; + fi +} + +function volinfo_field() +{ + local vol=$1; + local field=$2; + + $CLI_1 volume info $vol | grep "^$field: " | sed 's/.*: //'; +} + +function two_diff_vols_create { + # Both volume creates should be successful + $CLI_1 volume create $V0 $H1:$B1/$V0 $H2:$B2/$V0 $H3:$B3/$V0 & + PID_1=$! + + $CLI_2 volume create $V1 $H1:$B1/$V1 $H2:$B2/$V1 $H3:$B3/$V1 & + PID_2=$! + + wait $PID_1 $PID_2 +} + +function two_diff_vols_start { + # Both volume starts should be successful + $CLI_1 volume start $V0 & + PID_1=$! + + $CLI_2 volume start $V1 & + PID_2=$! + + wait $PID_1 $PID_2 +} + +function two_diff_vols_stop_force { + # Force stop, so that if rebalance from the + # remove bricks is in progress, stop can + # still go ahead. Both volume stops should + # be successful + $CLI_1 volume stop $V0 force & + PID_1=$! + + $CLI_2 volume stop $V1 force & + PID_2=$! + + wait $PID_1 $PID_2 +} + +function same_vol_remove_brick { + + # Running two same vol commands at the same time can result in + # two success', two failures, or one success and one failure, all + # of which are valid. The only thing that shouldn't happen is a + # glusterd crash. + + local vol=$1 + local brick=$2 + $CLI_1 volume remove-brick $1 $2 start & + PID=$! + $CLI_2 volume remove-brick $1 $2 start + wait $PID +} + +cleanup; + +TEST launch_cluster 3; +TEST $CLI_1 peer probe $H2; +TEST $CLI_1 peer probe $H3; + +EXPECT_WITHIN $PROBE_TIMEOUT 2 check_peers + +two_diff_vols_create +EXPECT 'Created' volinfo_field $V0 'Status'; +EXPECT 'Created' volinfo_field $V1 'Status'; + +two_diff_vols_start +EXPECT 'Started' volinfo_field $V0 'Status'; +EXPECT 'Started' volinfo_field $V1 'Status'; + +same_vol_remove_brick $V0 $H2:$B2/$V0 +# Checking glusterd crashed or not after same volume remove brick +# on both nodes. +EXPECT_WITHIN $PROBE_TIMEOUT 2 check_peers + +same_vol_remove_brick $V1 $H2:$B2/$V1 +# Checking glusterd crashed or not after same volume remove brick +# on both nodes. +EXPECT_WITHIN $PROBE_TIMEOUT 2 check_peers + +$CLI_1 volume set $V0 diagnostics.client-log-level DEBUG & +PID=$! +$CLI_1 volume set $V1 diagnostics.client-log-level DEBUG +wait $PID +kill_glusterd 3 +$CLI_1 volume status $V0 +$CLI_2 volume status $V1 +$CLI_1 peer status +EXPECT_WITHIN $PROBE_TIMEOUT 1 check_peers +EXPECT 'Started' volinfo_field $V0 'Status'; +EXPECT 'Started' volinfo_field $V1 'Status'; + +TEST $glusterd_3 +$CLI_1 volume status $V0 +$CLI_2 volume status $V1 +$CLI_1 peer status +cleanup; diff --git a/tests/basic/mount-options.disabled b/tests/basic/mount-options.disabled new file mode 100644 index 00000000000..a04c8686276 --- /dev/null +++ b/tests/basic/mount-options.disabled @@ -0,0 +1,143 @@ +#!/bin/bash + +. $(dirname $0)/../include.rc +. $(dirname $0)/../volume.rc + +cleanup; + +TEST glusterd --xlator-option=*.rpc-auth-allow-insecure=on +TEST pidof glusterd +TEST $CLI volume create $V0 replica 2 $H0:$B0/${V0}{0,1,2,3,4,5} +TEST $CLI volume set $V0 server.allow-insecure on +TEST $CLI volume start $V0 + +#test all the options available to see if the mount succeeds with those options +#or not. This does not test functionality. This is added to prevent options +#being removed in future breaking backward-compatibility. + +TEST glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0 +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 + +TEST glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0 --attribute-timeout=0 +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 + +TEST glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0 --entry-timeout=0 +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 + +TEST glusterfs --volfile=$GLUSTERD_WORKDIR/vols/$V0/${V0}-fuse.vol $M0 +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 + +TEST glusterfs --volfile-id=/$V0 --volfile-server=$H0 --log-file=/tmp/a.txt --log-level=DEBUG $M0 +EXPECT_NOT "0" wc -l /tmp/a.txt +TEST grep " D " /tmp/a.txt +TEST rm -f /tmp/a.txt +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 + +TEST glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0 --acl +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 + +TEST glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0 --aux-gfid-mount +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 + +TEST glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0 --enable-ino32 +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 + +TEST glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0 --fopen-keep-cache=yes +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 +TEST glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0 --fopen-keep-cache=no +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 +TEST ! glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0 --fopen-keep-cache=fail + +TEST glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0 --mac-compat=yes +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 +TEST glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0 --mac-compat=no +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 +TEST ! glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0 --mac-compat=fail + +TEST glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0 --use-readdirp=yes +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 +TEST glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0 --use-readdirp=no +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 +TEST ! glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0 --use-readdirp=fail + +TEST glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0 --direct-io-mode=yes +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 +TEST glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0 --direct-io-mode=no +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 +TEST ! glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0 --direct-io-mode=fail + +TEST glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0 --read-only +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 + +TEST glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0 --selinux +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 + +TEST glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0 --worm +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 + +TEST glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0 --volfile-check +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 + +TEST glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0 --dump-fuse=/tmp/a.txt +EXPECT "0" stat /tmp/a.txt +TEST rm -f /tmp/a.txt +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 + +TEST glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0 --gid-timeout=0 +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 + +TEST glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0 --gid-timeout=-1 +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 + +TEST ! glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0 --gid-timeout=abc + +TEST glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0 --background-qlen=16 +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 + +TEST ! glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0 --background-qlen=abc + +TEST ! glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0 --background-qlen=-1 + +TEST glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0 --congestion-threshold=12 +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 + +TEST ! glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0 --congestion-threshold=abc + +TEST ! glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0 --congestion=threshold=-1 + +TEST glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0 --negative-timeout=10 +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 + +TEST ! glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0 --negative-timeout=abc +TEST ! glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0 --negative-timeout=-1 + +TEST glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0 --pid-file=/tmp/a.txt +EXPECT_NOT "0" wc -l /tmp/a.txt +TEST rm -f /tmp/a.txt +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 + +TEST glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0 --volfile-server-port=24007 +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 + +TEST ! glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0 --volfile-server-port=2400 + +TEST glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0 --volfile-server-transport=tcp +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 + +TEST glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0 --volfile-server-transport=ib-verbs +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 + +TEST glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0 --auto-invalidation=off +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 + +TEST ! glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0 --volfile-server-port=socket + +TEST glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0 --volume-name=$V0 +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 + +TEST ! glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0 --volume-name=abcd + +TEST ! glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0 --invalid-option + +TEST ! glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0 --invalid-option=abc +cleanup; diff --git a/tests/basic/mount.t b/tests/basic/mount.t index 90e522c5ea0..3a3d7cc9d8d 100755 --- a/tests/basic/mount.t +++ b/tests/basic/mount.t @@ -1,16 +1,19 @@ #!/bin/bash . $(dirname $0)/../include.rc +. $(dirname $0)/../nfs.rc -cleanup; +#G_TESTDEF_TEST_STATUS_CENTOS6=NFS_TEST +cleanup; ## Start and create a volume TEST glusterd TEST pidof glusterd TEST $CLI volume info; -TEST $CLI volume create $V0 replica 2 stripe 2 $H0:$B0/${V0}{1,2,3,4,5,6,7,8}; +TEST $CLI volume create $V0 replica 3 $H0:$B0/${V0}{1,2,3,4,5,6,7,8,9}; +TEST $CLI volume set $V0 nfs.disable false function volinfo_field() { @@ -35,25 +38,24 @@ EXPECT 'Started' volinfo_field $V0 'Status'; TEST $CLI volume set $V0 performance.stat-prefetch off; ## Mount FUSE with caching disabled (read-write) -TEST glusterfs --entry-timeout=0 --attribute-timeout=0 -s $H0 --volfile-id $V0 $M0; +TEST $GFS -s $H0 --volfile-id $V0 $M0; ## Check consistent "rw" option -TEST 'mount -t fuse.glusterfs | grep -E "^$H0:$V0 .+ \(rw,"'; -TEST 'grep -E "^$H0:$V0 .+ ,?rw," /proc/mounts'; +TEST 'mount -t $MOUNT_TYPE_FUSE | grep -E "^$H0:$V0 "|$GREP_MOUNT_OPT_RW'; +TEST 'grep -E "^$H0:$V0 .+ ,?rw,?" /proc/mounts'; ## Mount FUSE with caching disabled (read-only) -TEST glusterfs --entry-timeout=0 --attribute-timeout=0 --read-only -s $H0 --volfile-id $V0 $M1; +TEST $GFS --read-only -s $H0 --volfile-id $V0 $M1; ## Check consistent "ro" option -TEST 'mount -t fuse.glusterfs | grep -E "^$H0:$V0 .+ \(ro,"'; -TEST 'grep -E "^$H0:$V0 .+ ,?ro,.+" /proc/mounts'; +TEST 'mount -t $MOUNT_TYPE_FUSE | grep -E "^$H0:$V0 "|$GREP_MOUNT_OPT_RO'; +TEST 'grep -E "^$H0:$V0 .+ ,?ro(,.+)?" /proc/mounts'; ## Wait for volume to register with rpc.mountd -sleep 5; +EXPECT_WITHIN $NFS_EXPORT_TIMEOUT "1" is_nfs_export_available; ## Mount NFS -TEST mount -t nfs -o nolock,soft,intr $H0:/$V0 $N0; - +TEST mount_nfs $H0:/$V0 $N0 nolock; ## Test for consistent views between NFS and FUSE mounts ## write access to $M1 should fail @@ -62,11 +64,16 @@ TEST ! touch $M1/newfile; TEST touch $M0/newfile; TEST stat $M1/newfile; TEST stat $N0/newfile; -TEST ! rm $M1/newfile; -TEST rm $N0/newfile; +TEST ! rm -f $M1/newfile; +TEST rm -f $N0/newfile; TEST ! stat $M0/newfile; TEST ! stat $M1/newfile; +# No need to check for status here right now +$(dirname $0)/rpc-coverage.sh $N0 >/dev/null + +## Before killing daemon to avoid deadlocks +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" umount_nfs $N0 ## Finish up TEST $CLI volume stop $V0; diff --git a/tests/basic/mpx-compat.t b/tests/basic/mpx-compat.t new file mode 100644 index 00000000000..baf629dbf9b --- /dev/null +++ b/tests/basic/mpx-compat.t @@ -0,0 +1,53 @@ +#!/bin/bash +#This test tests that self-heals don't perform fsync when durability is turned +#off + +. $(dirname $0)/../include.rc +. $(dirname $0)/../traps.rc +. $(dirname $0)/../volume.rc + +function count_processes { + # It would generally be a good idea to use "pgrep -x" to ensure an + # exact match, but the version of pgrep we have on NetBSD (a.k.a. + # the worst operating system ever) doesn't support that option. + # Fortunately, "glusterfsd" isn't the prefix of any other name, + # so this works anyway. For now. + pgrep glusterfsd | wc -w +} + +function count_brick_pids { + $CLI --xml volume status all | sed -n '/.*<pid>\([^<]*\).*/s//\1/p' \ + | grep -v "N/A" | sort | uniq | wc -l +} + +cleanup +TEST glusterd +TEST $CLI volume set all cluster.brick-multiplex yes + +# Create two vanilla volumes. +TEST $CLI volume create $V0 $H0:$B0/brick-${V0}-{0,1} +TEST $CLI volume create $V1 $H0:$B0/brick-${V1}-{0,1} + +# Enable brick log-level to DEBUG +gluster v set $V0 diagnostics.brick-log-level DEBUG + +# Start both. +TEST $CLI volume start $V0 +TEST $CLI volume start $V1 + +# There should be only one process for compatible volumes. We can't use +# EXPECT_WITHIN here because it could transiently see one process as two are +# coming up, and yield a false positive. +sleep $PROCESS_UP_TIMEOUT +EXPECT "1" count_processes +EXPECT 1 count_brick_pids + +# Make the second volume incompatible with the first. +TEST $CLI volume stop $V1 +TEST $CLI volume set $V1 server.manage-gids no +TEST $CLI volume start $V1 + +# There should be two processes this time (can't share protocol/server). +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "2" count_processes + +cleanup;
\ No newline at end of file diff --git a/tests/basic/multiple-volume-shd-mux.t b/tests/basic/multiple-volume-shd-mux.t new file mode 100644 index 00000000000..d7cfbaec85f --- /dev/null +++ b/tests/basic/multiple-volume-shd-mux.t @@ -0,0 +1,46 @@ +#!/bin/bash + +. $(dirname $0)/../include.rc +. $(dirname $0)/../volume.rc + +cleanup; + +TESTS_EXPECTED_IN_LOOP=16 + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 replica 3 $H0:$B0/${V0}{0,1,2,3,4,5} +TEST $CLI volume start $V0 + +shd_pid=$(get_shd_mux_pid $V0) +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "^6$" number_healer_threads_shd $V0 "afr_shd_index_healer" + +for i in $(seq 1 3); do + TEST $CLI volume create ${V0}_afr$i replica 3 $H0:$B0/${V0}_afr${i}{0,1,2,3,4,5} + TEST $CLI volume start ${V0}_afr$i + TEST $CLI volume create ${V0}_ec$i disperse 6 redundancy 2 $H0:$B0/${V0}_ec${i}{0,1,2,3,4,5} + TEST $CLI volume start ${V0}_ec$i +done + +#Check the thread count become to number of volumes*number of ec subvolume (3*6=18) +EXPECT_WITHIN $PROCESS_DOWN_TIMEOUT "^18$" number_healer_threads_shd $V0 "ec_shd_index_healer" +#Check the thread count become to number of volumes*number of afr subvolume (4*6=24) +EXPECT_WITHIN $PROCESS_DOWN_TIMEOUT "^24$" number_healer_threads_shd $V0 "afr_shd_index_healer" +#Delete the volumes +for i in $(seq 1 3); do + TEST $CLI volume stop ${V0}_afr$i + TEST $CLI volume stop ${V0}_ec$i + TEST $CLI volume delete ${V0}_afr$i + TEST $CLI volume delete ${V0}_ec$i +done + +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "^${shd_pid}$" get_shd_mux_pid $V0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "^1$" shd_count + +EXPECT_WITHIN $PROCESS_DOWN_TIMEOUT "^6$" number_healer_threads_shd $V0 "afr_shd_index_healer" + +TEST $CLI volume stop ${V0} +TEST $CLI volume delete ${V0} +EXPECT_WITHIN $PROCESS_DOWN_TIMEOUT "^0$" shd_count + +cleanup diff --git a/tests/basic/multiplex.t b/tests/basic/multiplex.t new file mode 100644 index 00000000000..2f558a6824b --- /dev/null +++ b/tests/basic/multiplex.t @@ -0,0 +1,78 @@ +#!/bin/bash + +. $(dirname $0)/../include.rc +. $(dirname $0)/../traps.rc +. $(dirname $0)/../volume.rc + +function count_up_bricks { + $CLI --xml volume status $V0 | grep '<status>1' | wc -l +} + +function count_brick_processes { + pgrep glusterfsd | wc -l +} + +function count_brick_pids { + $CLI --xml volume status $V0 | sed -n '/.*<pid>\([^<]*\).*/s//\1/p' \ + | grep -v "N/A" | sort | uniq | wc -l +} + +cleanup + +TEST glusterd +TEST $CLI volume set all cluster.brick-multiplex on + +TEST $CLI volume create $V0 $H0:$B0/brick{0,1} +TEST $CLI volume set $V0 features.trash enable + +TEST $CLI volume start $V0 +# Without multiplexing, there would be two. +EXPECT_WITHIN $PROCESS_UP_TIMEOUT 2 count_up_bricks +EXPECT 1 count_brick_processes + +TEST $CLI volume stop $V0 +#Testing the volume set command introduced for protocol/server +TEST $CLI volume set $V0 transport.listen-backlog 1024 +EXPECT_WITHIN $PROCESS_DOWN_TIMEOUT 0 count_brick_processes +TEST $CLI volume start $V0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT 2 count_up_bricks +EXPECT 1 count_brick_processes + +TEST kill_brick $V0 $H0 $B0/brick1 +EXPECT_WITHIN $PROCESS_DOWN_TIMEOUT 1 count_up_bricks +# Make sure the whole process didn't go away. +EXPECT 1 count_brick_processes + +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT 2 count_up_bricks +EXPECT 1 count_brick_processes + +# Killing the first brick is a bit more of a challenge due to socket-path +# issues. +TEST kill_brick $V0 $H0 $B0/brick0 +EXPECT_WITHIN $PROCESS_DOWN_TIMEOUT 1 count_up_bricks +EXPECT 1 count_brick_processes +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT 2 count_up_bricks +EXPECT 1 count_brick_processes + +# Make sure that the two bricks show the same PID. +EXPECT 1 count_brick_pids + +# Do a quick test to make sure that the bricks are acting as separate bricks +# even though they're in the same process. +TEST $GFS --volfile-id=$V0 --volfile-server=$H0 $M0 +for i in $(seq 10 99); do + echo hello > $M0/file$i +done +nbrick0=$(ls $B0/brick0/file?? | wc -l) +nbrick1=$(ls $B0/brick1/file?? | wc -l) +TEST [ $((nbrick0 + nbrick1)) -eq 90 ] +TEST [ $((nbrick0 * nbrick1)) -ne 0 ] + +pkill gluster +TEST glusterd +EXPECT_WITHIN $PROCESS_DOWN_TIMEOUT 1 count_brick_pids +EXPECT_WITHIN $PROCESS_DOWN_TIMEOUT 1 count_brick_processes + +cleanup;
\ No newline at end of file diff --git a/tests/basic/namespace.t b/tests/basic/namespace.t new file mode 100644 index 00000000000..d1bbe7eea29 --- /dev/null +++ b/tests/basic/namespace.t @@ -0,0 +1,131 @@ +#!/bin/bash + +. $(dirname $0)/../include.rc +. $(dirname $0)/../volume.rc +. $(dirname $0)/../nfs.rc + +#G_TESTDEF_TEST_STATUS_CENTOS6=NFS_TEST + +# These hashes are a result of calling SuperFastHash +# on the corresponding folder names. +NAMESPACE_HASH=28153613 +NAMESPACE2_HASH=3926991974 +NAMESPACE3_HASH=3493960770 + +function check_brick_multiplex() { + local ret=$($CLI volume info|grep "cluster.brick-multiplex"|cut -d" " -f2) + local cnt="$(ls /var/log/glusterfs/bricks|wc -l)" + local bcnt="$(brick_count)" + + if [ $bcnt -ne 1 ]; then + if [ -z $ret ]; then + ret="no" + fi + + if [ $ret = "on" ] || [ $cnt -eq 1 ]; then + echo "Y" + else + echo "N" + fi + else + echo "N" + fi +} + +function check_samples() { + local FOP_TYPE=$1 + local NS_HASH=$2 + local FILE=$3 + local BRICK=$4 + local GFID="$(getfattr -n trusted.gfid -e text --only-values $B0/$BRICK$FILE | xxd -p)" + local val="$(check_brick_multiplex)" + + if [ $val = "Y" ]; then + BRICK="${V0}0" + fi + + grep -i "ns_$OP" /var/log/glusterfs/bricks/d-backends-$BRICK.log | + grep -- $NS_HASH | sed 's/\-//g' | grep -- $GFID + if [ $? -eq 0 ]; then + echo "Y" + else + echo "N" + fi +} + +cleanup; + +TEST mkdir -p $B0/${V0}{0,1,2,3,4,5,6,7,8,9} + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 replica 3 $H0:$B0/${V0}{0,1,2,3,4,5,6,7,8} +TEST $CLI volume set $V0 nfs.disable off +TEST $CLI volume set $V0 performance.stat-prefetch off +TEST $CLI volume set $V0 performance.nfs.stat-prefetch off +TEST $CLI volume set $V0 cluster.read-subvolume-index 0 +TEST $CLI volume set $V0 diagnostics.brick-log-level DEBUG +TEST $CLI volume set $V0 features.tag-namespaces on +TEST $CLI volume set $V0 storage.build-pgfid on +TEST $CLI volume start $V0 + +sleep 2 + +TEST mount_nfs $H0:/$V0 $N0 nolock; + +################################ +# Paths in the samples # +################################ + +mkdir -p $N0/namespace + +# subvol_1 = bar, subvol_2 = foo, subvol_3 = hey +# Test create, write (tagged by loc, fd respectively). +touch $N0/namespace/{bar,foo,hey} +echo "garbage" > $N0/namespace/bar +echo "garbage" > $N0/namespace/foo +echo "garbage" > $N0/namespace/hey +EXPECT_WITHIN 10 "Y" check_samples CREATE $NAMESPACE_HASH /namespace/bar patchy0 +EXPECT_WITHIN 10 "Y" check_samples CREATE $NAMESPACE_HASH /namespace/foo patchy3 +EXPECT_WITHIN 10 "Y" check_samples CREATE $NAMESPACE_HASH /namespace/hey patchy6 +EXPECT_WITHIN 10 "Y" check_samples WRITEV $NAMESPACE_HASH /namespace/bar patchy0 +EXPECT_WITHIN 10 "Y" check_samples WRITEV $NAMESPACE_HASH /namespace/foo patchy3 +EXPECT_WITHIN 10 "Y" check_samples WRITEV $NAMESPACE_HASH /namespace/hey patchy6 + +# Test stat (tagged by loc) +stat $N0/namespace/bar &> /dev/null +stat $N0/namespace/foo &> /dev/null +stat $N0/namespace/hey &> /dev/null +EXPECT_WITHIN 10 "Y" check_samples STAT $NAMESPACE_HASH /namespace/bar patchy0 +EXPECT_WITHIN 10 "Y" check_samples STAT $NAMESPACE_HASH /namespace/foo patchy3 +EXPECT_WITHIN 10 "Y" check_samples STAT $NAMESPACE_HASH /namespace/hey patchy6 + +EXPECT_WITHIN 10 "Y" umount_nfs $N0; +sleep 1 +TEST mount_nfs $H0:/$V0 $N0 nolock; + +cat $N0/namespace/bar &> /dev/null +EXPECT_WITHIN 10 "Y" check_samples READ $NAMESPACE_HASH /namespace/bar patchy0 + +dir $N0/namespace &> /dev/null +EXPECT_WITHIN 10 "Y" check_samples LOOKUP $NAMESPACE_HASH /namespace patchy0 + +mkdir -p $N0/namespace{2,3} +EXPECT_WITHIN 10 "Y" check_samples MKDIR $NAMESPACE2_HASH /namespace2 patchy0 +EXPECT_WITHIN 10 "Y" check_samples MKDIR $NAMESPACE3_HASH /namespace3 patchy0 + +touch $N0/namespace2/file +touch $N0/namespace3/file +EXPECT_WITHIN 10 "Y" check_samples CREATE $NAMESPACE2_HASH /namespace2/file patchy0 +EXPECT_WITHIN 10 "Y" check_samples CREATE $NAMESPACE3_HASH /namespace3/file patchy0 + +truncate -s 0 $N0/namespace/bar +EXPECT_WITHIN 10 "Y" check_samples TRUNCATE $NAMESPACE_HASH /namespace/bar patchy0 + +ln -s $N0/namespace/foo $N0/namespace/foo_link +EXPECT_WITHIN 10 "Y" check_samples SYMLINK $NAMESPACE_HASH /namespace/foo patchy3 + +open $N0/namespace/hey +EXPECT_WITHIN 10 "Y" check_samples OPEN $NAMESPACE_HASH /namespace/hey patchy6 + +cleanup; diff --git a/tests/basic/netgroup_parsing.t b/tests/basic/netgroup_parsing.t new file mode 100644 index 00000000000..cf8d871f1f8 --- /dev/null +++ b/tests/basic/netgroup_parsing.t @@ -0,0 +1,56 @@ +#!/bin/bash + +. $(dirname $0)/../include.rc +. $(dirname $0)/../volume.rc + +NG_FILES=$(dirname $0)/../configfiles +cleanup; + +function test_ng_1 () +{ + glusterfsd --print-netgroups $1 | sed -n 1p +} + +function test_ng_2 () +{ + glusterfsd --print-netgroups $1 | sed -n 2p +} + +function test_ng_3 () +{ + glusterfsd --print-netgroups $1 | sed -n 3p +} + +function test_ng_4 () +{ + glusterfsd --print-netgroups $1 | sed -n 4p +} + +function test_bad_ng () +{ + glusterfsd --print-netgroups $1 2>&1 | sed -n 1p +} + +function test_large_file () +{ + # The build system needs this path for the test to pass. + # This is an important test because this file is ~1800 lines + # longs and is a "real-world" netgroups file. + glusterfsd --print-netgroups ~/opsfiles/storage/netgroup/netgroup | sed -n 1p +} + +function test_empty_ng () +{ + glusterfsd --print-netgroups $1 2>&1 | sed -n 2p +} + +EXPECT_KEYWORD "ng3 (dev-1763.prn-2.example.com,,)" test_ng_1 $NG_FILES/netgroups +EXPECT_KEYWORD "ng2 (dev1763.prn2.example.com,,)" test_ng_2 $NG_FILES/netgroups +EXPECT_KEYWORD "ng1 ng2 (dev1763.prn2.example.com,,)" test_ng_3 $NG_FILES/netgroups +EXPECT_KEYWORD "asdf ng1 ng2 (dev1763.prn2.example.com,,)" test_ng_4 $NG_FILES/netgroups +# TODO: get a real-world large netgroup file +#EXPECT_KEYWORD "wikipedia001.07.prn1 (wikipedia003.prn1.example.com,,)(wikipedia002.prn1.example.com,,)(wikipedia001.prn1.example.com,,)" test_large_file +EXPECT_KEYWORD "Parse error" test_bad_ng $NG_FILES/bad_netgroups +EXPECT_KEYWORD "No netgroups were specified except for the parent" test_empty_ng $NG_FILES/bad_netgroups + +cleanup; diff --git a/tests/basic/nl-cache.t b/tests/basic/nl-cache.t new file mode 100755 index 00000000000..90c778c8a88 --- /dev/null +++ b/tests/basic/nl-cache.t @@ -0,0 +1,98 @@ +#!/bin/bash + +. $(dirname $0)/../include.rc +. $(dirname $0)/../volume.rc + +cleanup; + +TEST glusterd + +TEST $CLI volume create $V0 $H0:$B0/${V0}{0..4} +EXPECT 'Created' volinfo_field $V0 'Status' + +TEST $CLI volume set $V0 group nl-cache +EXPECT '600' volinfo_field $V0 'performance.nl-cache-timeout' +EXPECT 'on' volinfo_field $V0 'performance.nl-cache' +EXPECT '600' volinfo_field $V0 'features.cache-invalidation-timeout' +EXPECT 'on' volinfo_field $V0 'features.cache-invalidation' +EXPECT '200000' volinfo_field $V0 'network.inode-lru-limit' +TEST $CLI volume set $V0 nl-cache-positive-entry on + +TEST $CLI volume start $V0; +EXPECT 'Started' volinfo_field $V0 'Status'; + +TEST glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0 +TEST glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M1 + +TEST ! ls $M0/file2 +TEST touch $M0/file1 +TEST ! ls $M0/file2 +TEST touch $M0/file2 +TEST ls $M0/file2 +TEST rm $M0/file2 +TEST rm $M0/file1 + +TEST mkdir $M0/dir1 +TEST ! ls -l $M0/dir1/file +TEST mkdir $M0/dir1/dir2 +TEST ! ls -l $M0/dir1/file +TEST ! ls -l $M0/dir1/dir2/file +TEST ls -l $M0/dir1/dir2 +TEST rmdir $M0/dir1/dir2 +TEST rmdir $M0/dir1 + +TEST ! ls -l $M0/file2 +TEST touch $M1/file2 +TEST ls -l $M0/file2 +TEST rm $M1/file2 + +TEST ! ls -l $M0/dir1 +TEST mkdir $M1/dir1 +TEST ls -l $M0/dir1 +TEST ! ls -l $M0/dir1/file1 +TEST mkdir $M1/dir1/dir2 +TEST ! ls -l $M0/dir1/file1 +TEST ls -l $M0/dir1/dir2 +TEST ! ls -l $M1/dir1/file1 + +TEST touch $M0/dir1/file +TEST ln $M0/dir1/file $M0/dir1/file_link +TEST ls -l $M1/dir1/file +TEST ls -l $M1/dir1/file_link +TEST rm $M0/dir1/file +TEST rm $M0/dir1/file_link +TEST rmdir $M0/dir1/dir2 +TEST rmdir $M0/dir1 + +#Check mknod +TEST ! ls -l $M0/dir +TEST mkdir $M0/dir +TEST mknod -m 0666 $M0/dir/block b 4 5 +TEST mknod -m 0666 $M0/dir/char c 1 5 +TEST mknod -m 0666 $M0/dir/fifo p +TEST rm $M0/dir/block +TEST rm $M0/dir/char +TEST rm $M0/dir/fifo + +#Check getxattr +TEST touch $M0/file1 +TEST getfattr -d -m. -e hex $M0/file1 +TEST getfattr -n "glusterfs.get_real_filename:file1" $M0; +TEST getfattr -n "glusterfs.get_real_filename:FILE1" $M0; +TEST ! getfattr -n "glusterfs.get_real_filename:FILE2" $M0; + +#Check statedump +TEST generate_mount_statedump $V0 $M0 +TEST cleanup_mount_statedump $V0 + +#Check reconfigure +TEST $CLI volume reset $V0 nl-cache-timeout +TEST $CLI volume reset $V0 nl-cache-positive-entry +TEST $CLI volume reset $V0 nl-cache-limit +TEST $CLI volume reset $V0 nl-cache-pass-through + +TEST $CLI volume stop $V0 +TEST $CLI volume delete $V0 + +cleanup; +#G_TESTDEF_TEST_STATUS_NETBSD7=BAD_TEST,BUG=000000 diff --git a/tests/basic/nufa.t b/tests/basic/nufa.t index 0d4c229a0fa..cb09fc5bbbf 100644 --- a/tests/basic/nufa.t +++ b/tests/basic/nufa.t @@ -2,6 +2,9 @@ . $(dirname $0)/../include.rc . $(dirname $0)/../volume.rc +. $(dirname $0)/../nfs.rc + +#G_TESTDEF_TEST_STATUS_CENTOS6=NFS_TEST cleanup; @@ -9,11 +12,12 @@ TEST glusterd TEST pidof glusterd TEST $CLI volume info; -TEST $CLI volume create $V0 replica 2 stripe 2 $H0:$B0/${V0}{1,2,3,4,5,6,7,8}; +TEST $CLI volume create $V0 replica 3 $H0:$B0/${V0}{1,2,3,4,5,6}; +TEST $CLI volume set $V0 nfs.disable false EXPECT "$V0" volinfo_field $V0 'Volume Name'; EXPECT 'Created' volinfo_field $V0 'Status'; -EXPECT '8' brick_count $V0 +EXPECT '6' brick_count $V0 TEST $CLI volume set $V0 nufa on; @@ -21,12 +25,17 @@ TEST $CLI volume start $V0; EXPECT 'Started' volinfo_field $V0 'Status'; ## Mount FUSE with caching disabled (read-only) -TEST glusterfs --entry-timeout=0 --attribute-timeout=0 --read-only -s $H0 --volfile-id $V0 $M1; +TEST $GFS --read-only -s $H0 --volfile-id $V0 $M1; ## Wait for volume to register with rpc.mountd sleep 5; +##Wait for connection establishment between nfs server and brick process +EXPECT_WITHIN $NFS_EXPORT_TIMEOUT "1" is_nfs_export_available; ## Mount NFS -TEST mount -t nfs -o nolock,soft,intr $H0:/$V0 $N0; +TEST mount_nfs $H0:/$V0 $N0 nolock; + +## Before killing daemon to avoid deadlocks +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" umount_nfs $N0 cleanup; diff --git a/tests/basic/op_errnos.t b/tests/basic/op_errnos.t new file mode 100755 index 00000000000..9c48d7a02ad --- /dev/null +++ b/tests/basic/op_errnos.t @@ -0,0 +1,34 @@ +#!/bin/bash + +. $(dirname $0)/../include.rc +. $(dirname $0)/../snapshot.rc + +function get-op_errno-xml() +{ + $CLI $1 --xml | xmllint --format - | grep opErrno | sed 's/\(<opErrno>\|<\/opErrno>\)//g' +} + +cleanup; +TEST verify_lvm_version; +TEST glusterd; +TEST pidof glusterd; + +TEST setup_lvm 1 + +TEST $CLI volume create $V0 $H0:$L1 +TEST $CLI volume start $V0 + +EXPECT 0 get-op_errno-xml "snapshot create snap1 $V0 no-timestamp" +EXPECT 30806 get-op_errno-xml "snapshot create snap1 imaginary_volume" +EXPECT 30807 get-op_errno-xml "snapshot delete imaginary_snap" +EXPECT 30809 get-op_errno-xml "snapshot restore snap1" +TEST $CLI volume stop $V0 +EXPECT 30810 get-op_errno-xml "snapshot create snap1 $V0" +TEST $CLI volume start $V0 +EXPECT 30811 get-op_errno-xml "snapshot clone $V0 snap1" +EXPECT 30812 get-op_errno-xml "snapshot create snap1 $V0 no-timestamp" + +EXPECT 0 get-op_errno-xml "snapshot delete snap1" +TEST $CLI volume stop $V0 + +cleanup; diff --git a/tests/basic/open-behind/open-behind.t b/tests/basic/open-behind/open-behind.t new file mode 100644 index 00000000000..5e865d602e2 --- /dev/null +++ b/tests/basic/open-behind/open-behind.t @@ -0,0 +1,183 @@ +#!/bin/bash + +WD="$(dirname "${0}")" + +. ${WD}/../../include.rc +. ${WD}/../../volume.rc + +function assign() { + local _assign_var="${1}" + local _assign_value="${2}" + + printf -v "${_assign_var}" "%s" "${_assign_value}" +} + +function pipe_create() { + local _pipe_create_var="${1}" + local _pipe_create_name + local _pipe_create_fd + + _pipe_create_name="$(mktemp -u)" + mkfifo "${_pipe_create_name}" + exec {_pipe_create_fd}<>"${_pipe_create_name}" + rm "${_pipe_create_name}" + + assign "${_pipe_create_var}" "${_pipe_create_fd}" +} + +function pipe_close() { + local _pipe_close_fd="${!1}" + + exec {_pipe_close_fd}>&- +} + +function tester_start() { + declare -ag tester + local tester_in + local tester_out + + pipe_create tester_in + pipe_create tester_out + + ${WD}/tester <&${tester_in} >&${tester_out} & + + tester=("$!" "${tester_in}" "${tester_out}") +} + +function tester_send() { + declare -ag tester + local tester_res + local tester_extra + + echo "${*}" >&${tester[1]} + + read -t 3 -u ${tester[2]} tester_res tester_extra + echo "${tester_res} ${tester_extra}" + if [[ "${tester_res}" == "OK" ]]; then + return 0 + fi + + return 1 +} + +function tester_stop() { + declare -ag tester + local tester_res + + tester_send "quit" + + tester_res=0 + if ! wait ${tester[0]}; then + tester_res=$? + fi + + unset tester + + return ${tester_res} +} + +function count_open() { + local file="$(realpath "${B0}/${V0}/${1}")" + local count="0" + local inode + local ref + + inode="$(stat -c %i "${file}")" + + for fd in /proc/${BRICK_PID}/fd/*; do + ref="$(readlink "${fd}")" + if [[ "${ref}" == "${B0}/${V0}/"* ]]; then + if [[ "$(stat -c %i "${ref}")" == "${inode}" ]]; then + count="$((${count} + 1))" + fi + fi + done + + echo "${count}" +} + +cleanup + +TEST build_tester ${WD}/tester.c ${WD}/tester-fd.c + +TEST glusterd +TEST pidof glusterd +TEST ${CLI} volume create ${V0} ${H0}:${B0}/${V0} +TEST ${CLI} volume set ${V0} flush-behind off +TEST ${CLI} volume set ${V0} write-behind off +TEST ${CLI} volume set ${V0} quick-read off +TEST ${CLI} volume set ${V0} stat-prefetch on +TEST ${CLI} volume set ${V0} io-cache off +TEST ${CLI} volume set ${V0} open-behind on +TEST ${CLI} volume set ${V0} lazy-open off +TEST ${CLI} volume set ${V0} read-after-open off +TEST ${CLI} volume start ${V0} + +TEST ${GFS} --volfile-id=/${V0} --volfile-server=${H0} ${M0}; + +BRICK_PID="$(get_brick_pid ${V0} ${H0} ${B0}/${V0})" + +TEST touch "${M0}/test" + +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 +TEST ${GFS} --volfile-id=/${V0} --volfile-server=${H0} ${M0}; + +TEST tester_start + +TEST tester_send fd open 0 "${M0}/test" +EXPECT_WITHIN 5 "1" count_open "/test" +TEST tester_send fd close 0 +EXPECT_WITHIN 5 "0" count_open "/test" + +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 +TEST ${CLI} volume set ${V0} lazy-open on +TEST ${GFS} --volfile-id=/${V0} --volfile-server=${H0} ${M0}; + +TEST tester_send fd open 0 "${M0}/test" +sleep 2 +EXPECT "0" count_open "/test" +TEST tester_send fd write 0 "test" +EXPECT "1" count_open "/test" +TEST tester_send fd close 0 +EXPECT_WITHIN 5 "0" count_open "/test" + +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 +TEST ${GFS} --volfile-id=/${V0} --volfile-server=${H0} ${M0}; + +TEST tester_send fd open 0 "${M0}/test" +EXPECT "0" count_open "/test" +EXPECT "test" tester_send fd read 0 64 +# Even though read-after-open is disabled, use-anonymous-fd is also disabled, +# so reads need to open the file first. +EXPECT "1" count_open "/test" +TEST tester_send fd close 0 +EXPECT "0" count_open "/test" + +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 +TEST ${GFS} --volfile-id=/${V0} --volfile-server=${H0} ${M0}; + +TEST tester_send fd open 0 "${M0}/test" +EXPECT "0" count_open "/test" +TEST tester_send fd open 1 "${M0}/test" +EXPECT "2" count_open "/test" +TEST tester_send fd close 0 +EXPECT_WITHIN 5 "1" count_open "/test" +TEST tester_send fd close 1 +EXPECT_WITHIN 5 "0" count_open "/test" + +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 +TEST ${CLI} volume set ${V0} read-after-open on +TEST ${GFS} --volfile-id=/${V0} --volfile-server=${H0} ${M0}; + +TEST tester_send fd open 0 "${M0}/test" +EXPECT "0" count_open "/test" +EXPECT "test" tester_send fd read 0 64 +EXPECT "1" count_open "/test" +TEST tester_send fd close 0 +EXPECT_WITHIN 5 "0" count_open "/test" + +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 + +TEST tester_stop + +cleanup diff --git a/tests/basic/open-behind/tester-fd.c b/tests/basic/open-behind/tester-fd.c new file mode 100644 index 00000000000..00f02bc5b0a --- /dev/null +++ b/tests/basic/open-behind/tester-fd.c @@ -0,0 +1,99 @@ +/* + Copyright (c) 2020 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + +#include "tester.h" + +#include <stdlib.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <string.h> +#include <ctype.h> +#include <errno.h> + +static int32_t +fd_open(context_t *ctx, command_t *cmd) +{ + obj_t *obj; + int32_t fd; + + obj = cmd->args[0].obj.ref; + + fd = open(cmd->args[1].str.data, O_RDWR); + if (fd < 0) { + return error(errno, "open() failed"); + } + + obj->type = OBJ_TYPE_FD; + obj->fd = fd; + + out_ok("%d", fd); + + return 0; +} + +static int32_t +fd_close(context_t *ctx, command_t *cmd) +{ + obj_t *obj; + + obj = cmd->args[0].obj.ref; + obj->type = OBJ_TYPE_NONE; + + if (close(obj->fd) != 0) { + return error(errno, "close() failed"); + } + + out_ok(); + + return 0; +} + +static int32_t +fd_write(context_t *ctx, command_t *cmd) +{ + ssize_t len, ret; + + len = strlen(cmd->args[1].str.data); + ret = write(cmd->args[0].obj.ref->fd, cmd->args[1].str.data, len); + if (ret < 0) { + return error(errno, "write() failed"); + } + + out_ok("%zd", ret); + + return 0; +} + +static int32_t +fd_read(context_t *ctx, command_t *cmd) +{ + char data[cmd->args[1].num.value + 1]; + ssize_t ret; + + ret = read(cmd->args[0].obj.ref->fd, data, cmd->args[1].num.value); + if (ret < 0) { + return error(errno, "read() failed"); + } + + data[ret] = 0; + + out_ok("%zd %s", ret, data); + + return 0; +} + +command_t fd_commands[] = { + {"open", fd_open, CMD_ARGS(ARG_VAL(OBJ_TYPE_NONE), ARG_STR(1024))}, + {"close", fd_close, CMD_ARGS(ARG_VAL(OBJ_TYPE_FD))}, + {"write", fd_write, CMD_ARGS(ARG_VAL(OBJ_TYPE_FD), ARG_STR(1024))}, + {"read", fd_read, CMD_ARGS(ARG_VAL(OBJ_TYPE_FD), ARG_NUM(0, 1024))}, + CMD_END}; diff --git a/tests/basic/open-behind/tester.c b/tests/basic/open-behind/tester.c new file mode 100644 index 00000000000..b2da71c8385 --- /dev/null +++ b/tests/basic/open-behind/tester.c @@ -0,0 +1,444 @@ +/* + Copyright (c) 2020 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + +#include "tester.h" + +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <ctype.h> +#include <errno.h> + +static void * +mem_alloc(size_t size) +{ + void *ptr; + + ptr = malloc(size); + if (ptr == NULL) { + error(ENOMEM, "Failed to allocate memory (%zu bytes)", size); + } + + return ptr; +} + +static void +mem_free(void *ptr) +{ + free(ptr); +} + +static bool +buffer_create(context_t *ctx, size_t size) +{ + ctx->buffer.base = mem_alloc(size); + if (ctx->buffer.base == NULL) { + return false; + } + + ctx->buffer.size = size; + ctx->buffer.len = 0; + ctx->buffer.pos = 0; + + return true; +} + +static void +buffer_destroy(context_t *ctx) +{ + mem_free(ctx->buffer.base); + ctx->buffer.size = 0; + ctx->buffer.len = 0; +} + +static int32_t +buffer_get(context_t *ctx) +{ + ssize_t len; + + if (ctx->buffer.pos >= ctx->buffer.len) { + len = read(0, ctx->buffer.base, ctx->buffer.size); + if (len < 0) { + return error(errno, "read() failed"); + } + if (len == 0) { + return 0; + } + + ctx->buffer.len = len; + ctx->buffer.pos = 0; + } + + return ctx->buffer.base[ctx->buffer.pos++]; +} + +static int32_t +str_skip_spaces(context_t *ctx, int32_t current) +{ + while ((current > 0) && (current != '\n') && isspace(current)) { + current = buffer_get(ctx); + } + + return current; +} + +static int32_t +str_token(context_t *ctx, char *buffer, uint32_t size, int32_t current) +{ + uint32_t len; + + current = str_skip_spaces(ctx, current); + + len = 0; + while ((size > 0) && (current > 0) && (current != '\n') && + !isspace(current)) { + len++; + *buffer++ = current; + size--; + current = buffer_get(ctx); + } + + if (len == 0) { + return error(ENODATA, "Expecting a token"); + } + + if (size == 0) { + return error(ENOBUFS, "Token too long"); + } + + *buffer = 0; + + return current; +} + +static int32_t +str_number(context_t *ctx, uint64_t min, uint64_t max, uint64_t *value, + int32_t current) +{ + char text[32], *ptr; + uint64_t num; + + current = str_token(ctx, text, sizeof(text), current); + if (current > 0) { + num = strtoul(text, &ptr, 0); + if ((*ptr != 0) || (num < min) || (num > max)) { + return error(ERANGE, "Invalid number"); + } + *value = num; + } + + return current; +} + +static int32_t +str_eol(context_t *ctx, int32_t current) +{ + current = str_skip_spaces(ctx, current); + if (current != '\n') { + return error(EINVAL, "Expecting end of command"); + } + + return current; +} + +static void +str_skip(context_t *ctx, int32_t current) +{ + while ((current > 0) && (current != '\n')) { + current = buffer_get(ctx); + } +} + +static int32_t +cmd_parse_obj(context_t *ctx, arg_t *arg, int32_t current) +{ + obj_t *obj; + uint64_t id; + + current = str_number(ctx, 0, ctx->obj_count, &id, current); + if (current <= 0) { + return current; + } + + obj = &ctx->objs[id]; + if (obj->type != arg->obj.type) { + if (obj->type != OBJ_TYPE_NONE) { + return error(EBUSY, "Object is in use"); + } + return error(ENOENT, "Object is not defined"); + } + + arg->obj.ref = obj; + + return current; +} + +static int32_t +cmd_parse_num(context_t *ctx, arg_t *arg, int32_t current) +{ + return str_number(ctx, arg->num.min, arg->num.max, &arg->num.value, + current); +} + +static int32_t +cmd_parse_str(context_t *ctx, arg_t *arg, int32_t current) +{ + return str_token(ctx, arg->str.data, arg->str.size, current); +} + +static int32_t +cmd_parse_args(context_t *ctx, command_t *cmd, int32_t current) +{ + arg_t *arg; + + for (arg = cmd->args; arg->type != ARG_TYPE_NONE; arg++) { + switch (arg->type) { + case ARG_TYPE_OBJ: + current = cmd_parse_obj(ctx, arg, current); + break; + case ARG_TYPE_NUM: + current = cmd_parse_num(ctx, arg, current); + break; + case ARG_TYPE_STR: + current = cmd_parse_str(ctx, arg, current); + break; + default: + return error(EINVAL, "Unknown argument type"); + } + } + + if (current < 0) { + return current; + } + + current = str_eol(ctx, current); + if (current <= 0) { + return error(EINVAL, "Syntax error"); + } + + return cmd->handler(ctx, cmd); +} + +static int32_t +cmd_parse(context_t *ctx, command_t *cmds) +{ + char text[32]; + command_t *cmd; + int32_t current; + + cmd = cmds; + do { + current = str_token(ctx, text, sizeof(text), buffer_get(ctx)); + if (current <= 0) { + return current; + } + + while (cmd->name != NULL) { + if (strcmp(cmd->name, text) == 0) { + if (cmd->handler != NULL) { + return cmd_parse_args(ctx, cmd, current); + } + cmd = cmd->cmds; + break; + } + cmd++; + } + } while (cmd->name != NULL); + + str_skip(ctx, current); + + return error(ENOTSUP, "Unknown command"); +} + +static void +cmd_fini(context_t *ctx, command_t *cmds) +{ + command_t *cmd; + arg_t *arg; + + for (cmd = cmds; cmd->name != NULL; cmd++) { + if (cmd->handler == NULL) { + cmd_fini(ctx, cmd->cmds); + } else { + for (arg = cmd->args; arg->type != ARG_TYPE_NONE; arg++) { + switch (arg->type) { + case ARG_TYPE_STR: + mem_free(arg->str.data); + arg->str.data = NULL; + break; + default: + break; + } + } + } + } +} + +static bool +cmd_init(context_t *ctx, command_t *cmds) +{ + command_t *cmd; + arg_t *arg; + + for (cmd = cmds; cmd->name != NULL; cmd++) { + if (cmd->handler == NULL) { + if (!cmd_init(ctx, cmd->cmds)) { + return false; + } + } else { + for (arg = cmd->args; arg->type != ARG_TYPE_NONE; arg++) { + switch (arg->type) { + case ARG_TYPE_STR: + arg->str.data = mem_alloc(arg->str.size); + if (arg->str.data == NULL) { + return false; + } + break; + default: + break; + } + } + } + } + + return true; +} + +static bool +objs_create(context_t *ctx, uint32_t count) +{ + uint32_t i; + + ctx->objs = mem_alloc(sizeof(obj_t) * count); + if (ctx->objs == NULL) { + return false; + } + ctx->obj_count = count; + + for (i = 0; i < count; i++) { + ctx->objs[i].type = OBJ_TYPE_NONE; + } + + return true; +} + +static int32_t +objs_destroy(context_t *ctx) +{ + uint32_t i; + int32_t err; + + err = 0; + for (i = 0; i < ctx->obj_count; i++) { + if (ctx->objs[i].type != OBJ_TYPE_NONE) { + err = error(ENOTEMPTY, "Objects not destroyed"); + break; + } + } + + mem_free(ctx->objs); + ctx->objs = NULL; + ctx->obj_count = 0; + + return err; +} + +static context_t * +init(size_t size, uint32_t objs, command_t *cmds) +{ + context_t *ctx; + + ctx = mem_alloc(sizeof(context_t)); + if (ctx == NULL) { + goto failed; + } + + if (!buffer_create(ctx, size)) { + goto failed_ctx; + } + + if (!objs_create(ctx, objs)) { + goto failed_buffer; + } + + if (!cmd_init(ctx, cmds)) { + goto failed_objs; + } + + ctx->active = true; + + return ctx; + +failed_objs: + cmd_fini(ctx, cmds); + objs_destroy(ctx); +failed_buffer: + buffer_destroy(ctx); +failed_ctx: + mem_free(ctx); +failed: + return NULL; +} + +static int32_t +fini(context_t *ctx, command_t *cmds) +{ + int32_t ret; + + cmd_fini(ctx, cmds); + buffer_destroy(ctx); + + ret = objs_destroy(ctx); + + ctx->active = false; + + return ret; +} + +static int32_t +exec_quit(context_t *ctx, command_t *cmd) +{ + ctx->active = false; + + return 0; +} + +static command_t commands[] = {{"fd", NULL, CMD_SUB(fd_commands)}, + {"quit", exec_quit, CMD_ARGS()}, + CMD_END}; + +int32_t +main(int32_t argc, char *argv[]) +{ + context_t *ctx; + int32_t res; + + ctx = init(1024, 16, commands); + if (ctx == NULL) { + return 1; + } + + do { + res = cmd_parse(ctx, commands); + if (res < 0) { + out_err(-res); + } + } while (ctx->active); + + res = fini(ctx, commands); + if (res >= 0) { + out_ok(); + return 0; + } + + out_err(-res); + + return 1; +} diff --git a/tests/basic/open-behind/tester.h b/tests/basic/open-behind/tester.h new file mode 100644 index 00000000000..64e940c78fc --- /dev/null +++ b/tests/basic/open-behind/tester.h @@ -0,0 +1,145 @@ +/* + Copyright (c) 2020 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + +#ifndef __TESTER_H__ +#define __TESTER_H__ + +#include <stdio.h> +#include <inttypes.h> +#include <stdbool.h> + +enum _obj_type; +typedef enum _obj_type obj_type_t; + +enum _arg_type; +typedef enum _arg_type arg_type_t; + +struct _buffer; +typedef struct _buffer buffer_t; + +struct _obj; +typedef struct _obj obj_t; + +struct _context; +typedef struct _context context_t; + +struct _arg; +typedef struct _arg arg_t; + +struct _command; +typedef struct _command command_t; + +enum _obj_type { OBJ_TYPE_NONE, OBJ_TYPE_FD }; + +enum _arg_type { ARG_TYPE_NONE, ARG_TYPE_OBJ, ARG_TYPE_NUM, ARG_TYPE_STR }; + +struct _buffer { + char *base; + uint32_t size; + uint32_t len; + uint32_t pos; +}; + +struct _obj { + obj_type_t type; + union { + int32_t fd; + }; +}; + +struct _context { + obj_t *objs; + buffer_t buffer; + uint32_t obj_count; + bool active; +}; + +struct _arg { + arg_type_t type; + union { + struct { + obj_type_t type; + obj_t *ref; + } obj; + struct { + uint64_t value; + uint64_t min; + uint64_t max; + } num; + struct { + uint32_t size; + char *data; + } str; + }; +}; + +struct _command { + const char *name; + int32_t (*handler)(context_t *ctx, command_t *cmd); + union { + arg_t *args; + command_t *cmds; + }; +}; + +#define msg(_stream, _fmt, _args...) \ + do { \ + fprintf(_stream, _fmt "\n", ##_args); \ + fflush(_stream); \ + } while (0) + +#define msg_out(_fmt, _args...) msg(stdout, _fmt, ##_args) +#define msg_err(_err, _fmt, _args...) \ + ({ \ + int32_t __msg_err = (_err); \ + msg(stderr, "[%4u:%-15s] " _fmt, __LINE__, __FUNCTION__, __msg_err, \ + ##_args); \ + -__msg_err; \ + }) + +#define error(_err, _fmt, _args...) msg_err(_err, "E(%4d) " _fmt, ##_args) +#define warn(_err, _fmt, _args...) msg_err(_err, "W(%4d) " _fmt, ##_args) +#define info(_err, _fmt, _args...) msg_err(_err, "I(%4d) " _fmt, ##_args) + +#define out_ok(_args...) msg_out("OK " _args) +#define out_err(_err) msg_out("ERR %d", _err) + +#define ARG_END \ + { \ + ARG_TYPE_NONE \ + } + +#define CMD_ARGS1(_x, _args...) \ + .args = (arg_t[]) { _args } +#define CMD_ARGS(_args...) CMD_ARGS1(, ##_args, ARG_END) + +#define CMD_SUB(_cmds) .cmds = _cmds + +#define CMD_END \ + { \ + NULL, NULL, CMD_SUB(NULL) \ + } + +#define ARG_VAL(_type) \ + { \ + ARG_TYPE_OBJ, .obj = {.type = _type } \ + } +#define ARG_NUM(_min, _max) \ + { \ + ARG_TYPE_NUM, .num = {.min = _min, .max = _max } \ + } +#define ARG_STR(_size) \ + { \ + ARG_TYPE_STR, .str = {.size = _size } \ + } + +extern command_t fd_commands[]; + +#endif /* __TESTER_H__ */
\ No newline at end of file diff --git a/tests/basic/open-fd-snap-delete.t b/tests/basic/open-fd-snap-delete.t new file mode 100644 index 00000000000..a9f47cac19d --- /dev/null +++ b/tests/basic/open-fd-snap-delete.t @@ -0,0 +1,74 @@ +#!/bin/bash + +. $(dirname $0)/../include.rc +. $(dirname $0)/../volume.rc +. $(dirname $0)/../snapshot.rc +. $(dirname $0)/../fileio.rc + +cleanup; + +TEST init_n_bricks 3; +TEST setup_lvm 3; + +# start glusterd +TEST glusterd; + +TEST pidof glusterd; + +TEST $CLI volume create $V0 $H0:$L1 $H0:$L2 $H0:$L3; +TEST $CLI volume set $V0 nfs.disable false + + +TEST $CLI volume start $V0; + +TEST $GFS --volfile-server=$H0 --volfile-id=$V0 $M0; + +for i in {1..10} ; do echo "file" > $M0/file$i ; done + +# Create file and directory +TEST touch $M0/f1 +TEST mkdir $M0/dir + +TEST $CLI snapshot config activate-on-create enable +TEST $CLI volume set $V0 features.uss enable; + +for i in {1..10} ; do echo "file" > $M0/dir/file$i ; done + +TEST $CLI snapshot create snap1 $V0 no-timestamp; + +for i in {11..20} ; do echo "file" > $M0/file$i ; done +for i in {11..20} ; do echo "file" > $M0/dir/file$i ; done + +TEST $CLI snapshot create snap2 $V0 no-timestamp; + +TEST fd1=`fd_available` +TEST fd_open $fd1 'r' $M0/.snaps/snap2/dir/file11; +TEST fd_cat $fd1 + +TEST $CLI snapshot delete snap2; + +TEST ! fd_cat $fd1; + +# the return value of this command (i.e. fd_close) depetends +# mainly on how the release operation on a file descriptor is +# handled in snapview-server process. As of now snapview-server +# returns 0 for the release operation. And it is similar to how +# posix xlator does. So, as of now the expectation is to receive +# success for the close operation. +TEST fd_close $fd1; + +# This check is mainly to ensure that the snapshot daemon +# (snapd) is up and running. If it is not running, the following +# stat would receive ENOTCONN. + +TEST stat $M0/.snaps/snap1/dir/file1 + +TEST $CLI snapshot delete snap1; + +TEST rm -rf $M0/*; + +TEST $CLI volume stop $V0; + +TEST $CLI volume delete $V0; + +cleanup diff --git a/tests/basic/peer-parsing.t b/tests/basic/peer-parsing.t new file mode 100644 index 00000000000..813b65e2ae1 --- /dev/null +++ b/tests/basic/peer-parsing.t @@ -0,0 +1,52 @@ +#!/bin/bash + +. $(dirname $0)/../include.rc + +PEER_DIR="$GLUSTERD_WORKDIR"/peers +TEST mkdir -p $PEER_DIR + +declare -i HOST_NUM=100 + +create_random_peer_files() { + for i in $(seq 0 9); do + local peer_uuid=$(uuidgen) + # The rules for quoting and variable substitution in + # here documents would force this to be even less + # readable that way. + ( + echo "state=1" + echo "uuid=$peer_uuid" + echo "hostname=127.0.0.$HOST_NUM" + ) > $PEER_DIR/$peer_uuid + HOST_NUM+=1 + done +} + +create_non_peer_file() { + echo "random stuff" > $PEER_DIR/not_a_peer_file +} + +create_malformed_peer_file() { + echo "more random stuff" > $PEER_DIR/$(uuidgen) +} + +# We create lots of files, in batches, to ensure that our bogus ones are +# properly interspersed with the valid ones. + +TEST create_random_peer_files +TEST create_non_peer_file +TEST create_random_peer_files +TEST create_malformed_peer_file +TEST create_random_peer_files + +# There should be 30 peers, not counting the two bogus files. +TEST glusterd +N_PEERS=$($CLI peer status | grep ^Uuid: | wc -l) +TEST [ "$N_PEERS" = "30" ] + +# For extra credit, check the logs for messages about bogus files. + +cleanup + + + diff --git a/tests/basic/pgfid-feat.t b/tests/basic/pgfid-feat.t new file mode 100644 index 00000000000..a7baeec7b7a --- /dev/null +++ b/tests/basic/pgfid-feat.t @@ -0,0 +1,35 @@ +#!/bin/bash + +. $(dirname $0)/../include.rc +. $(dirname $0)/../volume.rc + +cleanup; + +function get_ancestry_path() { + local path=$1 + local ancestry=$(getfattr --absolute-names -e text -n glusterfs.ancestry.path "$M0/$path" | grep "^glusterfs.ancestry.path" | cut -d"=" -f2 | tr -d \"); + echo $ancestry; +} + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume info; + +TEST $CLI volume create $V0 replica 2 $H0:$B0/${V0}{1,2,3,4}; +TEST $CLI volume set $V0 build-pgfid on; + +TEST $CLI volume start $V0; +TEST $GFS -s $H0 --volfile-id $V0 $M0; + +TEST mkdir $M0/a; +TEST touch $M0/a/b; + +EXPECT "/a/b" get_ancestry_path "/a/b"; + +TEST $CLI volume set $V0 build-pgfid off; +EXPECT "" get_ancestry_path "/a/b"; + +TEST $CLI volume stop $V0; +TEST $CLI volume delete $V0; + +cleanup; diff --git a/tests/basic/playground/template-xlator-sanity.t b/tests/basic/playground/template-xlator-sanity.t new file mode 100755 index 00000000000..1c665502bfe --- /dev/null +++ b/tests/basic/playground/template-xlator-sanity.t @@ -0,0 +1,43 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +cleanup; + +TEST mkdir -p $B0/single-brick +cat > $B0/template.vol <<EOF +volume posix + type storage/posix + option directory $B0/single-brick +end-volume + +volume template + type playground/template + subvolumes posix + option dummy 13 +end-volume +EOF + +TEST glusterfs -f $B0/template.vol $M0 + +TEST $(dirname $0)/../rpc-coverage.sh --no-locks $M0 + +# Take statedump to get maximum code coverage +pid=$(ps auxww | grep glusterfs | grep -E "template.vol" | awk '{print $2}' | head -1) + +TEST generate_statedump $pid + +# For monitor output +kill -USR2 $pid + +# Handle SIGHUP and reconfigure +sed -i -e '/s/dummy 13/dummy 42/g' $B0/template.vol +kill -HUP $pid + +# for calling 'fini()' +kill -TERM $pid + +force_umount $M0 + +cleanup; diff --git a/tests/basic/posix/shared-statfs.t b/tests/basic/posix/shared-statfs.t new file mode 100644 index 00000000000..0e4a1bb409f --- /dev/null +++ b/tests/basic/posix/shared-statfs.t @@ -0,0 +1,58 @@ +#!/bin/bash +#Test that statfs is not served from posix backend FS. + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +cleanup; +TEST glusterd + +#Create brick partitions +TEST truncate -s 100M $B0/brick1 +TEST truncate -s 100M $B0/brick2 +LO1=`SETUP_LOOP $B0/brick1` +TEST [ $? -eq 0 ] +TEST MKFS_LOOP $LO1 +LO2=`SETUP_LOOP $B0/brick2` +TEST [ $? -eq 0 ] +TEST MKFS_LOOP $LO2 +TEST mkdir -p $B0/${V0}1 $B0/${V0}2 +TEST MOUNT_LOOP $LO1 $B0/${V0}1 +TEST MOUNT_LOOP $LO2 $B0/${V0}2 + +total_brick_blocks=$(df -P $B0/${V0}1 $B0/${V0}2 | tail -2 | awk '{sum = sum+$2}END{print sum}') +#Account for rounding error +brick_blocks_two_percent_less=$((total_brick_blocks*98/100)) +# Create a subdir in mountpoint and use that for volume. +TEST $CLI volume create $V0 $H0:$B0/${V0}1/1 $H0:$B0/${V0}2/1; +TEST $CLI volume start $V0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "2" online_brick_count +TEST $GFS --volfile-server=$H0 --volfile-id=$V0 $M0 +total_mount_blocks=$(df -P $M0 | tail -1 | awk '{ print $2}') +# Keeping the size less than 200M mainly because XFS will use +# some storage in brick to keep its own metadata. +TEST [ $total_mount_blocks -gt $brick_blocks_two_percent_less -a $total_mount_blocks -lt 200000 ] + + +TEST force_umount $M0 +TEST $CLI volume stop $V0 +EXPECT 'Stopped' volinfo_field $V0 'Status'; + +# From the same mount point, share another 2 bricks with the volume +TEST $CLI volume add-brick $V0 $H0:$B0/${V0}1/2 $H0:$B0/${V0}2/2 $H0:$B0/${V0}1/3 $H0:$B0/${V0}2/3 + +TEST $CLI volume start $V0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "6" online_brick_count +TEST $GFS --volfile-server=$H0 --volfile-id=$V0 $M0 +total_mount_blocks=$(df -P $M0 | tail -1 | awk '{ print $2}') +TEST [ $total_mount_blocks -gt $brick_blocks_two_percent_less -a $total_mount_blocks -lt 200000 ] + +TEST force_umount $M0 +TEST $CLI volume stop $V0 +EXPECT 'Stopped' volinfo_field $V0 'Status'; + +TEST $CLI volume delete $V0; + +UMOUNT_LOOP ${B0}/${V0}{1,2} +rm -f ${B0}/brick{1,2} +cleanup; diff --git a/tests/basic/posix/zero-fill-enospace.c b/tests/basic/posix/zero-fill-enospace.c new file mode 100644 index 00000000000..b1f142c6be9 --- /dev/null +++ b/tests/basic/posix/zero-fill-enospace.c @@ -0,0 +1,67 @@ +#include <stdio.h> +#include <stdlib.h> +#include <glusterfs/api/glfs.h> +#include <glusterfs/api/glfs-handles.h> + +int +main(int argc, char *argv[]) +{ + glfs_t *fs = NULL; + glfs_fd_t *fd = NULL; + int ret = 1; + off_t size = 0; + + if (argc != 6) { + fprintf(stderr, + "Syntax: %s <host> <volname> <file-path> <log-file> <size>\n", + argv[0]); + return 1; + } + + fs = glfs_new(argv[2]); + if (!fs) { + fprintf(stderr, "glfs_new: returned NULL\n"); + return 1; + } + + ret = glfs_set_volfile_server(fs, "tcp", argv[1], 24007); + if (ret != 0) { + fprintf(stderr, "glfs_set_volfile_server: returned %d\n", ret); + goto out; + } + ret = glfs_set_logging(fs, argv[4], 7); + if (ret != 0) { + fprintf(stderr, "glfs_set_logging: returned %d\n", ret); + goto out; + } + ret = glfs_init(fs); + if (ret != 0) { + fprintf(stderr, "glfs_init: returned %d\n", ret); + goto out; + } + + fd = glfs_open(fs, argv[3], O_RDWR); + if (fd == NULL) { + fprintf(stderr, "glfs_open: returned NULL\n"); + goto out; + } + + size = strtol(argv[5], NULL, 10); + if (size < 0) { + fprintf(stderr, "Wrong size %s", argv[5]); + goto out; + } + ret = glfs_zerofill(fd, 0, size); + if (ret <= 0) { + fprintf(stderr, "glfs_zerofill: returned %d\n", ret); + goto out; + } + + ret = 0; + +out: + if (fd) + glfs_close(fd); + glfs_fini(fs); + return ret; +} diff --git a/tests/basic/posix/zero-fill-enospace.t b/tests/basic/posix/zero-fill-enospace.t new file mode 100644 index 00000000000..ac2e61b10cf --- /dev/null +++ b/tests/basic/posix/zero-fill-enospace.t @@ -0,0 +1,35 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc +. $(dirname $0)/../../dht.rc + +cleanup; + +TEST glusterd; +TEST pidof glusterd; + +TEST truncate -s 100M $B0/brick1 + +TEST L1=`SETUP_LOOP $B0/brick1` +TEST MKFS_LOOP $L1 + +TEST mkdir -p $B0/${V0}1 + +TEST MOUNT_LOOP $L1 $B0/${V0}1 + +TEST $CLI volume create $V0 $H0:$B0/${V0}1 + +TEST $CLI volume start $V0; + +TEST glusterfs -s $H0 --volfile-id=$V0 $M0 +TEST touch $M0/foo +TEST build_tester $(dirname $0)/zero-fill-enospace.c -lgfapi -Wall -O2 +TEST ! $(dirname $0)/zero-fill-enospace $H0 $V0 /foo `gluster --print-logdir`/glfs-$V0.log 104857600 + +TEST force_umount $M0 +TEST $CLI volume stop $V0 +UMOUNT_LOOP ${B0}/${V0}1 +rm -f ${B0}/brick1 + +cleanup diff --git a/tests/basic/posixonly.t b/tests/basic/posixonly.t index b9de317a4d0..4844818fcc3 100755 --- a/tests/basic/posixonly.t +++ b/tests/basic/posixonly.t @@ -1,6 +1,7 @@ #!/bin/bash . $(dirname $0)/../include.rc +. $(dirname $0)/../volume.rc cleanup; @@ -25,6 +26,6 @@ TEST chown 100:100 $M0/dirname/filename; TEST chown 100:100 $M0/dirname; TEST rm -rf $M0/filename $M0/dirname; -TEST umount $M0; +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 cleanup; diff --git a/tests/basic/pump.t b/tests/basic/pump.t deleted file mode 100644 index 3faf06f0502..00000000000 --- a/tests/basic/pump.t +++ /dev/null @@ -1,44 +0,0 @@ -#!/bin/bash - -. $(dirname $0)/../include.rc -. $(dirname $0)/../volume.rc - -cleanup; - -TEST glusterd -TEST pidof glusterd -TEST $CLI volume create $V0 $H0:$B0/${V0}0 -TEST $CLI volume start $V0 -TEST glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0 --attribute-timeout=0 --entry-timeout=0 -cd $M0 -for i in {1..3} -do - for j in {1..10} - do - dd if=/dev/urandom of=file$j bs=128K count=10 2>/dev/null 1>/dev/null - done - mkdir dir$i && cd dir$i -done -cd -TEST umount $M0 -TEST $CLI volume replace-brick $V0 $H0:$B0/${V0}0 $H0:$B0/${V0}1 start -EXPECT_WITHIN 60 "Y" gd_is_replace_brick_completed $H0 $V0 $H0:$B0/${V0}0 $H0:$B0/${V0}1 -TEST $CLI volume replace-brick $V0 $H0:$B0/${V0}0 $H0:$B0/${V0}1 commit -TEST $CLI volume stop $V0 -TEST diff -r --exclude=.glusterfs $B0/${V0}0 $B0/${V0}1 - -files="" - -cd $B0/${V0}0 -for f in `find . -path ./.glusterfs -prune -o -print`; -do - if [ -d $f ]; then continue; fi - cmp $f $B0/${V0}1/$f - if [ $? -ne 0 ]; then - files="$files $f" - fi -done - -EXPECT "" echo $files - -cleanup diff --git a/tests/basic/quick-read-with-upcall.t b/tests/basic/quick-read-with-upcall.t new file mode 100644 index 00000000000..dfb751dfcdb --- /dev/null +++ b/tests/basic/quick-read-with-upcall.t @@ -0,0 +1,72 @@ +#!/bin/bash + +. $(dirname $0)/../include.rc + #. $(dirname $0)/../volume.rc + +cleanup; + +#Basic checks +TEST glusterd +TEST pidof glusterd +TEST $CLI volume info + +#Create a distributed volume +TEST $CLI volume create $V0 $H0:$B0/${V0}{1..2}; +TEST $CLI volume start $V0 + +# Mount FUSE without selinux: +TEST glusterfs -s $H0 --volfile-id $V0 --direct-io-mode=enable $M0; +TEST glusterfs -s $H0 --volfile-id $V0 --direct-io-mode=enable $M1; + +D0="test-message0"; +D1="test-message1"; + +function write_to() +{ + local file="$1"; + local data="$2"; + echo "$data" > "$file"; +} + + +TEST write_to "$M0/test.txt" "$D0" +EXPECT "$D0" cat $M0/test.txt +EXPECT "$D0" cat $M1/test.txt + +TEST write_to "$M0/test.txt" "$D1" +EXPECT "$D1" cat $M0/test.txt +EXPECT "$D0" cat $M1/test.txt + +sleep 1 + +# TODO: This line normally fails +EXPECT "$D1" cat $M1/test.txt + +TEST $CLI volume set $V0 features.cache-invalidation on +TEST $CLI volume set $V0 performance.quick-read-cache-timeout 15 +TEST $CLI volume set $V0 performance.md-cache-timeout 15 + +TEST write_to "$M0/test1.txt" "$D0" +EXPECT "$D0" cat $M0/test1.txt +EXPECT "$D0" cat $M1/test1.txt + +TEST write_to "$M0/test1.txt" "$D1" +EXPECT "$D1" cat $M0/test1.txt +EXPECT "$D0" cat $M1/test1.txt + +sleep 1 +EXPECT "$D0" cat $M1/test1.txt + +sleep 30 +EXPECT "$D1" cat $M1/test1.txt + +TEST $CLI volume set $V0 performance.quick-read-cache-invalidation on +TEST $CLI volume set $V0 performance.cache-invalidation on + +TEST write_to "$M0/test2.txt" "$D0" +EXPECT "$D0" cat $M0/test2.txt +EXPECT "$D0" cat $M1/test2.txt + +TEST write_to "$M0/test2.txt" "$D1" +EXPECT "$D1" cat $M0/test2.txt +EXPECT "$D1" cat $M1/test2.txt diff --git a/tests/basic/quota-ancestry-building.t b/tests/basic/quota-ancestry-building.t new file mode 100755 index 00000000000..fcb39ee31f5 --- /dev/null +++ b/tests/basic/quota-ancestry-building.t @@ -0,0 +1,71 @@ +#!/bin/bash + +. $(dirname $0)/../include.rc +. $(dirname $0)/../volume.rc +. $(dirname $0)/../fileio.rc + +cleanup; +# This tests quota enforcing on an inode without any path information. +# This should cover anon-fd type of workload as well. + +QDD=$(dirname $0)/quota +# compile the test write program and run it +build_tester $(dirname $0)/quota.c -o $QDD + +TESTS_EXPECTED_IN_LOOP=8 +TEST glusterd +TEST pidof glusterd +TEST $CLI volume info; + +TEST $CLI volume create $V0 replica 2 $H0:$B0/brick1 $H0:$B0/brick2; + +TEST $CLI volume set $V0 performance.write-behind off +TEST $CLI volume set $V0 cluster.self-heal-daemon off +TEST $CLI volume start $V0; +TEST glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0 --attribute-timeout=0 --entry-timeout=0 +EXPECT 'Started' volinfo_field $V0 'Status'; + +TEST $CLI volume quota $V0 enable +TEST $CLI volume quota $V0 limit-usage / 1B +TEST $CLI volume quota $V0 soft-timeout 0 +TEST $CLI volume quota $V0 hard-timeout 0 + +deep=/0/1/2/3/4/5/6/7/8/9 +TEST mkdir -p $M0/$deep + +TEST touch $M0/$deep/file1 $M0/$deep/file2 $M0/$deep/file3 $M0/$deep/file4 + +TEST fd_open 3 'w' "$M0/$deep/file1" +TEST fd_open 4 'w' "$M0/$deep/file2" +TEST fd_open 5 'w' "$M0/$deep/file3" +TEST fd_open 6 'w' "$M0/$deep/file4" + +# consume all quota +TEST ! $QDD $M0/$deep/file 256 4 + +# simulate name-less lookups for re-open where the parent information is lost. +# Stopping and starting the bricks will trigger client re-open which happens on +# a gfid without any parent information. Since no operations are performed on +# the fds {3..6} every-xl will be under the impression that they are good fds + +TEST $CLI volume stop $V0 +TEST $CLI volume start $V0 force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 1 + +for i in $(seq 3 6); do +# failing writes indicate that we are enforcing quota set on / +TEST_IN_LOOP ! fd_write $i "content" +TEST_IN_LOOP sync +done + +exec 3>&- +exec 4>&- +exec 5>&- +exec 6>&- + +TEST $CLI volume stop $V0 + +rm -f $QDD +cleanup; +#G_TESTDEF_TEST_STATUS_NETBSD7=BAD_TEST,BUG=1332020 diff --git a/tests/basic/quota-anon-fd-nfs.t b/tests/basic/quota-anon-fd-nfs.t new file mode 100755 index 00000000000..9e6675af6ec --- /dev/null +++ b/tests/basic/quota-anon-fd-nfs.t @@ -0,0 +1,117 @@ +#!/bin/bash + +. $(dirname $0)/../include.rc +. $(dirname $0)/../volume.rc +. $(dirname $0)/../nfs.rc +. $(dirname $0)/../fileio.rc + +#G_TESTDEF_TEST_STATUS_CENTOS6=NFS_TEST + +cleanup; + +QDD=$(dirname $0)/quota +# compile the test write program and run it +build_tester $(dirname $0)/quota.c -o $QDD + +TESTS_EXPECTED_IN_LOOP=16 +TEST glusterd +TEST pidof glusterd +TEST $CLI volume info; + +TEST $CLI volume create $V0 $H0:$B0/brick1; +EXPECT 'Created' volinfo_field $V0 'Status'; +TEST $CLI volume set $V0 nfs.disable false + + +# The test makes use of inode-lru-limit to hit a scenario, where we +# find an inode whose ancestry is not there. Following is the +# hypothesis (which is confirmed by seeing logs indicating that +# codepath has been executed, but not through a good understanding of +# NFS internals). + +# At the end of an fop, the reference count of an inode would be +# zero. The inode (and its ancestry) persists in memory only +# because of non-zero lookup count. These looked up inodes are put +# in an lru queue of size 1 (here). So, there can be at most one +# such inode in memory. + +# NFS Server makes use of anonymous fds. So, if it cannot find +# valid fd, it does a nameless lookup. This gives us an inode +# whose ancestry is NULL. When a write happens on this inode, +# quota-enforcer/marker finds a NULL ancestry and asks +# storage/posix to build it. + +TEST $CLI volume set $V0 network.inode-lru-limit 1 +TEST $CLI volume set $V0 performance.nfs.write-behind off + +TEST $CLI volume start $V0; +EXPECT 'Started' volinfo_field $V0 'Status'; + +TEST $CLI volume quota $V0 enable +TEST $CLI volume quota $V0 limit-usage / 1 +TEST $CLI volume quota $V0 soft-timeout 0 +TEST $CLI volume quota $V0 hard-timeout 0 + +EXPECT_WITHIN $NFS_EXPORT_TIMEOUT "1" is_nfs_export_available; +TEST mount_nfs $H0:/$V0 $N0 noac,soft,nolock,vers=3; +deep=/0/1/2/3/4/5/6/7/8/9 +TEST mkdir -p $N0/$deep + +TEST touch $N0/$deep/file1 $N0/$deep/file2 $N0/$deep/file3 $N0/$deep/file4 + +TEST fd_open 3 'w' "$N0/$deep/file1" +TEST fd_open 4 'w' "$N0/$deep/file2" +TEST fd_open 5 'w' "$N0/$deep/file3" +TEST fd_open 6 'w' "$N0/$deep/file4" + +# consume all quota +echo "Hello" > $N0/$deep/new_file_1 +echo "World" >> $N0/$deep/new_file_1 +echo 1 >> $N0/$deep/new_file_1 +echo 2 >> $N0/$deep/new_file_1 + +# Try to create a 1M file which should fail +TEST ! $QDD $N0/$deep/new_file_2 256 4 + + +# At the end of each fop in server, reference count of the +# inode associated with each of the file above drops to zero and hence +# put into lru queue. Since lru-limit is set to 1, an fop next file +# will displace the current inode from itable. This will ensure that +# when writes happens on same fd, fd resolution results in +# nameless lookup from server and quota_writev encounters an fd +# associated with an inode whose parent is not present in itable. + +for j in $(seq 1 2); do + for i in $(seq 3 6); do + # failing writes indicate that we are enforcing quota set on / + # even with anonymous fds. + TEST_IN_LOOP ! fd_write $i "content" + TEST_IN_LOOP sync + done +done + +exec 3>&- +exec 4>&- +exec 5>&- +exec 6>&- + +$CLI volume statedump $V0 all + +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $N0 + +# This is ugly, but there seems to be a latent race between other actions and +# stopping the volume. The visible symptom is that "umount -l" (run from +# gf_umount_lazy in glusterd) hangs. This happens pretty consistently with the +# new mem-pool code, though it's not really anything to do with memory pools - +# just with changed timing. Adding the sleep here makes it work consistently. +# +# If anyone else wants to debug the race condition, feel free. +sleep 3 + +TEST $CLI volume stop $V0 + +rm -f $QDD + +cleanup; +#G_TESTDEF_TEST_STATUS_NETBSD7=BAD_TEST,BUG=000000 diff --git a/tests/basic/quota-nfs.t b/tests/basic/quota-nfs.t new file mode 100755 index 00000000000..de94a950a7f --- /dev/null +++ b/tests/basic/quota-nfs.t @@ -0,0 +1,66 @@ +#!/bin/bash + +. $(dirname $0)/../include.rc +. $(dirname $0)/../volume.rc +. $(dirname $0)/../nfs.rc + +#G_TESTDEF_TEST_STATUS_CENTOS6=NFS_TEST + +cleanup; +QDD=$(dirname $0)/quota +# compile the test write program and run it +build_tester $(dirname $0)/quota.c -o $QDD + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume info; + +TEST $CLI volume create $V0 $H0:$B0/brick1; +EXPECT 'Created' volinfo_field $V0 'Status'; +TEST $CLI volume set $V0 nfs.disable false + +TEST $CLI volume set $V0 network.inode-lru-limit 1 +TEST $CLI volume set $V0 performance.nfs.write-behind off + +TEST $CLI volume start $V0; +EXPECT 'Started' volinfo_field $V0 'Status'; + +EXPECT_WITHIN $NFS_EXPORT_TIMEOUT 1 is_nfs_export_available +TEST mount_nfs $H0:/$V0 $N0 +deep=/0/1/2/3/4/5/6/7/8/9 +TEST mkdir -p $N0/$deep + +TEST $QDD $N0/$deep/file 256 40 + +TEST $CLI volume quota $V0 enable +TEST $CLI volume quota $V0 limit-usage / 20MB +TEST $CLI volume quota $V0 soft-timeout 0 +TEST $CLI volume quota $V0 hard-timeout 0 + +TEST $QDD $N0/$deep/newfile_1 256 20 + +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "0" STAT $N0/$deep/file +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "0" STAT $N0/$deep/newfile_1 + +#Unmount and mount to flush the data +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" umount_nfs $N0 +TEST mount_nfs $H0:/$V0 $N0 + +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "0" STAT $N0/$deep/file +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "0" STAT $N0/$deep/newfile_1 + +# wait for write behind to complete. +EXPECT_WITHIN $MARKER_UPDATE_TIMEOUT "15.0MB" quotausage "/" + +# Try to create a 100Mb file which should fail +TEST ! $QDD $N0/$deep/newfile_2 256 400 +TEST rm -f $N0/$deep/newfile_2 + +## Before killing daemon to avoid deadlocks +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" umount_nfs $N0 + +TEST $CLI volume stop $V0 + +rm -f $QDD +cleanup; +#G_TESTDEF_TEST_STATUS_NETBSD7=BAD_TEST,BUG=000000 diff --git a/tests/basic/quota-rename.t b/tests/basic/quota-rename.t new file mode 100644 index 00000000000..37438689d9f --- /dev/null +++ b/tests/basic/quota-rename.t @@ -0,0 +1,37 @@ +#!/bin/bash + +# This regression test tries to ensure renaming a directory with content, and +# no limit set, is accounted properly, when moved into a directory with quota +# limit set. + +. $(dirname $0)/../include.rc +. $(dirname $0)/../volume.rc + +cleanup; + +TEST glusterd + +TEST $CLI volume create $V0 $H0:$B0/${V0} +TEST $CLI volume start $V0; + +TEST $CLI volume quota $V0 enable; + +TEST glusterfs --volfile-id=$V0 --volfile-server=$H0 $M0; + +TEST $CLI volume quota $V0 hard-timeout 0 +TEST $CLI volume quota $V0 soft-timeout 0 + +TEST mkdir -p $M0/dir/dir1 +TEST $CLI volume quota $V0 limit-objects /dir 20 + +TEST mkdir $M0/dir/dir1/d{1..5} +TEST touch $M0/dir/dir1/f{1..5} +TEST mv $M0/dir/dir1 $M0/dir/dir2 + +#Number of files under /dir is 5 +EXPECT_WITHIN $MARKER_UPDATE_TIMEOUT "5" quota_object_list_field "/dir" 4 + +#Number of directories under /dir is 7 +EXPECT_WITHIN $MARKER_UPDATE_TIMEOUT "7" quota_object_list_field "/dir" 5 + +cleanup; diff --git a/tests/basic/quota.c b/tests/basic/quota.c new file mode 100644 index 00000000000..809ceb8e54c --- /dev/null +++ b/tests/basic/quota.c @@ -0,0 +1,89 @@ +#include <stdlib.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <errno.h> +#include <string.h> +#include <unistd.h> + +ssize_t +nwrite(int fd, const void *buf, size_t count) +{ + ssize_t ret = 0; + ssize_t written = 0; + + for (written = 0; written != count; written += ret) { + ret = write(fd, buf + written, count - written); + if (ret < 0) { + if (errno == EINTR) + ret = 0; + else + goto out; + } + } + + ret = written; +out: + return ret; +} + +int +file_write(char *filename, int bs, int count) +{ + int fd = 0; + int ret = -1; + int i = 0; + char *buf = NULL; + + bs = bs * 1024; + + buf = (char *)malloc(bs); + if (buf == NULL) + goto out; + + memset(buf, 0, bs); + + fd = open(filename, O_RDWR | O_CREAT | O_SYNC, 0600); + while (i < count) { + ret = nwrite(fd, buf, bs); + if (ret == -1) { + close(fd); + goto out; + } + i++; + } + + ret = fdatasync(fd); + if (ret) { + close(fd); + goto out; + } + + ret = close(fd); + if (ret) + goto out; + + ret = 0; + +out: + if (buf) + free(buf); + return ret; +} + +int +main(int argc, char **argv) +{ + if (argc != 4) { + printf("Usage: %s <filename> <block size in k> <count>\n", argv[0]); + return EXIT_FAILURE; + } + + if (file_write(argv[1], atoi(argv[2]), atoi(argv[3])) < 0) { + perror("write failed"); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} diff --git a/tests/basic/quota.t b/tests/basic/quota.t index ef015a30d92..46d1bafff84 100755 --- a/tests/basic/quota.t +++ b/tests/basic/quota.t @@ -2,50 +2,235 @@ . $(dirname $0)/../include.rc . $(dirname $0)/../volume.rc +. $(dirname $0)/../nfs.rc +. $(dirname $0)/../dht.rc +. $(dirname $0)/../nfs.rc + +#G_TESTDEF_TEST_STATUS_CENTOS6=NFS_TEST cleanup; +QDD=$(dirname $0)/quota +# compile the test write program and run it +build_tester $(dirname $0)/quota.c -o $QDD + +TESTS_EXPECTED_IN_LOOP=19 + TEST glusterd TEST pidof glusterd TEST $CLI volume info; -TEST $CLI volume create $V0 replica 2 stripe 2 $H0:$B0/${V0}{1,2,3,4,5,6,7,8}; - -function limit_on() -{ - local QUOTA_PATH=$1; - $CLI volume quota $V0 list | grep "$QUOTA_PATH" | awk '{print $2}' -} +TEST $CLI volume create $V0 replica 2 $H0:$B0/${V0}{1,2,3,4}; EXPECT "$V0" volinfo_field $V0 'Volume Name'; EXPECT 'Created' volinfo_field $V0 'Status'; -EXPECT '8' brick_count $V0 +EXPECT '4' brick_count $V0 +TEST $CLI volume set $V0 nfs.disable false TEST $CLI volume start $V0; EXPECT 'Started' volinfo_field $V0 'Status'; -## ------------------------------ -## Verify quota commands -## ------------------------------ +TEST $GFS -s $H0 --volfile-id $V0 $M0; + +TEST mkdir -p $M0/test_dir/in_test_dir + +## -------------------------------------------------------------------------- +## Verify quota commands and check if quota-deem-statfs is enabled by default +## -------------------------------------------------------------------------- TEST $CLI volume quota $V0 enable +EXPECT 'on' volinfo_field $V0 'features.quota' +EXPECT 'on' volinfo_field $V0 'features.inode-quota' +EXPECT 'on' volinfo_field $V0 'features.quota-deem-statfs' + TEST $CLI volume quota $V0 limit-usage /test_dir 100MB TEST $CLI volume quota $V0 limit-usage /test_dir/in_test_dir 150MB -EXPECT "150MB" limit_on "/test_dir/in_test_dir"; +EXPECT "150.0MB" quota_hard_limit "/test_dir/in_test_dir"; +EXPECT "80%" quota_soft_limit "/test_dir/in_test_dir"; TEST $CLI volume quota $V0 remove /test_dir/in_test_dir -EXPECT "100MB" limit_on "/test_dir"; +EXPECT "100.0MB" quota_hard_limit "/test_dir"; + +TEST $CLI volume quota $V0 limit-usage /test_dir 10MB +EXPECT "10.0MB" quota_hard_limit "/test_dir"; +EXPECT "80%" quota_soft_limit "/test_dir"; + +TEST $CLI volume quota $V0 soft-timeout 0 +TEST $CLI volume quota $V0 hard-timeout 0 -TEST $CLI volume quota $V0 disable ## ------------------------------ +## Verify quota enforcement +## ----------------------------- -TEST $CLI volume stop $V0; -EXPECT 'Stopped' volinfo_field $V0 'Status'; +# Try to create a 12MB file which should fail +TEST ! $QDD $M0/test_dir/1.txt 256 48 +TEST rm $M0/test_dir/1.txt + +# wait for marker's accounting to complete +EXPECT_WITHIN $MARKER_UPDATE_TIMEOUT "0Bytes" quotausage "/test_dir" + +TEST $QDD $M0/test_dir/2.txt 256 32 +EXPECT_WITHIN $MARKER_UPDATE_TIMEOUT "8.0MB" quotausage "/test_dir" + +# Checking internal xattr +# This confirms that pgfid is also filtered +TEST ! "getfattr -d -e hex -m . $M0/test_dir/2.txt | grep pgfid "; +# just check for quota xattr are visible or not +TEST ! "getfattr -d -e hex -m . $M0/test_dir | grep quota"; + +# setfattr should fail +TEST ! setfattr -n trusted.glusterfs.quota.limit-set -v 10 $M0/test_dir; + +# remove xattr should fail +TEST ! setfattr -x trusted.glusterfs.quota.limit-set $M0/test_dir; -TEST $CLI volume delete $V0; -TEST ! $CLI volume info $V0; +TEST rm $M0/test_dir/2.txt +EXPECT_WITHIN $MARKER_UPDATE_TIMEOUT "0Bytes" quotausage "/test_dir" + +## rename tests +TEST $QDD $M0/test_dir/2 256 32 +EXPECT_WITHIN $MARKER_UPDATE_TIMEOUT "8.0MB" quotausage "/test_dir" +TEST mv $M0/test_dir/2 $M0/test_dir/0 +EXPECT_WITHIN $MARKER_UPDATE_TIMEOUT "8.0MB" quotausage "/test_dir" +TEST rm $M0/test_dir/0 +EXPECT_WITHIN $MARKER_UPDATE_TIMEOUT "0Bytes" quotausage "/test_dir" + +## rename tests under different directories +TEST mkdir -p $M0/1/2; +TEST $CLI volume quota $V0 limit-usage /1/2 100MB 70%; + +# The corresponding write(3) should fail with EDQUOT ("Disk quota exceeded") +TEST ! $QDD $M0/1/2/file 256 408 + +TEST mkdir -p $M0/1/3; +TEST $QDD $M0/1/3/file 256 408 + +#The corresponding rename(3) should fail with EDQUOT ("Disk quota exceeded") +TEST ! mv $M0/1/3/ $M0/1/2/3_mvd; + +## --------------------------- + +## ------------------------------ +## Check if presence of nfs mount results in ESTALE errors for I/O +# on a fuse mount. Note: Quota command internally uses a fuse mount, +# though this may change. +## ----------------------------- + +##Wait for connection establishment between nfs server and brick process +EXPECT_WITHIN $NFS_EXPORT_TIMEOUT "1" is_nfs_export_available; + +TEST mount_nfs $H0:/$V0 $N0 nolock; +TEST $CLI volume quota $V0 limit-usage /test_dir 100MB + +TEST $CLI volume quota $V0 limit-usage /test_dir/in_test_dir 150MB + +EXPECT "150.0MB" quota_hard_limit "/test_dir/in_test_dir"; +## ----------------------------- + + +################################################### +## ------------------------------------------------ +## <Test quota functionality in add-brick scenarios> +## ------------------------------------------------ +################################################### +QUOTALIMIT=100 +QUOTALIMITROOT=2048 +TESTDIR="addbricktest" + +rm -rf $M0/*; + +## <Create directories and test> +## ----------------------------- +# 41-42 +TEST mkdir $M0/$TESTDIR +TEST mkdir $M0/$TESTDIR/dir{1..10}; + + +# 43-52 +## <set limits> +## ----------------------------- +TEST $CLI volume quota $V0 limit-usage / "$QUOTALIMITROOT"MB; +for i in {1..10}; do + TEST_IN_LOOP $CLI volume quota $V0 limit-usage /$TESTDIR/dir$i \ + "$QUOTALIMIT"MB; +done +## </Enable quota and set limits> + +#53-62 +for i in `seq 1 9`; do + TEST_IN_LOOP $QDD "$M0/$TESTDIR/dir1/10MBfile$i" 256 40 +done + +# 63-64 +## <Add brick and start rebalance> +## ------------------------------- +TEST $CLI volume add-brick $V0 $H0:$B0/brick{3,4} +TEST $CLI volume rebalance $V0 start; + +## Wait for rebalance +EXPECT_WITHIN $REBALANCE_TIMEOUT "0" rebalance_completed + +## <Try creating data beyond limit> +## -------------------------------- +for i in `seq 1 200`; do + $QDD of="$M0/$TESTDIR/dir1/1MBfile$i" 256 4\ + 2>&1 | egrep -v '(No space left|Disc quota exceeded)' +done + +# 65 +## <Test whether quota limit crossed more than 10% of limit> +## --------------------------------------------------------- +USED_KB=`du -ks $M0/$TESTDIR/dir1 | cut -f1`; +USED_MB=$(($USED_KB/1024)); +TEST [ $USED_MB -le $((($QUOTALIMIT * 110) / 100)) ] + +# 66-67 +## <Test the xattrs healed to new brick> +## ------------------------------------- +TEST getfattr -d -m "trusted.glusterfs.quota.limit-set" -e hex \ + --absolute-names $B0/brick{3,4}/$TESTDIR/dir{1..10}; +# Test on root. +TEST getfattr -d -m "trusted.glusterfs.quota.limit-set" -e hex \ + --absolute-names $B0/brick{3,4}; + +## ------------------------------------------------- +## </Test quota functionality in add-brick scenarios> +## ------------------------------------------------- + +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $N0 + +## --------------------------- +## Test quota volume options +## --------------------------- +TEST $CLI volume reset $V0 +EXPECT 'on' volinfo_field $V0 'features.quota' +EXPECT 'on' volinfo_field $V0 'features.inode-quota' +EXPECT 'on' volinfo_field $V0 'features.quota-deem-statfs' + +TEST $CLI volume reset $V0 force +EXPECT 'on' volinfo_field $V0 'features.quota' +EXPECT 'on' volinfo_field $V0 'features.inode-quota' +EXPECT 'on' volinfo_field $V0 'features.quota-deem-statfs' + +TEST $CLI volume reset $V0 features.quota-deem-statfs +EXPECT 'on' volinfo_field $V0 'features.quota-deem-statfs' + +TEST $CLI volume set $V0 features.quota-deem-statfs off +EXPECT 'off' volinfo_field $V0 'features.quota-deem-statfs' + +TEST $CLI volume set $V0 features.quota-deem-statfs on +EXPECT 'on' volinfo_field $V0 'features.quota-deem-statfs' + +TEST $CLI volume quota $V0 disable +EXPECT 'off' volinfo_field $V0 'features.quota' +EXPECT 'off' volinfo_field $V0 'features.inode-quota' +EXPECT '' volinfo_field $V0 'features.quota-deem-statfs' + +TEST $CLI volume stop $V0; +rm -f $QDD cleanup; +#G_TESTDEF_TEST_STATUS_NETBSD7=BAD_TEST,BUG=1332045 diff --git a/tests/basic/quota_aux_mount.t b/tests/basic/quota_aux_mount.t new file mode 100755 index 00000000000..78d7f47e373 --- /dev/null +++ b/tests/basic/quota_aux_mount.t @@ -0,0 +1,53 @@ +#!/bin/bash + +. $(dirname $0)/../include.rc +. $(dirname $0)/../volume.rc + +cleanup; + +##------------------------------------------------------------- +## Tests to verify that aux mount is unmounted after each quota +## command executes. +##------------------------------------------------------------- + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume info; + +TEST $CLI volume create $V0 replica 2 $H0:$B0/${V0}{1,2,3,4}; + +EXPECT "$V0" volinfo_field $V0 'Volume Name'; +EXPECT 'Created' volinfo_field $V0 'Status'; +EXPECT '4' brick_count $V0 + +TEST $CLI volume start $V0; +EXPECT 'Started' volinfo_field $V0 'Status'; + +TEST $GFS -s $H0 --volfile-id $V0 $M0; + +TEST mkdir -p $M0/test_dir/ + +TEST $CLI volume quota $V0 enable +EXPECT 'on' volinfo_field $V0 'features.quota' +EXPECT 'on' volinfo_field $V0 'features.inode-quota' + +TEST $CLI volume quota $V0 limit-usage /test_dir 150MB +EXPECT "1" get_limit_aux +TEST $CLI volume quota $V0 limit-objects /test_dir 10 +EXPECT "1" get_limit_aux +EXPECT "150.0MB" quota_hard_limit "/test_dir"; +EXPECT "1" get_list_aux +EXPECT "10" quota_object_hard_limit "/test_dir"; +EXPECT "1" get_list_aux + +TEST $CLI volume quota $V0 remove /test_dir/ +EXPECT "1" get_limit_aux +TEST $CLI volume quota $V0 remove-objects /test_dir +EXPECT "1" get_limit_aux + +TEST $CLI volume quota $V0 disable + +TEST $CLI volume stop $V0; + +cleanup; +#G_TESTDEF_TEST_STATUS_NETBSD7=BAD_TEST,BUG=1447344 diff --git a/tests/basic/rpc-coverage.sh b/tests/basic/rpc-coverage.sh new file mode 100755 index 00000000000..6203f0ac7cb --- /dev/null +++ b/tests/basic/rpc-coverage.sh @@ -0,0 +1,499 @@ +#!/bin/bash + +# This script can be used to provoke 35 fops (if afr is used), +# 28 fops (if afr is not used) (-fstat,-readdirp, and lk,xattrop calls) +# Pending are 7 procedures. +# getspec, fsyncdir, access, fentrylk, fsetxattr, fgetxattr, rchecksum +# TODO: add commands which can generate fops for missing fops + +## Script tests below File Operations over RPC (when afr is used) + +# CREATE +# ENTRYLK +# FINODELK +# FLUSH +# FSTAT +# FSYNC +# FTRUNCATE +# FXATTROP +# GETXATTR +# INODELK +# LINK +# LK +# LOOKUP +# MKDIR +# MKNOD +# OPEN +# OPENDIR +# READ +# READDIR +# READDIRP +# READLINK +# RELEASE +# RELEASEDIR +# REMOVEXATTR +# RENAME +# RMDIR +# SETATTR +# SETXATTR +# STAT +# STATFS +# SYMLINK +# TRUNCATE +# UNLINK +# WRITE +# XATTROP + +#set -e; +set -o pipefail; + +# pull compatibility functions (e.g.: stat replacement if not running Linux) +. $(dirname $0)/../include.rc + +function fail() { + echo "$*: failed."; + exit 1; +} + +function test_mkdir() +{ + mkdir -p $PFX/dir; + test $(stat -c '%F' $PFX/dir) == "directory" || fail "mkdir" +} + + +function test_create() +{ + : > $PFX/dir/file; + + test "$(stat -c '%F' $PFX/dir/file)" == "regular empty file" || fail "create" +} + + +function test_statfs() +{ + local size; + + mode=$(stat -c '%a' $PFX/dir/file); + test "x$mode" == "x644" || fail "statfs" +} + + +function test_open() +{ + exec 4<$PFX/dir/file || fail "open" + exec 4>&- || fail "open" +} + + +function test_write() +{ + dd if=/dev/zero of=$PFX/dir/file bs=65536 count=16 + test $(stat -c '%s' $PFX/dir/file) == 1048576 || fail "write" +} + + +function test_read() +{ + local count; + + count=$(dd if=$PFX/dir/file bs=64k count=16 2>/dev/null | wc -c); + test $count == 1048576 || fail "read" +} + + +function test_truncate() +{ + truncate -s 512 $PFX/dir/file; + test $(stat -c '%s' $PFX/dir/file) == 512 || fail "truncate" + + truncate -s 0 $PFX/dir/file; + test $(stat -c '%s' $PFX/dir/file) == 0 || fail "truncate" +} + + +function test_fstat() +{ + local msg; + + export PFX; + echo hooha > $PFX/dir/file + sleep 1 + msg=$(sh -c 'tail $PFX/dir/file') + test "x$msg" == "xhooha" || fail "fstat" +} + + +function test_mknod() +{ + mknod -m 0666 $PFX/dir/block b 13 42; + test "$(stat -c '%F %a %t %T' $PFX/dir/block)" == "block special file 666 d 2a" \ + || fail "mknod for block device" + + mknod -m 0666 $PFX/dir/char c 13 42; + test "$(stat -c '%F %a %t %T' $PFX/dir/char)" == "character special file 666 d 2a" \ + || fail "mknod for character device" + + mknod -m 0666 $PFX/dir/fifo p; + test "$(stat -c '%F %a' $PFX/dir/fifo)" == "fifo 666" || \ + fail "mknod for fifo" +} + + +function test_symlink() +{ + local msg; + + ( cd $PFX/dir && ln -s file symlink; ) + + test "$(stat -c '%F' $PFX/dir/symlink)" == "symbolic link" || fail "Creation of symlink" + + msg=$(cat $PFX/dir/symlink); + test "x$msg" == "xhooha" || fail "Content match for symlink" +} + + +function test_hardlink() +{ + local ino1; + local ino2; + local nlink1; + local nlink2; + local msg; + + ln $PFX/dir/file $PFX/dir/hardlink; + + ino1=$(stat -c '%i' $PFX/dir/file); + nlink1=$(stat -c '%h' $PFX/dir/file); + ino2=$(stat -c '%i' $PFX/dir/hardlink); + nlink2=$(stat -c '%h' $PFX/dir/hardlink); + + test $ino1 == $ino2 || fail "Inode comparison for hardlink" + test $nlink1 == 2 || fail "Link count for hardlink" + test $nlink2 == 2 || fail "Link count for hardlink" + + msg=$(cat $PFX/dir/hardlink); + + test "x$msg" == "xhooha" || fail "Content match for hardlinks" +} + + +function test_rename() +{ + local ino1; + local ino2; + local ino3; + local msg; + + #### file + + ino1=$(stat -c '%i' $PFX/dir/file); + + mv $PFX/dir/file $PFX/dir/file2 || fail "mv" + msg=$(cat $PFX/dir/file2); + test "x$msg" == "xhooha" || fail "File contents comparison after mv" + + ino2=$(stat -c '%i' $PFX/dir/file2); + test $ino1 == $ino2 || fail "Inode comparison after mv" + + mv $PFX/dir/file2 $PFX/dir/file; + msg=$(cat $PFX/dir/file); + test "x$msg" == "xhooha" || fail "File contents comparison after mv" + + ino3=$(stat -c '%i' $PFX/dir/file); + test $ino1 == $ino3 || fail "Inode comparison after mv" + + #### dir + + ino1=$(stat -c '%i' $PFX/dir); + + mv $PFX/dir $PFX/dir2 || fail "Directory mv" + ino2=$(stat -c '%i' $PFX/dir2); + test $ino1 == $ino2 || fail "Inode comparison after directory mv" + + mv $PFX/dir2 $PFX/dir || fail "Directory mv" + ino3=$(stat -c '%i' $PFX/dir); + test $ino1 == $ino3 || fail "Inode comparison after directory mv" +} + + +function test_chmod() +{ + local mode0; + local mode1; + local mode2; + + + #### file + + mode0=$(stat -c '%a' $PFX/dir/file); + chmod 0753 $PFX/dir/file || fail "chmod" + + mode1=$(stat -c '%a' $PFX/dir/file); + test 0$mode1 == 0753 || fail "Mode comparison after chmod" + + chmod 0$mode0 $PFX/dir/file || fail "chmod" + mode2=$(stat -c '%a' $PFX/dir/file); + test 0$mode2 == 0$mode0 || fail "Mode comparison after chmod" + + #### dir + + mode0=$(stat -c '%a' $PFX/dir); + chmod 0753 $PFX/dir || fail "chmod" + + mode1=$(stat -c '%a' $PFX/dir); + test 0$mode1 == 0753 || fail "Mode comparison after chmod" + + chmod 0$mode0 $PFX/dir || fail "chmod" + mode2=$(stat -c '%a' $PFX/dir); + test 0$mode2 == 0$mode0 || fail "Mode comparison after chmod" +} + + +function test_chown() +{ + local user1; + local user2; + local group1; + local group2; + + #### file + + user1=$(stat -c '%u' $PFX/dir/file); + group1=$(stat -c '%g' $PFX/dir/file); + + chown 13:42 $PFX/dir/file || fail "chown" + + user2=$(stat -c '%u' $PFX/dir/file); + group2=$(stat -c '%g' $PFX/dir/file); + + test $user2 == 13 || fail "User comparison after chown" + test $group2 == 42 || fail "Group comparison after chown" + + chown $user1:$group1 $PFX/dir/file || fail "chown" + + user2=$(stat -c '%u' $PFX/dir/file); + group2=$(stat -c '%g' $PFX/dir/file); + + test $user2 == $user1 || fail "User comparison after chown" + test $group2 == $group1 || fail "Group comparison after chown" + + #### dir + + user1=$(stat -c '%u' $PFX/dir); + group1=$(stat -c '%g' $PFX/dir); + + chown 13:42 $PFX/dir || fail "chown" + + user2=$(stat -c '%u' $PFX/dir); + group2=$(stat -c '%g' $PFX/dir); + + test $user2 == 13 || fail "User comparison after chown" + test $group2 == 42 || fail "Group comparison after chown" + + chown $user1:$group1 $PFX/dir || fail "chown" + + user2=$(stat -c '%u' $PFX/dir); + group2=$(stat -c '%g' $PFX/dir); + + test $user2 == $user1 || fail "User comparison after chown" + test $group2 == $group1 || fail "Group comparison after chown" +} + + +function test_utimes() +{ + local acc0; + local acc1; + local acc2; + local mod0; + local mod1; + local mod2; + + #### file + + acc0=$(stat -c '%X' $PFX/dir/file); + mod0=$(stat -c '%Y' $PFX/dir/file); + + sleep 1; + touch -a $PFX/dir/file || fail "atime change on file" + + acc1=$(stat -c '%X' $PFX/dir/file); + mod1=$(stat -c '%Y' $PFX/dir/file); + + sleep 1; + touch -m $PFX/dir/file || fail "mtime change on file" + + acc2=$(stat -c '%X' $PFX/dir/file); + mod2=$(stat -c '%Y' $PFX/dir/file); + + test $acc0 != $acc1 || fail "atime mismatch comparison on file" + test $acc1 == $acc2 || fail "atime match comparison on file" + test $mod0 == $mod1 || fail "mtime match comparison on file" + test $mod1 != $mod2 || fail "mtime mismatch comparison on file" + + #### dir + + acc0=$(stat -c '%X' $PFX/dir); + mod0=$(stat -c '%Y' $PFX/dir); + + sleep 1; + touch -a $PFX/dir || fail "atime change on directory" + + acc1=$(stat -c '%X' $PFX/dir); + mod1=$(stat -c '%Y' $PFX/dir); + + sleep 1; + touch -m $PFX/dir || fail "mtime change on directory" + + acc2=$(stat -c '%X' $PFX/dir); + mod2=$(stat -c '%Y' $PFX/dir); + + test $acc0 != $acc1 || fail "atime mismatch comparison on directory" + test $acc1 == $acc2 || fail "atime match comparison on directory" + test $mod0 == $mod1 || fail "mtime match comparison on directory" + test $mod1 != $mod2 || fail "mtime mismatch comparison on directory" +} + + +function test_locks() +{ + exec 100>$PFX/dir/lockfile || fail "exec" + + ## exclusive locks test + flock -x 100 || fail "flock -x" + ! flock -n -x $PFX/dir/lockfile -c true || fail "! flock -n -x" + ! flock -n -s $PFX/dir/lockfile -c true || fail "! flock -n -s" + flock -u 100 || fail "flock -u" + + ## shared locks test + flock -s 100 || fail "flock -s" + ! flock -n -x $PFX/dir/lockfile -c true || fail "! flock -n -x" + flock -n -s $PFX/dir/lockfile -c true || fail "! flock -n -s" + flock -u 100 || fail "flock -u" + + exec 100>&- || fail "exec" + +} + + +function test_readdir() +{ + /bin/ls $PFX/dir >/dev/null || fail "ls" +} + + +function test_setxattr() +{ + setfattr -n trusted.testing -v c00k33 $PFX/dir/file || fail "setfattr" +} + + +function test_listxattr() +{ + getfattr -m trusted $PFX/dir/file 2>/dev/null | grep -q trusted.testing || fail "getfattr" +} + + +function test_getxattr() +{ + getfattr -n trusted.testing $PFX/dir/file 2>/dev/null | grep -q c00k33 || fail "getfattr" +} + + +function test_removexattr() +{ + setfattr -x trusted.testing $PFX/dir/file || fail "setfattr remove" + getfattr -n trusted.testing $PFXf/dir/file 2>&1 | grep -q "No such attribute" +} + + +function test_unlink() +{ + rm $PFX/dir/file || fail "rm" +} + + +function test_rmdir() +{ + rm -rf $PFX || fail "rm -rf" +} + +function test_statvfs() +{ + df $DIR 2>&1 || fail "df" +} + + +function run_tests() +{ + test_statvfs; + test_mkdir; + test_create; + test_statfs; + test_open; + test_write; + test_read; + test_truncate; + test_fstat; + test_mknod; + test_hardlink; + test_symlink; + test_rename; + test_chmod; + test_chown; + test_readdir; + test_setxattr; + test_listxattr; + test_getxattr; + test_removexattr; + if [ "$run_lock_tests" = "1" ]; then + test_locks; + fi + test_utimes; + test_unlink; + test_rmdir; +} + + +function _init() +{ + DIR=$(pwd); +} + +run_lock_tests=1 +function parse_cmdline() +{ + if [ "x$1" == "x" ] ; then + echo "Usage: $0 [--no-locks] /path/mount" + exit 1 + fi + + if [ "$1" == "--no-locks" ] ; then + run_lock_tests=0 + shift + fi + + DIR=$1; + + if [ ! -d "$DIR" ] ; then + echo "$DIR: not a directory" + exit 1 + fi + + PFX="$DIR/coverage"; + rm -rvf $PFX; +} + + +function main() +{ + parse_cmdline "$@"; + + run_tests; + + exit 0; +} + + +_init && main "$@"; diff --git a/tests/basic/rpc-coverage.t b/tests/basic/rpc-coverage.t new file mode 100755 index 00000000000..2c1bcd5a63a --- /dev/null +++ b/tests/basic/rpc-coverage.t @@ -0,0 +1,25 @@ +#!/bin/bash + +. $(dirname $0)/../include.rc +. $(dirname $0)/../volume.rc + +cleanup; + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume info; + +TEST $CLI volume create $V0 replica 3 $H0:$B0/${V0}{1,2,3,4,5,6,7,8,9}; + +EXPECT "$V0" volinfo_field $V0 'Volume Name'; +EXPECT 'Created' volinfo_field $V0 'Status'; +EXPECT '9' brick_count $V0 + +TEST $CLI volume start $V0; +EXPECT 'Started' volinfo_field $V0 'Status'; + +## Mount FUSE +TEST $GFS -s $H0 --volfile-id $V0 $M1; + +TEST $(dirname $0)/rpc-coverage.sh $M1 +cleanup; diff --git a/tests/basic/rpm.t b/tests/basic/rpm.t deleted file mode 100755 index ef4b5abf0cb..00000000000 --- a/tests/basic/rpm.t +++ /dev/null @@ -1,103 +0,0 @@ -#!/bin/bash - -. $(dirname $0)/../include.rc - -RESULT_DIR=$(mktemp -d -p /var/tmp rpm-tests.XXXXXXXX) - -# enable some extra debugging -if [ -n "${DEBUG}" -a "${DEBUG}" != "0" ] -then - exec &> ${RESULT_DIR}/log - set -x -fi - -# detect the branch we're based off -if [ -n "${BRANCH}" ] ; then - # $BRANCH is set in the environment (by Jenkins or other) - GIT_PARENT="origin/${BRANCH}" -else - # get a reference to the latest clean tree - GIT_PARENT=$(git describe --abbrev=0) -fi - -# check for changed files -CHANGED_FILES=$(git diff --name-only ${GIT_PARENT}) -# filter out any files not affecting the build itself -CHANGED_FILES=$(grep -E -v \ - -e '\.c$' \ - -e '\.h$' \ - -e '\.py$' \ - -e '^tests/' \ - <<< "${CHANGED_FILES}") -if [ -z "${CHANGED_FILES}" ] -then - # only contents of files were changed, no need to retest rpmbuild - SKIP_TESTS - rm -rf ${RESULT_DIR} - cleanup - exit 0 -fi - -# checkout the sources to a new directory to execute ./configure and all -REPO=${PWD} -COMMIT=$(git describe) -mkdir ${RESULT_DIR}/sources -cd ${RESULT_DIR}/sources -git clone -q -s file://${REPO} . -git checkout -q -b rpm-test ${COMMIT} - -# build the glusterfs-*.tar.gz -[ -e configure ] || ./autogen.sh 2>&1 > /dev/null -TEST ./configure --enable-fusermount -TEST make dist - -# build the glusterfs src.rpm -ls extras -TEST make -C extras/LinuxRPM testsrpm - -chmod g=rwx ${RESULT_DIR} -chown :mock ${RESULT_DIR} - -# build for the last two Fedora EPEL releases (x86_64 only) -# TAP/Prove aren't smart about loops -TESTS_EXPECTED_IN_LOOP=2 -for MOCK_CONF in $(ls -x1 /etc/mock/*.cfg | egrep -e 'epel-[0-9]+-x86_64.cfg$' | tail -n2) -do - EPEL_RELEASE=$(basename ${MOCK_CONF} .cfg) - mkdir ${RESULT_DIR}/${EPEL_RELEASE} - chmod g=rwx ${RESULT_DIR}/${EPEL_RELEASE} - chown :mock ${RESULT_DIR}/${EPEL_RELEASE} - # expand the mock command line - MOCK_CMD=$(echo /usr/bin/mock --cleanup-after \ - --resultdir=${RESULT_DIR}/${EPEL_RELEASE} \ - -r ${EPEL_RELEASE} --rebuild ${PWD}/*.src.rpm) - - # write the mock command to a file, so that its easier to execute - cat << EOF > ${RESULT_DIR}/${EPEL_RELEASE}/mock.sh -#!/bin/sh -${MOCK_CMD} -EOF - chmod +x ${RESULT_DIR}/${EPEL_RELEASE}/mock.sh - - # root can not run 'mock', it needs to drop priviledges - if (groups | grep -q mock) - then - # the current user is in group 'mock' - RUNMOCK="${RESULT_DIR}/${EPEL_RELEASE}/mock.sh" - else - # switch to the user called 'mock' - chown mock:mock ${RESULT_DIR}/${EPEL_RELEASE} - # "su" might not work, using sudo instead - RUNMOCK="sudo -u mock -E ${RESULT_DIR}/${EPEL_RELEASE}/mock.sh" - fi - TEST_IN_LOOP ${RUNMOCK} -done - -# we could build for the last two Fedora releases too, but that is not -# possible on EPEL-5/6 installations, Fedora 17 and newer have unmet -# dependencies on the build-server :-/ - -# only remove ${RESULT_DIR} if we're not debugging -[ "${DEBUG}" = "0" ] && rm -rf ${RESULT_DIR} - -cleanup diff --git a/tests/basic/sdfs-sanity.t b/tests/basic/sdfs-sanity.t new file mode 100644 index 00000000000..16d0bed866f --- /dev/null +++ b/tests/basic/sdfs-sanity.t @@ -0,0 +1,28 @@ +#!/bin/bash + +. $(dirname $0)/../include.rc +. $(dirname $0)/../volume.rc + +cleanup; + +TEST glusterd +TEST pidof glusterd + +TEST $CLI volume create $V0 replica 3 $H0:$B0/${V0}{1,2,3,4,5,6,7,8,9}; +TEST $CLI volume set $V0 features.sdfs enable; +TEST $CLI volume start $V0; + +## Mount FUSE +TEST $GFS -s $H0 --volfile-id $V0 $M1; + +# This test covers lookup, mkdir, mknod, symlink, link, rename, +# create operations +TEST $(dirname $0)/rpc-coverage.sh $M1 + +TEST cp $(dirname ${0})/gfapi/glfsxmp-coverage.c glfsxmp.c +TEST build_tester ./glfsxmp.c -lgfapi +TEST ./glfsxmp $V0 $H0 +TEST cleanup_tester ./glfsxmp +TEST rm ./glfsxmp.c + +cleanup; diff --git a/tests/basic/seek.c b/tests/basic/seek.c new file mode 100644 index 00000000000..54fa6f463af --- /dev/null +++ b/tests/basic/seek.c @@ -0,0 +1,182 @@ + +#define _GNU_SOURCE + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <string.h> +#include <errno.h> + +static char buffer[65536]; + +static int +parse_int(const char *text, size_t *value) +{ + char *ptr; + size_t val; + + val = strtoul(text, &ptr, 0); + if (*ptr != 0) { + return 0; + } + + *value = val; + + return 1; +} + +static int +fill_area(int fd, off_t offset, size_t size) +{ + size_t len; + ssize_t res; + + while (size > 0) { + len = sizeof(buffer); + if (len > size) { + len = size; + } + res = pwrite(fd, buffer, len, offset); + if (res < 0) { + fprintf(stderr, "pwrite(%d, %p, %lu, %lu) failed: %d\n", fd, buffer, + size, offset, errno); + return 0; + } + if (res != len) { + fprintf(stderr, + "pwrite(%d, %p, %lu, %lu) didn't wrote all " + "data: %lu/%lu\n", + fd, buffer, size, offset, res, len); + return 0; + } + offset += len; + size -= len; + } + + return 1; +} + +static void +syntax(void) +{ + fprintf(stderr, "Syntax: seek create <path> <offset> <size> [...]\n"); + fprintf(stderr, " seek scan <path> data|hole <offset>\n"); +} + +static int +seek_create(const char *path, int argc, char *argv[]) +{ + size_t off, size; + int fd; + int ret = 1; + + fd = open(path, O_CREAT | O_TRUNC | O_RDWR, 0644); + if (fd < 0) { + fprintf(stderr, "Failed to create the file\n"); + goto out; + } + + while (argc > 0) { + if (!parse_int(argv[0], &off) || !parse_int(argv[1], &size)) { + syntax(); + goto out_close; + } + if (!fill_area(fd, off, size)) { + goto out_close; + } + argv += 2; + argc -= 2; + } + + ret = 0; + +out_close: + close(fd); +out: + return ret; +} + +static int +seek_scan(const char *path, const char *type, const char *pos) +{ + size_t off, res; + int fd, whence; + int ret = 1; + + if (strcmp(type, "data") == 0) { + whence = SEEK_DATA; + } else if (strcmp(type, "hole") == 0) { + whence = SEEK_HOLE; + } else { + syntax(); + goto out; + } + + if (!parse_int(pos, &off)) { + syntax(); + goto out; + } + + fd = open(path, O_RDWR); + if (fd < 0) { + fprintf(stderr, "Failed to open the file\n"); + goto out; + } + + res = lseek(fd, off, whence); + if (res == (off_t)-1) { + if (errno != ENXIO) { + fprintf(stderr, "seek(%d, %lu, %d) failed: %d\n", fd, off, whence, + errno); + goto out_close; + } + fprintf(stdout, "ENXIO\n"); + } else { + fprintf(stdout, "%lu\n", res); + } + + ret = 0; + +out_close: + close(fd); +out: + return ret; +} + +int +main(int argc, char *argv[]) +{ + int ret = 1; + + memset(buffer, 0x55, sizeof(buffer)); + + if (argc < 3) { + syntax(); + goto out; + } + + if (strcmp(argv[1], "create") == 0) { + if (((argc - 3) & 1) != 0) { + syntax(); + goto out; + } + ret = seek_create(argv[2], argc - 3, argv + 3); + } else if (strcmp(argv[1], "scan") == 0) { + if (argc != 5) { + syntax(); + goto out; + } + ret = seek_scan(argv[2], argv[3], argv[4]); + } else { + syntax(); + goto out; + } + + ret = 0; + +out: + return ret; +} diff --git a/tests/basic/self-heald.t b/tests/basic/self-heald.t deleted file mode 100644 index 4468c881bac..00000000000 --- a/tests/basic/self-heald.t +++ /dev/null @@ -1,48 +0,0 @@ -#!/bin/bash - -. $(dirname $0)/../include.rc -. $(dirname $0)/../volume.rc - -cleanup; - -TEST glusterd -TEST pidof glusterd -TEST $CLI volume create $V0 replica 2 $H0:$B0/${V0}{0,1,2,3,4,5} -TEST $CLI volume set $V0 cluster.background-self-heal-count 0 -TEST $CLI volume set $V0 cluster.eager-lock off -TEST $CLI volume start $V0 -TEST glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0 --attribute-timeout=0 --entry-timeout=0 -TEST kill_brick $V0 $H0 $B0/${V0}0 -TEST kill_brick $V0 $H0 $B0/${V0}2 -TEST kill_brick $V0 $H0 $B0/${V0}4 -cd $M0 -HEAL_FILES=0 -for i in {1..10} -do - dd if=/dev/urandom of=f bs=1M count=10 2>/dev/null - HEAL_FILES=$(($HEAL_FILES+1)) - mkdir a; cd a; - HEAL_FILES=$(($HEAL_FILES+3)) #As many times as distribute subvols -done -HEAL_FILES=$(($HEAL_FILES + 3)) #Count the brick root dir - -cd ~ -EXPECT "$HEAL_FILES" afr_get_pending_heal_count $V0 -TEST ! $CLI volume heal $V0 -TEST $CLI volume set $V0 cluster.self-heal-daemon off -TEST ! $CLI volume heal $V0 info -TEST ! $CLI volume heal $V0 -TEST $CLI volume start $V0 force -TEST $CLI volume set $V0 cluster.self-heal-daemon on -EXPECT_WITHIN 20 "Y" glustershd_up_status -EXPECT_WITHIN 20 "1" afr_child_up_status_in_shd $V0 0 -EXPECT_WITHIN 20 "1" afr_child_up_status_in_shd $V0 2 -EXPECT_WITHIN 20 "1" afr_child_up_status_in_shd $V0 4 -TEST $CLI volume heal $V0 -sleep 5 #Until the heal-statistics command implementation -#check that this heals the contents partially -TEST [ $HEAL_FILES -gt $(afr_get_pending_heal_count $V0) ] - -TEST $CLI volume heal $V0 full -EXPECT_WITHIN 30 "0" afr_get_pending_heal_count $V0 -cleanup diff --git a/tests/basic/shd-mux-afr.t b/tests/basic/shd-mux-afr.t new file mode 100644 index 00000000000..cf300c148bb --- /dev/null +++ b/tests/basic/shd-mux-afr.t @@ -0,0 +1,70 @@ +#!/bin/bash + +. $(dirname $0)/../include.rc +. $(dirname $0)/../volume.rc + +cleanup; + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 replica 3 $H0:$B0/${V0}{0,1,2,3,4,5} +TEST $CLI volume set $V0 cluster.background-self-heal-count 0 +TEST $CLI volume set $V0 cluster.eager-lock off +TEST $CLI volume set $V0 performance.flush-behind off +TEST $CLI volume start $V0 +TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0 + +shd_pid=$(get_shd_mux_pid $V0) +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "^6$" number_healer_threads_shd $V0 "afr_shd_index_healer" + +#Create a one more volume +TEST $CLI volume create ${V0}_1 replica 3 $H0:$B0/${V0}_1{0,1,2,3,4,5} +TEST $CLI volume start ${V0}_1 + +#Check whether the shd has multiplexed or not +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "^1$" shd_count +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "^${shd_pid}$" get_shd_mux_pid ${V0}_1 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "^${shd_pid}$" get_shd_mux_pid ${V0} + +TEST $CLI volume set ${V0}_1 cluster.background-self-heal-count 0 +TEST $CLI volume set ${V0}_1 cluster.eager-lock off +TEST $CLI volume set ${V0}_1 performance.flush-behind off +TEST $GFS --volfile-id=/${V0}_1 --volfile-server=$H0 $M1 + +TEST kill_brick $V0 $H0 $B0/${V0}0 +TEST kill_brick $V0 $H0 $B0/${V0}4 +TEST kill_brick ${V0}_1 $H0 $B0/${V0}_10 +TEST kill_brick ${V0}_1 $H0 $B0/${V0}_14 + +TEST touch $M0/foo{1..100} +TEST touch $M1/foo{1..100} + +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "^204$" get_pending_heal_count $V0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "^204$" get_pending_heal_count ${V0}_1 + +TEST $CLI volume start ${V0} force +TEST $CLI volume start ${V0}_1 force + +EXPECT_WITHIN $HEAL_TIMEOUT "^0$" get_pending_heal_count $V0 +EXPECT_WITHIN $HEAL_TIMEOUT "^0$" get_pending_heal_count ${V0}_1 + +TEST rm -rf $M0/* +TEST rm -rf $M1/* +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M1 + +#Stop the volume +TEST $CLI volume stop ${V0}_1 +TEST $CLI volume delete ${V0}_1 + +#Check the stop succeeded and detached the volume with out restarting it +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "^1$" shd_count + +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "^${shd_pid}$" get_shd_mux_pid $V0 + +#Check the thread count become to earlier number after stopping +EXPECT_WITHIN $PROCESS_DOWN_TIMEOUT "^6$" number_healer_threads_shd $V0 "afr_shd_index_healer" + +TEST $CLI volume stop ${V0} +TEST $CLI volume delete ${V0} +EXPECT_WITHIN $PROCESS_DOWN_TIMEOUT "^0$" shd_count +cleanup diff --git a/tests/basic/shd-mux-ec.t b/tests/basic/shd-mux-ec.t new file mode 100644 index 00000000000..ef4d65018d3 --- /dev/null +++ b/tests/basic/shd-mux-ec.t @@ -0,0 +1,75 @@ +#!/bin/bash + +. $(dirname $0)/../include.rc +. $(dirname $0)/../volume.rc + +cleanup; + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 replica 3 $H0:$B0/${V0}{0,1,2,3,4,5} +TEST $CLI volume set $V0 cluster.background-self-heal-count 0 +TEST $CLI volume set $V0 cluster.eager-lock off +TEST $CLI volume set $V0 performance.flush-behind off +TEST $CLI volume start $V0 +TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0 + +shd_pid=$(get_shd_mux_pid $V0) +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "^6$" number_healer_threads_shd $V0 "afr_shd_index_healer" + +#Now create a ec volume and check mux works +TEST $CLI volume create ${V0}_2 disperse 6 redundancy 2 $H0:$B0/${V0}_2{0,1,2,3,4,5} +TEST $CLI volume start ${V0}_2 + +#Check whether the shd has multiplexed or not +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "^1$" shd_count +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "^${shd_pid}$" get_shd_mux_pid ${V0}_2 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "^${shd_pid}$" get_shd_mux_pid ${V0} + +TEST $CLI volume set ${V0}_2 cluster.background-self-heal-count 0 +TEST $CLI volume set ${V0}_2 cluster.eager-lock off +TEST $CLI volume set ${V0}_2 performance.flush-behind off +TEST $GFS --volfile-id=/${V0}_2 --volfile-server=$H0 $M1 + +TEST kill_brick $V0 $H0 $B0/${V0}0 +TEST kill_brick $V0 $H0 $B0/${V0}4 +TEST kill_brick ${V0}_2 $H0 $B0/${V0}_20 +TEST kill_brick ${V0}_2 $H0 $B0/${V0}_22 + +TEST touch $M0/foo{1..100} +TEST touch $M1/foo{1..100} + +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "^204$" get_pending_heal_count $V0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "^404$" get_pending_heal_count ${V0}_2 + +TEST $CLI volume start ${V0} force +TEST $CLI volume start ${V0}_2 force + +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "^6$" number_healer_threads_shd $V0 "ec_shd_index_healer" + +EXPECT_WITHIN $HEAL_TIMEOUT "^0$" get_pending_heal_count $V0 +EXPECT_WITHIN $HEAL_TIMEOUT "^0$" get_pending_heal_count ${V0}_2 + +TEST rm -rf $M0/* +TEST rm -rf $M1/* + + +#Stop the volume +TEST $CLI volume stop ${V0}_2 +TEST $CLI volume delete ${V0}_2 + +#Check the stop succeeded and detached the volume with out restarting it +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "^1$" shd_count + +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "^${shd_pid}$" get_shd_mux_pid $V0 + +#Check the thread count become to zero for ec related threads +EXPECT_WITHIN $PROCESS_DOWN_TIMEOUT "^0$" number_healer_threads_shd $V0 "ec_shd_index_healer" +#Check the thread count become to earlier number after stopping +EXPECT_WITHIN $PROCESS_DOWN_TIMEOUT "^6$" number_healer_threads_shd $V0 "afr_shd_index_healer" + +TEST $CLI volume stop ${V0} +TEST $CLI volume delete ${V0} +EXPECT_WITHIN $PROCESS_DOWN_TIMEOUT "^0$" shd_count + +cleanup diff --git a/tests/basic/stats-dump.t b/tests/basic/stats-dump.t new file mode 100644 index 00000000000..ed73fd1d14a --- /dev/null +++ b/tests/basic/stats-dump.t @@ -0,0 +1,55 @@ +#!/bin/bash + +. $(dirname $0)/../include.rc +. $(dirname $0)/../volume.rc +. $(dirname $0)/../nfs.rc + +#G_TESTDEF_TEST_STATUS_CENTOS6=NFS_TEST + +cleanup; + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 replica 3 $H0:$B0/${V0}{0,1,2} +TEST $CLI volume set $V0 diagnostics.latency-measurement on +TEST $CLI volume set $V0 diagnostics.count-fop-hits on +TEST $CLI volume set $V0 diagnostics.stats-dump-interval 1 +TEST $CLI volume set $V0 performance.nfs.io-threads on +TEST $CLI volume set $V0 nfs.disable off +TEST $CLI volume start $V0 +EXPECT_WITHIN $NFS_EXPORT_TIMEOUT "1" is_nfs_export_available +TEST glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0 --attribute-timeout=0 --entry-timeout=0 +TEST mount_nfs $H0:/$V0 $N0 nolock,soft,intr + +for i in {1..10};do + dd if=/dev/zero of=$M0/fuse_testfile$i bs=4k count=100 +done + +for i in {1..10};do + dd if=/dev/zero of=$N0/nfs_testfile$i bs=4k count=100 +done + +# Wait for one dump interval to be done, some seconds past 1 that is the dump +# interval set +sleep 2 + +# Change the dump interval to 0, so that when reading the file contents we +# do not get them truncated by the next interval that is overwriting the latest +# stats data +TEST $CLI volume set $V0 diagnostics.stats-dump-interval 0 + +# Verify we have non-zero write counts from the bricks, gNFSd +# and the FUSE mount. +TEST [ $(grep 'aggr.fop.write.count' ${GLUSTERD_WORKDIR}/stats/glusterfs_nfsd.dump|tail -1|cut -d: -f2) != "0," ] +TEST [ $(grep 'aggr.fop.write.count' ${GLUSTERD_WORKDIR}/stats/glusterfs_patchy.dump|tail -1|cut -d: -f2) != "0," ] +TEST [ $(grep 'aggr.fop.write.count' ${GLUSTERD_WORKDIR}/stats/glusterfsd__d_backends_patchy0.dump|tail -1|cut -d: -f2) != "0," ] +TEST [ $(grep 'aggr.fop.write.count' ${GLUSTERD_WORKDIR}/stats/glusterfsd__d_backends_patchy1.dump|tail -1|cut -d: -f2) != "0," ] +TEST [ $(grep 'aggr.fop.write.count' ${GLUSTERD_WORKDIR}/stats/glusterfsd__d_backends_patchy2.dump|tail -1|cut -d: -f2) != "0," ] + +# Test that io-stats is getting queue sizes from io-threads +TEST grep '.queue_size' ${GLUSTERD_WORKDIR}/stats/glusterfs_nfsd.dump +TEST grep '.queue_size' ${GLUSTERD_WORKDIR}/stats/glusterfsd__d_backends_patchy0.dump +TEST grep '.queue_size' ${GLUSTERD_WORKDIR}/stats/glusterfsd__d_backends_patchy1.dump +TEST grep '.queue_size' ${GLUSTERD_WORKDIR}/stats/glusterfsd__d_backends_patchy2.dump + +cleanup; diff --git a/tests/basic/symbol-check.sh b/tests/basic/symbol-check.sh new file mode 100755 index 00000000000..0f8243ca731 --- /dev/null +++ b/tests/basic/symbol-check.sh @@ -0,0 +1,114 @@ +#!/bin/bash + +syscalls=$'access\nchmod\nchown\nclose\nclosedir\ncreat64\n\ +fallocate64\nfchmod\nfchown\nfdatasync\nfgetxattr\nflistxattr\n\ +fremovexattr\nfsetxattr\nfsync\nftruncate64\n__fxstat64\n\ +__fxstatat64\nlchown\nlgetxattr\nlinkat\nllistxattr\nlremovexattr\n\ +lseek64\nlsetxattr\n__lxstat64\nmkdir\nmkdirat\nopenat64\nopendir\n\ +pread64\npwrite64\npreadv64\npwritev64\nread\nreaddir64\nreadlink\n\ +readv\nrename\nrmdir\n statvfs64\nsymlink\n\truncate64\nunlink\n\ +utimeswrite\nwritev\n\__xmknod\n__xstat64' + +syscalls32=$'creat\nfallocate\nftruncate\n__fxstat\n__fxstatat\n\ +lseek\n__lxstat\nopenat\nreaddir\nstatvfs\ntruncate\nstat\n\ +preadv\npwritev\npread\npwrite' + +glibccalls=$'tmpfile' + +exclude_files=$'/libglusterfs/src/.libs/libglusterfs_la-syscall.o\n\ +/libglusterfs/src/.libs/libglusterfs_la-gen_uuid.o\n\ +/contrib/fuse-util/fusermount.o\n\ +/contrib/fuse-util/mount_util.o\n\ +/contrib/fuse-util/mount-common.o\n\ +/xlators/mount/fuse/src/.libs/mount.o\n\ +/xlators/mount/fuse/src/.libs/mount-common.o\n\ +/xlators/features/qemu-block/src/.libs/block.o\n\ +/xlators/features/qemu-block/src/.libs/cutils.o\n\ +/xlators/features/qemu-block/src/.libs/oslib-posix.o' + +function main() +{ + for exclude_file in ${exclude_files}; do + if [[ ${1} = *${exclude_file} ]]; then + exit 0 + fi + done + + local retval=0 + local t + t=$(nm "${1}" | grep " U " | sed -e "s/ //g" -e "s/ U //g") + + for symy in ${t}; do + + for symx in ${syscalls}; do + + if [[ ${symx} = "${symy}" ]]; then + + case ${symx} in + "creat64") sym="creat";; + "fallocate64") sym="fallocate";; + "ftruncate64") sym="ftruncate";; + "lseek64") sym="lseek";; + "preadv64") sym="preadv";; + "pwritev64") sym="pwritev";; + "pread64") sym="pread";; + "pwrite64") sym="pwrite";; + "openat64") sym="openat";; + "readdir64") sym="readdir";; + "truncate64") sym="truncate";; + "__statvfs64") sym="statvfs";; + "__fxstat64") sym="fstat";; + "__fxstatat64") sym="fstatat";; + "__lxstat64") sym="lstat";; + "__xmknod") sym="mknod";; + "__xstat64") sym="stat";; + *) sym=${symx};; + esac + + echo "${1} should call sys_${sym}, not ${sym}" >&2 + retval=1 + fi + + done + + for symx in ${syscalls32}; do + + if [[ ${symx} = "${symy}" ]]; then + + echo "${1} was not compiled with -D_FILE_OFFSET_BITS=64" >&2 + retval=1 + fi + done + + symy_glibc=$(echo "${symy}" | sed -e "s/@@GLIBC.*//g") + # Eliminate false positives, check if we have a GLIBC symbol in 'y' + if [[ ${symy} != "${symy_glibc}" ]]; then + for symx in ${glibccalls}; do + + if [[ ${symx} = "${symy_glibc}" ]]; then + + case ${symx} in + "tmpfile") alt="mkstemp";; + *) alt="none";; + esac + + if [[ ${alt} = "none" ]]; then + echo "${1} should not call ${symy_glibc}"; + else + echo "${1} should use ${alt} instead of ${symy_glibc}" >&2; + fi + + retval=1 + fi + done + fi + + done + + if [ ${retval} = 1 ]; then + touch ./.symbol-check-errors + fi + exit ${retval} +} + +main "$@" diff --git a/tests/basic/trace.t b/tests/basic/trace.t new file mode 100755 index 00000000000..01e7c9e0a25 --- /dev/null +++ b/tests/basic/trace.t @@ -0,0 +1,55 @@ +#!/bin/bash + +. $(dirname $0)/../include.rc +. $(dirname $0)/../volume.rc + +cleanup; + +TEST mkdir -p $B0/single-brick +cat > $B0/template.vol <<EOF +volume posix + type storage/posix + option directory $B0/single-brick +end-volume + +volume trace + type debug/trace + option log-file yes + option log-history yes + subvolumes posix +end-volume +EOF + +TEST glusterfs -f $B0/template.vol $M0 + +TEST $(dirname $0)/rpc-coverage.sh --no-locks $M0 + +# Take statedump to get maximum code coverage +pid=$(ps auxww | grep glusterfs | grep -E "template.vol" | awk '{print $2}' | head -1) + +TEST generate_statedump $pid + +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 + +# Now, use the glusterd way of enabling trace +TEST glusterd +TEST $CLI volume create $V0 replica 3 $H0:$B0/${V0}{1,2,3,4,5,6}; + +TEST $CLI volume set $V0 debug.trace marker +TEST $CLI volume set $V0 debug.log-file yes +#TEST $CLI volume set $V0 debug.log-history yes + +TEST $CLI volume start $V0; + +TEST $GFS -s $H0 --volfile-id $V0 $M1; + +TEST $(dirname $0)/rpc-coverage.sh --no-locks $M1 +cp $(dirname ${0})/gfapi/glfsxmp-coverage.c ./glfsxmp.c +build_tester ./glfsxmp.c -lgfapi +./glfsxmp $V0 $H0 > /dev/null +cleanup_tester ./glfsxmp +rm ./glfsxmp.c + +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M1 + +cleanup; diff --git a/tests/basic/uss.t b/tests/basic/uss.t new file mode 100644 index 00000000000..09dd00ef995 --- /dev/null +++ b/tests/basic/uss.t @@ -0,0 +1,421 @@ +#!/bin/bash + +. $(dirname $0)/../include.rc +. $(dirname $0)/../volume.rc +. $(dirname $0)/../snapshot.rc +. $(dirname $0)/../fileio.rc +. $(dirname $0)/../nfs.rc + +#G_TESTDEF_TEST_STATUS_CENTOS6=NFS_TEST + +function check_readonly() +{ + $@ 2>&1 | grep -q 'Read-only file system' + return $? +} + +function lookup() +{ + ls $1 + if [ "$?" == "0" ] + then + echo "Y" + else + echo "N" + fi +} + +cleanup; +TESTS_EXPECTED_IN_LOOP=10 + +TEST init_n_bricks 3; +TEST setup_lvm 3; + +TEST glusterd; + +TEST pidof glusterd; + +TEST $CLI volume create $V0 $H0:$L1 $H0:$L2 $H0:$L3; + +TEST $CLI volume set $V0 nfs.disable false + + +TEST $CLI volume start $V0; + +TEST $GFS --volfile-server=$H0 --volfile-id=$V0 $M0; + +for i in {1..10} ; do echo "file" > $M0/file$i ; done + +# Create file and hard-links +TEST touch $M0/f1 +TEST mkdir $M0/dir +TEST ln $M0/f1 $M0/f2 +TEST ln $M0/f1 $M0/dir/f3 + +TEST $CLI snapshot config activate-on-create enable +TEST $CLI volume set $V0 features.uss enable; + +TEST ! $CLI snapshot create snap1 $V0 no-timestamp description ""; +TEST $CLI snapshot create snap1 $V0 no-timestamp; + +for i in {11..20} ; do echo "file" > $M0/file$i ; done + +TEST $CLI snapshot create snap2 $V0 no-timestamp; + +########### Test inode numbers ########### +s1_f1_ino=$(STAT_INO $M0/.snaps/snap1/f1) +TEST [ $s1_f1_ino != 0 ] + +# Inode number of f1 should be same as f2 f3 within snapshot +EXPECT $s1_f1_ino STAT_INO $M0/.snaps/snap1/f2 +EXPECT $s1_f1_ino STAT_INO $M0/.snaps/snap1/dir/f3 +EXPECT $s1_f1_ino STAT_INO $M0/dir/.snaps/snap1/f3 + +# Inode number of f1 in snap1 should be different from f1 in snap2 +tmp_ino=$(STAT_INO $M0/.snaps/snap2/f1) +TEST [ $s1_f1_ino != $tmp_ino ] + +# Inode number of f1 in snap1 should be different from f1 in regular volume +tmp_ino=$(STAT_INO $M0/f1) +TEST [ $s1_f1_ino != $tmp_ino ] + +# Directory inode of snap1 should be different in each sub-dir +s1_ino=$(STAT_INO $M0/.snaps/snap1) +tmp_ino=$(STAT_INO $M0/dir/.snaps/snap1) +TEST [ $s1_ino != $tmp_ino ] +########################################## + +mkdir $M0/dir1; +mkdir $M0/dir2; + +for i in {1..10} ; do echo "foo" > $M0/dir1/foo$i ; done +for i in {1..10} ; do echo "foo" > $M0/dir2/foo$i ; done + +TEST $CLI snapshot create snap3 $V0 no-timestamp; + +for i in {11..20} ; do echo "foo" > $M0/dir1/foo$i ; done +for i in {11..20} ; do echo "foo" > $M0/dir2/foo$i ; done + +TEST $CLI snapshot create snap4 $V0 no-timestamp; +## Test that features.uss takes only options enable/disable and throw error for +## any other argument. +for i in {1..10}; do + RANDOM_STRING=$(uuidgen | tr -dc 'a-zA-Z' | head -c 8) + TEST_IN_LOOP ! $CLI volume set $V0 features.uss $RANDOM_STRING +done + +## Test that features.snapshot-directory: +## contains only '0-9a-z-_' +# starts with dot (.) +# value cannot exceed 255 characters +## and throws error for any other argument. +TEST ! $CLI volume set $V0 features.snapshot-directory a/b +TEST ! $CLI volume set $V0 features.snapshot-directory snaps +TEST ! $CLI volume set $V0 features.snapshot-directory -a +TEST ! $CLI volume set $V0 features.snapshot-directory . +TEST ! $CLI volume set $V0 features.snapshot-directory .. +TEST ! $CLI volume set $V0 features.snapshot-directory .123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345 + +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 + +TEST $GFS --volfile-server=$H0 --volfile-id=$V0 $M0; + +# test 15 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "4" count_snaps $M0 + +NUM_SNAPS=$(ls $M0/.snaps | wc -l); + +TEST [ $NUM_SNAPS == 4 ] +TEST ls $M0/.snaps/snap1; +TEST ls $M0/.snaps/snap2; +TEST ls $M0/.snaps/snap3; +TEST ls $M0/.snaps/snap4; + +TEST ls $M0/.snaps/snap3/dir1; +TEST ls $M0/.snaps/snap3/dir2; + +TEST ls $M0/.snaps/snap4/dir1; +TEST ls $M0/.snaps/snap4/dir2; + +TEST ls $M0/dir1/.snaps/ +TEST ! ls $M0/dir1/.snaps/snap1; +TEST ! ls $M0/dir2/.snaps/snap2; +TEST ls $M0/dir1/.snaps/snap3; +TEST ls $M0/dir2/.snaps/snap4; + +TEST fd1=`fd_available` +TEST fd_open $fd1 'r' $M0/.snaps/snap1/file1; +TEST fd_cat $fd1 + +# opening fd with in write mode for snapshot files should fail +TEST fd2=`fd_available` +TEST ! fd_open $fd1 'w' $M0/.snaps/snap1/file2; + +# lookup on .snaps in the snapshot world should fail +TEST ! stat $M0/.snaps/snap1/.snaps + +# creating new entries in snapshots should fail +TEST check_readonly mkdir $M0/.snaps/new +TEST check_readonly touch $M0/.snaps/snap2/other; + +TEST fd3=`fd_available` +TEST fd_open $fd3 'r' $M0/dir1/.snaps/snap3/foo1 + +TEST fd_cat $fd3; + +TEST fd_close $fd1; +TEST fd_close $fd2; +TEST fd_close $fd3 + + +# similar tests on nfs mount +##Wait for connection establishment between nfs server and brick process +EXPECT_WITHIN $NFS_EXPORT_TIMEOUT "1" is_nfs_export_available; +#test 44 +TEST mount_nfs $H0:/$V0 $N0 nolock; + +NUM_SNAPS=$(ls $N0/.snaps | wc -l); + +TEST [ $NUM_SNAPS == 4 ]; + +TEST stat $N0/.snaps/snap1; +TEST stat $N0/.snaps/snap2; + +TEST ls -l $N0/.snaps; + +# readdir + lookup on each entry +TEST ls -l $N0/.snaps/snap1; +TEST ls -l $N0/.snaps/snap2; + +# readdir + access each entry by doing stat. If snapview-server has not +# filled the fs instance and handle in the inode context of the entry as +# part of readdirp, then when stat comes (i.e fop comes directly without +# a previous lookup), snapview-server should do a lookup of the entry via +# gfapi call and fill in the fs instance + handle information in the inode +# context +TEST ls $N0/.snaps/snap3/; +TEST stat $N0/.snaps/snap3/dir1; +TEST stat $N0/.snaps/snap3/dir2; + +TEST ls -l $N0/.snaps/snap3/dir1; +TEST ls -l $N0/.snaps/snap3/dir2; +TEST ls -l $N0/.snaps/snap4/dir1; +TEST ls -l $N0/.snaps/snap4/dir2; + +TEST ! ls -l $N0/dir1/.snaps/snap1; +TEST ! ls -l $N0/dir2/.snaps/snap2; +TEST ls -l $N0/dir1/.snaps/snap3; +TEST ls -l $N0/dir2/.snaps/snap4; + + +TEST fd1=`fd_available` +TEST fd_open $fd1 'r' $N0/.snaps/snap1/file1; +TEST fd_cat $fd1 + +TEST fd2=`fd_available` +TEST ! fd_open $fd1 'w' $N0/.snaps/snap1/file2; + +TEST ! stat $N0/.snaps/snap1/.stat + +TEST check_readonly mkdir $N0/.snaps/new + +TEST check_readonly touch $N0/.snaps/snap2/other; + +TEST fd3=`fd_available` +TEST fd_open $fd3 'r' $N0/dir1/.snaps/snap3/foo1 + +TEST fd_cat $fd3; + + +TEST fd_close $fd1; +TEST fd_close $fd2; +TEST fd_close $fd3; + +# test 73 +TEST $CLI volume set $V0 "features.snapshot-directory" .history + +#snapd client might take fraction of time to compare the volfile from glusterd +#hence a EXPECT_WITHIN is a better choice here +EXPECT_WITHIN 2 "Y" lookup "$M0/.history"; + +NUM_SNAPS=$(ls $M0/.history | wc -l); + +TEST [ $NUM_SNAPS == 4 ] + +TEST ls $M0/.history/snap1; +TEST ls $M0/.history/snap2; +TEST ls $M0/.history/snap3; +TEST ls $M0/.history/snap4; + +TEST ls $M0/.history/snap3/dir1; +TEST ls $M0/.history/snap3/dir2; + +TEST ls $M0/.history/snap4/dir1; +TEST ls $M0/.history/snap4/dir2; + +TEST ls $M0/dir1/.history/ +TEST ! ls $M0/dir1/.history/snap1; +TEST ! ls $M0/dir2/.history/snap2; +TEST ls $M0/dir1/.history/snap3; +TEST ls $M0/dir2/.history/snap4; + +TEST fd1=`fd_available` +TEST fd_open $fd1 'r' $M0/.history/snap1/file1; +TEST fd_cat $fd1 + +# opening fd with in write mode for snapshot files should fail +TEST fd2=`fd_available` +TEST ! fd_open $fd1 'w' $M0/.history/snap1/file2; + +# lookup on .history in the snapshot world should fail +TEST ! stat $M0/.history/snap1/.history + +# creating new entries in snapshots should fail +TEST check_readonly mkdir $M0/.history/new +TEST check_readonly touch $M0/.history/snap2/other; + +TEST fd3=`fd_available` +TEST fd_open $fd3 'r' $M0/dir1/.history/snap3/foo1 + +TEST fd_cat $fd3; + +TEST fd_close $fd1; +TEST fd_close $fd2; +TEST fd_close $fd3 + + +# similar tests on nfs mount +# test 103 +TEST ls $N0/.history; + +NUM_SNAPS=$(ls $N0/.history | wc -l); + +TEST [ $NUM_SNAPS == 4 ]; + +TEST ls -l $N0/.history/snap1; +TEST ls -l $N0/.history/snap2; +TEST ls -l $N0/.history/snap3; +TEST ls -l $N0/.history/snap4; + +TEST ls -l $N0/.history/snap3/dir1; +TEST ls -l $N0/.history/snap3/dir2; + +TEST ls -l $N0/.history/snap4/dir1; +TEST ls -l $N0/.history/snap4/dir2; + +TEST ! ls -l $N0/dir1/.history/snap1; +TEST ! ls -l $N0/dir2/.history/snap2; +TEST ls -l $N0/dir1/.history/snap3; +TEST ls -l $N0/dir2/.history/snap4; + +TEST fd1=`fd_available` +TEST fd_open $fd1 'r' $N0/.history/snap1/file1; +TEST fd_cat $fd1 + +TEST fd2=`fd_available` +TEST ! fd_open $fd1 'w' $N0/.history/snap1/file2; + +TEST ! stat $N0/.history/snap1/.stat + +TEST check_readonly mkdir $N0/.history/new + +TEST check_readonly touch $N0/.history/snap2/other; + +TEST fd3=`fd_available` +TEST fd_open $fd3 'r' $N0/dir1/.history/snap3/foo1 + +TEST fd_cat $fd3; + +TEST fd_close $fd1; +TEST fd_close $fd2; +TEST fd_close $fd3; + +## Before killing daemon to avoid deadlocks +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" umount_nfs $N0 + +#test 131 +TEST $CLI snapshot create snap5 $V0 no-timestamp +TEST ls $M0/.history; + +function count_snaps +{ + local mount_point=$1; + local num_snaps; + + num_snaps=$(ls $mount_point/.history | wc -l); + + echo $num_snaps; +} + +EXPECT_WITHIN 30 "5" count_snaps $M0; + +# deletion of a snapshot and creation of a new snapshot with same name +# should not create problems. The data that was supposed to be present +# in the deleted snapshot need not be present in the new snapshot just +# because the name is same. Ex: +# 1) Create a file "aaa" +# 2) Create a snapshot snap6 +# 3) stat the file "aaa" in snap6 and it should succeed +# 4) delete the file "aaa" +# 5) Delete the snapshot snap6 +# 6) Create a snapshot snap6 +# 7) stat the file "aaa" in snap6 and it should fail now + +echo "aaa" > $M0/aaa; + +TEST $CLI snapshot create snap6 $V0 no-timestamp + +TEST ls $M0/.history; + +EXPECT_WITHIN 30 "6" count_snaps $M0; + +EXPECT_WITHIN 10 "Y" lookup $M0/.history/snap6/aaa + +TEST rm -f $M0/aaa; + +TEST $CLI snapshot delete snap6; + +# drop the caches so that, the dentry for "snap6" is +# is forgotten from the client cache. +drop_cache $M0 + +EXPECT_WITHIN 30 "5" count_snaps $M0; + +# This should fail, as snap6 just got deleted. +TEST ! stat $M0/.history/snap6 + +TEST $CLI snapshot create snap6 $V0 no-timestamp + +TEST ls $M0/.history; + +EXPECT_WITHIN 30 "6" count_snaps $M0; + +TEST ls $M0/.history/snap6/; + +TEST ! stat $M0/.history/snap6/aaa; + +TEST stat $M0 + +# done with the tests start cleaning up of things +TEST $CLI volume set $V0 features.uss disable + +TEST $CLI snapshot delete snap6; + +TEST $CLI snapshot delete snap5; + +TEST $CLI snapshot delete snap4; + +TEST $CLI snapshot delete snap3; + +TEST $CLI snapshot delete snap2; + +TEST $CLI snapshot delete snap1; + +# nfs client has been already unmounted at line 333 +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 + +TEST $CLI volume stop $V0 + +TEST $CLI volume delete $V0 + +cleanup; diff --git a/tests/basic/volfile-sanity.t b/tests/basic/volfile-sanity.t new file mode 100644 index 00000000000..ef2f9344468 --- /dev/null +++ b/tests/basic/volfile-sanity.t @@ -0,0 +1,29 @@ +#!/bin/bash + +. $(dirname $0)/../include.rc + +cleanup; + +## Start and create a volume +TEST glusterd +TEST pidof glusterd + +TEST $CLI volume create $V0 $H0:$B0/${V0}1 + +killall glusterd + +# Client by default tries to connect to port 24007 +# So, start server on that port, and you can see +# client successfully working. +TEST $GFS --xlator-option "${V0}-server.transport.socket.listen-port=24007" \ + -f /var/lib/glusterd/vols/${V0}/${V0}.${H0}.*.vol +TEST $GFS -f /var/lib/glusterd/vols/${V0}/${V0}.tcp-fuse.vol $M0 + +TEST $(df -h $M0 | grep -q ${V0}) +TEST $(cat /proc/mounts | grep -q $M0) + +TEST ! stat $M0/newfile; +TEST touch $M0/newfile; +TEST rm $M0/newfile; + +cleanup; diff --git a/tests/basic/volume-scale-shd-mux.t b/tests/basic/volume-scale-shd-mux.t new file mode 100644 index 00000000000..102de22468e --- /dev/null +++ b/tests/basic/volume-scale-shd-mux.t @@ -0,0 +1,116 @@ +#!/bin/bash + +. $(dirname $0)/../include.rc +. $(dirname $0)/../volume.rc + +cleanup; + +TESTS_EXPECTED_IN_LOOP=6 + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 replica 3 $H0:$B0/${V0}{0,1,2,3,4,5} +TEST $CLI volume set $V0 cluster.background-self-heal-count 0 +TEST $CLI volume set $V0 cluster.eager-lock off +TEST $CLI volume set $V0 performance.flush-behind off +TEST $CLI volume start $V0 + +for i in $(seq 1 2); do + TEST $CLI volume create ${V0}_afr$i replica 3 $H0:$B0/${V0}_afr${i}{0,1,2,3,4,5} + TEST $CLI volume start ${V0}_afr$i + TEST $CLI volume create ${V0}_ec$i disperse 6 redundancy 2 $H0:$B0/${V0}_ec${i}{0,1,2,3,4,5} + TEST $CLI volume start ${V0}_ec$i +done + +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "^1$" shd_count +#Check the thread count become to number of volumes*number of ec subvolume (2*6=12) +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "^12$" number_healer_threads_shd $V0 "ec_shd_index_healer" +#Check the thread count become to number of volumes*number of afr subvolume (3*6=18) +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "^18$" number_healer_threads_shd $V0 "afr_shd_index_healer" + +TEST $CLI volume add-brick $V0 replica 3 $H0:$B0/${V0}{6,7,8}; +#Check the thread count become to number of volumes*number of afr subvolume plus 3 additional threads from newly added bricks (3*6+3=21) + +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "^1$" shd_count +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "^21$" number_healer_threads_shd $V0 "afr_shd_index_healer" + +#Remove the brick and check the detach is successful +$CLI volume remove-brick $V0 $H0:$B0/${V0}{6,7,8} force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "^18$" number_healer_threads_shd $V0 "afr_shd_index_healer" + +EXPECT_WITHIN $PROCESS_DOWN_TIMEOUT "^0$" number_healer_threads_shd $V0 "glusterfs_graph_cleanup" +TEST $CLI volume add-brick ${V0}_ec1 $H0:$B0/${V0}_ec1_add{0,1,2,3,4,5}; +#Check the thread count become to number of volumes*number of ec subvolume plus 2 additional threads from newly added bricks (2*6+6=18) + +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "^1$" shd_count +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "^18$" number_healer_threads_shd $V0 "ec_shd_index_healer" + +#Remove the brick and check the detach is successful +$CLI volume remove-brick ${V0}_ec1 $H0:$B0/${V0}_ec1_add{0,1,2,3,4,5} force + +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "^12$" number_healer_threads_shd $V0 "ec_shd_index_healer" + + +for i in $(seq 1 2); do + TEST $CLI volume stop ${V0}_afr$i + TEST $CLI volume stop ${V0}_ec$i +done + +EXPECT_WITHIN $PROCESS_DOWN_TIMEOUT "^6$" number_healer_threads_shd $V0 "afr_shd_index_healer" + +TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0 + +TEST kill_brick $V0 $H0 $B0/${V0}0 +TEST kill_brick $V0 $H0 $B0/${V0}4 + +TEST touch $M0/foo{1..100} + +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "^204$" get_pending_heal_count $V0 + +TEST $CLI volume start ${V0} force + +EXPECT_WITHIN $HEAL_TIMEOUT "^0$" get_pending_heal_count $V0 + +TEST rm -rf $M0/* +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 +shd_pid=$(get_shd_mux_pid $V0) +TEST $CLI volume create ${V0}_distribute1 $H0:$B0/${V0}_distribute10 +TEST $CLI volume start ${V0}_distribute1 + +#Creating a non-replicate/non-ec volume should not have any effect in shd +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "^6$" number_healer_threads_shd $V0 "afr_shd_index_healer" +EXPECT "^${shd_pid}$" get_shd_mux_pid $V0 + +TEST mkdir $B0/add/ +#Now convert the distributed volume to replicate +TEST $CLI volume add-brick ${V0}_distribute1 replica 3 $H0:$B0/add/{2..3} +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "^9$" number_healer_threads_shd $V0 "afr_shd_index_healer" + +#scale down the volume +TEST $CLI volume remove-brick ${V0}_distribute1 replica 1 $H0:$B0/add/{2..3} force +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "^6$" number_healer_threads_shd $V0 "afr_shd_index_healer" + +#Before stopping the process, make sure there is no pending clenup threads hanging +EXPECT_WITHIN $PROCESS_DOWN_TIMEOUT "^0$" number_healer_threads_shd $V0 "glusterfs_graph_cleanup" + +TEST $CLI volume stop ${V0} +TEST $CLI volume delete ${V0} +EXPECT_WITHIN $PROCESS_DOWN_TIMEOUT "^0$" shd_count + +TEST rm -rf $B0/add/2 $B0/add/3 + +#Now convert the distributed volume back to replicate and make sure that a new shd is spawned +TEST $CLI volume add-brick ${V0}_distribute1 replica 3 $H0:$B0/add/{2..3}; +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "^1$" shd_count +EXPECT_WITHIN $HEAL_TIMEOUT "^3$" number_healer_threads_shd ${V0}_distribute1 "afr_shd_index_healer" + +#Now convert the replica volume to distribute again and make sure the shd is now stopped +TEST $CLI volume remove-brick ${V0}_distribute1 replica 1 $H0:$B0/add/{2..3} force +TEST rm -rf $B0/add/ + +EXPECT_WITHIN $PROCESS_DOWN_TIMEOUT "^0$" shd_count + +cleanup + +#G_TESTDEF_TEST_STATUS_NETBSD7=BAD_TEST,BUG=1708929 +#G_TESTDEF_TEST_STATUS_CENTOS6=BAD_TEST,BUG=1708929 diff --git a/tests/basic/volume-snap-scheduler.t b/tests/basic/volume-snap-scheduler.t new file mode 100644 index 00000000000..a638c5cc46a --- /dev/null +++ b/tests/basic/volume-snap-scheduler.t @@ -0,0 +1,49 @@ +#!/bin/bash + +. $(dirname $0)/../include.rc +. $(dirname $0)/../volume.rc + +cleanup; + +TEST glusterd; +TEST pidof glusterd; + +TEST $CLI volume create $V0 replica 2 $H0:$B0/${GMV0}{1,2,3,4}; +TEST $CLI volume start $V0 + +## Create, start and mount meta_volume as +## snap_scheduler expects shared storage to be enabled. +## This test is very basic in nature not creating any snapshot +## and purpose is to validate snap scheduling commands. + +TEST $CLI volume create $META_VOL replica 3 $H0:$B0/${META_VOL}{1,2,3}; +TEST $CLI volume start $META_VOL +TEST mkdir -p $META_MNT +TEST glusterfs -s $H0 --volfile-id $META_VOL $META_MNT + +##function to check status +function check_status_scheduler() +{ + local key=$1 + snap_scheduler.py status | grep -F "$key" | wc -l +} + +##Basic snap_scheduler command test init/enable/disable/list + +TEST snap_scheduler.py init + +TEST snap_scheduler.py enable + +EXPECT 1 check_status_scheduler "Enabled" + +TEST snap_scheduler.py disable + +EXPECT 1 check_status_scheduler "Disabled" + +TEST snap_scheduler.py list + +TEST $CLI volume stop $V0; + +TEST $CLI volume delete $V0; + +cleanup; diff --git a/tests/basic/volume-snapshot-clone.t b/tests/basic/volume-snapshot-clone.t new file mode 100755 index 00000000000..e6da9d7ddca --- /dev/null +++ b/tests/basic/volume-snapshot-clone.t @@ -0,0 +1,129 @@ +#!/bin/bash + +. $(dirname $0)/../include.rc +. $(dirname $0)/../volume.rc +. $(dirname $0)/../cluster.rc +. $(dirname $0)/../snapshot.rc + + +V1="patchy2" + +function create_volumes() { + $CLI_1 volume create $V0 $H1:$L1 & + PID_1=$! + + $CLI_2 volume create $V1 $H2:$L2 $H3:$L3 & + PID_2=$! + + wait $PID_1 $PID_2 +} + +function create_snapshots() { + + $CLI_1 snapshot create $1 $2 no-timestamp& + PID_1=$! + + wait $PID_1 +} + + + +function delete_snapshot() { + $CLI_1 snapshot delete $1 & + PID_1=$! + + wait $PID_1 +} + +cleanup; + +TEST verify_lvm_version; +#Create cluster with 3 nodes +TEST launch_cluster 3; +TEST setup_lvm 3 + +TEST $CLI_1 peer probe $H2; +TEST $CLI_1 peer probe $H3; +EXPECT_WITHIN $PROBE_TIMEOUT 2 peer_count; + +create_volumes +EXPECT 'Created' volinfo_field $V0 'Status'; +EXPECT 'Created' volinfo_field $V1 'Status'; + +start_volumes 2 +EXPECT 'Started' volinfo_field $V0 'Status'; +EXPECT 'Started' volinfo_field $V1 'Status'; + +TEST $CLI_1 snapshot config activate-on-create enable + +#Snapshot Operations +create_snapshots ${V0}_snap ${V0}; +create_snapshots ${V1}_snap ${V1}; + +EXPECT 'Started' snapshot_status ${V0}_snap; +EXPECT 'Started' snapshot_status ${V1}_snap; + +sleep 5 +TEST $CLI_1 snapshot clone ${V0}_clone ${V0}_snap +TEST $CLI_1 snapshot clone ${V1}_clone ${V1}_snap + +EXPECT 'Created' volinfo_field ${V0}_clone 'Status'; +EXPECT 'Created' volinfo_field ${V1}_clone 'Status'; + +TEST $CLI_1 volume start ${V0}_clone force; +TEST $CLI_1 volume start ${V1}_clone force; + +EXPECT 'Started' volinfo_field ${V0}_clone 'Status'; +EXPECT 'Started' volinfo_field ${V1}_clone 'Status'; + + +TEST glusterfs -s $H1 --volfile-id=/${V0}_clone $M0 +TEST glusterfs -s $H2 --volfile-id=/${V1}_clone $M1 + +TEST touch $M0/file1 +TEST touch $M1/file1 + +TEST echo "Hello world" $M0/file1 +TEST echo "Hello world" $M1/file1 + +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M1 + +TEST kill_glusterd 2; +sleep 15 +TEST $glusterd_2; +sleep 15 + +EXPECT_WITHIN $PROBE_TIMEOUT 2 peer_count; + +EXPECT_WITHIN $PROCESS_UP_TIMEOUT 'Started' volinfo_field ${V0}_clone 'Status'; +EXPECT_WITHIN $PROCESS_UP_TIMEOUT 'Started' volinfo_field ${V1}_clone 'Status'; + +TEST $CLI_1 volume stop ${V0}_clone +TEST $CLI_1 volume stop ${V1}_clone + +TEST $CLI_1 volume delete ${V0}_clone +TEST $CLI_1 volume delete ${V1}_clone + +TEST $CLI_1 snapshot clone ${V0}_clone ${V0}_snap +TEST $CLI_1 snapshot clone ${V1}_clone ${V1}_snap + +EXPECT 'Created' volinfo_field ${V0}_clone 'Status'; +EXPECT 'Created' volinfo_field ${V1}_clone 'Status'; + +#Clean up +stop_force_volumes 2 +EXPECT_WITHIN $CONFIG_UPDATE_TIMEOUT 'Stopped' volinfo_field $V0 'Status'; +EXPECT_WITHIN $CONFIG_UPDATE_TIMEOUT 'Stopped' volinfo_field $V1 'Status'; + +TEST delete_snapshot ${V0}_snap +TEST delete_snapshot ${V1}_snap + +TEST ! snapshot_exists 1 ${V0}_snap +TEST ! snapshot_exists 1 ${V1}_snap + +delete_volumes 2 +EXPECT_WITHIN $CONFIG_UPDATE_TIMEOUT "N" volume_exists $V0 +EXPECT_WITHIN $CONFIG_UPDATE_TIMEOUT "N" volume_exists $V1 + +cleanup; diff --git a/tests/basic/volume-snapshot-xml.t b/tests/basic/volume-snapshot-xml.t new file mode 100755 index 00000000000..ff63b54538d --- /dev/null +++ b/tests/basic/volume-snapshot-xml.t @@ -0,0 +1,72 @@ +#!/bin/bash + +. $(dirname $0)/../include.rc +. $(dirname $0)/../volume.rc +. $(dirname $0)/../snapshot.rc + +cleanup; +TEST verify_lvm_version; +TEST glusterd; +TEST pidof glusterd; + +TEST setup_lvm 1 + +TEST $CLI volume create $V0 $H0:$L1 +TEST $CLI volume start $V0 + +# Snapshot config xmls +EXPECT "enable" get-xml "snapshot config activate-on-create enable" "activateOnCreate" +EXPECT "100" get-xml "snapshot config $V0 snap-max-hard-limit 100" "newHardLimit" +EXPECT "70" get-xml "snapshot config snap-max-soft-limit 70" "newSoftLimit" +EXPECT "enable" get-xml "snapshot config auto-delete enable" "autoDelete" + +# Snapshot create, activate, deactivate xmls +EXPECT "snap1" get-xml "snapshot create snap1 $V0 no-timestamp" "name" +EXPECT "snap1" get-xml "snapshot deactivate snap1" "name" +EXPECT "snap1" get-xml "snapshot activate snap1" "name" +EXPECT "snap2" get-xml "snapshot create snap2 $V0 no-timestamp" "name" + +# Snapshot info xmls +EXPECT "2" get-xml "snapshot info" "count" +EXPECT "Started" get-xml "snapshot info" "status" +EXPECT "2" get-xml "snapshot info volume $V0" "count" +EXPECT "Started" get-xml "snapshot info volume $V0" "status" +EXPECT "1" get-xml "snapshot info snap1" "count" +EXPECT "2" get-xml "snapshot info snap1" "snapCount" +EXPECT "Started" get-xml "snapshot info snap1" "status" + +# Snapshot list xmls +EXPECT "2" get-xml "snapshot list" "count" +EXPECT "snap2" get-xml "snapshot list $V0" "snapshot" + +# Snapshot status xmls +EXPECT "snap2" get-xml "snapshot status" "name" +EXPECT "snap2" get-xml "snapshot deactivate snap2" "name" +#XPECT "N/A" get-xml "snapshot status" "pid" +EXPECT "snap1" get-xml "snapshot status snap1" "name" +EXPECT "Yes" get-xml "snapshot status snap1" "brick_running" + +# Snapshot restore xmls +TEST $CLI volume stop $V0 +EXPECT "snap2" get-xml "snapshot restore snap2" "name" +EXPECT "30807" get-xml "snapshot restore snap2" "opErrno" +EXPECT "0" get-xml "snapshot restore snap1" "opErrno" + +# Snapshot delete xmls +TEST $CLI volume start $V0 force +EXPECT "snap1" get-xml "snapshot create snap1 $V0 no-timestamp" "name" +EXPECT "snap2" get-xml "snapshot create snap2 $V0 no-timestamp" "name" +EXPECT "snap3" get-xml "snapshot create snap3 $V0 no-timestamp" "name" +EXPECT "Success" get-xml "snapshot delete snap3" "status" +EXPECT "Success" get-xml "snapshot delete all" "status" +EXPECT "0" get-xml "snapshot list" "count" +#XPECT "snap1" get-xml "snapshot create snap1 $V0 no-timestamp" "name" +#XPECT "snap2" get-xml "snapshot create snap2 $V0 no-timestamp" "name" +#XPECT "snap3" get-xml "snapshot create snap3 $V0 no-timestamp" "name" +#XPECT "Success" get-xml "snapshot delete volume $V0" "status" +#XPECT "0" get-xml "snapshot list" "count" + +# Snapshot clone xmls +# Snapshot clone xml is broken. Once it is fixed it will be added here. + +cleanup; diff --git a/tests/basic/volume-snapshot.t b/tests/basic/volume-snapshot.t new file mode 100755 index 00000000000..dd938b4064a --- /dev/null +++ b/tests/basic/volume-snapshot.t @@ -0,0 +1,172 @@ +#!/bin/bash + +. $(dirname $0)/../include.rc +. $(dirname $0)/../volume.rc +. $(dirname $0)/../cluster.rc +. $(dirname $0)/../snapshot.rc + + +V1="patchy2" + +function create_volumes() { + $CLI_1 volume create $V0 $H1:$L1 & + PID_1=$! + + $CLI_2 volume create $V1 $H2:$L2 $H3:$L3 & + PID_2=$! + + wait $PID_1 $PID_2 +} + +function create_snapshots() { + $CLI_1 snapshot create ${V0}_snap ${V0} no-timestamp & + PID_1=$! + + $CLI_1 snapshot create ${V1}_snap ${V1} no-timestamp & + PID_2=$! + + wait $PID_1 $PID_2 +} + +function create_snapshots_with_timestamp() { + $CLI_1 snapshot create ${V0}_snap1 ${V0}& + PID_1=$! + $CLI_1 snapshot create ${V1}_snap1 ${V1}& + PID_2=$! + + wait $PID_1 $PID_2 +} + + +function activate_snapshots() { + $CLI_1 snapshot activate ${V0}_snap & + PID_1=$! + + $CLI_1 snapshot activate ${V1}_snap & + PID_2=$! + + wait $PID_1 $PID_2 +} + +function deactivate_snapshots() { + $CLI_1 snapshot deactivate ${V0}_snap & + PID_1=$! + + $CLI_1 snapshot deactivate ${V1}_snap & + PID_2=$! + + wait $PID_1 $PID_2 +} + +function delete_snapshots() { + $CLI_1 snapshot delete $1 & + PID_1=$! + + $CLI_1 snapshot delete $2 & + PID_2=$! + + wait $PID_1 $PID_2 +} + +function restore_snapshots() { + $CLI_1 snapshot restore ${V0}_snap & + PID_1=$! + + $CLI_1 snapshot restore ${V1}_snap & + PID_2=$! + + wait $PID_1 $PID_2 +} +cleanup; + +TEST verify_lvm_version; +#Create cluster with 3 nodes +TEST launch_cluster 3; +TEST setup_lvm 3 + +TEST $CLI_1 peer probe $H2; +TEST $CLI_1 peer probe $H3; +EXPECT_WITHIN $PROBE_TIMEOUT 2 peer_count; + +create_volumes +EXPECT 'Created' volinfo_field $V0 'Status'; +EXPECT 'Created' volinfo_field $V1 'Status'; + +start_volumes 2 +EXPECT 'Started' volinfo_field $V0 'Status'; +EXPECT 'Started' volinfo_field $V1 'Status'; + +TEST $CLI_1 snapshot config activate-on-create enable + +#Snapshot Operations +create_snapshots + +EXPECT 'Started' snapshot_status ${V0}_snap; +EXPECT 'Started' snapshot_status ${V1}_snap; + +EXPECT '1' volinfo_field $V0 'Snapshot Count'; +EXPECT '1' volinfo_field $V1 'Snapshot Count'; +EXPECT "1" get-cmd-field-xml "volume info $V0" "snapshotCount" +EXPECT "1" get-cmd-field-xml "volume info $V1" "snapshotCount" + +deactivate_snapshots + +EXPECT 'Stopped' snapshot_status ${V0}_snap; +EXPECT 'Stopped' snapshot_status ${V1}_snap; + +activate_snapshots + +EXPECT 'Started' snapshot_status ${V0}_snap; +EXPECT 'Started' snapshot_status ${V1}_snap; + +deactivate_snapshots +activate_snapshots + +TEST snapshot_exists 1 ${V0}_snap +TEST snapshot_exists 1 ${V1}_snap +TEST $CLI_1 snapshot config $V0 snap-max-hard-limit 100 +TEST $CLI_1 snapshot config $V1 snap-max-hard-limit 100 + +TEST glusterfs -s $H1 --volfile-id=/snaps/${V0}_snap/${V0} $M0 +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 +TEST glusterfs -s $H2 --volfile-id=/snaps/${V1}_snap/${V1} $M0 +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 + +#create timestamp appended snaps +create_snapshots_with_timestamp; +new_name1=`$CLI_1 snapshot list ${V0} | grep ${V0}_snap1`; +new_name2=`$CLI_1 snapshot list ${V1} | grep ${V1}_snap1`; + +EXPECT '2' volinfo_field $V0 'Snapshot Count'; +EXPECT '2' volinfo_field $V1 'Snapshot Count'; +EXPECT "2" get-cmd-field-xml "volume info $V0" "snapshotCount" +EXPECT "2" get-cmd-field-xml "volume info $V1" "snapshotCount" + +EXPECT_NOT "{V0}_snap1" echo $new_name1; +EXPECT_NOT "{V1}_snap1" echo $new_name1; +delete_snapshots $new_name1 $new_name2; + +EXPECT '1' volinfo_field $V0 'Snapshot Count'; +EXPECT '1' volinfo_field $V1 'Snapshot Count'; +EXPECT "1" get-cmd-field-xml "volume info $V0" "snapshotCount" +EXPECT "1" get-cmd-field-xml "volume info $V1" "snapshotCount" + +#Clean up +stop_force_volumes 2 +EXPECT 'Stopped' volinfo_field $V0 'Status'; +EXPECT 'Stopped' volinfo_field $V1 'Status'; + +restore_snapshots +TEST ! snapshot_exists 1 ${V0}_snap +TEST ! snapshot_exists 1 ${V1}_snap + +EXPECT '0' volinfo_field $V0 'Snapshot Count'; +EXPECT '0' volinfo_field $V1 'Snapshot Count'; +EXPECT "0" get-cmd-field-xml "volume info $V0" "snapshotCount" +EXPECT "0" get-cmd-field-xml "volume info $V1" "snapshotCount" + +delete_volumes 2 +EXPECT_WITHIN $CONFIG_UPDATE_TIMEOUT "N" volume_exists $V0 +EXPECT_WITHIN $CONFIG_UPDATE_TIMEOUT "N" volume_exists $V1 + +cleanup; diff --git a/tests/basic/volume-status.t b/tests/basic/volume-status.t index f4196ac30f0..01d7ebf6c07 100644 --- a/tests/basic/volume-status.t +++ b/tests/basic/volume-status.t @@ -2,36 +2,64 @@ . $(dirname $0)/../include.rc . $(dirname $0)/../volume.rc +. $(dirname $0)/../nfs.rc + +#G_TESTDEF_TEST_STATUS_CENTOS6=NFS_TEST cleanup; +function gluster_client_list_status () { + gluster volume status $V0 client-list | sed -n '/Name/','/total/'p | wc -l +} + +function gluster_fd_status () { + gluster volume status $V0 fd | sed -n '/Brick :/ p' | wc -l +} + +function gluster_inode_status () { + gluster volume status $V0 inode | sed -n '/Connection / p' | wc -l +} + TEST glusterd TEST pidof glusterd TEST $CLI volume info; -TEST $CLI volume create $V0 replica 2 stripe 2 $H0:$B0/${V0}{1,2,3,4,5,6,7,8}; +TEST $CLI volume create $V0 replica 3 $H0:$B0/${V0}{1,2,3,4,5,6}; +TEST $CLI volume set $V0 nfs.disable false TEST $CLI volume start $V0; -sleep 2 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "Y" glustershd_up_status +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "Y" nfs_up_status ## Mount FUSE -TEST glusterfs -s $H0 --volfile-id $V0 $M0; +TEST $GFS -s $H0 --volfile-id $V0 $M0; +TEST touch $M0/file{1..20} + +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "6" gluster_fd_status + +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "768" gluster_inode_status + +##Disabling this test until the client-list command works for brick-multiplexing +#EXPECT_WITHIN $PROCESS_UP_TIMEOUT "7" gluster_client_list_status + +##Wait for connection establishment between nfs server and brick process +EXPECT_WITHIN $NFS_EXPORT_TIMEOUT "1" is_nfs_export_available; ## Mount NFS -TEST mount -t nfs -o vers=3,nolock,soft,intr $H0:/$V0 $N0; +TEST mount_nfs $H0:/$V0 $N0 nolock; TEST $CLI volume status all TEST $CLI volume status $V0 -EXPECT_WITHIN 10 'Y' nfs_up_status -EXPECT_WITHIN 10 'Y' glustershd_up_status function test_nfs_cmds () { local ret=0 declare -a nfs_cmds=("clients" "mem" "inode" "callpool") for cmd in ${nfs_cmds[@]}; do $CLI volume status $V0 nfs $cmd (( ret += $? )) + $CLI volume status $V0 nfs $cmd --xml + (( ret += $? )) done return $ret } @@ -42,6 +70,8 @@ function test_shd_cmds () { for cmd in ${shd_cmds[@]}; do $CLI volume status $V0 shd $cmd (( ret += $? )) + $CLI volume status $V0 shd $cmd --xml + (( ret += $? )) done return $ret } @@ -53,14 +83,32 @@ function test_brick_cmds () { for i in {1..2}; do $CLI volume status $V0 $H0:$B0/${V0}$i $cmd (( ret += $? )) + $CLI volume status $V0 $H0:$B0/${V0}$i $cmd --xml + (( ret += $? )) done done return $ret } +function test_status_cmds () { + local ret=0 + declare -a cmds=("detail" "clients" "mem" "inode" "fd" "callpool" "tasks" "client-list") + for cmd in ${cmds[@]}; do + $CLI volume status $V0 $cmd + (( ret += $? )) + $CLI volume status $V0 $cmd --xml + (( ret += $? )) + done + return $ret +} + TEST test_shd_cmds; TEST test_nfs_cmds; TEST test_brick_cmds; +TEST test_status_cmds; -cleanup; +## Before killing daemon to avoid deadlocks +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" umount_nfs $N0 + +cleanup; diff --git a/tests/basic/volume.t b/tests/basic/volume.t index 2f9096055e7..27fe093d07d 100755..100644 --- a/tests/basic/volume.t +++ b/tests/basic/volume.t @@ -9,26 +9,52 @@ TEST glusterd TEST pidof glusterd TEST $CLI volume info; -TEST $CLI volume create $V0 replica 2 stripe 2 $H0:$B0/${V0}{1,2,3,4,5,6,7,8}; - +TEST $CLI volume create $V0 replica 3 $H0:$B0/${V0}{1,2,3,4,5,6}; EXPECT "$V0" volinfo_field $V0 'Volume Name'; EXPECT 'Created' volinfo_field $V0 'Status'; -EXPECT '8' brick_count $V0 +EXPECT '6' brick_count $V0 TEST $CLI volume start $V0; EXPECT 'Started' volinfo_field $V0 'Status'; -TEST $CLI volume add-brick $V0 $H0:$B0/${V0}{9,10,11,12}; -EXPECT '12' brick_count $V0 +TEST $CLI volume add-brick $V0 $H0:$B0/${V0}{9,10,11}; +EXPECT '9' brick_count $V0 + +TEST $CLI volume remove-brick $V0 $H0:$B0/${V0}{1,2,3} force; +EXPECT '6' brick_count $V0 + +TEST $CLI volume top $V0 read-perf bs 4096 count 1000 +TEST $CLI volume top $V0 write-perf bs 1048576 count 2 + +TEST touch $M0/foo + +# statedump path should be a directory, setting it to a file path should fail + +TEST ! $CLI v set $V0 server.statedump-path $M0/foo; +EXPECT '/var/run/gluster' $CLI v get $V0 server.statedump-path + +#set the statedump path to an existing ditectory which should succeed +TEST mkdir $D0/level; +TEST $CLI v set $V0 server.statedump-path $D0/level +EXPECT '/level' volinfo_field $V0 'server.statedump-path' + +ret=$(ls $D0/level | wc -l); +TEST [ $ret == 0 ] +TEST $CLI v statedump $V0; +ret=$(ls $D0/level | wc -l); +TEST ! [ $ret == 0 ] + +#set the statedump path to a non - existing directory which should fail +TEST ! $CLI v set $V0 server.statedump-path /root/test +EXPECT '/level' volinfo_field $V0 'server.statedump-path' -TEST $CLI volume remove-brick $V0 $H0:$B0/${V0}{1,2,3,4}; -EXPECT '8' brick_count $V0 +TEST rm -rf $D0/level -TEST $CLI volume stop $V0; -EXPECT 'Stopped' volinfo_field $V0 'Status'; +TEST $CLI volume stop $V0 +EXPECT 'Stopped' volinfo_field $V0 'Status' -TEST $CLI volume delete $V0; -TEST ! $CLI volume info $V0; +TEST $CLI volume delete $V0 +TEST ! $CLI volume info $V0 cleanup; diff --git a/tests/basic/xlator-pass-through-sanity.t b/tests/basic/xlator-pass-through-sanity.t new file mode 100644 index 00000000000..e996be89260 --- /dev/null +++ b/tests/basic/xlator-pass-through-sanity.t @@ -0,0 +1,22 @@ +#!/bin/bash + +. $(dirname $0)/../include.rc +. $(dirname $0)/../volume.rc + +cleanup; + +TEST glusterd +TEST pidof glusterd + +TEST $CLI volume create $V0 $H0:$B0/${V0} +TEST $CLI volume set $V0 performance.io-cache-pass-through enable; +TEST $CLI volume start $V0; + +## Mount FUSE +TEST $GFS -s $H0 --volfile-id $V0 $M1; + +# This test covers lookup, mkdir, mknod, symlink, link, rename, +# create operations +TEST $(dirname $0)/rpc-coverage.sh $M1 + +cleanup; |
