From e6918187568dbd01842d8d1d2c808ce16a894239 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 21 Apr 2024 13:54:28 +0200 Subject: Adding upstream version 18.2.2. Signed-off-by: Daniel Baumann --- qa/workunits/fs/.gitignore | 1 + qa/workunits/fs/Makefile | 11 ++ qa/workunits/fs/cephfs_mirror_ha_gen.sh | 69 ++++++++ qa/workunits/fs/cephfs_mirror_ha_verify.sh | 40 +++++ qa/workunits/fs/cephfs_mirror_helpers.sh | 66 +++++++ qa/workunits/fs/damage/test-first-damage.sh | 194 +++++++++++++++++++++ qa/workunits/fs/fscrypt.sh | 119 +++++++++++++ qa/workunits/fs/full/subvolume_clone.sh | 114 ++++++++++++ qa/workunits/fs/full/subvolume_rm.sh | 72 ++++++++ qa/workunits/fs/full/subvolume_snapshot_rm.sh | 86 +++++++++ qa/workunits/fs/maxentries/maxentries.sh | 155 ++++++++++++++++ qa/workunits/fs/misc/acl.sh | 50 ++++++ qa/workunits/fs/misc/chmod.sh | 60 +++++++ qa/workunits/fs/misc/dac_override.sh | 19 ++ qa/workunits/fs/misc/direct_io.py | 42 +++++ qa/workunits/fs/misc/dirfrag.sh | 52 ++++++ qa/workunits/fs/misc/filelock_deadlock.py | 72 ++++++++ qa/workunits/fs/misc/filelock_interrupt.py | 94 ++++++++++ qa/workunits/fs/misc/i_complete_vs_rename.sh | 31 ++++ qa/workunits/fs/misc/layout_vxattrs.sh | 115 ++++++++++++ qa/workunits/fs/misc/mkpool_layout_vxattrs.sh | 15 ++ qa/workunits/fs/misc/multiple_rsync.sh | 25 +++ qa/workunits/fs/misc/rstats.sh | 80 +++++++++ qa/workunits/fs/misc/trivial_sync.sh | 7 + qa/workunits/fs/misc/xattrs.sh | 14 ++ qa/workunits/fs/multiclient_sync_read_eof.py | 42 +++++ qa/workunits/fs/norstats/kernel_untar_tar.sh | 26 +++ qa/workunits/fs/quota/quota.sh | 128 ++++++++++++++ qa/workunits/fs/snap-hierarchy.sh | 24 +++ qa/workunits/fs/snaps/snap-rm-diff.sh | 10 ++ qa/workunits/fs/snaps/snaptest-1.sh | 29 +++ qa/workunits/fs/snaps/snaptest-2.sh | 59 +++++++ qa/workunits/fs/snaps/snaptest-authwb.sh | 12 ++ qa/workunits/fs/snaps/snaptest-capwb.sh | 33 ++++ qa/workunits/fs/snaps/snaptest-dir-rename.sh | 17 ++ qa/workunits/fs/snaps/snaptest-double-null.sh | 23 +++ qa/workunits/fs/snaps/snaptest-estale.sh | 13 ++ qa/workunits/fs/snaps/snaptest-git-ceph.sh | 52 ++++++ qa/workunits/fs/snaps/snaptest-hardlink.sh | 25 +++ qa/workunits/fs/snaps/snaptest-intodir.sh | 22 +++ .../fs/snaps/snaptest-multiple-capsnaps.sh | 42 +++++ qa/workunits/fs/snaps/snaptest-name-limits.sh | 27 +++ qa/workunits/fs/snaps/snaptest-parents.sh | 39 +++++ qa/workunits/fs/snaps/snaptest-realm-split.sh | 31 ++++ qa/workunits/fs/snaps/snaptest-snap-rename.sh | 33 ++++ qa/workunits/fs/snaps/snaptest-snap-rm-cmp.sh | 24 +++ qa/workunits/fs/snaps/snaptest-upchildrealms.sh | 28 +++ qa/workunits/fs/snaps/snaptest-xattrwb.sh | 29 +++ qa/workunits/fs/snaps/untar_snap_rm.sh | 18 ++ qa/workunits/fs/test_o_trunc.c | 45 +++++ qa/workunits/fs/test_o_trunc.sh | 7 + qa/workunits/fs/test_python.sh | 6 + 52 files changed, 2447 insertions(+) create mode 100644 qa/workunits/fs/.gitignore create mode 100644 qa/workunits/fs/Makefile create mode 100755 qa/workunits/fs/cephfs_mirror_ha_gen.sh create mode 100755 qa/workunits/fs/cephfs_mirror_ha_verify.sh create mode 100644 qa/workunits/fs/cephfs_mirror_helpers.sh create mode 100755 qa/workunits/fs/damage/test-first-damage.sh create mode 100755 qa/workunits/fs/fscrypt.sh create mode 100755 qa/workunits/fs/full/subvolume_clone.sh create mode 100755 qa/workunits/fs/full/subvolume_rm.sh create mode 100755 qa/workunits/fs/full/subvolume_snapshot_rm.sh create mode 100755 qa/workunits/fs/maxentries/maxentries.sh create mode 100755 qa/workunits/fs/misc/acl.sh create mode 100755 qa/workunits/fs/misc/chmod.sh create mode 100755 qa/workunits/fs/misc/dac_override.sh create mode 100755 qa/workunits/fs/misc/direct_io.py create mode 100755 qa/workunits/fs/misc/dirfrag.sh create mode 100755 qa/workunits/fs/misc/filelock_deadlock.py create mode 100755 qa/workunits/fs/misc/filelock_interrupt.py create mode 100755 qa/workunits/fs/misc/i_complete_vs_rename.sh create mode 100755 qa/workunits/fs/misc/layout_vxattrs.sh create mode 100755 qa/workunits/fs/misc/mkpool_layout_vxattrs.sh create mode 100755 qa/workunits/fs/misc/multiple_rsync.sh create mode 100755 qa/workunits/fs/misc/rstats.sh create mode 100755 qa/workunits/fs/misc/trivial_sync.sh create mode 100755 qa/workunits/fs/misc/xattrs.sh create mode 100755 qa/workunits/fs/multiclient_sync_read_eof.py create mode 100755 qa/workunits/fs/norstats/kernel_untar_tar.sh create mode 100755 qa/workunits/fs/quota/quota.sh create mode 100755 qa/workunits/fs/snap-hierarchy.sh create mode 100755 qa/workunits/fs/snaps/snap-rm-diff.sh create mode 100755 qa/workunits/fs/snaps/snaptest-1.sh create mode 100755 qa/workunits/fs/snaps/snaptest-2.sh create mode 100755 qa/workunits/fs/snaps/snaptest-authwb.sh create mode 100755 qa/workunits/fs/snaps/snaptest-capwb.sh create mode 100755 qa/workunits/fs/snaps/snaptest-dir-rename.sh create mode 100755 qa/workunits/fs/snaps/snaptest-double-null.sh create mode 100755 qa/workunits/fs/snaps/snaptest-estale.sh create mode 100755 qa/workunits/fs/snaps/snaptest-git-ceph.sh create mode 100755 qa/workunits/fs/snaps/snaptest-hardlink.sh create mode 100755 qa/workunits/fs/snaps/snaptest-intodir.sh create mode 100755 qa/workunits/fs/snaps/snaptest-multiple-capsnaps.sh create mode 100755 qa/workunits/fs/snaps/snaptest-name-limits.sh create mode 100755 qa/workunits/fs/snaps/snaptest-parents.sh create mode 100755 qa/workunits/fs/snaps/snaptest-realm-split.sh create mode 100755 qa/workunits/fs/snaps/snaptest-snap-rename.sh create mode 100755 qa/workunits/fs/snaps/snaptest-snap-rm-cmp.sh create mode 100755 qa/workunits/fs/snaps/snaptest-upchildrealms.sh create mode 100755 qa/workunits/fs/snaps/snaptest-xattrwb.sh create mode 100755 qa/workunits/fs/snaps/untar_snap_rm.sh create mode 100644 qa/workunits/fs/test_o_trunc.c create mode 100755 qa/workunits/fs/test_o_trunc.sh create mode 100755 qa/workunits/fs/test_python.sh (limited to 'qa/workunits/fs') diff --git a/qa/workunits/fs/.gitignore b/qa/workunits/fs/.gitignore new file mode 100644 index 000000000..f7f7a0614 --- /dev/null +++ b/qa/workunits/fs/.gitignore @@ -0,0 +1 @@ +test_o_trunc diff --git a/qa/workunits/fs/Makefile b/qa/workunits/fs/Makefile new file mode 100644 index 000000000..c9934254d --- /dev/null +++ b/qa/workunits/fs/Makefile @@ -0,0 +1,11 @@ +CFLAGS = -Wall -Wextra -D_GNU_SOURCE + +TARGETS = test_o_trunc + +.c: + $(CC) $(CFLAGS) $@.c -o $@ + +all: $(TARGETS) + +clean: + rm $(TARGETS) diff --git a/qa/workunits/fs/cephfs_mirror_ha_gen.sh b/qa/workunits/fs/cephfs_mirror_ha_gen.sh new file mode 100755 index 000000000..35ee9d4c7 --- /dev/null +++ b/qa/workunits/fs/cephfs_mirror_ha_gen.sh @@ -0,0 +1,69 @@ +#!/bin/bash -ex +# +# cephfs_mirror_ha_gen.sh - generate workload to synchronize +# + +. $(dirname $0)/cephfs_mirror_helpers.sh + +cleanup() +{ + for i in `seq 1 $NR_DIRECTORIES` + do + local repo_name="${REPO_PATH_PFX}_$i" + for j in `seq 1 $NR_SNAPSHOTS` + do + snap_name=$repo_name/.snap/snap_$j + if test -d $snap_name; then + rmdir $snap_name + fi + done + done + exit 1 +} +trap cleanup EXIT + +configure_peer() +{ + ceph mgr module enable mirroring + ceph fs snapshot mirror enable $PRIMARY_FS + ceph fs snapshot mirror peer_add $PRIMARY_FS client.mirror_remote@ceph $BACKUP_FS + + for i in `seq 1 $NR_DIRECTORIES` + do + local repo_name="${REPO_PATH_PFX}_$i" + ceph fs snapshot mirror add $PRIMARY_FS "$MIRROR_SUBDIR/$repo_name" + done +} + +create_snaps() +{ + for i in `seq 1 $NR_DIRECTORIES` + do + local repo_name="${REPO_PATH_PFX}_$i" + for j in `seq 1 $NR_SNAPSHOTS` + do + snap_name=$repo_name/.snap/snap_$j + r=$(( $RANDOM % 100 + 5 )) + arr=($repo_name "reset" "--hard" "HEAD~$r") + exec_git_cmd "${arr[@]}" + mkdir $snap_name + store_checksum $snap_name + done + done +} + +unset CEPH_CLI_TEST_DUP_COMMAND + +echo "running generator on prmary file system..." + +# setup git repos to be used as data set +setup_repos + +# turn on mirroring, add peers... +configure_peer + +# snapshots on primary +create_snaps + +# do not cleanup when exiting on success.. +trap - EXIT diff --git a/qa/workunits/fs/cephfs_mirror_ha_verify.sh b/qa/workunits/fs/cephfs_mirror_ha_verify.sh new file mode 100755 index 000000000..8d8b3859c --- /dev/null +++ b/qa/workunits/fs/cephfs_mirror_ha_verify.sh @@ -0,0 +1,40 @@ +#!/bin/bash -ex +# +# cephfs_mirror_ha_verify.sh - verify synchronized snapshots +# + +. $(dirname $0)/cephfs_mirror_helpers.sh + +echo "running verifier on secondary file system..." + +for i in `seq 1 $NR_DIRECTORIES` +do + repo_name="${REPO_PATH_PFX}_$i" + for j in `seq 1 $NR_SNAPSHOTS` + do + for s in 1 1 2 4 4 4 4 4 8 8 8 8 16 16 32 64 64 128 128 + do + sleep $s + snap_name=$repo_name/.snap/snap_$j + if test -d $repo_name; then + echo "checking snapshot [$snap_name] in $repo_name" + if test -d $snap_name; then + echo "generating hash for $snap_name" + cksum='' + calc_checksum $snap_name cksum + ret=$(compare_checksum $cksum $snap_name) + if [ $ret -ne 0 ]; then + echo "checksum failed $snap_name ($cksum)" + return $ret + else + echo "checksum matched $snap_name ($cksum)" + break + fi + fi + fi + done + echo "couldn't complete verification for: $snap_name" + done +done + +echo "verify done!" diff --git a/qa/workunits/fs/cephfs_mirror_helpers.sh b/qa/workunits/fs/cephfs_mirror_helpers.sh new file mode 100644 index 000000000..69f1c6f3d --- /dev/null +++ b/qa/workunits/fs/cephfs_mirror_helpers.sh @@ -0,0 +1,66 @@ +PRIMARY_FS='dc' +BACKUP_FS='dc-backup' + +REPO=ceph-qa-suite +REPO_DIR=ceph_repo +REPO_PATH_PFX="$REPO_DIR/$REPO" + +NR_DIRECTORIES=4 +NR_SNAPSHOTS=4 +MIRROR_SUBDIR='/mirror' + +calc_checksum() +{ + local path=$1 + local -n ref=$2 + ref=`find -L $path -type f -exec md5sum {} + | awk '{ print $1 }' | md5sum | awk '{ print $1 }'` +} + +store_checksum() +{ + local path=$1 + local cksum='' #something invalid + local fhash=`echo -n $path | md5sum | awk '{ print $1 }'` + calc_checksum $path cksum + echo -n $cksum > "/tmp/primary-$fhash" +} + +compare_checksum() +{ + local ret=0 + local cksum=$1 + local path=$2 + local fhash=`echo -n $path | md5sum | awk '{ print $1 }'` + local cksum_ondisk=`cat /tmp/primary-$fhash` + if [ $cksum != $cksum_ondisk ]; then + echo "$cksum <> $cksum_ondisk" + ret=1 + fi + echo $ret +} + +exec_git_cmd() +{ + local arg=("$@") + local repo_name=${arg[0]} + local cmd=${arg[@]:1} + git --git-dir "$repo_name/.git" $cmd +} + +clone_repo() +{ + local repo_name=$1 + git clone --branch giant "http://github.com/ceph/$REPO" $repo_name +} + +setup_repos() +{ + mkdir "$REPO_DIR" + + for i in `seq 1 $NR_DIRECTORIES` + do + local repo_name="${REPO_PATH_PFX}_$i" + mkdir $repo_name + clone_repo $repo_name + done +} diff --git a/qa/workunits/fs/damage/test-first-damage.sh b/qa/workunits/fs/damage/test-first-damage.sh new file mode 100755 index 000000000..57447b957 --- /dev/null +++ b/qa/workunits/fs/damage/test-first-damage.sh @@ -0,0 +1,194 @@ +#!/bin/bash + +set -ex + +FIRST_DAMAGE="first-damage.py" +FS=cephfs +METADATA_POOL=cephfs_meta +MOUNT=~/mnt/mnt.0 +PYTHON=python3 + +function usage { + printf '%s: [--fs=] [--metadata-pool=] [--first-damage=]\n' + exit 1 +} + + +function create { + ceph config set mds mds_bal_fragment_dirs 0 + mkdir dir + DIR_INODE=$(stat -c '%i' dir) + touch dir/a + touch dir/"a space" + touch -- $(printf 'dir/\xff') + mkdir dir/.snap/1 + mkdir dir/.snap/2 + # two snaps + rm dir/a + mkdir dir/.snap/3 + # not present in HEAD + touch dir/a + mkdir dir/.snap/4 + # one snap + rm dir/a + touch dir/a + mkdir dir/.snap/5 + # unlink then create + rm dir/a + touch dir/a + # unlink then create, HEAD not snapped + ls dir/.snap/*/ + mkdir big + BIG_DIR_INODE=$(stat -c '%i' big) + for i in `seq 1 15000`; do + touch $(printf 'big/%08d' $i) + done +} + +function flush { + ceph tell mds."$FS":0 flush journal +} + +function damage { + local IS=$(printf '%llx.%08llx' "$DIR_INODE" 0) + local LS=$(ceph tell mds."$FS":0 dump snaps | jq .last_created) + + local T=$(mktemp -p /tmp) + + # nuke snap 1 version of "a" + rados --pool="$METADATA_POOL" getomapval "$IS" a_$(printf %x $((LS-4))) "$T" + printf '\xff\xff\xff\xf0' | dd of="$T" count=4 bs=1 conv=notrunc,nocreat + rados --pool="$METADATA_POOL" setomapval "$IS" a_$(printf %x $((LS-4))) --input-file="$T" + + # nuke snap 4 version of "a" + rados --pool="$METADATA_POOL" getomapval "$IS" a_$(printf %x $((LS-1))) "$T" + printf '\xff\xff\xff\xff' | dd of="$T" count=4 bs=1 conv=notrunc,nocreat + rados --pool="$METADATA_POOL" setomapval "$IS" a_$(printf %x $((LS-1))) --input-file="$T" + + # screw up HEAD + rados --pool="$METADATA_POOL" getomapval "$IS" a_head "$T" + printf '\xfe\xff\xff\xff' | dd of="$T" count=4 bs=1 conv=notrunc,nocreat + rados --pool="$METADATA_POOL" setomapval "$IS" a_head --input-file="$T" + + # screw up HEAD on what dentry in big + IS=$(printf '%llx.%08llx' "$BIG_DIR_INODE" 0) + rados --pool="$METADATA_POOL" getomapval "$IS" 00009999_head "$T" + printf '\xfe\xff\xff\xff' | dd of="$T" count=4 bs=1 conv=notrunc,nocreat + rados --pool="$METADATA_POOL" setomapval "$IS" 00009999_head --input-file="$T" + + rm -f "$T" +} + +function recover { + flush + ceph fs fail "$FS" + sleep 5 + cephfs-journal-tool --rank="$FS":0 event recover_dentries summary + cephfs-journal-tool --rank="$FS":0 journal reset + "$PYTHON" $FIRST_DAMAGE --debug /tmp/debug1 --memo /tmp/memo1 "$METADATA_POOL" + "$PYTHON" $FIRST_DAMAGE --debug /tmp/debug2 --memo /tmp/memo2 --repair-nosnap "$METADATA_POOL" + "$PYTHON" $FIRST_DAMAGE --debug /tmp/debug3 --memo /tmp/memo3 --remove "$METADATA_POOL" + ceph fs set "$FS" joinable true +} + +function check { + stat dir || exit 1 + stat dir/a || exit 1 + for i in `seq 1 5`; do + stat dir/.snap/$i || exit 2 + done + stat dir/.snap/2/a || exit 3 + stat dir/.snap/5/a || exit 4 + if stat dir/.snap/1/a; then + echo should be gone + exit 5 + fi + if stat dir/.snap/3/a; then + echo should not ever exist + exit 6 + fi + if stat dir/.snap/4/a; then + echo should be gone + exit 7 + fi +} + +function cleanup { + rmdir dir/.snap/* + find dir + rm -rf dir +} + +function mount { + sudo --preserve-env=CEPH_CONF bin/mount.ceph :/ "$MOUNT" -o name=admin,noshare + df -h "$MOUNT" +} + +function main { + eval set -- $(getopt --name "$0" --options '' --longoptions 'help,fs:,metadata-pool:,first-damage:,mount:,python:' -- "$@") + + while [ "$#" -gt 0 ]; do + echo "$*" + echo "$1" + case "$1" in + -h|--help) + usage + ;; + --fs) + FS="$2" + shift 2 + ;; + --metadata-pool) + METADATA_POOL="$2" + shift 2 + ;; + --mount) + MOUNT="$2" + shift 2 + ;; + --first-damage) + FIRST_DAMAGE="$2" + shift 2 + ;; + --python) + PYTHON="$2" + shift 2 + ;; + --) + shift + break + ;; + *) + usage + ;; + esac + done + + mount + + pushd "$MOUNT" + create + popd + + sudo umount -f "$MOUNT" + + # flush dentries/inodes to omap + flush + + damage + + recover + + sleep 5 # for mds to join + + mount + + pushd "$MOUNT" + check + cleanup + popd + + sudo umount -f "$MOUNT" +} + +main "$@" diff --git a/qa/workunits/fs/fscrypt.sh b/qa/workunits/fs/fscrypt.sh new file mode 100755 index 000000000..ca856a62e --- /dev/null +++ b/qa/workunits/fs/fscrypt.sh @@ -0,0 +1,119 @@ +#!/usr/bin/env bash + +set -xe + +mydir=`dirname $0` + +if [ $# -ne 2 ] +then + echo "2 parameters are required!\n" + echo "Usage:" + echo " fscrypt.sh " + echo " type: should be any of 'none', 'unlocked' or 'locked'" + echo " testdir: the test direcotry name" + exit 1 +fi + +fscrypt=$1 +testcase=$2 +testdir=fscrypt_test_${fscrypt}_${testcase} +mkdir $testdir + +XFSPROGS_DIR='xfprogs-dev-dir' +XFSTESTS_DIR='xfstest-dev-dir' +export XFS_IO_PROG="$(type -P xfs_io)" + +# Setup the xfstests env +setup_xfstests_env() +{ + git clone https://git.ceph.com/xfstests-dev.git $XFSTESTS_DIR --depth 1 + pushd $XFSTESTS_DIR + . common/encrypt + popd +} + +install_deps() +{ + local system_value=$(sudo lsb_release -is | awk '{print tolower($0)}') + case $system_value in + "centos" | "centosstream" | "fedora") + sudo yum install -y inih-devel userspace-rcu-devel \ + libblkid-devel gettext libedit-devel \ + libattr-devel device-mapper-devel libicu-devel + ;; + "ubuntu" | "debian") + sudo apt-get install -y libinih-dev liburcu-dev \ + libblkid-dev gettext libedit-dev libattr1-dev \ + libdevmapper-dev libicu-dev pkg-config + ;; + *) + echo "Unsupported distro $system_value" + exit 1 + ;; + esac +} + +# Install xfsprogs-dev from source to support "add_enckey" for xfs_io +install_xfsprogs() +{ + local install_xfsprogs=0 + + xfs_io -c "help add_enckey" | grep -q 'not found' && install_xfsprogs=1 + + if [ $install_xfsprogs -eq 1 ]; then + install_deps + + git clone https://git.ceph.com/xfsprogs-dev.git $XFSPROGS_DIR --depth 1 + pushd $XFSPROGS_DIR + make + sudo make install + popd + fi +} + +clean_up() +{ + rm -rf $XFSPROGS_DIR + rm -rf $XFSTESTS_DIR + rm -rf $testdir +} + +# For now will test the V2 encryption policy only as the +# V1 encryption policy is deprecated + +install_xfsprogs +setup_xfstests_env + +# Generate a fixed keying identifier +raw_key=$(_generate_raw_encryption_key) +keyid=$(_add_enckey $testdir "$raw_key" | awk '{print $NF}') + +case ${fscrypt} in + "none") + # do nothing for the test directory and will test it + # as one non-encrypted directory. + pushd $testdir + ${mydir}/../suites/${testcase}.sh + popd + clean_up + ;; + "unlocked") + # set encrypt policy with the key provided and then + # the test directory will be encrypted & unlocked + _set_encpolicy $testdir $keyid + pushd $testdir + ${mydir}/../suites/${testcase}.sh + popd + clean_up + ;; + "locked") + # remove the key, then the test directory will be locked + # and any modification will be denied by requiring the key + _rm_enckey $testdir $keyid + clean_up + ;; + *) + clean_up + echo "Unknown parameter $1" + exit 1 +esac diff --git a/qa/workunits/fs/full/subvolume_clone.sh b/qa/workunits/fs/full/subvolume_clone.sh new file mode 100755 index 000000000..a11131215 --- /dev/null +++ b/qa/workunits/fs/full/subvolume_clone.sh @@ -0,0 +1,114 @@ +#!/usr/bin/env bash +set -ex + +# This testcase tests the 'ceph fs subvolume snapshot clone' when the osd is full. +# The clone fails with 'MetadataMgrException: -28 (error in write)' and +# truncates the config file of corresponding subvolume while updating the config file. +# Hence the subsequent subvolume commands on the clone fails with +# 'MetadataMgrException: -2 (section 'GLOBAL' does not exist)' traceback. + +# The osd is of the size 1GB. The full-ratios are set so that osd is treated full +# at around 600MB. The subvolume is created and 100MB is written. +# The subvolume is snapshotted and cloned ten times. Since the clone delay is set to 15 seconds, +# all the clones reach pending state for sure. Among ten clones, only few succeed and rest fails +# with ENOSPACE. + +# At this stage, ".meta" config file of the failed clones are checked if it's truncated. +# and clone status command is checked for traceback. + +# Note that the failed clones would be in retry loop and it's state would be 'pending' or 'in-progress'. +# It's state is not updated to 'failed' as the config update to gets ENOSPACE too. + +set -e +ignore_failure() { + if "$@"; then return 0; else return 0; fi +} + +expect_failure() { + if "$@"; then return 1; else return 0; fi +} + +NUM_CLONES=10 + +ceph fs subvolume create cephfs sub_0 +subvol_path_0=$(ceph fs subvolume getpath cephfs sub_0 2>/dev/null) + +# For debugging +echo "Before ratios are set" +df $CEPH_MNT +ceph osd df + +ceph osd set-full-ratio 0.6 +ceph osd set-nearfull-ratio 0.50 +ceph osd set-backfillfull-ratio 0.55 + +# For debugging +echo "After ratios are set" +df -h +ceph osd df + +for i in {1..100};do sudo dd if=/dev/urandom of=$CEPH_MNT$subvol_path_0/1MB_file-$i status=progress bs=1M count=1 conv=fdatasync;done + +# For debugging +echo "After subvolumes are written" +df -h $CEPH_MNT +ceph osd df + +# snapshot +ceph fs subvolume snapshot create cephfs sub_0 snap_0 + +# Set clone snapshot delay +ceph config set mgr mgr/volumes/snapshot_clone_delay 15 + +# Schedule few clones, some would fail with no space +for i in $(eval echo {1..$NUM_CLONES});do ceph fs subvolume snapshot clone cephfs sub_0 snap_0 clone_$i;done + +# Wait for osd is full +timeout=90 +while [ $timeout -gt 0 ] +do + health=$(ceph health detail) + [[ $health = *"OSD_FULL"* ]] && echo "OSD is full" && break + echo "Wating for osd to be full: $timeout" + sleep 1 + let "timeout-=1" +done + +# For debugging +echo "After osd is full" +df -h $CEPH_MNT +ceph osd df + +# Check clone status, this should not crash +for i in $(eval echo {1..$NUM_CLONES}) +do + ignore_failure ceph fs clone status cephfs clone_$i >/tmp/out_${PID}_file 2>/tmp/error_${PID}_file + cat /tmp/error_${PID}_file + if grep "complete" /tmp/out_${PID}_file; then + echo "The clone_$i is completed" + else + #in-progress/pending clones, No traceback should be found in stderr + echo clone_$i in PENDING/IN-PROGRESS + expect_failure sudo grep "Traceback" /tmp/error_${PID}_file + #config file should not be truncated and GLOBAL section should be found + sudo grep "GLOBAL" $CEPH_MNT/volumes/_nogroup/clone_$i/.meta + fi +done + +# Hard cleanup +ignore_failure sudo rm -rf $CEPH_MNT/_index/clone/* +ignore_failure sudo rm -rf $CEPH_MNT/volumes/_nogroup/clone_* +ignore_failure sudo rmdir $CEPH_MNT/volumes/_nogroup/sub_0/.snap/snap_0 +ignore_failure sudo rm -rf $CEPH_MNT/volumes/_nogroup/sub_0 + +#Set the ratios back for other full tests to run +ceph osd set-full-ratio 0.95 +ceph osd set-nearfull-ratio 0.95 +ceph osd set-backfillfull-ratio 0.95 + +#After test +echo "After test" +df -h $CEPH_MNT +ceph osd df + +echo OK diff --git a/qa/workunits/fs/full/subvolume_rm.sh b/qa/workunits/fs/full/subvolume_rm.sh new file mode 100755 index 000000000..a464e30f5 --- /dev/null +++ b/qa/workunits/fs/full/subvolume_rm.sh @@ -0,0 +1,72 @@ +#!/usr/bin/env bash +set -ex + +# This testcase tests the scenario of the 'ceph fs subvolume rm' mgr command +# when the osd is full. The command used to hang. The osd is of the size 1GB. +# The subvolume is created and 500MB file is written. The full-ratios are +# set below 500MB such that the osd is treated as full. Now the subvolume is +# is removed. This should be successful with the introduction of FULL +# capabilities which the mgr holds. + +set -e +expect_failure() { + if "$@"; then return 1; else return 0; fi +} + +ceph fs subvolume create cephfs sub_0 +subvol_path=$(ceph fs subvolume getpath cephfs sub_0 2>/dev/null) + +#For debugging +echo "Before write" +df -h +ceph osd df + +sudo dd if=/dev/urandom of=$CEPH_MNT$subvol_path/500MB_file-1 status=progress bs=1M count=500 + +ceph osd set-full-ratio 0.2 +ceph osd set-nearfull-ratio 0.16 +ceph osd set-backfillfull-ratio 0.18 + +timeout=30 +while [ $timeout -gt 0 ] +do + health=$(ceph health detail) + [[ $health = *"OSD_FULL"* ]] && echo "OSD is full" && break + echo "Wating for osd to be full: $timeout" + sleep 1 + let "timeout-=1" +done + +#For debugging +echo "After ratio set" +df -h +ceph osd df + +#Delete subvolume +ceph fs subvolume rm cephfs sub_0 + +#Validate subvolume is deleted +expect_failure ceph fs subvolume info cephfs sub_0 + +#Wait for subvolume to delete data +trashdir=$CEPH_MNT/volumes/_deleting +timeout=30 +while [ $timeout -gt 0 ] +do + [ -z "$(sudo ls -A $trashdir)" ] && echo "Trash directory $trashdir is empty" && break + echo "Wating for trash dir to be empty: $timeout" + sleep 1 + let "timeout-=1" +done + +#Set the ratios back for other full tests to run +ceph osd set-full-ratio 0.95 +ceph osd set-nearfull-ratio 0.95 +ceph osd set-backfillfull-ratio 0.95 + +#After test +echo "After test" +df -h +ceph osd df + +echo OK diff --git a/qa/workunits/fs/full/subvolume_snapshot_rm.sh b/qa/workunits/fs/full/subvolume_snapshot_rm.sh new file mode 100755 index 000000000..f6d0add9f --- /dev/null +++ b/qa/workunits/fs/full/subvolume_snapshot_rm.sh @@ -0,0 +1,86 @@ +#!/usr/bin/env bash +set -ex + +# This testcase tests the 'ceph fs subvolume snapshot rm' when the osd is full. +# The snapshot rm fails with 'MetadataMgrException: -28 (error in write)' and +# truncates the config file of corresponding subvolume. Hence the subsequent +# snapshot rm of the same snapshot fails with 'MetadataMgrException: -2 (section 'GLOBAL' does not exist)' +# traceback. + +# The osd is of the size 1GB. The subvolume is created and 800MB file is written. +# Then full-ratios are set below 500MB such that the osd is treated as full. +# The subvolume snapshot is taken which succeeds as no extra space is required +# for snapshot. Now, the removal of the snapshot fails with ENOSPACE as it +# fails to remove the snapshot metadata set. The snapshot removal fails +# but should not traceback and truncate the config file. + +set -e +expect_failure() { + if "$@"; then return 1; else return 0; fi +} + +ignore_failure() { + if "$@"; then return 0; else return 0; fi +} + +ceph fs subvolume create cephfs sub_0 +subvol_path=$(ceph fs subvolume getpath cephfs sub_0 2>/dev/null) + +#For debugging +echo "Before write" +df $CEPH_MNT +ceph osd df + +# Write 800MB file and set full ratio to around 200MB +ignore_failure sudo dd if=/dev/urandom of=$CEPH_MNT$subvol_path/800MB_file-1 status=progress bs=1M count=800 conv=fdatasync + +ceph osd set-full-ratio 0.2 +ceph osd set-nearfull-ratio 0.16 +ceph osd set-backfillfull-ratio 0.18 + +timeout=30 +while [ $timeout -gt 0 ] +do + health=$(ceph health detail) + [[ $health = *"OSD_FULL"* ]] && echo "OSD is full" && break + echo "Wating for osd to be full: $timeout" + sleep 1 + let "timeout-=1" +done + +#Take snapshot +ceph fs subvolume snapshot create cephfs sub_0 snap_0 + +#Remove snapshot fails but should not throw traceback +expect_failure ceph fs subvolume snapshot rm cephfs sub_0 snap_0 2>/tmp/error_${PID}_file +cat /tmp/error_${PID}_file + +# No traceback should be found +expect_failure grep "Traceback" /tmp/error_${PID}_file + +# Validate config file is not truncated and GLOBAL section exists +sudo grep "GLOBAL" $CEPH_MNT/volumes/_nogroup/sub_0/.meta + +#For debugging +echo "After write" +df $CEPH_MNT +ceph osd df + +# Snapshot removal with force option should succeed +ceph fs subvolume snapshot rm cephfs sub_0 snap_0 --force + +#Cleanup from backend +ignore_failure sudo rm -f /tmp/error_${PID}_file +ignore_failure sudo rm -rf $CEPH_MNT/volumes/_nogroup/sub_0 + +#Set the ratios back for other full tests to run +ceph osd set-full-ratio 0.95 +ceph osd set-nearfull-ratio 0.95 +ceph osd set-backfillfull-ratio 0.95 + +#After test +echo "After test" +df -h $CEPH_MNT +ceph osd df + +echo OK diff --git a/qa/workunits/fs/maxentries/maxentries.sh b/qa/workunits/fs/maxentries/maxentries.sh new file mode 100755 index 000000000..d48fd956e --- /dev/null +++ b/qa/workunits/fs/maxentries/maxentries.sh @@ -0,0 +1,155 @@ +#!/usr/bin/env bash + +set -ex + +function expect_false() +{ + set -x + if "$@"; then return 1; else return 0; fi +} + +function make_files() +{ + set +x + temp_dir=`mktemp -d mkfile_test_XXXXXX` + for i in $(seq 1 $1) + do + echo -n | dd of="${temp_dir}/file_$i" conv=fsync || return 1 + sync "${temp_dir}" || return 1 + done + set -x + return 0 +} + +function make_dirs() +{ + set +x + temp_dir=`mktemp -d mkdir_test_XXXXXX` + for i in $(seq 1 $1) + do + mkdir -p ${temp_dir}/dir_${i} || return 1 + sync "${temp_dir}" || return 1 + done + set -x + return 0 +} + +function make_nodes() +{ + set +x + temp_dir=`mktemp -d mknod_test_XXXXXX` + for i in $(seq 1 $1) + do + mknod ${temp_dir}/fifo_${i} p || return 1 + sync "${temp_dir}" || return 1 + done + set -x + return 0 +} + +function rename_files() +{ + set +x + temp_dir=`mktemp -d rename_test_XXXXXX` + mkdir -p ${temp_dir}/rename + + for i in $(seq 1 $1) + do + touch ${temp_dir}/file_${i} || return 1 + + mv ${temp_dir}/file_${i} ${temp_dir}/rename/ || return 1 + sync "${temp_dir}" || return 1 + done + set -x + return 0 +} + +function make_symlinks() +{ + set +x + temp_dir=`mktemp -d symlink_test_XXXXXX` + mkdir -p ${temp_dir}/symlink + + touch ${temp_dir}/file + + for i in $(seq 1 $1) + do + ln -s ../file ${temp_dir}/symlink/sym_${i} || return 1 + sync "${temp_dir}" || return 1 + done + set -x + return 0 +} + +function make_links() +{ + set +x + temp_dir=`mktemp -d link_test_XXXXXX` + mkdir -p ${temp_dir}/link + + touch ${temp_dir}/file + + for i in $(seq 1 $1) + do + ln ${temp_dir}/file ${temp_dir}/link/link_${i} || return 1 + sync "${temp_dir}" || return 1 + done + set -x + return 0 +} + +function cleanup() +{ + rm -rf * +} + +test_dir="max_entries" +mkdir -p $test_dir +pushd $test_dir + +dir_max_entries=100 +ceph config set mds mds_dir_max_entries $dir_max_entries + +ok_dir_max_entries=$dir_max_entries +fail_dir_max_entries=$((dir_max_entries+1)) + +# make files test +make_files $ok_dir_max_entries +expect_false make_files $fail_dir_max_entries + +# make dirs test +make_dirs $ok_dir_max_entries +expect_false make_dirs $fail_dir_max_entries + +# make nodes test +make_nodes $ok_dir_max_entries +expect_false make_nodes $fail_dir_max_entries + +# rename files test +rename_files $ok_dir_max_entries +expect_false rename_files $fail_dir_max_entries + +# symlink files test +make_symlinks $ok_dir_max_entries +expect_false make_symlinks $fail_dir_max_entries + +# link files test +make_links $ok_dir_max_entries +expect_false make_links $fail_dir_max_entries + +# no limit (e.g., default value) +dir_max_entries=0 +ceph config set mds mds_dir_max_entries $dir_max_entries + +make_files 500 +make_dirs 500 +make_nodes 500 +rename_files 500 +make_symlinks 500 +make_links 500 + +cleanup + +popd # $test_dir + +echo OK diff --git a/qa/workunits/fs/misc/acl.sh b/qa/workunits/fs/misc/acl.sh new file mode 100755 index 000000000..198b05671 --- /dev/null +++ b/qa/workunits/fs/misc/acl.sh @@ -0,0 +1,50 @@ +#!/bin/sh -x + +set -e +mkdir -p testdir +cd testdir + +set +e +setfacl -d -m u:nobody:rw . +if test $? != 0; then + echo "Filesystem does not support ACL" + exit 0 +fi + +expect_failure() { + if "$@"; then return 1; else return 0; fi +} + +set -e +c=0 +while [ $c -lt 100 ] +do + c=`expr $c + 1` + # inherited ACL from parent directory's default ACL + mkdir d1 + c1=`getfacl d1 | grep -c "nobody:rw"` + echo 3 | sudo tee /proc/sys/vm/drop_caches > /dev/null + c2=`getfacl d1 | grep -c "nobody:rw"` + rmdir d1 + if [ $c1 -ne 2 ] || [ $c2 -ne 2 ] + then + echo "ERROR: incorrect ACLs" + exit 1 + fi +done + +mkdir d1 + +# The ACL xattr only contains ACL header. ACL should be removed +# in this case. +setfattr -n system.posix_acl_access -v 0x02000000 d1 +setfattr -n system.posix_acl_default -v 0x02000000 . + +expect_failure getfattr -n system.posix_acl_access d1 +expect_failure getfattr -n system.posix_acl_default . + + +rmdir d1 +cd .. +rmdir testdir +echo OK diff --git a/qa/workunits/fs/misc/chmod.sh b/qa/workunits/fs/misc/chmod.sh new file mode 100755 index 000000000..de66776f1 --- /dev/null +++ b/qa/workunits/fs/misc/chmod.sh @@ -0,0 +1,60 @@ +#!/bin/sh -x + +set -e + +check_perms() { + + file=$1 + r=$(ls -la ${file}) + if test $? != 0; then + echo "ERROR: File listing/stat failed" + exit 1 + fi + + perms=$2 + if test "${perms}" != $(echo ${r} | awk '{print $1}') && \ + test "${perms}." != $(echo ${r} | awk '{print $1}') && \ + test "${perms}+" != $(echo ${r} | awk '{print $1}'); then + echo "ERROR: Permissions should be ${perms}" + exit 1 + fi +} + +file=test_chmod.$$ + +echo "foo" > ${file} +if test $? != 0; then + echo "ERROR: Failed to create file ${file}" + exit 1 +fi + +chmod 400 ${file} +if test $? != 0; then + echo "ERROR: Failed to change mode of ${file}" + exit 1 +fi + +check_perms ${file} "-r--------" + +set +e +echo "bar" >> ${file} +if test $? = 0; then + echo "ERROR: Write to read-only file should Fail" + exit 1 +fi + +set -e +chmod 600 ${file} +echo "bar" >> ${file} +if test $? != 0; then + echo "ERROR: Write to writeable file failed" + exit 1 +fi + +check_perms ${file} "-rw-------" + +echo "foo" >> ${file} +if test $? != 0; then + echo "ERROR: Failed to write to file" + exit 1 +fi diff --git a/qa/workunits/fs/misc/dac_override.sh b/qa/workunits/fs/misc/dac_override.sh new file mode 100755 index 000000000..dfb1a9091 --- /dev/null +++ b/qa/workunits/fs/misc/dac_override.sh @@ -0,0 +1,19 @@ +#!/bin/sh -x + +expect_failure() { + if "$@"; then return 1; else return 0; fi +} + +set -e + +mkdir -p testdir +file=test_chmod.$$ + +echo "foo" > testdir/${file} +sudo chmod 600 testdir + +# only root can read +expect_failure cat testdir/${file} + +# directory read/write DAC override for root should allow read +sudo cat testdir/${file} diff --git a/qa/workunits/fs/misc/direct_io.py b/qa/workunits/fs/misc/direct_io.py new file mode 100755 index 000000000..f7d59d95a --- /dev/null +++ b/qa/workunits/fs/misc/direct_io.py @@ -0,0 +1,42 @@ +#!/usr/bin/python3 + +import mmap +import os +import subprocess + +def main(): + path = "testfile" + fd = os.open(path, os.O_RDWR | os.O_CREAT | os.O_TRUNC | os.O_DIRECT, 0o644) + + ino = os.fstat(fd).st_ino + obj_name = "{ino:x}.00000000".format(ino=ino) + pool_name = os.getxattr(path, "ceph.file.layout.pool") + + buf = mmap.mmap(-1, 1) + buf.write(b'1') + os.write(fd, buf) + + proc = subprocess.Popen(['rados', '-p', pool_name, 'get', obj_name, 'tmpfile']) + proc.wait() + + with open('tmpfile', 'rb') as tmpf: + out = tmpf.read(1) + if out != b'1': + raise RuntimeError("data were not written to object store directly") + + with open('tmpfile', 'wb') as tmpf: + tmpf.write(b'2') + + proc = subprocess.Popen(['rados', '-p', pool_name, 'put', obj_name, 'tmpfile']) + proc.wait() + + os.lseek(fd, 0, os.SEEK_SET) + out = os.read(fd, 1) + if out != b'2': + raise RuntimeError("data were not directly read from object store") + + os.close(fd) + print('ok') + + +main() diff --git a/qa/workunits/fs/misc/dirfrag.sh b/qa/workunits/fs/misc/dirfrag.sh new file mode 100755 index 000000000..eea0ec3bc --- /dev/null +++ b/qa/workunits/fs/misc/dirfrag.sh @@ -0,0 +1,52 @@ +#!/usr/bin/env bash + +set -e + +DEPTH=5 +COUNT=10000 + +kill_jobs() { + jobs -p | xargs kill +} +trap kill_jobs INT + +create_files() { + for i in `seq 1 $COUNT` + do + touch file$i + done +} + +delete_files() { + for i in `ls -f` + do + if [[ ${i}a = file*a ]] + then + rm -f $i + fi + done +} + +rm -rf testdir +mkdir testdir +cd testdir + +echo "creating folder hierarchy" +for i in `seq 1 $DEPTH`; do + mkdir dir$i + cd dir$i + create_files & +done +wait + +echo "created hierarchy, now cleaning up" + +for i in `seq 1 $DEPTH`; do + delete_files & + cd .. +done +wait + +echo "cleaned up hierarchy" +cd .. +rm -rf testdir diff --git a/qa/workunits/fs/misc/filelock_deadlock.py b/qa/workunits/fs/misc/filelock_deadlock.py new file mode 100755 index 000000000..398902f6c --- /dev/null +++ b/qa/workunits/fs/misc/filelock_deadlock.py @@ -0,0 +1,72 @@ +#!/usr/bin/python3 + +import errno +import fcntl +import os +import signal +import struct +import time + + +def handler(signum, frame): + pass + + +def lock_two(f1, f2): + lockdata = struct.pack('hhllhh', fcntl.F_WRLCK, 0, 0, 10, 0, 0) + fcntl.fcntl(f1, fcntl.F_SETLKW, lockdata) + time.sleep(10) + + # don't wait forever + signal.signal(signal.SIGALRM, handler) + signal.alarm(10) + exitcode = 0 + try: + fcntl.fcntl(f2, fcntl.F_SETLKW, lockdata) + except IOError as e: + if e.errno == errno.EDEADLK: + exitcode = 1 + elif e.errno == errno.EINTR: + exitcode = 2 + else: + exitcode = 3 + os._exit(exitcode) + + +def main(): + pid1 = os.fork() + if pid1 == 0: + f1 = open("testfile1", 'w') + f2 = open("testfile2", 'w') + lock_two(f1, f2) + + pid2 = os.fork() + if pid2 == 0: + f1 = open("testfile2", 'w') + f2 = open("testfile3", 'w') + lock_two(f1, f2) + + pid3 = os.fork() + if pid3 == 0: + f1 = open("testfile3", 'w') + f2 = open("testfile1", 'w') + lock_two(f1, f2) + + deadlk_count = 0 + i = 0 + while i < 3: + pid, status = os.wait() + exitcode = status >> 8 + if exitcode == 1: + deadlk_count += 1 + elif exitcode != 0: + raise RuntimeError("unexpect exit code of child") + i += 1 + + if deadlk_count != 1: + raise RuntimeError("unexpect count of EDEADLK") + + print('ok') + + +main() diff --git a/qa/workunits/fs/misc/filelock_interrupt.py b/qa/workunits/fs/misc/filelock_interrupt.py new file mode 100755 index 000000000..b261d74fb --- /dev/null +++ b/qa/workunits/fs/misc/filelock_interrupt.py @@ -0,0 +1,94 @@ +#!/usr/bin/python3 + +from contextlib import contextmanager +import errno +import fcntl +import signal +import struct + +@contextmanager +def timeout(seconds): + def timeout_handler(signum, frame): + raise InterruptedError + + orig_handler = signal.signal(signal.SIGALRM, timeout_handler) + try: + signal.alarm(seconds) + yield + finally: + signal.alarm(0) + signal.signal(signal.SIGALRM, orig_handler) + + +""" +introduced by Linux 3.15 +""" +setattr(fcntl, "F_OFD_GETLK", 36) +setattr(fcntl, "F_OFD_SETLK", 37) +setattr(fcntl, "F_OFD_SETLKW", 38) + + +def main(): + f1 = open("testfile", 'w') + f2 = open("testfile", 'w') + + fcntl.flock(f1, fcntl.LOCK_SH | fcntl.LOCK_NB) + + """ + is flock interruptible? + """ + with timeout(5): + try: + fcntl.flock(f2, fcntl.LOCK_EX) + except InterruptedError: + pass + else: + raise RuntimeError("expect flock to block") + + fcntl.flock(f1, fcntl.LOCK_UN) + + lockdata = struct.pack('hhllhh', fcntl.F_WRLCK, 0, 0, 10, 0, 0) + try: + fcntl.fcntl(f1, fcntl.F_OFD_SETLK, lockdata) + except IOError as e: + if e.errno != errno.EINVAL: + raise + else: + print('kernel does not support fcntl.F_OFD_SETLK') + return + + lockdata = struct.pack('hhllhh', fcntl.F_WRLCK, 0, 10, 10, 0, 0) + fcntl.fcntl(f2, fcntl.F_OFD_SETLK, lockdata) + + """ + is posix lock interruptible? + """ + with timeout(5): + try: + lockdata = struct.pack('hhllhh', fcntl.F_WRLCK, 0, 0, 0, 0, 0) + fcntl.fcntl(f2, fcntl.F_OFD_SETLKW, lockdata) + except InterruptedError: + pass + else: + raise RuntimeError("expect posix lock to block") + + """ + file handler 2 should still hold lock on 10~10 + """ + try: + lockdata = struct.pack('hhllhh', fcntl.F_WRLCK, 0, 10, 10, 0, 0) + fcntl.fcntl(f1, fcntl.F_OFD_SETLK, lockdata) + except IOError as e: + if e.errno == errno.EAGAIN: + pass + else: + raise RuntimeError("expect file handler 2 to hold lock on 10~10") + + lockdata = struct.pack('hhllhh', fcntl.F_UNLCK, 0, 0, 0, 0, 0) + fcntl.fcntl(f1, fcntl.F_OFD_SETLK, lockdata) + fcntl.fcntl(f2, fcntl.F_OFD_SETLK, lockdata) + + print('ok') + + +main() diff --git a/qa/workunits/fs/misc/i_complete_vs_rename.sh b/qa/workunits/fs/misc/i_complete_vs_rename.sh new file mode 100755 index 000000000..a9b98271d --- /dev/null +++ b/qa/workunits/fs/misc/i_complete_vs_rename.sh @@ -0,0 +1,31 @@ +#!/bin/sh + +set -e + +mkdir x +cd x +touch a +touch b +touch c +touch d +ls +chmod 777 . +stat e || true +touch f +touch g + +# over existing file +echo attempting rename over existing file... +touch ../xx +mv ../xx f +ls | grep f || false +echo rename over existing file is okay + +# over negative dentry +echo attempting rename over negative dentry... +touch ../xx +mv ../xx e +ls | grep e || false +echo rename over negative dentry is ok + +echo OK diff --git a/qa/workunits/fs/misc/layout_vxattrs.sh b/qa/workunits/fs/misc/layout_vxattrs.sh new file mode 100755 index 000000000..811336273 --- /dev/null +++ b/qa/workunits/fs/misc/layout_vxattrs.sh @@ -0,0 +1,115 @@ +#!/usr/bin/env bash + +set -ex + +# detect data pool +datapool= +dir=. +while true ; do + echo $dir + datapool=$(getfattr -n ceph.dir.layout.pool $dir --only-values) && break + dir=$dir/.. +done + +# file +rm -f file file2 +touch file file2 + +getfattr -n ceph.file.layout file +getfattr -n ceph.file.layout file | grep -q object_size= +getfattr -n ceph.file.layout file | grep -q stripe_count= +getfattr -n ceph.file.layout file | grep -q stripe_unit= +getfattr -n ceph.file.layout file | grep -q pool= +getfattr -n ceph.file.layout.pool file +getfattr -n ceph.file.layout.pool_namespace file +getfattr -n ceph.file.layout.stripe_unit file +getfattr -n ceph.file.layout.stripe_count file +getfattr -n ceph.file.layout.object_size file + +getfattr -n ceph.file.layout.bogus file 2>&1 | grep -q 'No such attribute' +getfattr -n ceph.dir.layout file 2>&1 | grep -q 'No such attribute' + +setfattr -n ceph.file.layout.stripe_unit -v 1048576 file2 +setfattr -n ceph.file.layout.stripe_count -v 8 file2 +setfattr -n ceph.file.layout.object_size -v 10485760 file2 + +setfattr -n ceph.file.layout.pool -v $datapool file2 +getfattr -n ceph.file.layout.pool file2 | grep -q $datapool +setfattr -n ceph.file.layout.pool_namespace -v foons file2 +getfattr -n ceph.file.layout.pool_namespace file2 | grep -q foons +setfattr -x ceph.file.layout.pool_namespace file2 +getfattr -n ceph.file.layout.pool_namespace file2 | grep -q -v foons + +getfattr -n ceph.file.layout.stripe_unit file2 | grep -q 1048576 +getfattr -n ceph.file.layout.stripe_count file2 | grep -q 8 +getfattr -n ceph.file.layout.object_size file2 | grep -q 10485760 + +setfattr -n ceph.file.layout -v "stripe_unit=4194304 stripe_count=16 object_size=41943040 pool=$datapool pool_namespace=foons" file2 +getfattr -n ceph.file.layout.stripe_unit file2 | grep -q 4194304 +getfattr -n ceph.file.layout.stripe_count file2 | grep -q 16 +getfattr -n ceph.file.layout.object_size file2 | grep -q 41943040 +getfattr -n ceph.file.layout.pool file2 | grep -q $datapool +getfattr -n ceph.file.layout.pool_namespace file2 | grep -q foons + +setfattr -n ceph.file.layout -v "stripe_unit=1048576" file2 +getfattr -n ceph.file.layout.stripe_unit file2 | grep -q 1048576 +getfattr -n ceph.file.layout.stripe_count file2 | grep -q 16 +getfattr -n ceph.file.layout.object_size file2 | grep -q 41943040 +getfattr -n ceph.file.layout.pool file2 | grep -q $datapool +getfattr -n ceph.file.layout.pool_namespace file2 | grep -q foons + +setfattr -n ceph.file.layout -v "stripe_unit=2097152 stripe_count=4 object_size=2097152 pool=$datapool pool_namespace=barns" file2 +getfattr -n ceph.file.layout.stripe_unit file2 | grep -q 2097152 +getfattr -n ceph.file.layout.stripe_count file2 | grep -q 4 +getfattr -n ceph.file.layout.object_size file2 | grep -q 2097152 +getfattr -n ceph.file.layout.pool file2 | grep -q $datapool +getfattr -n ceph.file.layout.pool_namespace file2 | grep -q barns + +# dir +rm -f dir/file || true +rmdir dir || true +mkdir -p dir + +getfattr -d -m - dir | grep -q ceph.dir.layout && exit 1 || true +getfattr -d -m - dir | grep -q ceph.file.layout && exit 1 || true +getfattr -n ceph.dir.layout dir && exit 1 || true + +setfattr -n ceph.dir.layout.stripe_unit -v 1048576 dir +setfattr -n ceph.dir.layout.stripe_count -v 8 dir +setfattr -n ceph.dir.layout.object_size -v 10485760 dir +setfattr -n ceph.dir.layout.pool -v $datapool dir +setfattr -n ceph.dir.layout.pool_namespace -v dirns dir + +getfattr -n ceph.dir.layout dir +getfattr -n ceph.dir.layout dir | grep -q object_size=10485760 +getfattr -n ceph.dir.layout dir | grep -q stripe_count=8 +getfattr -n ceph.dir.layout dir | grep -q stripe_unit=1048576 +getfattr -n ceph.dir.layout dir | grep -q pool=$datapool +getfattr -n ceph.dir.layout dir | grep -q pool_namespace=dirns +getfattr -n ceph.dir.layout.pool dir | grep -q $datapool +getfattr -n ceph.dir.layout.stripe_unit dir | grep -q 1048576 +getfattr -n ceph.dir.layout.stripe_count dir | grep -q 8 +getfattr -n ceph.dir.layout.object_size dir | grep -q 10485760 +getfattr -n ceph.dir.layout.pool_namespace dir | grep -q dirns + + +setfattr -n ceph.file.layout -v "stripe_count=16" file2 +getfattr -n ceph.file.layout.stripe_count file2 | grep -q 16 +setfattr -n ceph.file.layout -v "object_size=10485760 stripe_count=8 stripe_unit=1048576 pool=$datapool pool_namespace=dirns" file2 +getfattr -n ceph.file.layout.stripe_count file2 | grep -q 8 + +touch dir/file +getfattr -n ceph.file.layout.pool dir/file | grep -q $datapool +getfattr -n ceph.file.layout.stripe_unit dir/file | grep -q 1048576 +getfattr -n ceph.file.layout.stripe_count dir/file | grep -q 8 +getfattr -n ceph.file.layout.object_size dir/file | grep -q 10485760 +getfattr -n ceph.file.layout.pool_namespace dir/file | grep -q dirns + +setfattr -x ceph.dir.layout.pool_namespace dir +getfattr -n ceph.dir.layout dir | grep -q -v pool_namespace=dirns + +setfattr -x ceph.dir.layout dir +getfattr -n ceph.dir.layout dir 2>&1 | grep -q 'No such attribute' + +echo OK + diff --git a/qa/workunits/fs/misc/mkpool_layout_vxattrs.sh b/qa/workunits/fs/misc/mkpool_layout_vxattrs.sh new file mode 100755 index 000000000..6b2fecbc0 --- /dev/null +++ b/qa/workunits/fs/misc/mkpool_layout_vxattrs.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash + +set -e + +touch foo.$$ +ceph osd pool create foo.$$ 8 +ceph fs add_data_pool cephfs foo.$$ +setfattr -n ceph.file.layout.pool -v foo.$$ foo.$$ + +# cleanup +rm foo.$$ +ceph fs rm_data_pool cephfs foo.$$ +ceph osd pool rm foo.$$ foo.$$ --yes-i-really-really-mean-it + +echo OK diff --git a/qa/workunits/fs/misc/multiple_rsync.sh b/qa/workunits/fs/misc/multiple_rsync.sh new file mode 100755 index 000000000..4397c1e7f --- /dev/null +++ b/qa/workunits/fs/misc/multiple_rsync.sh @@ -0,0 +1,25 @@ +#!/bin/sh -ex + + +# Populate with some arbitrary files from the local system. Take +# a copy to protect against false fails from system updates during test. +export PAYLOAD=/tmp/multiple_rsync_payload.$$ +sudo cp -r /usr/lib/ $PAYLOAD + +set -e + +sudo rsync -av $PAYLOAD payload.1 +sudo rsync -av $PAYLOAD payload.2 + +# this shouldn't transfer any additional files +echo we should get 4 here if no additional files are transferred +sudo rsync -auv $PAYLOAD payload.1 | tee /tmp/$$ +hexdump -C /tmp/$$ +wc -l /tmp/$$ | grep 4 +sudo rsync -auv $PAYLOAD payload.2 | tee /tmp/$$ +hexdump -C /tmp/$$ +wc -l /tmp/$$ | grep 4 +echo OK + +rm /tmp/$$ +sudo rm -rf $PAYLOAD diff --git a/qa/workunits/fs/misc/rstats.sh b/qa/workunits/fs/misc/rstats.sh new file mode 100755 index 000000000..e6b3eddf2 --- /dev/null +++ b/qa/workunits/fs/misc/rstats.sh @@ -0,0 +1,80 @@ +#!/usr/bin/env bash + +set -x + +timeout=30 +old_value="" +new_value="" + +wait_until_changed() { + name=$1 + wait=0 + while [ $wait -lt $timeout ]; do + new_value=`getfattr --only-value -n ceph.dir.$name .` + [ $new_value == $old_value ] || return 0 + sleep 1 + wait=$(($wait + 1)) + done + return 1 +} + +check_rctime() { + old_sec=$(echo $old_value | cut -d. -f1) + old_nsec=$(echo $old_value | cut -d. -f2) + new_sec=$(echo $new_value | cut -d. -f1) + new_nsec=$(echo $new_value | cut -d. -f2) + [ "$old_sec" -lt "$new_sec" ] && return 0 + [ "$old_sec" -gt "$new_sec" ] && return 1 + [ "$old_nsec" -lt "$new_nsec" ] && return 0 + return 1 +} + +# sync(3) does not make ceph-fuse flush dirty caps, because fuse kernel module +# does not notify ceph-fuse about it. Use fsync(3) instead. +fsync_path() { + cmd="import os; fd=os.open(\"$1\", os.O_RDONLY); os.fsync(fd); os.close(fd)" + python3 -c "$cmd" +} + +set -e + +mkdir -p rstats_testdir/d1/d2 +cd rstats_testdir + +# rfiles +old_value=`getfattr --only-value -n ceph.dir.rfiles .` +[ $old_value == 0 ] || false +touch d1/d2/f1 +wait_until_changed rfiles +[ $new_value == $(($old_value + 1)) ] || false + +# rsubdirs +old_value=`getfattr --only-value -n ceph.dir.rsubdirs .` +[ $old_value == 3 ] || false +mkdir d1/d2/d3 +wait_until_changed rsubdirs +[ $new_value == $(($old_value + 1)) ] || false + +# rbytes +old_value=`getfattr --only-value -n ceph.dir.rbytes .` +[ $old_value == 0 ] || false +echo hello > d1/d2/f2 +fsync_path d1/d2/f2 +wait_until_changed rbytes +[ $new_value == $(($old_value + 6)) ] || false + +#rctime +old_value=`getfattr --only-value -n ceph.dir.rctime .` +touch d1/d2/d3 # touch existing file +fsync_path d1/d2/d3 +wait_until_changed rctime +check_rctime + +old_value=`getfattr --only-value -n ceph.dir.rctime .` +touch d1/d2/f3 # create new file +wait_until_changed rctime +check_rctime + +cd .. +rm -rf rstats_testdir +echo OK diff --git a/qa/workunits/fs/misc/trivial_sync.sh b/qa/workunits/fs/misc/trivial_sync.sh new file mode 100755 index 000000000..7c8c4e2b4 --- /dev/null +++ b/qa/workunits/fs/misc/trivial_sync.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + +set -e + +mkdir foo +echo foo > bar +sync diff --git a/qa/workunits/fs/misc/xattrs.sh b/qa/workunits/fs/misc/xattrs.sh new file mode 100755 index 000000000..fcd94d22c --- /dev/null +++ b/qa/workunits/fs/misc/xattrs.sh @@ -0,0 +1,14 @@ +#!/bin/sh -x + +set -e + +touch file + +setfattr -n user.foo -v foo file +setfattr -n user.bar -v bar file +setfattr -n user.empty file +getfattr -d file | grep foo +getfattr -d file | grep bar +getfattr -d file | grep empty + +echo OK. diff --git a/qa/workunits/fs/multiclient_sync_read_eof.py b/qa/workunits/fs/multiclient_sync_read_eof.py new file mode 100755 index 000000000..15ecbb825 --- /dev/null +++ b/qa/workunits/fs/multiclient_sync_read_eof.py @@ -0,0 +1,42 @@ +#!/usr/bin/python3 + +import argparse +import os + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument('mnt1') + parser.add_argument('mnt2') + parser.add_argument('fn') + args = parser.parse_args() + + open(os.path.join(args.mnt1, args.fn), 'w') + f1 = open(os.path.join(args.mnt1, args.fn), 'r+') + f2 = open(os.path.join(args.mnt2, args.fn), 'r+') + + f1.write('foo') + f1.flush() + a = f2.read(3) + print('got "%s"' % a) + assert a == 'foo' + f2.write('bar') + f2.flush() + a = f1.read(3) + print('got "%s"' % a) + assert a == 'bar' + + ## test short reads + f1.write('short') + f1.flush() + a = f2.read(100) + print('got "%s"' % a) + assert a == 'short' + f2.write('longer') + f2.flush() + a = f1.read(1000) + print('got "%s"' % a) + assert a == 'longer' + + print('ok') + +main() diff --git a/qa/workunits/fs/norstats/kernel_untar_tar.sh b/qa/workunits/fs/norstats/kernel_untar_tar.sh new file mode 100755 index 000000000..6a175dcd9 --- /dev/null +++ b/qa/workunits/fs/norstats/kernel_untar_tar.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +# check if there is file changed while being archived + +set -e + +KERNEL=linux-4.0.5 + +wget -q http://download.ceph.com/qa/$KERNEL.tar.xz + +mkdir untar_tar +cd untar_tar + +tar Jxvf ../$KERNEL.tar.xz $KERNEL/Documentation/ +tar cf doc.tar $KERNEL + +tar xf doc.tar +sync +tar c $KERNEL >/dev/null + +rm -rf $KERNEL + +tar xf doc.tar +sync +tar c $KERNEL >/dev/null + +echo Ok diff --git a/qa/workunits/fs/quota/quota.sh b/qa/workunits/fs/quota/quota.sh new file mode 100755 index 000000000..1315be6d8 --- /dev/null +++ b/qa/workunits/fs/quota/quota.sh @@ -0,0 +1,128 @@ +#!/usr/bin/env bash + +set -ex + +function expect_false() +{ + set -x + if "$@"; then return 1; else return 0; fi +} + +function write_file() +{ + set +x + for ((i=1;i<=$2;i++)) + do + dd if=/dev/zero of=$1 bs=1M count=1 conv=notrunc oflag=append 2>/dev/null >/dev/null + if [ $? != 0 ]; then + echo Try to write $(($i * 1048576)) + set -x + return 1 + fi + sleep 0.05 + done + set -x + return 0 +} + +mkdir quota-test +cd quota-test + +# bytes +setfattr . -n ceph.quota.max_bytes -v 100000000 # 100m +expect_false write_file big 1000 # 1g +expect_false write_file second 10 +setfattr . -n ceph.quota.max_bytes -v 0 +dd if=/dev/zero of=third bs=1M count=10 +dd if=/dev/zero of=big2 bs=1M count=100 + + +rm -rf * + +# files +setfattr . -n ceph.quota.max_files -v 5 +mkdir ok +touch ok/1 +touch ok/2 +touch 3 +expect_false touch shouldbefail # 5 files will include the "." +expect_false touch ok/shouldbefail # 5 files will include the "." +setfattr . -n ceph.quota.max_files -v 0 +touch shouldbecreated +touch shouldbecreated2 + + +rm -rf * + +# mix +mkdir bytes bytes/files + +setfattr bytes -n ceph.quota.max_bytes -v 10000000 #10m +setfattr bytes/files -n ceph.quota.max_files -v 5 +dd if=/dev/zero of=bytes/files/1 bs=1M count=4 +dd if=/dev/zero of=bytes/files/2 bs=1M count=4 +expect_false write_file bytes/files/3 1000 +expect_false write_file bytes/files/4 1000 +expect_false write_file bytes/files/5 1000 +stat --printf="%n %s\n" bytes/files/1 #4M +stat --printf="%n %s\n" bytes/files/2 #4M +stat --printf="%n %s\n" bytes/files/3 #bigger than 2M +stat --printf="%n %s\n" bytes/files/4 #should be zero +expect_false stat bytes/files/5 #shouldn't be exist + + + + +rm -rf * + +#mv +mkdir files limit +truncate files/file -s 10G +setfattr limit -n ceph.quota.max_bytes -v 1000000 #1m +expect_false mv files limit/ + + + +rm -rf * + +#limit by ancestor + +mkdir -p ancestor/p1/p2/parent/p3 +setfattr ancestor -n ceph.quota.max_bytes -v 1000000 +setfattr ancestor/p1/p2/parent -n ceph.quota.max_bytes -v 1000000000 #1g +expect_false write_file ancestor/p1/p2/parent/p3/file1 900 #900m +stat --printf="%n %s\n" ancestor/p1/p2/parent/p3/file1 + + +#get/set attribute + +setfattr -n ceph.quota.max_bytes -v 0 . +setfattr -n ceph.quota.max_bytes -v 1 . +setfattr -n ceph.quota.max_bytes -v 9223372036854775807 . +expect_false setfattr -n ceph.quota.max_bytes -v 9223372036854775808 . +expect_false setfattr -n ceph.quota.max_bytes -v -1 . +expect_false setfattr -n ceph.quota.max_bytes -v -9223372036854775808 . +expect_false setfattr -n ceph.quota.max_bytes -v -9223372036854775809 . + +setfattr -n ceph.quota.max_files -v 0 . +setfattr -n ceph.quota.max_files -v 1 . +setfattr -n ceph.quota.max_files -v 9223372036854775807 . +expect_false setfattr -n ceph.quota.max_files -v 9223372036854775808 . +expect_false setfattr -n ceph.quota.max_files -v -1 . +expect_false setfattr -n ceph.quota.max_files -v -9223372036854775808 . +expect_false setfattr -n ceph.quota.max_files -v -9223372036854775809 . + +setfattr -n ceph.quota -v "max_bytes=0 max_files=0" . +setfattr -n ceph.quota -v "max_bytes=1 max_files=0" . +setfattr -n ceph.quota -v "max_bytes=0 max_files=1" . +setfattr -n ceph.quota -v "max_bytes=1 max_files=1" . +expect_false setfattr -n ceph.quota -v "max_bytes=-1 max_files=0" . +expect_false setfattr -n ceph.quota -v "max_bytes=0 max_files=-1" . +expect_false setfattr -n ceph.quota -v "max_bytes=-1 max_files=-1" . + +#addme + +cd .. +rm -rf quota-test + +echo OK diff --git a/qa/workunits/fs/snap-hierarchy.sh b/qa/workunits/fs/snap-hierarchy.sh new file mode 100755 index 000000000..67f0e014b --- /dev/null +++ b/qa/workunits/fs/snap-hierarchy.sh @@ -0,0 +1,24 @@ +#!/bin/sh + +set -ex + +if [ -d "$1" ]; then + mkdir -p -- "$1" && cd "$1" +fi + +[ "$VERIFY" != verify ] && mkdir 1 +[ "$VERIFY" != verify ] && mkdir 1/.snap/first +stat 1/.snap/first +[ "$VERIFY" != verify ] && mkdir 1/2 +stat 1/.snap/first/2 && exit 1 +[ "$VERIFY" != verify ] && mkdir 1/2/.snap/second +stat 1/2/.snap/second +[ "$VERIFY" != verify ] && touch 1/foo +stat 1/.snap/first/foo && exit 1 +[ "$VERIFY" != verify ] && mkdir 1/.snap/third +stat 1/.snap/third/foo || exit 1 +[ "$VERIFY" != verify ] && mkdir 1/2/3 +[ "$VERIFY" != verify ] && mkdir 1/2/.snap/fourth +stat 1/2/.snap/fourth/3 + +exit 0 diff --git a/qa/workunits/fs/snaps/snap-rm-diff.sh b/qa/workunits/fs/snaps/snap-rm-diff.sh new file mode 100755 index 000000000..30ffa9113 --- /dev/null +++ b/qa/workunits/fs/snaps/snap-rm-diff.sh @@ -0,0 +1,10 @@ +#!/bin/sh -ex + +wget -q http://download.ceph.com/qa/linux-2.6.33.tar.bz2 +mkdir foo +cp linux* foo +mkdir foo/.snap/barsnap +rm foo/linux* +diff -q foo/.snap/barsnap/linux* linux* && echo "passed: files are identical" +rmdir foo/.snap/barsnap +echo OK diff --git a/qa/workunits/fs/snaps/snaptest-1.sh b/qa/workunits/fs/snaps/snaptest-1.sh new file mode 100755 index 000000000..431e83387 --- /dev/null +++ b/qa/workunits/fs/snaps/snaptest-1.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash + +set -ex + +echo 1 > file1 +echo 2 > file2 +echo 3 > file3 +[ -e file4 ] && rm file4 +mkdir .snap/snap1 +echo 4 > file4 +now=`ls` +then=`ls .snap/snap1` +rmdir .snap/snap1 +if [ "$now" = "$then" ]; then + echo live and snap contents are identical? + false +fi + +# do it again +echo 1 > file1 +echo 2 > file2 +echo 3 > file3 +mkdir .snap/snap1 +echo 4 > file4 +rmdir .snap/snap1 + +rm file? + +echo OK diff --git a/qa/workunits/fs/snaps/snaptest-2.sh b/qa/workunits/fs/snaps/snaptest-2.sh new file mode 100755 index 000000000..11fe9316a --- /dev/null +++ b/qa/workunits/fs/snaps/snaptest-2.sh @@ -0,0 +1,59 @@ +#!/usr/bin/env bash + +echo "Create dir 100 to 199 ..." +for i in $(seq 100 199); do + echo " create dir $i" + mkdir "$i" + for y in $(seq 10 20); do + echo "This is a test file before any snapshot was taken." >"$i/$y" + done +done + +echo "Take first snapshot .snap/test1" +mkdir .snap/test1 + +echo "Create dir 200 to 299 ..." +for i in $(seq 200 299); do + echo " create dir $i" + mkdir $i + for y in $(seq 20 29); do + echo "This is a test file. Created after .snap/test1" >"$i/$y" + done +done + +echo "Create a snapshot in every first level dir ..." +for dir in $(ls); do + echo " create $dir/.snap/snap-subdir-test" + mkdir "$dir/.snap/snap-subdir-test" + for y in $(seq 30 39); do + echo " create $dir/$y file after the snapshot" + echo "This is a test file. Created after $dir/.snap/snap-subdir-test" >"$dir/$y" + done +done + +echo "Take second snapshot .snap/test2" +mkdir .snap/test2 + +echo "Copy content of .snap/test1 to copyofsnap1 ..." +mkdir copyofsnap1 +cp -Rv .snap/test1 copyofsnap1/ + + +echo "Take third snapshot .snap/test3" +mkdir .snap/test3 + +echo "Delete the snapshots..." + +find ./ -type d -print | \ + xargs -I% -n1 find %/.snap -mindepth 1 -maxdepth 1 \ + \( ! -name "_*" \) -print 2>/dev/null + +find ./ -type d -print | \ + xargs -I% -n1 find %/.snap -mindepth 1 -maxdepth 1 \ + \( ! -name "_*" \) -print 2>/dev/null | \ + xargs -n1 rmdir + +echo "Delete all the files and directories ..." +rm -Rfv ./* + +echo OK diff --git a/qa/workunits/fs/snaps/snaptest-authwb.sh b/qa/workunits/fs/snaps/snaptest-authwb.sh new file mode 100755 index 000000000..965ee8512 --- /dev/null +++ b/qa/workunits/fs/snaps/snaptest-authwb.sh @@ -0,0 +1,12 @@ +#!/bin/sh -x + +set -e + +touch foo +chmod +x foo +mkdir .snap/s +find .snap/s/foo -executable | grep foo +rmdir .snap/s +rm foo + +echo OK diff --git a/qa/workunits/fs/snaps/snaptest-capwb.sh b/qa/workunits/fs/snaps/snaptest-capwb.sh new file mode 100755 index 000000000..d26f324b6 --- /dev/null +++ b/qa/workunits/fs/snaps/snaptest-capwb.sh @@ -0,0 +1,33 @@ +#!/bin/sh -x + +set -e + +mkdir foo + +# make sure mds handles it when the client does not send flushsnap +echo x > foo/x +sync +mkdir foo/.snap/ss +ln foo/x foo/xx +cat foo/.snap/ss/x +rmdir foo/.snap/ss + +# +echo a > foo/a +echo b > foo/b +mkdir foo/.snap/s +r=`cat foo/.snap/s/a` +[ -z "$r" ] && echo "a appears empty in snapshot" && false + +ln foo/b foo/b2 +cat foo/.snap/s/b + +echo "this used to hang:" +echo more >> foo/b2 +echo "oh, it didn't hang! good job." +cat foo/b +rmdir foo/.snap/s + +rm -r foo + +echo OK diff --git a/qa/workunits/fs/snaps/snaptest-dir-rename.sh b/qa/workunits/fs/snaps/snaptest-dir-rename.sh new file mode 100755 index 000000000..3bbd9a11e --- /dev/null +++ b/qa/workunits/fs/snaps/snaptest-dir-rename.sh @@ -0,0 +1,17 @@ +#!/bin/sh -x + +set -e + +# +# make sure we keep an existing dn's seq +# + +mkdir a +mkdir .snap/bar +mkdir a/.snap/foo +rmdir a/.snap/foo +rmdir a +stat .snap/bar/a +rmdir .snap/bar + +echo OK diff --git a/qa/workunits/fs/snaps/snaptest-double-null.sh b/qa/workunits/fs/snaps/snaptest-double-null.sh new file mode 100755 index 000000000..cdf32e4f0 --- /dev/null +++ b/qa/workunits/fs/snaps/snaptest-double-null.sh @@ -0,0 +1,23 @@ +#!/bin/sh -x + +set -e + +# multiple intervening snapshots with no modifications, and thus no +# snapflush client_caps messages. make sure the mds can handle this. + +for f in `seq 1 20` ; do + +mkdir a +cat > a/foo & +mkdir a/.snap/one +mkdir a/.snap/two +chmod 777 a/foo +sync # this might crash the mds +ps +rmdir a/.snap/* +rm a/foo +rmdir a + +done + +echo OK diff --git a/qa/workunits/fs/snaps/snaptest-estale.sh b/qa/workunits/fs/snaps/snaptest-estale.sh new file mode 100755 index 000000000..a4fb94368 --- /dev/null +++ b/qa/workunits/fs/snaps/snaptest-estale.sh @@ -0,0 +1,13 @@ +#!/bin/sh -x + +mkdir .snap/foo + +echo "We want ENOENT, not ESTALE, here." +for f in `seq 1 100` +do + stat .snap/foo/$f 2>&1 | grep 'No such file' +done + +rmdir .snap/foo + +echo "OK" diff --git a/qa/workunits/fs/snaps/snaptest-git-ceph.sh b/qa/workunits/fs/snaps/snaptest-git-ceph.sh new file mode 100755 index 000000000..12c1f0fdc --- /dev/null +++ b/qa/workunits/fs/snaps/snaptest-git-ceph.sh @@ -0,0 +1,52 @@ +#!/bin/sh -x + +set -e + +# try it again if the clone is slow and the second time +retried=false +trap -- 'retry' EXIT +retry() { + rm -rf ceph + # double the timeout value + timeout 3600 git clone https://git.ceph.com/ceph.git +} +rm -rf ceph +timeout 1800 git clone https://git.ceph.com/ceph.git +trap - EXIT +cd ceph + +versions=`seq 1 90` + +for v in $versions +do + if [ $v -eq 48 ]; then + continue + fi + ver="v0.$v" + echo $ver + git reset --hard $ver + mkdir .snap/$ver +done + +for v in $versions +do + if [ $v -eq 48 ]; then + continue + fi + ver="v0.$v" + echo checking $ver + cd .snap/$ver + git diff --exit-code + cd ../.. +done + +for v in $versions +do + if [ $v -eq 48 ]; then + continue + fi + ver="v0.$v" + rmdir .snap/$ver +done + +echo OK diff --git a/qa/workunits/fs/snaps/snaptest-hardlink.sh b/qa/workunits/fs/snaps/snaptest-hardlink.sh new file mode 100755 index 000000000..90f3583b1 --- /dev/null +++ b/qa/workunits/fs/snaps/snaptest-hardlink.sh @@ -0,0 +1,25 @@ +#!/bin/sh -x + +set -e + +mkdir 1 2 +echo asdf >1/file1 +echo asdf >1/file2 + +ln 1/file1 2/file1 +ln 1/file2 2/file2 + +mkdir 2/.snap/s1 + +echo qwer >1/file1 +grep asdf 2/.snap/s1/file1 + +rm -f 1/file2 +grep asdf 2/.snap/s1/file2 +rm -f 2/file2 +grep asdf 2/.snap/s1/file2 + +rmdir 2/.snap/s1 +rm -rf 1 2 + +echo OK diff --git a/qa/workunits/fs/snaps/snaptest-intodir.sh b/qa/workunits/fs/snaps/snaptest-intodir.sh new file mode 100755 index 000000000..d6a220f73 --- /dev/null +++ b/qa/workunits/fs/snaps/snaptest-intodir.sh @@ -0,0 +1,22 @@ +#!/bin/sh -ex + +# this tests fix for #1399 +mkdir foo +mkdir foo/.snap/one +touch bar +mv bar foo +sync +# should not crash :) + +mkdir baz +mkdir baz/.snap/two +mv baz foo +sync +# should not crash :) + +# clean up. +rmdir foo/baz/.snap/two +rmdir foo/.snap/one +rm -r foo + +echo OK diff --git a/qa/workunits/fs/snaps/snaptest-multiple-capsnaps.sh b/qa/workunits/fs/snaps/snaptest-multiple-capsnaps.sh new file mode 100755 index 000000000..5ebc852cf --- /dev/null +++ b/qa/workunits/fs/snaps/snaptest-multiple-capsnaps.sh @@ -0,0 +1,42 @@ +#!/bin/sh -x + +set -e + +echo asdf > a +mkdir .snap/1 +chmod 777 a +mkdir .snap/2 +echo qwer > a +mkdir .snap/3 +chmod 666 a +mkdir .snap/4 +echo zxcv > a +mkdir .snap/5 + +ls -al .snap/?/a + +grep asdf .snap/1/a +stat .snap/1/a | grep 'Size: 5' + +grep asdf .snap/2/a +stat .snap/2/a | grep 'Size: 5' +stat .snap/2/a | grep -- '-rwxrwxrwx' + +grep qwer .snap/3/a +stat .snap/3/a | grep 'Size: 5' +stat .snap/3/a | grep -- '-rwxrwxrwx' + +grep qwer .snap/4/a +stat .snap/4/a | grep 'Size: 5' +stat .snap/4/a | grep -- '-rw-rw-rw-' + +grep zxcv .snap/5/a +stat .snap/5/a | grep 'Size: 5' +stat .snap/5/a | grep -- '-rw-rw-rw-' + +rmdir .snap/[12345] + +echo "OK" + + + diff --git a/qa/workunits/fs/snaps/snaptest-name-limits.sh b/qa/workunits/fs/snaps/snaptest-name-limits.sh new file mode 100755 index 000000000..f40d0231e --- /dev/null +++ b/qa/workunits/fs/snaps/snaptest-name-limits.sh @@ -0,0 +1,27 @@ +#!/bin/bash +# +# This tests snapshot names limits: names have to be < 240 chars +# + +function cleanup () +{ + rmdir d1/.snap/* + rm -rf d1 +} + +function fail () +{ + echo $@ + cleanup + exit 1 +} + +mkdir d1 + +longname=$(printf "%.241d" 2) +mkdir d1/.snap/$longname 2> /dev/null +[ -d d1/.snap/$longname ] && fail "Invalid snapshot exists: $longname" + +cleanup + +echo OK diff --git a/qa/workunits/fs/snaps/snaptest-parents.sh b/qa/workunits/fs/snaps/snaptest-parents.sh new file mode 100755 index 000000000..7ab1ba7cf --- /dev/null +++ b/qa/workunits/fs/snaps/snaptest-parents.sh @@ -0,0 +1,39 @@ +#!/bin/sh + +set -e + +echo "making directory tree and files" +mkdir -p 1/a/b/c/ +echo "i'm file1" > 1/a/file1 +echo "i'm file2" > 1/a/b/file2 +echo "i'm file3" > 1/a/b/c/file3 +echo "snapshotting" +mkdir 1/.snap/foosnap1 +mkdir 2 +echo "moving tree" +mv 1/a 2 +echo "checking snapshot contains tree..." +dir1=`find 1/.snap/foosnap1 | wc -w` +dir2=`find 2/ | wc -w` +#diff $dir1 $dir2 && echo "Success!" +test $dir1==$dir2 && echo "Success!" +echo "adding folder and file to tree..." +mkdir 2/a/b/c/d +echo "i'm file 4!" > 2/a/b/c/d/file4 +echo "snapshotting tree 2" +mkdir 2/.snap/barsnap2 +echo "comparing snapshots" +dir1=`find 1/.snap/foosnap1/ -maxdepth 2 | wc -w` +dir2=`find 2/.snap/barsnap2/ -maxdepth 2 | wc -w` +#diff $dir1 $dir2 && echo "Success!" +test $dir1==$dir2 && echo "Success!" +echo "moving subtree to first folder" +mv 2/a/b/c 1 +echo "comparing snapshots and new tree" +dir1=`find 1/ | wc -w` +dir2=`find 2/.snap/barsnap2/a/b/c | wc -w` +#diff $dir1 $dir2 && echo "Success!" +test $dir1==$dir2 && echo "Success!" +rmdir 1/.snap/* +rmdir 2/.snap/* +echo "OK" diff --git a/qa/workunits/fs/snaps/snaptest-realm-split.sh b/qa/workunits/fs/snaps/snaptest-realm-split.sh new file mode 100755 index 000000000..300cca21d --- /dev/null +++ b/qa/workunits/fs/snaps/snaptest-realm-split.sh @@ -0,0 +1,31 @@ +#!/bin/sh -x + +set -e + +mkdir -p 1/a +exec 3<> 1/a/file1 + +echo -n a >&3 + +mkdir 1/.snap/s1 + +echo -n b >&3 + +mkdir 2 +# create new snaprealm at dir a, file1's cap should be attached to the new snaprealm +mv 1/a 2 + +mkdir 2/.snap/s2 + +echo -n c >&3 + +exec 3>&- + +grep '^a$' 1/.snap/s1/a/file1 +grep '^ab$' 2/.snap/s2/a/file1 +grep '^abc$' 2/a/file1 + +rmdir 1/.snap/s1 +rmdir 2/.snap/s2 +rm -rf 1 2 +echo OK diff --git a/qa/workunits/fs/snaps/snaptest-snap-rename.sh b/qa/workunits/fs/snaps/snaptest-snap-rename.sh new file mode 100755 index 000000000..aa7325b92 --- /dev/null +++ b/qa/workunits/fs/snaps/snaptest-snap-rename.sh @@ -0,0 +1,33 @@ +#!/bin/sh -x + +expect_failure() { + if "$@"; then return 1; else return 0; fi +} +set -e + +mkdir -p d1/d2 +mkdir -p d1/d3 +mkdir d1/.snap/foo +mkdir d1/d2/.snap/foo +mkdir d1/d3/.snap/foo +mkdir d1/d3/.snap/bar +mv d1/d2/.snap/foo d1/d2/.snap/bar +# snapshot name can't start with _ +expect_failure mv d1/d2/.snap/bar d1/d2/.snap/_bar +# can't rename parent snapshot +expect_failure mv d1/d2/.snap/_foo_* d1/d2/.snap/foo +expect_failure mv d1/d2/.snap/_foo_* d1/d2/.snap/_foo_1 +# can't rename snapshot to different directroy +expect_failure mv d1/d2/.snap/bar d1/.snap/ +# can't overwrite existing snapshot +expect_failure python3 -c "import os; os.rename('d1/d3/.snap/foo', 'd1/d3/.snap/bar')" +# can't move snaphost out of snapdir +expect_failure python3 -c "import os; os.rename('d1/.snap/foo', 'd1/foo')" + +rmdir d1/.snap/foo +rmdir d1/d2/.snap/bar +rmdir d1/d3/.snap/foo +rmdir d1/d3/.snap/bar +rm -rf d1 + +echo OK diff --git a/qa/workunits/fs/snaps/snaptest-snap-rm-cmp.sh b/qa/workunits/fs/snaps/snaptest-snap-rm-cmp.sh new file mode 100755 index 000000000..88a0e8ae5 --- /dev/null +++ b/qa/workunits/fs/snaps/snaptest-snap-rm-cmp.sh @@ -0,0 +1,24 @@ +#!/bin/sh -x + +set -e + +file=linux-2.6.33.tar.bz2 +wget -q http://download.ceph.com/qa/$file + +real=`md5sum $file | awk '{print $1}'` + +for f in `seq 1 20` +do + echo $f + cp $file a + mkdir .snap/s + rm a + cp .snap/s/a /tmp/a + cur=`md5sum /tmp/a | awk '{print $1}'` + if [ "$cur" != "$real" ]; then + echo "FAIL: bad match, /tmp/a $cur != real $real" + false + fi + rmdir .snap/s +done +rm $file diff --git a/qa/workunits/fs/snaps/snaptest-upchildrealms.sh b/qa/workunits/fs/snaps/snaptest-upchildrealms.sh new file mode 100755 index 000000000..4e531a966 --- /dev/null +++ b/qa/workunits/fs/snaps/snaptest-upchildrealms.sh @@ -0,0 +1,28 @@ +#!/bin/sh -x + +set -e + +# +# verify that a snap update on a parent realm will induce +# snap cap writeback for inodes child realms +# + +mkdir a +mkdir a/b +mkdir a/.snap/a1 +mkdir a/b/.snap/b1 +echo asdf > a/b/foo +mkdir a/.snap/a2 +# client _should_ have just queued a capsnap for writeback +ln a/b/foo a/b/bar # make the server cow the inode + +echo "this should not hang..." +cat a/b/.snap/_a2_*/foo +echo "good, it did not hang." + +rmdir a/b/.snap/b1 +rmdir a/.snap/a1 +rmdir a/.snap/a2 +rm -r a + +echo "OK" diff --git a/qa/workunits/fs/snaps/snaptest-xattrwb.sh b/qa/workunits/fs/snaps/snaptest-xattrwb.sh new file mode 100755 index 000000000..e503aed77 --- /dev/null +++ b/qa/workunits/fs/snaps/snaptest-xattrwb.sh @@ -0,0 +1,29 @@ +#!/bin/sh -x + +set -e + +echo "testing simple xattr wb" +touch x +setfattr -n user.foo x +mkdir .snap/s1 +getfattr -n user.foo .snap/s1/x | grep user.foo +rm x +rmdir .snap/s1 + +echo "testing wb with pre-wb server cow" +mkdir a +mkdir a/b +mkdir a/b/c +# b now has As but not Ax +setfattr -n user.foo a/b +mkdir a/.snap/s +mkdir a/b/cc +# b now has been cowed on the server, but we still have dirty xattr caps +getfattr -n user.foo a/b # there they are... +getfattr -n user.foo a/.snap/s/b | grep user.foo # should be there, too! + +# ok, clean up +rmdir a/.snap/s +rm -r a + +echo OK diff --git a/qa/workunits/fs/snaps/untar_snap_rm.sh b/qa/workunits/fs/snaps/untar_snap_rm.sh new file mode 100755 index 000000000..8a8412e66 --- /dev/null +++ b/qa/workunits/fs/snaps/untar_snap_rm.sh @@ -0,0 +1,18 @@ +#!/bin/sh + +set -e + +do_tarball() { + wget http://download.ceph.com/qa/$1 + tar xvf$2 $1 + mkdir .snap/k + sync + rm -rv $3 + cp -av .snap/k . + rmdir .snap/k + rm -rv k + rm $1 +} + +do_tarball coreutils_8.5.orig.tar.gz z coreutils-8.5 +do_tarball linux-2.6.33.tar.bz2 j linux-2.6.33 diff --git a/qa/workunits/fs/test_o_trunc.c b/qa/workunits/fs/test_o_trunc.c new file mode 100644 index 000000000..1ce19e4bb --- /dev/null +++ b/qa/workunits/fs/test_o_trunc.c @@ -0,0 +1,45 @@ +#include +#include +#include +#include +#include +#include +#include + +int main(int argc, char *argv[]) +{ + char obuf[32], ibuf[1024]; + int n, max = 0; + + if (argc > 2) + max = atoi(argv[2]); + if (!max) + max = 600; + + memset(obuf, 0xff, sizeof(obuf)); + + for (n = 1; n <= max; ++n) { + int fd, ret; + fd = open(argv[1], O_RDWR | O_CREAT | O_TRUNC, 0644); + printf("%d/%d: open fd = %d\n", n, max, fd); + + ret = write(fd, obuf, sizeof(obuf)); + printf("write ret = %d\n", ret); + + sleep(1); + + ret = write(fd, obuf, sizeof(obuf)); + printf("write ret = %d\n", ret); + + ret = pread(fd, ibuf, sizeof(ibuf), 0); + printf("pread ret = %d\n", ret); + + if (memcmp(obuf, ibuf, sizeof(obuf))) { + printf("mismatch\n"); + close(fd); + break; + } + close(fd); + } + return 0; +} diff --git a/qa/workunits/fs/test_o_trunc.sh b/qa/workunits/fs/test_o_trunc.sh new file mode 100755 index 000000000..90a72600d --- /dev/null +++ b/qa/workunits/fs/test_o_trunc.sh @@ -0,0 +1,7 @@ +#!/bin/sh -ex + +mydir=`dirname $0` +$mydir/test_o_trunc trunc.foo 600 + +echo OK + diff --git a/qa/workunits/fs/test_python.sh b/qa/workunits/fs/test_python.sh new file mode 100755 index 000000000..6e39b95a4 --- /dev/null +++ b/qa/workunits/fs/test_python.sh @@ -0,0 +1,6 @@ +#!/bin/sh -ex + +# Running as root because the filesystem root directory will be +# owned by uid 0, and that's where we're writing. +sudo python3 -m pytest -v $(dirname $0)/../../../src/test/pybind/test_cephfs.py +exit 0 -- cgit v1.2.3