X-Git-Url: https://git.whamcloud.com/?p=fs%2Flustre-release.git;a=blobdiff_plain;f=lustre%2Ftests%2Fsanity-quota.sh;h=b38f191d5656059f926265f877a24bfe7ee65376;hp=a65daccbcfce7c66bf8b2e48f4910d0af55b760b;hb=4e41ef7e1632e2223d4b8cb7ee3f02d424d713ff;hpb=5c033757a9a36b83bf891715e683ed06a4bded8e diff --git a/lustre/tests/sanity-quota.sh b/lustre/tests/sanity-quota.sh index a65dacc..b38f191 100755 --- a/lustre/tests/sanity-quota.sh +++ b/lustre/tests/sanity-quota.sh @@ -13,14 +13,14 @@ init_test_env $@ init_logging ALWAYS_EXCEPT="$SANITY_QUOTA_EXCEPT " -# Bug number for skipped test: LU-5152 -ALWAYS_EXCEPT+=" 55" +# Bug number for skipped test: +ALWAYS_EXCEPT+="" # UPDATE THE COMMENT ABOVE WITH BUG NUMBERS WHEN CHANGING ALWAYS_EXCEPT! # Test duration: 30 min [ "$SLOW" = "no" ] && EXCEPT_SLOW="61" -if [ $(facet_fstype $SINGLEMDS) = "zfs" ]; then +if [ "$mds1_FSTYPE" = zfs ]; then # bug number: LU-2887 # Test duration: 21 9 min" [ "$SLOW" = "no" ] && EXCEPT_SLOW+=" 12a 9" @@ -39,15 +39,20 @@ BLK_SZ=1024 MAX_DQ_TIME=604800 MAX_IQ_TIME=604800 QTYPE="ugp" +VERSION_WITH_QP="2.13.53" +mds_supports_qp() { + [ $MDS1_VERSION -lt $(version_code $VERSION_WITH_QP) ] && + skip "Needs MDS version $VERSION_WITH_QP or later." +} require_dsh_mds || exit 0 require_dsh_ost || exit 0 # Does e2fsprogs support quota feature? -if [ $(facet_fstype $SINGLEMDS) == ldiskfs ] && +if [ "$mds1_FSTYPE" == ldiskfs ] && do_facet $SINGLEMDS "! $DEBUGFS -c -R supported_features | grep -q 'quota'"; then - skip_env "e2fsprogs doesn't support quota" && exit 0 + skip_env "e2fsprogs doesn't support quota" fi QUOTALOG=${TESTSUITELOG:-$TMP/$(basename $0 .sh).log} @@ -123,24 +128,29 @@ resetquota() { quota_scan() { local local_ugp=$1 local local_id=$2 + local count if [ "$local_ugp" == "a" -o "$local_ugp" == "u" ]; then $LFS quota -v -u $local_id $DIR - log "Files for user ($local_id):" + count=$($LFS find --user $local_id $DIR | wc -l) + log "Files for user ($local_id), count=$count:" ($LFS find --user $local_id $DIR | head -n 4 | xargs stat 2>/dev/null) fi if [ "$local_ugp" == "a" -o "$local_ugp" == "g" ]; then $LFS quota -v -g $local_id $DIR - log "Files for group ($local_id):" + count=$($LFS find --group $local_id $DIR | wc -l) + log "Files for group ($local_id), count=$count:" ($LFS find --group $local_id $DIR | head -n 4 | xargs stat 2>/dev/null) fi + is_project_quota_supported || return 0 if [ "$local_ugp" == "a" -o "$local_ugp" == "p" ]; then $LFS quota -v -p $TSTPRJID $DIR - log "Files for project ($TSTPRJID):" + count=$($LFS find --projid $TSTPRJID $DIR | wc -l) + log "Files for project ($TSTPRJID), count=$count:" ($LFS find --projid $TSTPRJID $DIR | head -n 4 | xargs stat 2>/dev/null) fi @@ -160,14 +170,17 @@ quota_log() { # get quota for a user or a group # usage: getquota -u|-g|-p || global| \ -# bhardlimit|bsoftlimit|bgrace|ihardlimit|isoftlimit|igrace +# bhardlimit|bsoftlimit|bgrace|ihardlimit|isoftlimit|igrace \ +# getquota() { local spec local uuid + local pool_arg sync_all_data > /dev/null 2>&1 || true - [ "$#" != 4 ] && error "getquota: wrong number of arguments: $#" + [ "$#" != 4 -a "$#" != 5 ] && + error "getquota: wrong number of arguments: $#" [ "$1" != "-u" -a "$1" != "-g" -a "$1" != "-p" ] && error "getquota: wrong u/g/p specifier $1 passed" @@ -185,9 +198,10 @@ getquota() { *) error "unknown quota parameter $4";; esac + [ ! -z "$5" ] && pool_arg="--pool $5 " [ "$uuid" = "global" ] && uuid=$DIR - $LFS quota -v "$1" "$2" $DIR | + $LFS quota -v "$1" "$2" $pool_arg $DIR | awk 'BEGIN { num='$spec' } { if ($1 == "'$uuid'") \ { if (NF == 1) { getline } else { num++ } ; print $num;} }' \ | tr -d "*" @@ -205,7 +219,7 @@ set_mdt_qtype() { if [[ $PERM_CMD == *"set_param -P"* ]]; then do_facet mgs $PERM_CMD \ - osd-*.$FSNAME-MDT*.quota_slave.enable=$qtype + osd-*.$FSNAME-MDT*.quota_slave.enabled=$qtype else do_facet mgs $PERM_CMD $FSNAME.quota.mdt=$qtype fi @@ -235,7 +249,7 @@ set_ost_qtype() { if [[ $PERM_CMD == *"set_param -P"* ]]; then do_facet mgs $PERM_CMD \ - osd-*.$FSNAME-OST*.quota_slave.enable=$qtype + osd-*.$FSNAME-OST*.quota_slave.enabled=$qtype else do_facet mgs $PERM_CMD $FSNAME.quota.ost=$qtype fi @@ -324,8 +338,10 @@ wait_ost_reint() { wait_grace_time() { local qtype=$1 local flavour=$2 - local extrasleep=${3:-5} + local pool=${3:-} + local extrasleep=${4:-5} local qarg + local parg case $qtype in u|g) qarg=$TSTUSR ;; @@ -333,46 +349,75 @@ wait_grace_time() { *) error "get_grace_time: Invalid quota type: $qtype" esac + if [ $pool ]; then + parg="--pool "$pool + echo "Quota info for $pool:" + $LFS quota -$qtype $qarg $parg $DIR + fi + case $flavour in block) - time=$(lfs quota -$qtype $qarg $DIR| - awk 'NR == 3{ print $5 }'| sed 's/s$//') + time=$(lfs quota -$qtype $qarg $parg $DIR| + awk 'NR == 3{ print $5 }') ;; file) time=$(lfs quota -$qtype $qarg $DIR| - awk 'NR == 3{ print $9 }'| sed 's/s$//') + awk 'NR == 3{ print $9 }') ;; *) error "Unknown quota type: $flavour" ;; esac + local sleep_seconds=0 + local orig_time=$time + + echo "Grace time is $time" + # from lfs.c:__sec2str() + # const char spec[] = "smhdw"; + # {1, 60, 60*60, 24*60*60, 7*24*60*60}; + [[ $time == *w* ]] && w_time=${time%w*} && + let sleep_seconds+=$((w_time*7*24*60*60)); + time=${time#*w} + [[ $time == *d* ]] && d_time=${time%d*} && + let sleep_seconds+=$((d_time*24*60*60)); + time=${time#*d} + [[ $time == *h* ]] && h_time=${time%h*} && + let sleep_seconds+=$((h_time*60*60)); + time=${time#*h} + [[ $time == *m* ]] && m_time=${time%m*} && + let sleep_seconds+=$((m_time*60)); + time=${time#*m} + [[ $time == *s* ]] && s_time=${time%s*} && + let sleep_seconds+=$s_time + echo "Sleep through grace ..." - [ "$time" == "-" ] && + [ "$orig_time" == "-" ] && error "Grace timeout was not set or quota not exceeded" - if [ "$time" == "none" ]; then + if [ "$orig_time" == "none" ]; then echo "...Grace timeout already expired" else - let time+=$extrasleep - echo "...sleep $time seconds" - sleep $time + let sleep_seconds+=$extrasleep + echo "...sleep $sleep_seconds seconds" + sleep $sleep_seconds fi } setup_quota_test() { wait_delete_completed echo "Creating test directory" - mkdir $DIR/$tdir || return 1 + mkdir_on_mdt0 $DIR/$tdir || return 1 chmod 0777 $DIR/$tdir || return 2 # always clear fail_loc in case of fail_loc isn't cleared # properly when previous test failed lustre_fail mds_ost 0 + stack_trap cleanup_quota_test EXIT } cleanup_quota_test() { - trap 0 echo "Delete files..." rm -rf $DIR/$tdir + [ -d $DIR/${tdir}_dom ] && rm -rf $DIR/${tdir}_dom echo "Wait for unlink objects finished..." wait_delete_completed sync_all_data || true @@ -412,13 +457,23 @@ quota_show_check() { project_quota_enabled () { local rc=0 - for num in $(seq $MDSCOUNT); do - do_facet mds$num $DEBUGFS -R features $(mdsdevname $num) | - grep -q project || rc=1 - done - for num in $(seq $OSTCOUNT); do - do_facet ost$num $DEBUGFS -R features $(ostdevname $num) | - grep -q project || rc=1 + local zfeat="feature@project_quota" + + for facet in $(seq -f mds%g $MDSCOUNT) $(seq -f ost%g $OSTCOUNT); do + local facet_fstype=${facet:0:3}1_FSTYPE + local devname + + if [ "${!facet_fstype}" = "zfs" ]; then + devname=$(zpool_name ${facet}) + do_facet ${facet} $ZPOOL get -H "$zfeat" $devname | + grep -wq active || rc=1 + else + [ ${facet:0:3} == "mds" ] && + devname=$(mdsdevname ${facet:3}) || + devname=$(ostdevname ${facet:3}) + do_facet ${facet} $DEBUGFS -R features $devname | + grep -q project || rc=1 + fi done [ $rc -eq 0 ] && PQ_CLEANUP=false || PQ_CLEANUP=true return $rc @@ -428,15 +483,20 @@ project_quota_enabled || enable_project_quota reset_quota_settings() { resetquota -u $TSTUSR + resetquota -u $TSTID resetquota -g $TSTUSR + resetquota -g $TSTID resetquota -u $TSTUSR2 + resetquota -u $TSTID2 resetquota -g $TSTUSR2 + resetquota -g $TSTID2 resetquota -p $TSTPRJID } # enable quota debug quota_init() { - do_nodes $(comma_list $(nodes_list)) "lctl set_param debug=+quota" + do_nodes $(comma_list $(nodes_list)) \ + "$LCTL set_param -n debug=+quota,trace" } quota_init reset_quota_settings @@ -455,22 +515,22 @@ test_quota_performance() { local etime=$(date +%s) delta=$((etime - stime)) if [ $delta -gt 0 ]; then - rate=$((size * 1024 / delta)) - if [ $(facet_fstype $SINGLEMDS) = "zfs" ]; then - # LU-2872 - see LU-2887 for fix - [ $rate -gt 64 ] || - error "SLOW IO for $TSTUSR (user): $rate KB/sec" - else - [ $rate -gt 1024 ] || - error "SLOW IO for $TSTUSR (user): $rate KB/sec" - fi + rate=$((size * 1024 / delta)) + if [ "$mds1_FSTYPE" = zfs ]; then + # LU-2872 - see LU-2887 for fix + [ $rate -gt 64 ] || + error "SLOW IO for $TSTUSR (user): $rate KB/sec" + else + [ $rate -gt 1024 ] || + error "SLOW IO for $TSTUSR (user): $rate KB/sec" + fi fi rm -f $TESTFILE } # test basic quota performance b=21696 test_0() { - local MB=100 # 100M + local MB=100 # MB [ "$SLOW" = "no" ] && MB=10 local free_space=$(lfs_df | grep "summary" | awk '{print $4}') @@ -478,7 +538,6 @@ test_0() { skip "not enough space ${free_space} KB, " \ "required $((MB * 1024)) KB" setup_quota_test || error "setup quota failed with $?" - trap cleanup_quota_test EXIT set_ost_qtype "none" || error "disable ost quota failed" test_quota_performance $MB @@ -487,2985 +546,5021 @@ test_0() { $LFS setquota -u $TSTUSR -b 0 -B 10G -i 0 -I 0 $DIR || error "set quota failed" test_quota_performance $MB - - cleanup_quota_test } run_test 0 "Test basic quota performance" +# usage: test_1_check_write tfile user|group|project +test_1_check_write() { + local testfile="$1" + local qtype="$2" + local limit=$3 + local short_qtype=${qtype:0:1} + + log "Write..." + $RUNAS $DD of=$testfile count=$((limit/2)) || + quota_error $short_qtype $TSTUSR \ + "$qtype write failure, but expect success" + log "Write out of block quota ..." + # this time maybe cache write, ignore it's failure + $RUNAS $DD of=$testfile count=$((limit/2)) seek=$((limit/2)) || true + # flush cache, ensure noquota flag is set on client + cancel_lru_locks osc + sync; sync_all_data || true + # sync means client wrote all it's cache, but id doesn't + # guarantee that slave received new edquot through glimpse. + # so wait a little to be sure slave got it. + sleep 5 + $RUNAS $DD of=$testfile count=1 seek=$limit && + quota_error $short_qtype $TSTUSR \ + "user write success, but expect EDQUOT" + return 0 +} + +check_write_fallocate() { + local testfile="$1" + local qtype="$2" + local limit=$3 + local short_qtype=${qtype:0:1} + + count=$((limit/2)) + log "Write ${count}MiB Using Fallocate" + $RUNAS fallocate -l${count}MiB $testfile || + quota_error $short_qtype $TSTUSR "Write ${count}MiB fail" + + cancel_lru_locks osc + sync; sync_all_data || true + sleep 2 + + count=$((limit + 1)) + log "Write ${count}MiB Using Fallocate" + $RUNAS fallocate -l${count}MiB $testfile && + quota_error $short_qtype $TSTUSR \ + "Write success, expect EDQUOT" || true +} + # test block hardlimit -test_1() { - local LIMIT=10 # 10M - local TESTFILE="$DIR/$tdir/$tfile-0" +test_1a() { + local limit=10 # MB + local testfile="$DIR/$tdir/$tfile-0" setup_quota_test || error "setup quota failed with $?" - trap cleanup_quota_test EXIT # enable ost quota set_ost_qtype $QTYPE || error "enable ost quota failed" # test for user - log "User quota (block hardlimit:$LIMIT MB)" - $LFS setquota -u $TSTUSR -b 0 -B ${LIMIT}M -i 0 -I 0 $DIR || + log "User quota (block hardlimit:$limit MB)" + $LFS setquota -u $TSTUSR -b 0 -B ${limit}M -i 0 -I 0 $DIR || error "set user quota failed" # make sure the system is clean - local USED=$(getquota -u $TSTUSR global curspace) - [ $USED -ne 0 ] && error "Used space($USED) for user $TSTUSR isn't 0." + local used=$(getquota -u $TSTUSR global curspace) + [ $used -ne 0 ] && error "Used space($used) for user $TSTUSR isn't 0." - $LFS setstripe $TESTFILE -c 1 || error "setstripe $TESTFILE failed" - chown $TSTUSR.$TSTUSR $TESTFILE || error "chown $TESTFILE failed" + $LFS setstripe $testfile -c 1 || error "setstripe $testfile failed" + chown $TSTUSR.$TSTUSR $testfile || error "chown $testfile failed" - log "Write..." - $RUNAS $DD of=$TESTFILE count=$((LIMIT/2)) || - quota_error u $TSTUSR "user write failure, but expect success" - log "Write out of block quota ..." - # this time maybe cache write, ignore it's failure - $RUNAS $DD of=$TESTFILE count=$((LIMIT/2)) seek=$((LIMIT/2)) || true - # flush cache, ensure noquota flag is set on client - cancel_lru_locks osc - sync; sync_all_data || true - $RUNAS $DD of=$TESTFILE count=1 seek=$LIMIT && - quota_error u $TSTUSR "user write success, but expect EDQUOT" + test_1_check_write $testfile "user" $limit - rm -f $TESTFILE + rm -f $testfile wait_delete_completed || error "wait_delete_completed failed" sync_all_data || true - USED=$(getquota -u $TSTUSR global curspace) - [ $USED -ne 0 ] && quota_error u $TSTUSR \ + used=$(getquota -u $TSTUSR global curspace) + [ $used -ne 0 ] && quota_error u $TSTUSR \ "user quota isn't released after deletion" resetquota -u $TSTUSR # test for group log "--------------------------------------" - log "Group quota (block hardlimit:$LIMIT MB)" - $LFS setquota -g $TSTUSR -b 0 -B ${LIMIT}M -i 0 -I 0 $DIR || + log "Group quota (block hardlimit:$limit MB)" + $LFS setquota -g $TSTUSR -b 0 -B ${limit}M -i 0 -I 0 $DIR || error "set group quota failed" - TESTFILE="$DIR/$tdir/$tfile-1" + testfile="$DIR/$tdir/$tfile-1" # make sure the system is clean - USED=$(getquota -g $TSTUSR global curspace) - [ $USED -ne 0 ] && error "Used space ($USED) for group $TSTUSR isn't 0" + used=$(getquota -g $TSTUSR global curspace) + [ $used -ne 0 ] && error "Used space ($used) for group $TSTUSR isn't 0" - $LFS setstripe $TESTFILE -c 1 || error "setstripe $TESTFILE failed" - chown $TSTUSR.$TSTUSR $TESTFILE || error "chown $TESTFILE failed" + $LFS setstripe $testfile -c 1 || error "setstripe $testfile failed" + chown $TSTUSR.$TSTUSR $testfile || error "chown $testfile failed" - log "Write ..." - $RUNAS $DD of=$TESTFILE count=$((LIMIT/2)) || - quota_error g $TSTUSR "Group write failure, but expect success" - log "Write out of block quota ..." - # this time maybe cache write, ignore it's failure - $RUNAS $DD of=$TESTFILE count=$((LIMIT/2)) seek=$((LIMIT/2)) || true - cancel_lru_locks osc - sync; sync_all_data || true - $RUNAS $DD of=$TESTFILE count=10 seek=$LIMIT && - quota_error g $TSTUSR "Group write success, but expect EDQUOT" - rm -f $TESTFILE + test_1_check_write $testfile "group" $limit + rm -f $testfile wait_delete_completed || error "wait_delete_completed failed" sync_all_data || true - USED=$(getquota -g $TSTUSR global curspace) - [ $USED -ne 0 ] && quota_error g $TSTUSR \ + used=$(getquota -g $TSTUSR global curspace) + [ $used -ne 0 ] && quota_error g $TSTUSR \ "Group quota isn't released after deletion" resetquota -g $TSTUSR if ! is_project_quota_supported; then echo "Project quota is not supported" - cleanup_quota_test return 0 fi - TESTFILE="$DIR/$tdir/$tfile-2" + testfile="$DIR/$tdir/$tfile-2" # make sure the system is clean - USED=$(getquota -p $TSTPRJID global curspace) - [ $USED -ne 0 ] && - error "used space($USED) for project $TSTPRJID isn't 0" + used=$(getquota -p $TSTPRJID global curspace) + [ $used -ne 0 ] && + error "used space($used) for project $TSTPRJID isn't 0" # test for Project log "--------------------------------------" - log "Project quota (block hardlimit:$LIMIT mb)" - $LFS setquota -p $TSTPRJID -b 0 -B ${LIMIT}M -i 0 -I 0 $DIR || + log "Project quota (block hardlimit:$limit mb)" + $LFS setquota -p $TSTPRJID -b 0 -B ${limit}M -i 0 -I 0 $DIR || error "set project quota failed" - $LFS setstripe $TESTFILE -c 1 || error "setstripe $TESTFILE failed" - chown $TSTUSR:$TSTUSR $TESTFILE || error "chown $TESTFILE failed" - change_project -p $TSTPRJID $TESTFILE - - log "write ..." - $RUNAS $DD of=$TESTFILE count=$((LIMIT/2)) || quota_error p $TSTPRJID \ - "project write failure, but expect success" - log "write out of block quota ..." - # this time maybe cache write, ignore it's failure - $RUNAS $DD of=$TESTFILE count=$((LIMIT/2)) seek=$((LIMIT/2)) || true - cancel_lru_locks osc - sync; sync_all_data || true - $RUNAS $DD of=$TESTFILE count=10 seek=$LIMIT && quota_error p \ - $TSTPRJID "project write success, but expect EDQUOT" + $LFS setstripe $testfile -c 1 || error "setstripe $testfile failed" + chown $TSTUSR:$TSTUSR $testfile || error "chown $testfile failed" + change_project -p $TSTPRJID $testfile + + test_1_check_write $testfile "project" $limit # cleanup cleanup_quota_test - USED=$(getquota -p $TSTPRJID global curspace) - [ $USED -eq 0 ] || quota_error p $TSTPRJID \ + used=$(getquota -p $TSTPRJID global curspace) + [ $used -ne 0 ] && quota_error p $TSTPRJID \ "project quota isn't released after deletion" -} -run_test 1 "Block hard limit (normal use and out of quota)" - -# test inode hardlimit -test_2() { - local LIMIT=$((1024 * 1024)) # 1M inodes - local TESTFILE="$DIR/$tdir/$tfile-0" - [ "$SLOW" = "no" ] && LIMIT=1024 # 1k inodes + resetquota -p $TSTPRJID +} +run_test 1a "Block hard limit (normal use and out of quota)" - local FREE_INODES=$(mdt_free_inodes 0) - echo "$FREE_INODES free inodes on master MDT" - [ $FREE_INODES -lt $LIMIT ] && - skip "not enough free inodes $FREE_INODES required $LIMIT" +test_1b() { + local limit=10 # MB + local global_limit=20 # MB + local testfile="$DIR/$tdir/$tfile-0" + local qpool="qpool1" + mds_supports_qp setup_quota_test || error "setup quota failed with $?" - trap cleanup_quota_test EXIT - # enable mdt quota - set_mdt_qtype $QTYPE || error "enable mdt quota failed" + # enable ost quota + set_ost_qtype $QTYPE || error "enable ost quota failed" # test for user - log "User quota (inode hardlimit:$LIMIT files)" - $LFS setquota -u $TSTUSR -b 0 -B 0 -i 0 -I $LIMIT $DIR || + log "User quota (block hardlimit:$global_limit MB)" + $LFS setquota -u $TSTUSR -b 0 -B ${global_limit}M -i 0 -I 0 $DIR || + error "set user quota failed" + + pool_add $qpool || error "pool_add failed" + pool_add_targets $qpool 0 $(($OSTCOUNT - 1)) || + error "pool_add_targets failed" + + # check qmt_pool_add dmesg error + local msg_rgx="QMT0000: can't add to $FSNAME-OST0000.*pool.*$qpool" + local dmesg_err + dmesg_err=$(do_facet mds1 dmesg | grep "$msg_rgx" | tail -1) + [[ -z "$dmesg_err" ]] || error "found qmt_pool_add error: $dmesg_err" + + $LFS setquota -u $TSTUSR -B ${limit}M --pool $qpool $DIR || error "set user quota failed" # make sure the system is clean - local USED=$(getquota -u $TSTUSR global curinodes) - [ $USED -ne 0 ] && error "Used inodes($USED) for user $TSTUSR isn't 0." + local used=$(getquota -u $TSTUSR global curspace) + echo "used $used" + [ $used -ne 0 ] && error "Used space($used) for user $TSTUSR isn't 0." - log "Create $LIMIT files ..." - $RUNAS createmany -m ${TESTFILE} $LIMIT || - quota_error u $TSTUSR "user create failure, but expect success" - log "Create out of file quota ..." - $RUNAS touch ${TESTFILE}_xxx && - quota_error u $TSTUSR "user create success, but expect EDQUOT" + used=$(getquota -u $TSTUSR global bhardlimit $qpool) - # cleanup - unlinkmany ${TESTFILE} $LIMIT || error "unlinkmany $TESTFILE failed" - rm -f ${TESTFILE}_xxx - wait_delete_completed + $LFS setstripe $testfile -c 1 || error "setstripe $testfile failed" + chown $TSTUSR.$TSTUSR $testfile || error "chown $testfile failed" + + test_1_check_write $testfile "user" $limit - USED=$(getquota -u $TSTUSR global curinodes) - [ $USED -ne 0 ] && quota_error u $TSTUSR \ + rm -f $testfile + wait_delete_completed || error "wait_delete_completed failed" + sync_all_data || true + used=$(getquota -u $TSTUSR global curspace $qpool) + [ $used -ne 0 ] && quota_error u $TSTUSR \ "user quota isn't released after deletion" resetquota -u $TSTUSR # test for group log "--------------------------------------" - log "Group quota (inode hardlimit:$LIMIT files)" - $LFS setquota -g $TSTUSR -b 0 -B 0 -i 0 -I $LIMIT $DIR || + log "Group quota (block hardlimit:$global_limit MB)" + $LFS setquota -g $TSTUSR -b 0 -B ${global_limit}M -i 0 -I 0 $DIR || error "set group quota failed" - TESTFILE=$DIR/$tdir/$tfile-1 - # make sure the system is clean - USED=$(getquota -g $TSTUSR global curinodes) - [ $USED -ne 0 ] && error "Used inodes($USED) for group $TSTUSR isn't 0." + $LFS setquota -g $TSTUSR -b 0 -B ${limit}M --pool $qpool $DIR || + error "set group quota failed" - log "Create $LIMIT files ..." - $RUNAS createmany -m ${TESTFILE} $LIMIT || - quota_error g $TSTUSR "group create failure, but expect success" - log "Create out of file quota ..." - $RUNAS touch ${TESTFILE}_xxx && - quota_error g $TSTUSR "group create success, but expect EDQUOT" + testfile="$DIR/$tdir/$tfile-1" + # make sure the system is clean + used=$(getquota -g $TSTUSR global curspace $qpool) + [ $used -ne 0 ] && error "Used space ($used) for group $TSTUSR isn't 0" - # cleanup - unlinkmany ${TESTFILE} $LIMIT || error "unlinkmany $TESTFILE failed" - rm -f ${TESTFILE}_xxx - wait_delete_completed + $LFS setstripe $testfile -c 1 || error "setstripe $testfile failed" + chown $TSTUSR.$TSTUSR $testfile || error "chown $testfile failed" - USED=$(getquota -g $TSTUSR global curinodes) - [ $USED -ne 0 ] && quota_error g $TSTUSR \ - "user quota isn't released after deletion" + test_1_check_write $testfile "group" $limit + rm -f $testfile + wait_delete_completed || error "wait_delete_completed failed" + sync_all_data || true + used=$(getquota -g $TSTUSR global curspace $qpool) + [ $used -ne 0 ] && quota_error g $TSTUSR \ + "Group quota isn't released after deletion" resetquota -g $TSTUSR - ! is_project_quota_supported && cleanup_quota_test && - echo "Skip project quota is not supported" && return 0 - # test for project + if ! is_project_quota_supported; then + echo "Project quota is not supported" + return 0 + fi + + testfile="$DIR/$tdir/$tfile-2" + # make sure the system is clean + used=$(getquota -p $TSTPRJID global curspace $qpool) + [ $used -ne 0 ] && + error "used space($used) for project $TSTPRJID isn't 0" + + # test for Project log "--------------------------------------" - log "Project quota (inode hardlimit:$LIMIT files)" - $LFS setquota -p $TSTPRJID -b 0 -B 0 -i 0 -I $LIMIT $DIR || + log "Project quota (block hardlimit:$global_limit mb)" + $LFS setquota -p $TSTPRJID -b 0 -B ${global_limit}M -i 0 -I 0 $DIR || error "set project quota failed" - TESTFILE=$DIR/$tdir/$tfile-1 - # make sure the system is clean - USED=$(getquota -p $TSTPRJID global curinodes) - [ $USED -ne 0 ] && - error "Used inodes($USED) for project $TSTPRJID isn't 0" + $LFS setquota -p $TSTPRJID -b 0 -B ${limit}M --pool $qpool $DIR || + error "set project quota failed" - change_project -sp $TSTPRJID $DIR/$tdir - log "Create $LIMIT files ..." - $RUNAS createmany -m ${TESTFILE} $((LIMIT-1)) || quota_error p \ - $TSTPRJID "project create fail, but expect success" - log "Create out of file quota ..." - $RUNAS touch ${TESTFILE}_xxx && quota_error p $TSTPRJID \ - "project create success, but expect EDQUOT" - change_project -C $DIR/$tdir + $LFS setstripe $testfile -c 1 || error "setstripe $testfile failed" + chown $TSTUSR:$TSTUSR $testfile || error "chown $testfile failed" + change_project -p $TSTPRJID $testfile + + test_1_check_write $testfile "project" $limit + + # cleanup cleanup_quota_test - USED=$(getquota -p $TSTPRJID global curinodes) - [ $USED -eq 0 ] || quota_error p $TSTPRJID \ - "project quota isn't released after deletion" + used=$(getquota -p $TSTPRJID global curspace) + [ $used -eq 0 ] || quota_error p $TSTPRJID \ + "project quota isn't released after deletion" } -run_test 2 "File hard limit (normal use and out of quota)" - -test_block_soft() { - local TESTFILE=$1 - local GRACE=$2 - local LIMIT=$3 - local OFFSET=0 - local qtype=$4 +run_test 1b "Quota pools: Block hard limit (normal use and out of quota)" - setup_quota_test - trap cleanup_quota_test EXIT +test_1c() { + local global_limit=20 # MB + local testfile="$DIR/$tdir/$tfile-0" + local qpool1="qpool1" + local qpool2="qpool2" - $LFS setstripe $TESTFILE -c 1 -i 0 - chown $TSTUSR.$TSTUSR $TESTFILE - [ "$qtype" == "p" ] && is_project_quota_supported && - change_project -p $TSTPRJID $TESTFILE + mds_supports_qp + setup_quota_test || error "setup quota failed with $?" - echo "Write up to soft limit" - $RUNAS $DD of=$TESTFILE count=$LIMIT || - quota_error a $TSTUSR "write failure, but expect success" - OFFSET=$((LIMIT * 1024)) - cancel_lru_locks osc + # enable ost quota + set_ost_qtype $QTYPE || error "enable ost quota failed" - echo "Write to exceed soft limit" - $RUNAS dd if=/dev/zero of=$TESTFILE bs=1K count=10 seek=$OFFSET || - quota_error a $TSTUSR "write failure, but expect success" - OFFSET=$((OFFSET + 1024)) # make sure we don't write to same block - cancel_lru_locks osc + # test for user + log "User quota (block hardlimit:$global_limit MB)" + $LFS setquota -u $TSTUSR -b 0 -B ${global_limit}M -i 0 -I 0 $DIR || + error "set user quota failed" - $SHOW_QUOTA_USER - $SHOW_QUOTA_GROUP - $SHOW_QUOTA_PROJID - $SHOW_QUOTA_INFO_USER - $SHOW_QUOTA_INFO_GROUP - $SHOW_QUOTA_INFO_PROJID + pool_add $qpool1 || error "pool_add failed" + pool_add_targets $qpool1 0 $(($OSTCOUNT - 1)) || + error "pool_add_targets failed" - echo "Write before timer goes off" - $RUNAS dd if=/dev/zero of=$TESTFILE bs=1K count=10 seek=$OFFSET || - quota_error a $TSTUSR "write failure, but expect success" - OFFSET=$((OFFSET + 1024)) - cancel_lru_locks osc + pool_add $qpool2 || error "pool_add failed" + pool_add_targets $qpool2 0 $(($OSTCOUNT - 1)) || + error "pool_add_targets failed" - wait_grace_time $qtype "block" + # create pools without hard limit + # initially such case raised several bugs + $LFS setquota -u $TSTUSR -B 0M --pool $qpool1 $DIR || + error "set user quota failed" - $SHOW_QUOTA_USER - $SHOW_QUOTA_GROUP - $SHOW_QUOTA_PROJID - $SHOW_QUOTA_INFO_USER - $SHOW_QUOTA_INFO_GROUP - $SHOW_QUOTA_INFO_PROJID + $LFS setquota -u $TSTUSR -B 0M --pool $qpool2 $DIR || + error "set user quota failed" - echo "Write after timer goes off" - # maybe cache write, ignore. - $RUNAS dd if=/dev/zero of=$TESTFILE bs=1K count=10 seek=$OFFSET || true - OFFSET=$((OFFSET + 1024)) - cancel_lru_locks osc - $RUNAS dd if=/dev/zero of=$TESTFILE bs=1K count=10 seek=$OFFSET && - quota_error a $TSTUSR "write success, but expect EDQUOT" + # make sure the system is clean + local used=$(getquota -u $TSTUSR global curspace) + echo "used $used" + [ $used -ne 0 ] && error "Used space($used) for user $TSTUSR isn't 0." - $SHOW_QUOTA_USER - $SHOW_QUOTA_GROUP - $SHOW_QUOTA_PROJID - $SHOW_QUOTA_INFO_USER - $SHOW_QUOTA_INFO_GROUP - $SHOW_QUOTA_INFO_PROJID + used=$(getquota -u $TSTUSR global bhardlimit $qpool) - echo "Unlink file to stop timer" - rm -f $TESTFILE - wait_delete_completed - sync_all_data || true + test_1_check_write $testfile "user" $global_limit - $SHOW_QUOTA_USER - $SHOW_QUOTA_GROUP - $SHOW_QUOTA_PROJID - $SHOW_QUOTA_INFO_USER - $SHOW_QUOTA_INFO_GROUP - $SHOW_QUOTA_INFO_PROJID + used=$(getquota -u $TSTUSR global curspace $qpool1) + echo "qpool1 used $used" + used=$(getquota -u $TSTUSR global curspace $qpool2) + echo "qpool2 used $used" - $LFS setstripe $TESTFILE -c 1 -i 0 - chown $TSTUSR.$TSTUSR $TESTFILE - [ "$qtype" == "p" ] && change_project -p $TSTPRJID $TESTFILE + rm -f $testfile + wait_delete_completed || error "wait_delete_completed failed" + sync_all_data || true - echo "Write ..." - $RUNAS $DD of=$TESTFILE count=$LIMIT || - quota_error a $TSTUSR "write failure, but expect success" - # cleanup - cleanup_quota_test + used=$(getquota -u $TSTUSR global curspace $qpool1) + [ $used -eq 0 ] || quota_error u $TSTUSR \ + "user quota isn't released after deletion" } +run_test 1c "Quota pools: check 3 pools with hardlimit only for global" -# block soft limit -test_3() { - local GRACE=20 # 20s - if [ $(facet_fstype $SINGLEMDS) = "zfs" ]; then - GRACE=60 - fi - local TESTFILE=$DIR/$tdir/$tfile-0 +test_1d() { + local limit1=10 # MB + local limit2=12 # MB + local global_limit=20 # MB + local testfile="$DIR/$tdir/$tfile-0" + local qpool1="qpool1" + local qpool2="qpool2" - # get minimum soft qunit size - local LIMIT=$(( $(do_facet $SINGLEMDS $LCTL get_param -n \ - qmt.$FSNAME-QMT0000.dt-0x0.soft_least_qunit) / 1024 )) + mds_supports_qp + setup_quota_test || error "setup quota failed with $?" + # enable ost quota set_ost_qtype $QTYPE || error "enable ost quota failed" - echo "User quota (soft limit:$LIMIT MB grace:$GRACE seconds)" - # make sure the system is clean - local USED=$(getquota -u $TSTUSR global curspace) - [ $USED -ne 0 ] && error "Used space($USED) for user $TSTUSR isn't 0." + # test for user + log "User quota (block hardlimit:$global_limit MB)" + $LFS setquota -u $TSTUSR -b 0 -B ${global_limit}M -i 0 -I 0 $DIR || + error "set user quota failed" - $LFS setquota -t -u --block-grace $GRACE --inode-grace \ - $MAX_IQ_TIME $DIR || error "set user grace time failed" - $LFS setquota -u $TSTUSR -b ${LIMIT}M -B 0 -i 0 -I 0 $DIR || + pool_add $qpool1 || error "pool_add failed" + pool_add_targets $qpool1 0 $(($OSTCOUNT - 1)) || + error "pool_add_targets failed" + + pool_add $qpool2 || error "pool_add failed" + pool_add_targets $qpool2 0 $(($OSTCOUNT - 1)) || + error "pool_add_targets failed" + + $LFS setquota -u $TSTUSR -B ${limit1}M --pool $qpool1 $DIR || error "set user quota failed" - test_block_soft $TESTFILE $GRACE $LIMIT "u" + $LFS setquota -u $TSTUSR -B ${limit2}M --pool $qpool2 $DIR || + error "set user quota failed" - echo "Group quota (soft limit:$LIMIT MB grace:$GRACE seconds)" - TESTFILE=$DIR/$tdir/$tfile-1 # make sure the system is clean - USED=$(getquota -g $TSTUSR global curspace) - [ $USED -ne 0 ] && error "Used space($USED) for group $TSTUSR isn't 0." - - $LFS setquota -t -g --block-grace $GRACE --inode-grace \ - $MAX_IQ_TIME $DIR || error "set group grace time failed" - $LFS setquota -g $TSTUSR -b ${LIMIT}M -B 0 -i 0 -I 0 $DIR || - error "set group quota failed" + local used=$(getquota -u $TSTUSR global curspace) + echo "used $used" + [ $used -ne 0 ] && error "used space($used) for user $TSTUSR isn't 0." - test_block_soft $TESTFILE $GRACE $LIMIT "g" + used=$(getquota -u $TSTUSR global bhardlimit $qpool) - if is_project_quota_supported; then - echo "Project quota (soft limit:$LIMIT MB grace:$GRACE sec)" - TESTFILE=$DIR/$tdir/$tfile-2 - # make sure the system is clean - USED=$(getquota -p $TSTPRJID global curspace) - [ $USED -ne 0 ] && error \ - "Used space($USED) for project $TSTPRJID isn't 0." + test_1_check_write $testfile "user" $limit1 - $LFS setquota -t -p --block-grace $GRACE --inode-grace \ - $MAX_IQ_TIME $DIR || - error "set project grace time failed" - $LFS setquota -p $TSTPRJID -b ${LIMIT}M -B 0 -i 0 -I 0 \ - $DIR || error "set project quota failed" + used=$(getquota -u $TSTUSR global curspace $qpool1) + echo "qpool1 used $used" + used=$(getquota -u $TSTUSR global curspace $qpool2) + echo "qpool2 used $used" - test_block_soft $TESTFILE $GRACE $LIMIT "p" - resetquota -p $TSTPRJID - $LFS setquota -t -p --block-grace $MAX_DQ_TIME --inode-grace \ - $MAX_IQ_TIME $DIR || - error "restore project grace time failed" - fi + rm -f $testfile + wait_delete_completed || error "wait_delete_completed failed" + sync_all_data || true - # cleanup - $LFS setquota -t -u --block-grace $MAX_DQ_TIME --inode-grace \ - $MAX_IQ_TIME $DIR || error "restore user grace time failed" - $LFS setquota -t -g --block-grace $MAX_DQ_TIME --inode-grace \ - $MAX_IQ_TIME $DIR || error "restore group grace time failed" + used=$(getquota -u $TSTUSR global curspace $qpool1) + [ $used -eq 0 ] || quota_error u $TSTUSR \ + "user quota isn't released after deletion" } -run_test 3 "Block soft limit (start timer, timer goes off, stop timer)" +run_test 1d "Quota pools: check block hardlimit on different pools" -test_file_soft() { - local TESTFILE=$1 - local LIMIT=$2 - local grace=$3 - local qtype=$4 +test_1e() { + local limit1=10 # MB + local global_limit=53000000 # MB + local testfile="$DIR/$tdir/$tfile-0" + local testfile2="$DIR/$tdir/$tfile-1" + local qpool1="qpool1" - setup_quota_test - trap cleanup_quota_test EXIT - is_project_quota_supported && change_project -sp $TSTPRJID $DIR/$tdir + mds_supports_qp + setup_quota_test || error "setup quota failed with $?" - echo "Create files to exceed soft limit" - $RUNAS createmany -m ${TESTFILE}_ $((LIMIT + 1)) || - quota_error a $TSTUSR "create failure, but expect success" - local trigger_time=$(date +%s) + # enable ost quota + set_ost_qtype $QTYPE || error "enable ost quota failed" - sync_all_data || true + # global_limit is much greater than limit1 to get + # different qunit's on osts. Since 1st qunit shrinking + # on OST1(that belongs to qpool1), this qunit should + # be sent to OST1. + log "User quota (block hardlimit:$global_limit MB)" + $LFS setquota -u $TSTUSR -b 0 -B ${global_limit}M -i 0 -I 0 $DIR || + error "set user quota failed" - local cur_time=$(date +%s) - [ $(($cur_time - $trigger_time)) -ge $grace ] && - error "Passed grace time $grace, $trigger_time, $cur_time" - - echo "Create file before timer goes off" - $RUNAS touch ${TESTFILE}_before || - quota_error a $TSTUSR "failed create before timer expired," \ - "but expect success. $trigger_time, $cur_time" - sync_all_data || true + pool_add $qpool1 || error "pool_add failed" + pool_add_targets $qpool1 1 1 || + error "pool_add_targets failed" - wait_grace_time $qtype "file" + $LFS setquota -u $TSTUSR -B ${limit1}M --pool $qpool1 $DIR || + error "set user quota failed" - $SHOW_QUOTA_USER - $SHOW_QUOTA_GROUP - $SHOW_QUOTA_PROJID - $SHOW_QUOTA_INFO_USER - $SHOW_QUOTA_INFO_GROUP - $SHOW_QUOTA_INFO_PROJID + # make sure the system is clean + local used=$(getquota -u $TSTUSR global curspace) + [ $used -ne 0 ] && error "Used space($used) for user $TSTUSR isn't 0." - echo "Create file after timer goes off" - # There is a window that space is accounted in the quota usage but - # hasn't been decreased from the pending write, if we acquire quota - # in this window, we'll acquire more than we needed. - $RUNAS touch ${TESTFILE}_after_1 ${TESTFILE}_after_2 || true - sync_all_data || true - $RUNAS touch ${TESTFILE}_after_3 && - quota_error a $TSTUSR "create after timer expired," \ - "but expect EDQUOT" - sync_all_data || true + $LFS setstripe $testfile -c 1 -i 1 || error "setstripe $testfile failed" + chown $TSTUSR.$TSTUSR $testfile || error "chown $testfile failed" - $SHOW_QUOTA_USER - $SHOW_QUOTA_GROUP - $SHOW_QUOTA_PROJID - $SHOW_QUOTA_INFO_USER - $SHOW_QUOTA_INFO_GROUP - $SHOW_QUOTA_INFO_PROJID + test_1_check_write $testfile "user" $limit1 - echo "Unlink files to stop timer" - find $(dirname $TESTFILE) -name "$(basename ${TESTFILE})*" | xargs rm -f - wait_delete_completed + $LFS setstripe $testfile2 -c 1 -i 0 || + error "setstripe $testfile2 failed" + chown $TSTUSR.$TSTUSR $testfile2 || error "chown $testfile2 failed" + # Now write to file with a stripe on OST0, that doesn't belong to qpool1 + log "Write..." + $RUNAS $DD of=$testfile2 count=20 || + quota_error u $TSTUSR \ + "$qtype write failure, but expect success" - echo "Create file" - $RUNAS touch ${TESTFILE}_xxx || - quota_error a $TSTUSR "touch after timer stop failure," \ - "but expect success" + rm -f $testfile + rm -f $testfile2 + wait_delete_completed || error "wait_delete_completed failed" sync_all_data || true - # cleanup - cleanup_quota_test + used=$(getquota -u $TSTUSR global curspace $qpool1) + [ $used -eq 0 ] || quota_error u $TSTUSR \ + "user quota isn't released after deletion" } +run_test 1e "Quota pools: global pool high block limit vs quota pool with small" -# file soft limit -test_4a() { - local LIMIT=$(do_facet $SINGLEMDS $LCTL get_param -n \ - qmt.$FSNAME-QMT0000.md-0x0.soft_least_qunit) - local TESTFILE=$DIR/$tdir/$tfile-0 - local GRACE=12 +test_1f() { + local global_limit=200 # MB + local limit1=10 # MB + local TESTDIR="$DIR/$tdir/" + local testfile="$TESTDIR/$tfile-0" + local qpool1="qpool1" - set_mdt_qtype $QTYPE || error "enable mdt quota failed" + mds_supports_qp + setup_quota_test || error "setup quota failed with $?" - echo "User quota (soft limit:$LIMIT files grace:$GRACE seconds)" - # make sure the system is clean - local USED=$(getquota -u $TSTUSR global curinodes) - [ $USED -ne 0 ] && error "Used space($USED) for user $TSTUSR isn't 0." + # enable ost quota + set_ost_qtype $QTYPE || error "enable ost quota failed" - $LFS setquota -t -u --block-grace $MAX_DQ_TIME --inode-grace \ - $GRACE $DIR || error "set user grace time failed" - $LFS setquota -u $TSTUSR -b 0 -B 0 -i $LIMIT -I 0 $DIR || + log "User quota (block hardlimit:$global_limit MB)" + $LFS setquota -u $TSTUSR -b 0 -B ${global_limit}M -i 0 -I 0 $DIR || error "set user quota failed" - [ $(facet_fstype $SINGLEMDS) = "zfs" ] && GRACE=20 + pool_add $qpool1 || error "pool_add failed" + pool_add_targets $qpool1 0 0 || + error "pool_add_targets failed" - test_file_soft $TESTFILE $LIMIT $GRACE "u" + $LFS setquota -u $TSTUSR -B ${limit1}M --pool $qpool1 $DIR || + error "set user quota failed" - echo "Group quota (soft limit:$LIMIT files grace:$GRACE seconds)" # make sure the system is clean - USED=$(getquota -g $TSTUSR global curinodes) - [ $USED -ne 0 ] && error "Used space($USED) for group $TSTUSR isn't 0." + local used=$(getquota -u $TSTUSR global curspace) + [ $used -ne 0 ] && error "Used space($used) for user $TSTUSR isn't 0." - $LFS setquota -t -g --block-grace $MAX_DQ_TIME --inode-grace \ - $GRACE $DIR || error "set group grace time failed" - $LFS setquota -g $TSTUSR -b 0 -B 0 -i $LIMIT -I 0 $DIR || - error "set group quota failed" - TESTFILE=$DIR/$tdir/$tfile-1 + $LFS setstripe $TESTDIR -c 1 -i 0 || error "setstripe $TESTDIR failed" - test_file_soft $TESTFILE $LIMIT $GRACE "g" + test_1_check_write $testfile "user" $limit1 - if is_project_quota_supported; then - echo "Project quota (soft limit:$LIMIT files grace:$GRACE sec)" - # make sure the system is clean - USED=$(getquota -p $TSTPRJID global curinodes) - [ $USED -ne 0 ] && error \ - "Used space($USED) for project $TSTPRJID isn't 0." + pool_remove_target $qpool1 0 + rm -f $testfile + wait_delete_completed || error "wait_delete_completed failed" + sync_all_data || true - $LFS setquota -t -p --block-grace $MAX_DQ_TIME --inode-grace \ - $GRACE $DIR || error "set project grace time failed" - $LFS setquota -p $TSTPRJID -b 0 -B 0 -i $LIMIT -I 0 $DIR || - error "set project quota failed" + pool_add_targets $qpool1 0 0 || error "pool_add_targets failed" + # qunit for appropriate element in lgd array should be set + # correctly(4096). Earlier it was not changed continuing to be 1024. + # This caused write to hung when it hit limit1 - qunit shrinking to 1024 + # for qpool1 lqe didn't cause changing qunit for OST0 in gld array + # as it already was 1024. As flag "need_update" for this qunit was + # not set, new qunit wasn't sent to OST0. Thus revoke was not set + # for "qpool1" lqe and it couldn't set EDQUOT despite granted + # became > 10M. QMT returned EINPROGRESS in a loop. + # Check that it doesn't hung anymore. + test_1_check_write $testfile "user" $limit1 +} +run_test 1f "Quota pools: correct qunit after removing/adding OST" - TESTFILE=$DIR/$tdir/$tfile-1 - # one less than limit, because of parent directory included. - test_file_soft $TESTFILE $((LIMIT-1)) $GRACE "p" - resetquota -p $TSTPRJID - $LFS setquota -t -p --block-grace $MAX_DQ_TIME --inode-grace \ - $MAX_IQ_TIME $DIR || - error "restore project grace time failed" - fi +test_1g() { + local limit=20 # MB + local global_limit=40 # MB + local testfile="$DIR/$tdir/$tfile-0" + local qpool="qpool1" + local mdmb_param="osc.*.max_dirty_mb" + local max_dirty_mb=$($LCTL get_param -n $mdmb_param | head -1) - # cleanup - $LFS setquota -t -u --block-grace $MAX_DQ_TIME --inode-grace \ - $MAX_IQ_TIME $DIR || error "restore user grace time failed" - $LFS setquota -t -g --block-grace $MAX_DQ_TIME --inode-grace \ - $MAX_IQ_TIME $DIR || error "restore group grace time failed" -} -run_test 4a "File soft limit (start timer, timer goes off, stop timer)" + mds_supports_qp + setup_quota_test || error "setup quota failed with $?" + $LCTL set_param $mdmb_param=1 + stack_trap "$LCTL set_param $mdmb_param=$max_dirty_mb" EXIT -test_4b() { - local GR_STR1="1w3d" - local GR_STR2="1000s" - local GR_STR3="5s" - local GR_STR4="1w2d3h4m5s" - local GR_STR5="5c" - local GR_STR6="18446744073709551615" - local GR_STR7="-1" + # enable ost quota + set_ost_qtype $QTYPE || error "enable ost quota failed" - wait_delete_completed + # test for user + log "User quota (block hardlimit:$global_limit MB)" + $LFS setquota -u $TSTUSR -b 0 -B ${global_limit}M -i 0 -I 0 $DIR || + error "set user quota failed" - # test of valid grace strings handling - echo "Valid grace strings test" - $LFS setquota -t -u --block-grace $GR_STR1 --inode-grace \ - $GR_STR2 $DIR || error "set user grace time failed" - $LFS quota -u -t $DIR | grep "Block grace time: $GR_STR1" - $LFS setquota -t -g --block-grace $GR_STR3 --inode-grace \ - $GR_STR4 $DIR || error "set group grace time quota failed" - $LFS quota -g -t $DIR | grep "Inode grace time: $GR_STR4" + pool_add $qpool || error "pool_add failed" + pool_add_targets $qpool 0 $(($OSTCOUNT - 1)) || + error "pool_add_targets failed" - # test of invalid grace strings handling - echo " Invalid grace strings test" - ! $LFS setquota -t -u --block-grace $GR_STR4 --inode-grace $GR_STR5 $DIR - ! $LFS setquota -t -g --block-grace $GR_STR4 --inode-grace $GR_STR6 $DIR - ! $LFS setquota -t -g --block-grace $GR_STR4 --inode-grace \ - $GR_STR7 $DIR + $LFS setquota -u $TSTUSR -B ${limit}M --pool $qpool $DIR || + error "set user quota failed" - # cleanup - $LFS setquota -t -u --block-grace $MAX_DQ_TIME --inode-grace \ - $MAX_IQ_TIME $DIR || error "restore user grace time failed" - $LFS setquota -t -g --block-grace $MAX_DQ_TIME --inode-grace \ - $MAX_IQ_TIME $DIR || error "restore group grace time failed" + # make sure the system is clean + local used=$(getquota -u $TSTUSR global curspace) + echo "used $used" + [ $used -ne 0 ] && error "Used space($used) for user $TSTUSR isn't 0." + + $LFS setstripe $testfile -C 200 || error "setstripe $testfile failed" + chown $TSTUSR.$TSTUSR $testfile || error "chown $testfile failed" + + log "Write..." + $RUNAS $DD of=$testfile count=$((limit/2)) || + quota_error u $TSTUSR \ + "$qtype write failure, but expect success" + log "Write out of block quota ..." + # this time maybe cache write, ignore it's failure + $RUNAS $DD of=$testfile count=$((limit/2)) seek=$((limit/2)) || true + # flush cache, ensure noquota flag is set on client + cancel_lru_locks osc + sync; sync_all_data || true + sleep 5 + $RUNAS $DD of=$testfile count=$OSTCOUNT seek=$limit && + quota_error u $TSTUSR \ + "user write success, but expect EDQUOT" + + rm -f $testfile + wait_delete_completed || error "wait_delete_completed failed" + sync_all_data || true + + used=$(getquota -u $TSTUSR global curspace $qpool) + [ $used -ne 0 ] && quota_error u $TSTUSR \ + "user quota isn't released after deletion" + return 0 } -run_test 4b "Grace time strings handling" +run_test 1g "Quota pools: Block hard limit with wide striping" -# chown & chgrp (chown & chgrp successfully even out of block/file quota) -test_5() { - local BLIMIT=10 # 10M - local ILIMIT=10 # 10 inodes +test_1h() { + local limit=10 # MB + local testfile="$DIR/$tdir/$tfile-0" + + check_set_fallocate_or_skip setup_quota_test || error "setup quota failed with $?" - trap cleanup_quota_test EXIT - set_mdt_qtype $QTYPE || error "enable mdt quota failed" + # enable ost quota set_ost_qtype $QTYPE || error "enable ost quota failed" - echo "Set quota limit (0 ${BLIMIT}M 0 $ILIMIT) for $TSTUSR.$TSTUSR" - $LFS setquota -u $TSTUSR -b 0 -B ${BLIMIT}M -i 0 -I $ILIMIT $DIR || + # test for user + log "User quota (block hardlimit:$limit MB)" + $LFS setquota -u $TSTUSR -b 0 -B ${limit}M -i 0 -I 0 $DIR || error "set user quota failed" - $LFS setquota -g $TSTUSR -b 0 -B ${BLIMIT}M -i 0 -I $ILIMIT $DIR || - if is_project_quota_supported; then - error "set group quota failed" - $LFS setquota -p $TSTPRJID -b 0 -B ${BLIMIT}M -i 0 \ - -I $ILIMIT $DIR || error "set project quota failed" - fi # make sure the system is clean - local USED=$(getquota -u $TSTUSR global curinodes) - [ $USED -ne 0 ] && error "Used inode($USED) for user $TSTUSR isn't 0." - USED=$(getquota -g $TSTUSR global curinodes) - [ $USED -ne 0 ] && error "Used inode($USED) for group $TSTUSR isn't 0." - USED=$(getquota -u $TSTUSR global curspace) - [ $USED -ne 0 ] && error "Used block($USED) for user $TSTUSR isn't 0." - USED=$(getquota -g $TSTUSR global curspace) - [ $USED -ne 0 ] && error "Used block($USED) for group $TSTUSR isn't 0." - if is_project_quota_supported; then - USED=$(getquota -p $TSTPRJID global curinodes) - [ $USED -ne 0 ] && - error "Used inode($USED) for project $TSTPRJID isn't 0." - USED=$(getquota -p $TSTPRJID global curspace) - [ $USED -ne 0 ] && - error "Used block($USED) for project $TSTPRJID isn't 0." - fi + local used=$(getquota -u $TSTUSR global curspace) + [ $used -ne 0 ] && error "Used space($used) for user $TSTUSR isn't 0." - echo "Create more than $ILIMIT files and more than $BLIMIT MB ..." - createmany -m $DIR/$tdir/$tfile-0_ $((ILIMIT + 1)) || - error "create failure, expect success" - if is_project_quota_supported; then - touch $DIR/$tdir/$tfile-0_1 - change_project -p $TSTPRJID $DIR/$tdir/$tfile-0_1 - fi - $DD of=$DIR/$tdir/$tfile-0_1 count=$((BLIMIT+1)) || - error "write failure, expect success" + $LFS setstripe $testfile -c 1 || error "setstripe $testfile failed" + chown $TSTUSR.$TSTUSR $testfile || error "chown $testfile failed" - echo "Chown files to $TSTUSR.$TSTUSR ..." - for i in $(seq 0 $ILIMIT); do - chown $TSTUSR.$TSTUSR $DIR/$tdir/$tfile-0_$i || - quota_error a $TSTUSR "chown failure, expect success" - done + check_write_fallocate $testfile "user" $limit - # cleanup - unlinkmany $DIR/$tdir/$tfile-0_ $((ILIMIT + 1)) || - error "unlinkmany $DIR/$tdir/$tfile-0_ failed" - cleanup_quota_test + rm -f $testfile + wait_delete_completed || error "wait_delete_completed failed" + sync_all_data || true + used=$(getquota -u $TSTUSR global curspace) + [ $used -eq 0 ] || quota_error u $TSTUSR \ + "user quota isn't released after deletion" } -run_test 5 "Chown & chgrp successfully even out of block/file quota" +run_test 1h "Block hard limit test using fallocate" + +test_1i() { + local global_limit=200 # 200M + local limit1=10 # 10M + local TESTDIR="$DIR/$tdir/" + local testfile="$TESTDIR/$tfile-0" + local testfile1="$TESTDIR/$tfile-1" + local testfile2="$TESTDIR/$tfile-2" + local qpool1="qpool1" + + mds_supports_qp + setup_quota_test || error "setup quota failed with $?" + stack_trap cleanup_quota_test EXIT -# test dropping acquire request on master -test_6() { - local LIMIT=3 # 3M + # enable ost quota + set_ost_qtype $QTYPE || error "enable ost quota failed" - # Clear dmesg so watchdog is not triggered by previous - # test output - do_facet ost1 dmesg -c > /dev/null + log "User quota (block hardlimit:$global_limit MB)" + $LFS setquota -u $TSTUSR -b 0 -B ${global_limit}M -i 0 -I 0 $DIR || + error "set user quota failed" - setup_quota_test || error "setup quota failed with $?" - trap cleanup_quota_test EXIT + pool_add $qpool1 || error "pool_add failed" + pool_add_targets $qpool1 0 0 || + error "pool_add_targets failed" + + $LFS setquota -u $TSTUSR -B ${limit1}M --pool $qpool1 $DIR || + error "set user quota failed" # make sure the system is clean - local USED=$(getquota -u $TSTUSR global curspace) - [ $USED -ne 0 ] && error "Used space($USED) for user $TSTUSR isn't 0." + local used=$(getquota -u $TSTUSR global curspace) + [ $used -ne 0 ] && error "Used space($used) for user $TSTUSR isn't 0." - # make sure no granted quota on ost - set_ost_qtype $QTYPE || error "enable ost quota failed" - resetquota -u $TSTUSR + $LFS setstripe $TESTDIR -c 1 -i 0 || error "setstripe $TESTDIR failed" - # create file for $TSTUSR - local TESTFILE=$DIR/$tdir/$tfile-$TSTUSR - $LFS setstripe $TESTFILE -c 1 -i 0 || error "setstripe $TESTFILE failed" - chown $TSTUSR.$TSTUSR $TESTFILE || error "chown $TESTFILE failed" + # hit pool limit + test_1_check_write $testfile "user" $limit1 + $LFS setquota -u $TSTUSR -B 0 --pool $qpool1 $DIR || + error "set user quota failed" - # create file for $TSTUSR2 - local TESTFILE2=$DIR/$tdir/$tfile-$TSTUSR2 - $LFS setstripe $TESTFILE2 -c 1 -i 0 || error "setstripe $TESTFILE2 failed" - chown $TSTUSR2.$TSTUSR2 $TESTFILE2 || error "chown $TESTFILE2 failed" + $LFS quota -uv $TSTUSR --pool $qpool1 $DIR + $RUNAS $DD of=$testfile1 count=$((limit1/2)) || + quota_error u $TSTUSR "write failure, but expect success" - # cache per-ID lock for $TSTUSR on slave - $LFS setquota -u $TSTUSR -b 0 -B ${LIMIT}M -i 0 -I 0 $DIR || - error "set quota failed" - $RUNAS $DD of=$TESTFILE count=1 || - error "write $TESTFILE failure, expect success" - $RUNAS2 $DD of=$TESTFILE2 count=1 || - error "write $TESTFILE2 failure, expect success" - sync; sync + rm -f $testfile + rm -f $testfile1 + wait_delete_completed || error "wait_delete_completed failed" sync_all_data || true - #define QUOTA_DQACQ 601 - #define OBD_FAIL_PTLRPC_DROP_REQ_OPC 0x513 - lustre_fail mds 0x513 601 + $LFS setquota -u $TSTUSR -B ${limit1}M --pool $qpool1 $DIR || + error "set user quota failed" + test_1_check_write $testfile "user" $limit1 + local tmp_limit=$(($limit1*2)) + # increase pool limit + $LFS setquota -u $TSTUSR -B ${tmp_limit}M --pool $qpool1 $DIR || + error "set user quota failed" + # now write shouldn't fail + $RUNAS $DD of=$testfile1 count=$((limit1/3)) || + quota_error u $TSTUSR "write failure, but expect success" + # decrease pool limit + $LFS setquota -u $TSTUSR -B ${limit1}M --pool $qpool1 $DIR || + error "set user quota failed" + $RUNAS $DD of=$testfile2 count=$((limit1/3)) + # flush cache, ensure noquota flag is set on client + cancel_lru_locks osc + sync; sync_all_data || true + $RUNAS $DD of=$testfile2 seek=$((limit1/3)) count=1 && + quota_error u $TSTUSR "write success, but expect failure" + return 0 +} +run_test 1i "Quota pools: different limit and usage relations" - if at_is_enabled; then - at_max_saved=$(at_max_get ost1) - at_max_set $TIMEOUT ost1 - fi +# test inode hardlimit +test_2() { + local testfile="$DIR/$tdir/$tfile-0" + local least_qunit=$(do_facet mds1 $LCTL get_param -n \ + qmt.$FSNAME-QMT0000.md-0x0.info | + sed -e 's/least qunit/least_qunit/' | + awk '/least_qunit/{ print $2 }') + local limit - do_facet ost1 $LCTL set_param \ - osd-*.$FSNAME-OST*.quota_slave.timeout=$((TIMEOUT / 2)) + [ "$SLOW" = "no" ] && limit=$((least_qunit * 2)) || + limit=$((least_qunit * 1024)) + echo "least_qunit: '$least_qunit', limit: '$limit'" - # write to un-enforced ID ($TSTUSR2) should succeed - $RUNAS2 $DD of=$TESTFILE2 count=$LIMIT seek=1 oflag=sync conv=notrunc || - error "write failure, expect success" + local free_inodes=$(mdt_free_inodes 0) + echo "$free_inodes free inodes on master MDT" + [ $free_inodes -lt $limit ] && + skip "not enough free inodes $free_inodes required $limit" - # write to enforced ID ($TSTUSR) in background, exceeding limit - # to make sure DQACQ is sent - $RUNAS $DD of=$TESTFILE count=$LIMIT seek=1 oflag=sync conv=notrunc & - DDPID=$! + setup_quota_test || error "setup quota failed with $?" - # watchdog timer uses a factor of 2 - echo "Sleep for $((TIMEOUT * 2 + 1)) seconds ..." - sleep $((TIMEOUT * 2 + 1)) + # enable mdt quota + set_mdt_qtype $QTYPE || error "enable mdt quota failed" - [ $at_max_saved -ne 0 ] && at_max_set $at_max_saved ost1 + # test for user + log "User quota (inode hardlimit:$limit files)" + $LFS setquota -u $TSTUSR -b 0 -B 0 -i 0 -I $limit $DIR || + error "set user quota failed" - # write should be blocked and never finished - if ! ps -p $DDPID > /dev/null 2>&1; then - lustre_fail mds 0 0 - error "write finished incorrectly!" - fi + # make sure the system is clean + local used=$(getquota -u $TSTUSR global curinodes) + [ $used -ne 0 ] && error "Used inodes($used) for user $TSTUSR isn't 0." - lustre_fail mds 0 0 + log "Create $((limit - least_qunit)) files ..." + $RUNAS createmany -m ${testfile} $((limit - least_qunit)) || + quota_error u $TSTUSR "user create failure, but expect success" + # it is ok, if it fails on the last qunit + $RUNAS createmany -m ${testfile}_yyy $least_qunit || true + log "Create out of file quota ..." + $RUNAS touch ${testfile}_xxx && + quota_error u $TSTUSR "user create success, but expect EDQUOT" - # no watchdog is triggered - do_facet ost1 dmesg > $TMP/lustre-log-${TESTNAME}.log - watchdog=$(awk '/Service thread pid/ && /was inactive/ \ - { print; }' $TMP/lustre-log-${TESTNAME}.log) - [ -z "$watchdog" ] || error "$watchdog" + # cleanup + unlinkmany ${testfile} $((limit - least_qunit)) || + error "unlinkmany $testfile failed" + # if 2nd createmany got EDQUOT, not all of nodes would be created + unlinkmany ${testfile}_yyy $least_qunit || true + rm -f ${testfile}_xxx + wait_delete_completed - rm -f $TMP/lustre-log-${TESTNAME}.log + used=$(getquota -u $TSTUSR global curinodes) + [ $used -ne 0 ] && quota_error u $TSTUSR \ + "user quota isn't released after deletion" + resetquota -u $TSTUSR - # write should continue then fail with EDQUOT - local count=0 - local c_size - while [ true ]; do - if ! ps -p ${DDPID} > /dev/null 2>&1; then break; fi - if [ $count -ge 240 ]; then - quota_error u $TSTUSR "dd not finished in $count secs" - fi - count=$((count + 1)) - if [ $((count % 30)) -eq 0 ]; then - c_size=$(stat -c %s $TESTFILE) - echo "Waiting $count secs. $c_size" - $SHOW_QUOTA_USER - fi - sleep 1 - done + # test for group + log "--------------------------------------" + log "Group quota (inode hardlimit:$limit files)" + $LFS setquota -g $TSTUSR -b 0 -B 0 -i 0 -I $limit $DIR || + error "set group quota failed" - cleanup_quota_test -} -run_test 6 "Test dropping acquire request on master" + testfile=$DIR/$tdir/$tfile-1 + # make sure the system is clean + used=$(getquota -g $TSTUSR global curinodes) + [ $used -ne 0 ] && error "Used inodes($used) for group $TSTUSR isn't 0." -# quota reintegration (global index) -test_7a() { - local TESTFILE=$DIR/$tdir/$tfile - local LIMIT=20 # 20M + log "Create $limit files ..." + $RUNAS createmany -m ${testfile} $((limit - least_qunit)) || + quota_error g $TSTUSR "group create failure, but expect success" + $RUNAS createmany -m ${testfile}_yyy $least_qunit || + log "Create out of file quota ..." + $RUNAS touch ${testfile}_xxx && + quota_error g $TSTUSR "group create success, but expect EDQUOT" - [ "$SLOW" = "no" ] && LIMIT=5 + # cleanup + unlinkmany ${testfile} $((limit - least_qunit)) || + error "unlinkmany $testfile failed" + unlinkmany ${testfile}_yyy $least_qunit || true + rm -f ${testfile}_xxx + wait_delete_completed - setup_quota_test || error "setup quota failed with $?" - trap cleanup_quota_test EXIT + used=$(getquota -g $TSTUSR global curinodes) + [ $used -ne 0 ] && quota_error g $TSTUSR \ + "user quota isn't released after deletion" - # make sure the system is clean - local USED=$(getquota -u $TSTUSR global curspace) - [ $USED -ne 0 ] && error "Used space($USED) for user $TSTUSR isn't 0." + resetquota -g $TSTUSR + ! is_project_quota_supported && + echo "Skip project quota is not supported" && return 0 - # make sure no granted quota on ost1 - set_ost_qtype $QTYPE || error "enable ost quota failed" - resetquota -u $TSTUSR - set_ost_qtype "none" || error "disable ost quota failed" + # test for project + log "--------------------------------------" + log "Project quota (inode hardlimit:$limit files)" + $LFS setquota -p $TSTPRJID -b 0 -B 0 -i 0 -I $limit $DIR || + error "set project quota failed" - local OSTUUID=$(ostuuid_from_index 0) - USED=$(getquota -u $TSTUSR $OSTUUID bhardlimit) - [ $USED -ne 0 ] && - error "limit($USED) on $OSTUUID for user $TSTUSR isn't 0" + testfile=$DIR/$tdir/$tfile-1 + # make sure the system is clean + used=$(getquota -p $TSTPRJID global curinodes) + [ $used -ne 0 ] && + error "Used inodes($used) for project $TSTPRJID isn't 0" - # create test file - $LFS setstripe $TESTFILE -c 1 -i 0 || error "setstripe $TESTFILE failed" - chown $TSTUSR.$TSTUSR $TESTFILE || error "chown $TESTFILE failed" + change_project -sp $TSTPRJID $DIR/$tdir + log "Create $limit files ..." + $RUNAS createmany -m ${testfile} $((limit-least_qunit)) || + quota_error p $TSTPRJID \ + "project create fail, but expect success" + $RUNAS createmany -m ${testfile}_yyy $least_qunit || true + log "Create out of file quota ..." + $RUNAS touch ${testfile}_xxx && quota_error p $TSTPRJID \ + "project create success, but expect EDQUOT" + change_project -C $DIR/$tdir - echo "Stop ost1..." - stop ost1 + cleanup_quota_test + used=$(getquota -p $TSTPRJID global curinodes) + [ $used -eq 0 ] || quota_error p $TSTPRJID \ + "project quota isn't released after deletion" - echo "Enable quota & set quota limit for $TSTUSR" - set_ost_qtype $QTYPE || error "enable ost quota failed" - $LFS setquota -u $TSTUSR -b 0 -B ${LIMIT}M -i 0 -I 0 $DIR || - error "set quota failed" +} +run_test 2 "File hard limit (normal use and out of quota)" - echo "Start ost1..." - start ost1 $(ostdevname 1) $OST_MOUNT_OPTS || error "start ost1 failed" - quota_init +test_block_soft() { + local testfile=$1 + local grace=$2 + local limit=$3 + local OFFSET=0 + local qtype=$4 + local pool=$5 + local soft_limit=$(do_facet $SINGLEMDS $LCTL get_param -n \ + qmt.$FSNAME-QMT0000.dt-0x0.soft_least_qunit) - wait_ost_reint $QTYPE || error "reintegration failed" + setup_quota_test - # hardlimit should have been fetched by slave during global - # reintegration, write will exceed quota - $RUNAS $DD of=$TESTFILE count=$((LIMIT + 1)) oflag=sync && - quota_error u $TSTUSR "write success, but expect EDQUOT" + $LFS setstripe $testfile -c 1 -i 0 + chown $TSTUSR.$TSTUSR $testfile + [ "$qtype" == "p" ] && is_project_quota_supported && + change_project -p $TSTPRJID $testfile - rm -f $TESTFILE - wait_delete_completed - sync_all_data || true - sleep 3 + echo "Write up to soft limit" + $RUNAS $DD of=$testfile count=$limit || + quota_error a $TSTUSR "write failure, but expect success" + OFFSET=$((limit * 1024)) + cancel_lru_locks osc - echo "Stop ost1..." - stop ost1 + echo "Write to exceed soft limit" + $RUNAS dd if=/dev/zero of=$testfile bs=1K count=10 seek=$OFFSET || + quota_error a $TSTUSR "write failure, but expect success" + OFFSET=$((OFFSET + 1024)) # make sure we don't write to same block + cancel_lru_locks osc - $LFS setquota -u $TSTUSR -b 0 -B 0 -i 0 -I 0 $DIR || - error "clear quota failed" + echo "mmap write when over soft limit" + $RUNAS $MULTIOP $testfile.mmap OT40960SMW || + quota_error a $TSTUSR "mmap write failure, but expect success" + cancel_lru_locks osc - echo "Start ost1..." - start ost1 $(ostdevname 1) $OST_MOUNT_OPTS || error "start ost1 failed" - quota_init + $SHOW_QUOTA_USER + $SHOW_QUOTA_GROUP + $SHOW_QUOTA_PROJID + $SHOW_QUOTA_INFO_USER + $SHOW_QUOTA_INFO_GROUP + $SHOW_QUOTA_INFO_PROJID - wait_ost_reint $QTYPE || error "reintegration failed" + echo "Write before timer goes off" + $RUNAS dd if=/dev/zero of=$testfile bs=1K count=10 seek=$OFFSET || + quota_error a $TSTUSR "write failure, but expect success" + OFFSET=$((OFFSET + 1024)) + cancel_lru_locks osc - # hardlimit should be cleared on slave during reintegration - $RUNAS $DD of=$TESTFILE count=$((LIMIT + 1)) oflag=sync || - quota_error u $TSTUSR "write error, but expect success" + wait_grace_time $qtype "block" $pool - cleanup_quota_test -} -run_test 7a "Quota reintegration (global index)" + $SHOW_QUOTA_USER + $SHOW_QUOTA_GROUP + $SHOW_QUOTA_PROJID + $SHOW_QUOTA_INFO_USER + $SHOW_QUOTA_INFO_GROUP + $SHOW_QUOTA_INFO_PROJID -# quota reintegration (slave index) -test_7b() { - local LIMIT="100G" - local TESTFILE=$DIR/$tdir/$tfile + log "Write after timer goes off" + # maybe cache write, ignore. + # write up to soft least quint to consume all + # possible slave granted space. + $RUNAS dd if=/dev/zero of=$testfile bs=1K \ + count=$soft_limit seek=$OFFSET || true + OFFSET=$((OFFSET + soft_limit)) + cancel_lru_locks osc + log "Write after cancel lru locks" + $RUNAS dd if=/dev/zero of=$testfile bs=1K count=10 seek=$OFFSET && + quota_error a $TSTUSR "write success, but expect EDQUOT" - setup_quota_test || error "setup quota failed with $?" - trap cleanup_quota_test EXIT + $SHOW_QUOTA_USER + $SHOW_QUOTA_GROUP + $SHOW_QUOTA_PROJID + $SHOW_QUOTA_INFO_USER + $SHOW_QUOTA_INFO_GROUP + $SHOW_QUOTA_INFO_PROJID - # make sure the system is clean - local USED=$(getquota -u $TSTUSR global curspace) - [ $USED -ne 0 ] && error "Used space($USED) for user $TSTUSR isn't 0." + echo "Unlink file to stop timer" + rm -f $testfile + wait_delete_completed + sync_all_data || true - # make sure no granted quota on ost1 - set_ost_qtype $QTYPE || error "enable ost quota failed" - resetquota -u $TSTUSR - set_ost_qtype "none" || error "disable ost quota failed" + $SHOW_QUOTA_USER + $SHOW_QUOTA_GROUP + $SHOW_QUOTA_PROJID + $SHOW_QUOTA_INFO_USER + $SHOW_QUOTA_INFO_GROUP + $SHOW_QUOTA_INFO_PROJID - local OSTUUID=$(ostuuid_from_index 0) - USED=$(getquota -u $TSTUSR $OSTUUID bhardlimit) - [ $USED -ne 0 ] && - error "limit($USED) on $OSTUUID for user $TSTUSR isn't 0" + $LFS setstripe $testfile -c 1 -i 0 + chown $TSTUSR.$TSTUSR $testfile + [ "$qtype" == "p" ] && change_project -p $TSTPRJID $testfile - # create test file - $LFS setstripe $TESTFILE -c 1 -i 0 || error "setstripe $TESTFILE failed" - chown $TSTUSR.$TSTUSR $TESTFILE || error "chown $TESTFILE failed" + echo "Write ..." + $RUNAS $DD of=$testfile count=$limit || + quota_error a $TSTUSR "write failure, but expect success" + # cleanup + cleanup_quota_test +} - # consume some space to make sure the granted space will not - # be released during reconciliation - $RUNAS $DD of=$TESTFILE count=1 oflag=sync || - error "consume space failure, expect success" +# block soft limit +test_3a() { + local grace=20 # seconds + if [ $(facet_fstype $SINGLEMDS) = "zfs" ]; then + grace=60 + fi + local testfile=$DIR/$tdir/$tfile-0 - # define OBD_FAIL_QUOTA_EDQUOT 0xa02 - lustre_fail mds 0xa02 + # get minimum soft qunit size + local limit=$(( $(do_facet $SINGLEMDS $LCTL get_param -n \ + qmt.$FSNAME-QMT0000.dt-0x0.soft_least_qunit) / 1024 )) set_ost_qtype $QTYPE || error "enable ost quota failed" - $LFS setquota -u $TSTUSR -b 0 -B $LIMIT -i 0 -I 0 $DIR || - error "set quota failed" - # ignore the write error - $RUNAS $DD of=$TESTFILE count=1 seek=1 oflag=sync conv=notrunc + echo "User quota (soft limit:$limit MB grace:$grace seconds)" + # make sure the system is clean + local used=$(getquota -u $TSTUSR global curspace) + [ $used -ne 0 ] && error "Used space($used) for user $TSTUSR isn't 0." - local old_used=$(getquota -u $TSTUSR $OSTUUID bhardlimit) + $LFS setquota -t -u --block-grace $grace --inode-grace \ + $MAX_IQ_TIME $DIR || error "set user grace time failed" + $LFS setquota -u $TSTUSR -b ${limit}M -B 0 -i 0 -I 0 $DIR || + error "set user quota failed" - lustre_fail mds 0 + test_block_soft $testfile $grace $limit "u" - echo "Restart ost to trigger reintegration..." - stop ost1 - start ost1 $(ostdevname 1) $OST_MOUNT_OPTS || error "start ost1 failed" - quota_init + echo "Group quota (soft limit:$limit MB grace:$grace seconds)" + testfile=$DIR/$tdir/$tfile-1 + # make sure the system is clean + used=$(getquota -g $TSTUSR global curspace) + [ $used -ne 0 ] && error "Used space($used) for group $TSTUSR isn't 0." - wait_ost_reint $QTYPE || error "reintegration failed" + $LFS setquota -t -g --block-grace $grace --inode-grace \ + $MAX_IQ_TIME $DIR || error "set group grace time failed" + $LFS setquota -g $TSTUSR -b ${limit}M -B 0 -i 0 -I 0 $DIR || + error "set group quota failed" - USED=$(getquota -u $TSTUSR $OSTUUID bhardlimit) - [ $USED -gt $old_used ] || error "limit on $OSTUUID $USED <= $old_used" + test_block_soft $testfile $grace $limit "g" - cleanup_quota_test - $SHOW_QUOTA_USER -} -run_test 7b "Quota reintegration (slave index)" + if is_project_quota_supported; then + echo "Project quota (soft limit:$limit MB grace:$grace sec)" + testfile=$DIR/$tdir/$tfile-2 + # make sure the system is clean + used=$(getquota -p $TSTPRJID global curspace) + [ $used -ne 0 ] && error \ + "Used space($used) for project $TSTPRJID isn't 0." -# quota reintegration (restart mds during reintegration) -test_7c() { - local LIMIT=20 # 20M - local TESTFILE=$DIR/$tdir/$tfile + $LFS setquota -t -p --block-grace $grace --inode-grace \ + $MAX_IQ_TIME $DIR || + error "set project grace time failed" + $LFS setquota -p $TSTPRJID -b ${limit}M -B 0 -i 0 -I 0 \ + $DIR || error "set project quota failed" - [ "$SLOW" = "no" ] && LIMIT=5 + test_block_soft $testfile $grace $limit "p" + resetquota -p $TSTPRJID + $LFS setquota -t -p --block-grace $MAX_DQ_TIME --inode-grace \ + $MAX_IQ_TIME $DIR || + error "restore project grace time failed" + fi - setup_quota_test || error "setup quota failed with $?" - trap cleanup_quota_test EXIT + # cleanup + $LFS setquota -t -u --block-grace $MAX_DQ_TIME --inode-grace \ + $MAX_IQ_TIME $DIR || error "restore user grace time failed" + $LFS setquota -t -g --block-grace $MAX_DQ_TIME --inode-grace \ + $MAX_IQ_TIME $DIR || error "restore group grace time failed" +} +run_test 3a "Block soft limit (start timer, timer goes off, stop timer)" - # make sure the system is clean - local USED=$(getquota -u $TSTUSR global curspace) - [ $USED -ne 0 ] && error "Used space($USED) for user $TSTUSR isn't 0." - - set_ost_qtype "none" || error "disable ost quota failed" - $LFS setquota -u $TSTUSR -b 0 -B ${LIMIT}M -i 0 -I 0 $DIR || - error "set quota failed" +test_3b() { + local grace=20 # seconds + local qpool="qpool1" + if [ $(facet_fstype $SINGLEMDS) = "zfs" ]; then + grace=60 + fi + local testfile=$DIR/$tdir/$tfile-0 - # define OBD_FAIL_QUOTA_DELAY_REINT 0xa03 - lustre_fail ost 0xa03 + mds_supports_qp + # get minimum soft qunit size + local limit=$(( $(do_facet $SINGLEMDS $LCTL get_param -n \ + qmt.$FSNAME-QMT0000.dt-0x0.soft_least_qunit) / 1024 )) + local glbl_limit=$((2*limit)) + local glbl_grace=$((2*grace)) + echo "limit $limit glbl_limit $glbl_limit" + echo "grace $grace glbl_grace $glbl_grace" - # enable ost quota set_ost_qtype $QTYPE || error "enable ost quota failed" - # trigger reintegration - local procf="osd-$(facet_fstype ost1).$FSNAME-OST*." - procf=${procf}quota_slave.force_reint - do_facet ost1 $LCTL set_param $procf=1 || - error "force reintegration failed" - - echo "Stop mds..." - stop mds1 - lustre_fail ost 0 + echo "User quota in $qpool(soft limit:$limit MB grace:$grace seconds)" + # make sure the system is clean + local used=$(getquota -u $TSTUSR global curspace) + [ $used -ne 0 ] && error "Used space($used) for user $TSTUSR isn't 0." - echo "Start mds..." - start mds1 $(mdsdevname 1) $MDS_MOUNT_OPTS - quota_init + pool_add $qpool || error "pool_add failed" + pool_add_targets $qpool 0 1 || + error "pool_add_targets failed" - # wait longer than usual to make sure the reintegration - # is triggered by quota wb thread. - wait_ost_reint $QTYPE 200 || error "reintegration failed" + $LFS setquota -t -u --block-grace $glbl_grace --inode-grace \ + $MAX_IQ_TIME $DIR || error "set user grace time failed" + $LFS setquota -t -u --block-grace $grace \ + --pool $qpool $DIR || error "set user grace time failed" - # hardlimit should have been fetched by slave during global - # reintegration, write will exceed quota - $RUNAS $DD of=$TESTFILE count=$((LIMIT + 1)) oflag=sync && - quota_error u $TSTUSR "write success, but expect EDQUOT" + $LFS setquota -u $TSTUSR -b ${glbl_limit}M -B 0 -i 0 -I 0 $DIR || + error "set user quota failed" + $LFS setquota -u $TSTUSR -b ${limit}M -B 0 --pool $qpool $DIR || + error "set user quota failed" - cleanup_quota_test -} -run_test 7c "Quota reintegration (restart mds during reintegration)" + test_block_soft $testfile $grace $limit "u" $qpool -# Quota reintegration (Transfer index in multiple bulks) -test_7d(){ - local TESTFILE=$DIR/$tdir/$tfile - local TESTFILE1="$DIR/$tdir/$tfile"-1 - local limit=20 #20M + echo "Group quota in $qpool(soft limit:$limit MB grace:$grace seconds)" + testfile=$DIR/$tdir/$tfile-1 + # make sure the system is clean + used=$(getquota -g $TSTUSR global curspace) + [ $used -ne 0 ] && error "Used space($used) for group $TSTUSR isn't 0." - setup_quota_test || error "setup quota failed with $?" - trap cleanup_quota_test EXIT + $LFS setquota -t -g --block-grace $glbl_grace --inode-grace \ + $MAX_IQ_TIME $DIR || error "set group grace time failed" + $LFS setquota -t -g --block-grace $grace \ + --pool $qpool $DIR || error "set group grace time failed" - set_ost_qtype "none" || error "disable ost quota failed" - $LFS setquota -u $TSTUSR -B ${limit}M $DIR || - error "set quota for $TSTUSR failed" - $LFS setquota -u $TSTUSR2 -B ${limit}M $DIR || - error "set quota for $TSTUSR2 failed" + $LFS setquota -g $TSTUSR -b ${glbl_limit}M -B 0 -i 0 -I 0 $DIR || + error "set group quota failed" + $LFS setquota -g $TSTUSR -b ${limit}M -B 0 --pool $qpool $DIR || + error "set group quota failed" - #define OBD_FAIL_OBD_IDX_READ_BREAK 0x608 - lustre_fail mds 0x608 0 + test_block_soft $testfile $grace $limit "g" $qpool - # enable quota to tirgger reintegration - set_ost_qtype "u" || error "enable ost quota failed" - wait_ost_reint "u" || error "reintegration failed" + if is_project_quota_supported; then + echo "Project quota in $qpool(soft:$limit MB grace:$grace sec)" + testfile=$DIR/$tdir/$tfile-2 + # make sure the system is clean + used=$(getquota -p $TSTPRJID global curspace) + [ $used -ne 0 ] && error \ + "Used space($used) for project $TSTPRJID isn't 0." - lustre_fail mds 0 + $LFS setquota -t -p --block-grace $glbl_grace --inode-grace \ + $MAX_IQ_TIME $DIR || + error "set project grace time failed" + $LFS setquota -t -p --block-grace $grace \ + --pool $qpool $DIR || + error "set project grace time failed" - # hardlimit should have been fetched by slave during global - # reintegration, write will exceed quota - $RUNAS $DD of=$TESTFILE count=$((limit + 1)) oflag=sync && - quota_error u $TSTUSR "$TSTUSR write success, expect EDQUOT" + $LFS setquota -p $TSTPRJID -b ${glbl_limit}M -B 0 -i 0 -I 0 \ + $DIR || error "set project quota failed" + $LFS setquota -p $TSTPRJID -b ${limit}M -B 0 \ + --pool $qpool $DIR || error "set project quota failed" - $RUNAS2 $DD of=$TESTFILE1 count=$((limit + 1)) oflag=sync && - quota_error u $TSTUSR2 "$TSTUSR2 write success, expect EDQUOT" + test_block_soft $testfile $grace $limit "p" $qpool + resetquota -p $TSTPRJID + $LFS setquota -t -p --block-grace $MAX_DQ_TIME --inode-grace \ + $MAX_IQ_TIME $DIR || + error "restore project grace time failed" + $LFS setquota -t -p --block-grace $MAX_DQ_TIME --pool $qpool \ + $DIR || error "set project grace time failed" + fi - cleanup_quota_test + # cleanup + $LFS setquota -t -u --block-grace $MAX_DQ_TIME --inode-grace \ + $MAX_IQ_TIME $DIR || error "restore user grace time failed" + $LFS setquota -t -u --block-grace $MAX_DQ_TIME \ + --pool $qpool $DIR || error "restore user grace time failed" + $LFS setquota -t -g --block-grace $MAX_DQ_TIME --inode-grace \ + $MAX_IQ_TIME $DIR || error "restore group grace time failed" + $LFS setquota -t -g --block-grace $MAX_DQ_TIME \ + --pool $qpool $DIR || error "restore group grace time failed" } -run_test 7d "Quota reintegration (Transfer index in multiple bulks)" +run_test 3b "Quota pools: Block soft limit (start timer, expires, stop timer)" -# quota reintegration (inode limits) -test_7e() { - [ "$MDSCOUNT" -lt "2" ] && skip "needs >= 2 MDTs" +test_3c() { + local grace=20 # seconds + local qpool="qpool1" + local qpool2="qpool2" + if [ $(facet_fstype $SINGLEMDS) = "zfs" ]; then + grace=60 + fi + local testfile=$DIR/$tdir/$tfile-0 - # LU-2435: skip this quota test if underlying zfs version has not - # supported native dnode accounting - [ "$(facet_fstype mds1)" == "zfs" ] && { - local F="feature@userobj_accounting" - local pool=$(zpool_name mds1) - local feature=$(do_facet mds1 $ZPOOL get -H $F $pool) + mds_supports_qp + # get minimum soft qunit size + local limit=$(( $(do_facet $SINGLEMDS $LCTL get_param -n \ + qmt.$FSNAME-QMT0000.dt-0x0.soft_least_qunit) / 1024 )) + local limit2=$((limit+4)) + local glbl_limit=$((limit+8)) + local grace1=$((grace+10)) + local grace2=$grace + local glbl_grace=$((grace+20)) + echo "limit $limit limit2 $limit2 glbl_limit $glbl_limit" + echo "grace1 $grace1 grace2 $grace2 glbl_grace $glbl_grace" - [[ "$feature" != *" active "* ]] && - skip "requires zpool with active userobj_accounting" - } + set_ost_qtype $QTYPE || error "enable ost quota failed" - local ilimit=$((1024 * 2)) # 2k inodes - local TESTFILE=$DIR/${tdir}-1/$tfile + echo "User quota in qpool2(soft:$limit2 MB grace:$grace2 seconds)" + # make sure the system is clean + local used=$(getquota -u $TSTUSR global curspace) + [ $used -ne 0 ] && error "Used space($used) for user $TSTUSR isn't 0." - setup_quota_test || error "setup quota failed with $?" - trap cleanup_quota_test EXIT + pool_add $qpool || error "pool_add failed" + pool_add_targets $qpool 0 1 || + error "pool_add_targets failed" - # make sure the system is clean - local USED=$(getquota -u $TSTUSR global curinodes) - [ $USED -ne 0 ] && error "Used inode($USED) for user $TSTUSR isn't 0." + pool_add $qpool2 || error "pool_add failed" + pool_add_targets $qpool2 0 1 || + error "pool_add_targets failed" - # make sure no granted quota on mdt1 - set_mdt_qtype $QTYPE || error "enable mdt quota failed" - resetquota -u $TSTUSR - set_mdt_qtype "none" || error "disable mdt quota failed" - local MDTUUID=$(mdtuuid_from_index $((MDSCOUNT - 1))) - USED=$(getquota -u $TSTUSR $MDTUUID ihardlimit) - [ $USED -ne 0 ] && error "limit($USED) on $MDTUUID for user" \ - "$TSTUSR isn't 0." + $LFS setquota -t -u --block-grace $glbl_grace --inode-grace \ + $MAX_IQ_TIME $DIR || error "set user grace time failed" + $LFS setquota -t -u --block-grace $grace1 \ + --pool $qpool $DIR || error "set user grace time failed" + $LFS setquota -t -u --block-grace $grace2 \ + --pool $qpool2 $DIR || error "set user grace time failed" - echo "Stop mds${MDSCOUNT}..." - stop mds${MDSCOUNT} + $LFS setquota -u $TSTUSR -b ${glbl_limit}M -B 0 -i 0 -I 0 $DIR || + error "set user quota failed" + $LFS setquota -u $TSTUSR -b ${limit}M -B 0 --pool $qpool $DIR || + error "set user quota failed" + # qpool has minimum soft limit, but its grace is greater than + # the grace period of qpool2. Thus write shouldn't fail when + # hit qpool soft limit - only when reaches up qpool2 limit + # after grace2 seconds. + $LFS setquota -u $TSTUSR -b ${limit2}M -B 0 --pool $qpool2 $DIR || + error "set user quota failed" - echo "Enable quota & set quota limit for $TSTUSR" - set_mdt_qtype $QTYPE || error "enable mdt quota failed" - $LFS setquota -u $TSTUSR -b 0 -B 0 -i 0 -I $ilimit $DIR || - error "set quota failed" + test_block_soft $testfile $grace2 $limit2 "u" $qpool2 - echo "Start mds${MDSCOUNT}..." - start mds${MDSCOUNT} $(mdsdevname $MDSCOUNT) $MDS_MOUNT_OPTS - quota_init + # cleanup + $LFS setquota -t -u --block-grace $MAX_DQ_TIME --inode-grace \ + $MAX_IQ_TIME $DIR || error "restore user grace time failed" + $LFS setquota -t -u --block-grace $MAX_DQ_TIME \ + --pool $qpool $DIR || error "restore user grace time failed" + $LFS setquota -t -u --block-grace $MAX_DQ_TIME \ + --pool $qpool2 $DIR || error "restore user grace time failed" +} +run_test 3c "Quota pools: check block soft limit on different pools" - wait_mdt_reint $QTYPE || error "reintegration failed" +test_file_soft() { + local TESTFILE=$1 + local LIMIT=$2 + local grace=$3 + local qtype=$4 + local SOFT_LIMIT=$(do_facet $SINGLEMDS $LCTL get_param -n \ + qmt.$FSNAME-QMT0000.md-0x0.soft_least_qunit) - echo "create remote dir" - $LFS mkdir -i $((MDSCOUNT - 1)) $DIR/${tdir}-1 || - error "create remote dir failed" - chmod 0777 $DIR/${tdir}-1 + setup_quota_test + is_project_quota_supported && change_project -sp $TSTPRJID $DIR/$tdir - # hardlimit should have been fetched by slave during global - # reintegration, create will exceed quota - $RUNAS createmany -m $TESTFILE $((ilimit + 1)) && - quota_error u $TSTUSR "create succeeded, expect EDQUOT" + echo "Create files to exceed soft limit" + $RUNAS createmany -m ${TESTFILE}_ $((LIMIT + 1)) || + quota_error a $TSTUSR "create failure, but expect success" + local trigger_time=$(date +%s) - $RUNAS unlinkmany $TESTFILE $ilimit || error "unlink files failed" - wait_delete_completed sync_all_data || true - echo "Stop mds${MDSCOUNT}..." - stop mds${MDSCOUNT} + local cur_time=$(date +%s) + [ $(($cur_time - $trigger_time)) -ge $grace ] && + error "Passed grace time $grace, $trigger_time, $cur_time" - $LFS setquota -u $TSTUSR -b 0 -B 0 -i 0 -I 0 $DIR || - error "clear quota failed" + echo "Create file before timer goes off" + $RUNAS touch ${TESTFILE}_before || + quota_error a $TSTUSR "failed create before timer expired," \ + "but expect success. $trigger_time, $cur_time" + sync_all_data || true - echo "Start mds${MDSCOUNT}..." - start mds${MDSCOUNT} $(mdsdevname $MDSCOUNT) $MDS_MOUNT_OPTS - quota_init + wait_grace_time $qtype "file" - wait_mdt_reint $QTYPE || error "reintegration failed" + $SHOW_QUOTA_USER + $SHOW_QUOTA_GROUP + $SHOW_QUOTA_PROJID + $SHOW_QUOTA_INFO_USER + $SHOW_QUOTA_INFO_GROUP + $SHOW_QUOTA_INFO_PROJID - # hardlimit should be cleared on slave during reintegration - $RUNAS createmany -m $TESTFILE $((ilimit + 1)) || - quota_error u $TSTUSR "create failed, expect success" + echo "Create file after timer goes off" + # exceed least soft limit is possible + $RUNAS createmany -m ${TESTFILE}_after_3 $((SOFT_LIMIT + 1)) && + quota_error a $TSTUSR "create after timer expired," \ + "but expect EDQUOT" + sync_all_data || true - $RUNAS unlinkmany $TESTFILE $((ilimit + 1)) || error "unlink failed" - rmdir $DIR/${tdir}-1 || error "unlink remote dir failed" + $SHOW_QUOTA_USER + $SHOW_QUOTA_GROUP + $SHOW_QUOTA_PROJID + $SHOW_QUOTA_INFO_USER + $SHOW_QUOTA_INFO_GROUP + $SHOW_QUOTA_INFO_PROJID + + echo "Unlink files to stop timer" + find $(dirname $TESTFILE) -name "$(basename ${TESTFILE})*" | xargs rm -f + wait_delete_completed + + echo "Create file" + $RUNAS touch ${TESTFILE}_xxx || + quota_error a $TSTUSR "touch after timer stop failure," \ + "but expect success" + sync_all_data || true + # cleanup cleanup_quota_test } -run_test 7e "Quota reintegration (inode limits)" - -# run dbench with quota enabled -test_8() { - local BLK_LIMIT="100g" #100G - local FILE_LIMIT=1000000 - setup_quota_test || error "setup quota failed with $?" - trap cleanup_quota_test EXIT +# file soft limit +test_4a() { + local LIMIT=$(do_facet $SINGLEMDS $LCTL get_param -n \ + qmt.$FSNAME-QMT0000.md-0x0.soft_least_qunit) + local TESTFILE=$DIR/$tdir/$tfile-0 + local GRACE=12 + [ "$mds1_FSTYPE" = zfs ] && GRACE=20 set_mdt_qtype $QTYPE || error "enable mdt quota failed" - set_ost_qtype $QTYPE || error "enable ost quota failed" - echo "Set enough high limit for user: $TSTUSR" - $LFS setquota -u $TSTUSR -b 0 -B $BLK_LIMIT -i 0 -I $FILE_LIMIT $DIR || - error "set user quota failed" - echo "Set enough high limit for group: $TSTUSR" - $LFS setquota -g $TSTUSR -b 0 -B $BLK_LIMIT -i 0 -I $FILE_LIMIT $DIR || - error "set group quota failed" - if is_project_quota_supported; then - change_project -sp $TSTPRJID $DIR/$tdir - echo "Set enough high limit for project: $TSTPRJID" - $LFS setquota -p $TSTPRJID -b 0 \ - -B $BLK_LIMIT -i 0 -I $FILE_LIMIT $DIR || - error "set project quota failed" - fi + echo "User quota (soft limit:$LIMIT files grace:$GRACE seconds)" + # make sure the system is clean + local USED=$(getquota -u $TSTUSR global curinodes) + [ $USED -ne 0 ] && error "Used space($USED) for user $TSTUSR isn't 0." - local duration="" - [ "$SLOW" = "no" ] && duration=" -t 120" - $RUNAS bash rundbench -D $DIR/$tdir 3 $duration || - quota_error a $TSTUSR "dbench failed!" + $LFS setquota -t -u --block-grace $MAX_DQ_TIME --inode-grace \ + $GRACE $DIR || error "set user grace time failed" + $LFS setquota -u $TSTUSR -b 0 -B 0 -i $LIMIT -I 0 $DIR || + error "set user quota failed" - is_project_quota_supported && change_project -C $DIR/$tdir - cleanup_quota_test -} -run_test 8 "Run dbench with quota enabled" + test_file_soft $TESTFILE $LIMIT $GRACE "u" -# this check is just for test_9 -OST0_MIN=4900000 #4.67G + echo "Group quota (soft limit:$LIMIT files grace:$GRACE seconds)" + # make sure the system is clean + USED=$(getquota -g $TSTUSR global curinodes) + [ $USED -ne 0 ] && error "Used space($USED) for group $TSTUSR isn't 0." -check_whether_skip () { - local OST0_SIZE=$($LFS df $DIR | awk '/\[OST:0\]/ {print $4}') - log "OST0_SIZE: $OST0_SIZE required: $OST0_MIN" - if [ $OST0_SIZE -lt $OST0_MIN ]; then - echo "WARN: OST0 has less than $OST0_MIN free, skip this test." - return 0 - else - return 1 - fi -} - -# run for fixing bug10707, it needs a big room. test for 64bit -test_9() { - local filesize=$((1024 * 9 / 2)) # 4.5G - - check_whether_skip && return 0 - - setup_quota_test || error "setup quota failed with $?" - trap cleanup_quota_test EXIT - - set_ost_qtype "ug" || error "enable ost quota failed" + $LFS setquota -t -g --block-grace $MAX_DQ_TIME --inode-grace \ + $GRACE $DIR || error "set group grace time failed" + $LFS setquota -g $TSTUSR -b 0 -B 0 -i $LIMIT -I 0 $DIR || + error "set group quota failed" + TESTFILE=$DIR/$tdir/$tfile-1 - local TESTFILE="$DIR/$tdir/$tfile-0" - local BLK_LIMIT=100G #100G - local FILE_LIMIT=1000000 + test_file_soft $TESTFILE $LIMIT $GRACE "g" - echo "Set block limit $BLK_LIMIT bytes to $TSTUSR.$TSTUSR" + if is_project_quota_supported; then + echo "Project quota (soft limit:$LIMIT files grace:$GRACE sec)" + # make sure the system is clean + USED=$(getquota -p $TSTPRJID global curinodes) + [ $USED -ne 0 ] && error \ + "Used space($USED) for project $TSTPRJID isn't 0." - log "Set enough high limit(block:$BLK_LIMIT; file: $FILE_LIMIT)" \ - "for user: $TSTUSR" - $LFS setquota -u $TSTUSR -b 0 -B $BLK_LIMIT -i 0 -I $FILE_LIMIT $DIR || - error "set user quota failed" + $LFS setquota -t -p --block-grace $MAX_DQ_TIME --inode-grace \ + $GRACE $DIR || error "set project grace time failed" + $LFS setquota -p $TSTPRJID -b 0 -B 0 -i $LIMIT -I 0 $DIR || + error "set project quota failed" - log "Set enough high limit(block:$BLK_LIMIT; file: $FILE_LIMIT)" \ - "for group: $TSTUSR" - $LFS setquota -g $TSTUSR -b 0 -B $BLK_LIMIT -i 0 -I $FILE_LIMIT $DIR || - error "set group quota failed" + TESTFILE=$DIR/$tdir/$tfile-1 + # one less than limit, because of parent directory included. + test_file_soft $TESTFILE $((LIMIT-1)) $GRACE "p" + resetquota -p $TSTPRJID + $LFS setquota -t -p --block-grace $MAX_DQ_TIME --inode-grace \ + $MAX_IQ_TIME $DIR || + error "restore project grace time failed" + fi - quota_show_check a u $TSTUSR - quota_show_check a g $TSTUSR + # cleanup + $LFS setquota -t -u --block-grace $MAX_DQ_TIME --inode-grace \ + $MAX_IQ_TIME $DIR || error "restore user grace time failed" + $LFS setquota -t -g --block-grace $MAX_DQ_TIME --inode-grace \ + $MAX_IQ_TIME $DIR || error "restore group grace time failed" +} +run_test 4a "File soft limit (start timer, timer goes off, stop timer)" - echo "Create test file" - $LFS setstripe $TESTFILE -c 1 -i 0 || error "setstripe $TESTFILE failed" - chown $TSTUSR.$TSTUSR $TESTFILE || error "chown $TESTFILE failed" +test_4b() { + local GR_STR1="1w3d" + local GR_STR2="1000s" + local GR_STR3="5s" + local GR_STR4="1w2d3h4m5s" + local GR_STR5="5c" + local GR_STR6="18446744073709551615" + local GR_STR7="-1" - log "Write the big file of 4.5G ..." - $RUNAS $DD of=$TESTFILE count=$filesize || - quota_error a $TSTUSR "write 4.5G file failure, expect success" + wait_delete_completed - $SHOW_QUOTA_USER - $SHOW_QUOTA_GROUP + # test of valid grace strings handling + echo "Valid grace strings test" + $LFS setquota -t -u --block-grace $GR_STR1 --inode-grace \ + $GR_STR2 $DIR || error "set user grace time failed" + $LFS quota -u -t $DIR | grep "Block grace time: $GR_STR1" + $LFS setquota -t -g --block-grace $GR_STR3 --inode-grace \ + $GR_STR4 $DIR || error "set group grace time quota failed" + $LFS quota -g -t $DIR | grep "Inode grace time: $GR_STR4" - cleanup_quota_test + # test of invalid grace strings handling + echo " Invalid grace strings test" + ! $LFS setquota -t -u --block-grace $GR_STR4 --inode-grace $GR_STR5 $DIR + ! $LFS setquota -t -g --block-grace $GR_STR4 --inode-grace $GR_STR6 $DIR + ! $LFS setquota -t -g --block-grace $GR_STR4 --inode-grace \ + $GR_STR7 $DIR - $SHOW_QUOTA_USER - $SHOW_QUOTA_GROUP + # cleanup + $LFS setquota -t -u --block-grace $MAX_DQ_TIME --inode-grace \ + $MAX_IQ_TIME $DIR || error "restore user grace time failed" + $LFS setquota -t -g --block-grace $MAX_DQ_TIME --inode-grace \ + $MAX_IQ_TIME $DIR || error "restore group grace time failed" } -run_test 9 "Block limit larger than 4GB (b10707)" +run_test 4b "Grace time strings handling" -test_10() { - local TESTFILE=$DIR/$tdir/$tfile +# chown & chgrp (chown & chgrp successfully even out of block/file quota) +test_5() { + local BLIMIT=10 # MB + local ILIMIT=10 # inodes setup_quota_test || error "setup quota failed with $?" - trap cleanup_quota_test EXIT - - # set limit to root user should fail - $LFS setquota -u root -b 100G -B 500G -i 1K -I 1M $DIR && - error "set limit for root user successfully, expect failure" - $LFS setquota -g root -b 1T -B 10T -i 5K -I 100M $DIR && - error "set limit for root group successfully, expect failure" - $LFS setquota -p 0 -b 1T -B 10T -i 5K -I 100M $DIR && - error "set limit for project 0 successfully, expect failure" - # root user can overrun quota - set_ost_qtype "ug" || error "enable ost quota failed" + set_mdt_qtype $QTYPE || error "enable mdt quota failed" + set_ost_qtype $QTYPE || error "enable ost quota failed" - $LFS setquota -u $TSTUSR -b 0 -B 2M -i 0 -I 0 $DIR || - error "set quota failed" - quota_show_check b u $TSTUSR + echo "Set quota limit (0 ${BLIMIT}M 0 $ILIMIT) for $TSTUSR.$TSTUSR" + $LFS setquota -u $TSTUSR -b 0 -B ${BLIMIT}M -i 0 -I $ILIMIT $DIR || + error "set user quota failed" + $LFS setquota -g $TSTUSR -b 0 -B ${BLIMIT}M -i 0 -I $ILIMIT $DIR || + if is_project_quota_supported; then + error "set group quota failed" + $LFS setquota -p $TSTPRJID -b 0 -B ${BLIMIT}M -i 0 \ + -I $ILIMIT $DIR || error "set project quota failed" + fi - $LFS setstripe $TESTFILE -c 1 || error "setstripe $TESTFILE failed" - chown $TSTUSR.$TSTUSR $TESTFILE || error "chown $TESTFILE failed" + # make sure the system is clean + local USED=$(getquota -u $TSTUSR global curinodes) + [ $USED -ne 0 ] && error "Used inode($USED) for user $TSTUSR isn't 0." + USED=$(getquota -g $TSTUSR global curinodes) + [ $USED -ne 0 ] && error "Used inode($USED) for group $TSTUSR isn't 0." + USED=$(getquota -u $TSTUSR global curspace) + [ $USED -ne 0 ] && error "Used block($USED) for user $TSTUSR isn't 0." + USED=$(getquota -g $TSTUSR global curspace) + [ $USED -ne 0 ] && error "Used block($USED) for group $TSTUSR isn't 0." + if is_project_quota_supported; then + USED=$(getquota -p $TSTPRJID global curinodes) + [ $USED -ne 0 ] && + error "Used inode($USED) for project $TSTPRJID isn't 0." + USED=$(getquota -p $TSTPRJID global curspace) + [ $USED -ne 0 ] && + error "Used block($USED) for project $TSTPRJID isn't 0." + fi - runas -u 0 -g 0 $DD of=$TESTFILE count=3 oflag=sync || + echo "Create more than $ILIMIT files and more than $BLIMIT MB ..." + createmany -m $DIR/$tdir/$tfile-0_ $((ILIMIT + 1)) || + error "create failure, expect success" + if is_project_quota_supported; then + touch $DIR/$tdir/$tfile-0_1 + change_project -p $TSTPRJID $DIR/$tdir/$tfile-0_1 + fi + $DD of=$DIR/$tdir/$tfile-0_1 count=$((BLIMIT+1)) || error "write failure, expect success" - cleanup_quota_test -} -run_test 10 "Test quota for root user" - -test_11() { - local TESTFILE=$DIR/$tdir/$tfile - setup_quota_test || error "setup quota failed with $?" - trap cleanup_quota_test EXIT - - set_mdt_qtype "ug" || error "enable mdt quota failed" - $LFS setquota -u $TSTUSR -b 0 -B 0 -i 0 -I 1 $DIR || - error "set quota failed" + echo "Chown files to $TSTUSR.$TSTUSR ..." + for i in $(seq 0 $ILIMIT); do + chown $TSTUSR.$TSTUSR $DIR/$tdir/$tfile-0_$i || + quota_error a $TSTUSR "chown failure, expect success" + done - touch "$TESTFILE"-0 || error "touch $TESTFILE-0 failed" - touch "$TESTFILE"-1 || error "touch $TESTFILE-0 failed" + # cleanup + unlinkmany $DIR/$tdir/$tfile-0_ $((ILIMIT + 1)) || + error "unlinkmany $DIR/$tdir/$tfile-0_ failed" +} +run_test 5 "Chown & chgrp successfully even out of block/file quota" - chown $TSTUSR.$TSTUSR "$TESTFILE"-0 || error "chown $TESTFILE-0 failed" - chown $TSTUSR.$TSTUSR "$TESTFILE"-1 || error "chown $TESTFILE-1 failed" +# test dropping acquire request on master +test_6() { + local LIMIT=3 # MB - $SHOW_QUOTA_USER - local USED=$(getquota -u $TSTUSR global curinodes) - [ $USED -ge 2 ] || error "Used inodes($USED) is less than 2" + # Clear dmesg so watchdog is not triggered by previous + # test output + do_facet ost1 dmesg -c > /dev/null - cleanup_quota_test -} -run_test 11 "Chown/chgrp ignores quota" + setup_quota_test || error "setup quota failed with $?" -test_12a() { - [ "$OSTCOUNT" -lt "2" ] && skip "needs >= 2 OSTs" + # make sure the system is clean + local USED=$(getquota -u $TSTUSR global curspace) + [ $USED -ne 0 ] && error "Used space($USED) for user $TSTUSR isn't 0." - local blimit=22 # 22M - local blk_cnt=$((blimit - 5)) - local TESTFILE0="$DIR/$tdir/$tfile"-0 - local TESTFILE1="$DIR/$tdir/$tfile"-1 + # make sure no granted quota on ost + set_ost_qtype $QTYPE || error "enable ost quota failed" + resetquota -u $TSTUSR - setup_quota_test || error "setup quota failed with $?" - trap cleanup_quota_test EXIT + # create file for $TSTUSR + local TESTFILE=$DIR/$tdir/$tfile-$TSTUSR + $LFS setstripe $TESTFILE -c 1 -i 0 || error "setstripe $TESTFILE failed" + chown $TSTUSR.$TSTUSR $TESTFILE || error "chown $TESTFILE failed" - set_ost_qtype "u" || error "enable ost quota failed" - quota_show_check b u $TSTUSR + # create file for $TSTUSR2 + local TESTFILE2=$DIR/$tdir/$tfile-$TSTUSR2 + $LFS setstripe $TESTFILE2 -c 1 -i 0 || error "setstripe $TESTFILE2 failed" + chown $TSTUSR2.$TSTUSR2 $TESTFILE2 || error "chown $TESTFILE2 failed" - $LFS setquota -u $TSTUSR -b 0 -B "$blimit"M -i 0 -I 0 $DIR || + # cache per-ID lock for $TSTUSR on slave + $LFS setquota -u $TSTUSR -b 0 -B ${LIMIT}M -i 0 -I 0 $DIR || error "set quota failed" + $RUNAS $DD of=$TESTFILE count=1 || + error "write $TESTFILE failure, expect success" + $RUNAS2 $DD of=$TESTFILE2 count=1 || + error "write $TESTFILE2 failure, expect success" - $LFS setstripe $TESTFILE0 -c 1 -i 0 || error "setstripe $TESTFILE0 failed" - $LFS setstripe $TESTFILE1 -c 1 -i 1 || error "setstripe $TESTFILE1 failed" - chown $TSTUSR.$TSTUSR $TESTFILE0 || error "chown $TESTFILE0 failed" - chown $TSTUSR.$TSTUSR $TESTFILE1 || error "chown $TESTFILE1 failed" - - echo "Write to ost0..." - $RUNAS $DD of=$TESTFILE0 count=$blk_cnt oflag=sync || - quota_error a $TSTUSR "dd failed" + if at_is_enabled; then + at_max_saved=$(at_max_get ost1) + at_max_set $TIMEOUT ost1 - echo "Write to ost1..." - $RUNAS $DD of=$TESTFILE1 count=$blk_cnt oflag=sync && - quota_error a $TSTUSR "dd succeed, expect EDQUOT" + # write to enforced ID ($TSTUSR) to exceed limit to make sure + # DQACQ is sent, which makes at_max to take effect + $RUNAS $DD of=$TESTFILE count=$LIMIT seek=1 oflag=sync \ + conv=notrunc + rm -f $TESTFILE + wait_delete_completed + fi - echo "Free space from ost0..." - rm -f $TESTFILE0 - wait_delete_completed + sync; sync sync_all_data || true - echo "Write to ost1 after space freed from ost0..." - $RUNAS $DD of=$TESTFILE1 count=$blk_cnt oflag=sync || - quota_error a $TSTUSR "rebalancing failed" + #define QUOTA_DQACQ 601 + #define OBD_FAIL_PTLRPC_DROP_REQ_OPC 0x513 + lustre_fail mds 0x513 601 - cleanup_quota_test -} -run_test 12a "Block quota rebalancing" + do_facet ost1 $LCTL set_param \ + osd-*.$FSNAME-OST*.quota_slave.timeout=$((TIMEOUT / 2)) -test_12b() { - [ "$MDSCOUNT" -lt "2" ] && skip "needs >= 2 MDTs" - - local ilimit=$((1024 * 2)) # 2k inodes - local TESTFILE0=$DIR/$tdir/$tfile - local TESTFILE1=$DIR/${tdir}-1/$tfile - - setup_quota_test || error "setup quota failed with $?" - trap cleanup_quota_test EXIT - - $LFS mkdir -i 1 $DIR/${tdir}-1 || error "create remote dir failed" - chmod 0777 $DIR/${tdir}-1 + # write to un-enforced ID ($TSTUSR2) should succeed + $RUNAS2 $DD of=$TESTFILE2 count=$LIMIT seek=1 oflag=sync conv=notrunc || + error "write failure, expect success" - set_mdt_qtype "u" || error "enable mdt quota failed" - quota_show_check f u $TSTUSR + # write to enforced ID ($TSTUSR) in background, exceeding limit + # to make sure DQACQ is sent + $RUNAS $DD of=$TESTFILE count=$LIMIT seek=1 oflag=sync conv=notrunc & + DDPID=$! - $LFS setquota -u $TSTUSR -b 0 -B 0 -i 0 -I $ilimit $DIR || - error "set quota failed" + # watchdog timer uses a factor of 2 + echo "Sleep for $((TIMEOUT * 2 + 1)) seconds ..." + sleep $((TIMEOUT * 2 + 1)) - echo "Create $ilimit files on mdt0..." - $RUNAS createmany -m $TESTFILE0 $ilimit || - quota_error u $TSTUSR "create failed, but expect success" + [ $at_max_saved -ne 0 ] && at_max_set $at_max_saved ost1 - echo "Create files on mdt1..." - $RUNAS createmany -m $TESTFILE1 1 && - quota_error a $TSTUSR "create succeeded, expect EDQUOT" + # write should be blocked and never finished + if ! ps -p $DDPID > /dev/null 2>&1; then + lustre_fail mds 0 0 + error "write finished incorrectly!" + fi - echo "Free space from mdt0..." - $RUNAS unlinkmany $TESTFILE0 $ilimit || error "unlink mdt0 files failed" - wait_delete_completed - sync_all_data || true + lustre_fail mds 0 0 - echo "Create files on mdt1 after space freed from mdt0..." - $RUNAS createmany -m $TESTFILE1 $((ilimit / 2)) || - quota_error a $TSTUSR "rebalancing failed" + # no watchdog is triggered + do_facet ost1 dmesg > $TMP/lustre-log-${TESTNAME}.log + watchdog=$(awk '/[Ss]ervice thread pid/ && /was inactive/ \ + { print; }' $TMP/lustre-log-${TESTNAME}.log) + [ -z "$watchdog" ] || error "$watchdog" - $RUNAS unlinkmany $TESTFILE1 $((ilimit / 2)) || - error "unlink mdt1 files failed" - rmdir $DIR/${tdir}-1 || error "unlink remote dir failed" + rm -f $TMP/lustre-log-${TESTNAME}.log - cleanup_quota_test + # write should continue then fail with EDQUOT + local count=0 + local c_size + while [ true ]; do + if ! ps -p ${DDPID} > /dev/null 2>&1; then break; fi + if [ $count -ge 240 ]; then + quota_error u $TSTUSR "dd not finished in $count secs" + fi + count=$((count + 1)) + if [ $((count % 30)) -eq 0 ]; then + c_size=$(stat -c %s $TESTFILE) + echo "Waiting $count secs. $c_size" + $SHOW_QUOTA_USER + fi + sleep 1 + done } -run_test 12b "Inode quota rebalancing" +run_test 6 "Test dropping acquire request on master" -test_13(){ +# quota reintegration (global index) +test_7a() { local TESTFILE=$DIR/$tdir/$tfile - # the name of lwp on ost1 name is MDT0000-lwp-OST0000 - local procf="ldlm.namespaces.*MDT0000-lwp-OST0000.lru_size" + local LIMIT=20 # MB + + [ "$SLOW" = "no" ] && LIMIT=5 setup_quota_test || error "setup quota failed with $?" - trap cleanup_quota_test EXIT - set_ost_qtype "u" || error "enable ost quota failed" - quota_show_check b u $TSTUSR + # make sure the system is clean + local USED=$(getquota -u $TSTUSR global curspace) + [ $USED -ne 0 ] && error "Used space($USED) for user $TSTUSR isn't 0." - $LFS setquota -u $TSTUSR -b 0 -B 10M -i 0 -I 0 $DIR || - error "set quota failed" + # make sure no granted quota on ost1 + set_ost_qtype $QTYPE || error "enable ost quota failed" + resetquota -u $TSTUSR + set_ost_qtype "none" || error "disable ost quota failed" + + local OSTUUID=$(ostuuid_from_index 0) + USED=$(getquota -u $TSTUSR $OSTUUID bhardlimit) + [ $USED -ne 0 ] && + error "limit($USED) on $OSTUUID for user $TSTUSR isn't 0" + + # create test file $LFS setstripe $TESTFILE -c 1 -i 0 || error "setstripe $TESTFILE failed" chown $TSTUSR.$TSTUSR $TESTFILE || error "chown $TESTFILE failed" - # clear the locks in cache first - do_facet ost1 $LCTL set_param -n $procf=clear - local nlock=$(do_facet ost1 $LCTL get_param -n $procf) - [ $nlock -eq 0 ] || error "$nlock cached locks" + echo "Stop ost1..." + stop ost1 - # write to acquire the per-ID lock - $RUNAS $DD of=$TESTFILE count=1 oflag=sync || - quota_error a $TSTUSR "dd failed" + echo "Enable quota & set quota limit for $TSTUSR" + set_ost_qtype $QTYPE || error "enable ost quota failed" + $LFS setquota -u $TSTUSR -b 0 -B ${LIMIT}M -i 0 -I 0 $DIR || + error "set quota failed" - nlock=$(do_facet ost1 $LCTL get_param -n $procf) - [ $nlock -eq 1 ] || error "lock count($nlock) isn't 1" + echo "Start ost1..." + start ost1 $(ostdevname 1) $OST_MOUNT_OPTS || error "start ost1 failed" + quota_init - # clear quota doesn't trigger per-ID lock cancellation - resetquota -u $TSTUSR - nlock=$(do_facet ost1 $LCTL get_param -n $procf) - [ $nlock -eq 1 ] || error "per-ID lock is lost on quota clear" + wait_ost_reint $QTYPE || error "reintegration failed" - # clear the per-ID lock - do_facet ost1 $LCTL set_param -n $procf=clear - nlock=$(do_facet ost1 $LCTL get_param -n $procf) - [ $nlock -eq 0 ] || error "per-ID lock isn't cleared" + # hardlimit should have been fetched by slave during global + # reintegration, write will exceed quota + $RUNAS $DD of=$TESTFILE count=$((LIMIT + 1)) oflag=sync && + quota_error u $TSTUSR "write success, but expect EDQUOT" - # spare quota should be released - local OSTUUID=$(ostuuid_from_index 0) - local limit=$(getquota -u $TSTUSR $OSTUUID bhardlimit) - local space=$(getquota -u $TSTUSR $OSTUUID curspace) - [ $limit -le $space ] || - error "spare quota isn't released, limit:$limit, space:$space" + rm -f $TESTFILE + wait_delete_completed + sync_all_data || true + sleep 3 - cleanup_quota_test -} -run_test 13 "Cancel per-ID lock in the LRU list" + echo "Stop ost1..." + stop ost1 -test_15(){ - local LIMIT=$((24 * 1024 * 1024 * 1024 * 1024)) # 24 TB + $LFS setquota -u $TSTUSR -b 0 -B 0 -i 0 -I 0 $DIR || + error "clear quota failed" - wait_delete_completed - sync_all_data || true + echo "Start ost1..." + start ost1 $(ostdevname 1) $OST_MOUNT_OPTS || error "start ost1 failed" + quota_init - # test for user - $LFS setquota -u $TSTUSR -b 0 -B $LIMIT -i 0 -I 0 $DIR || - error "set user quota failed" - local TOTAL_LIMIT=$(getquota -u $TSTUSR global bhardlimit) - [ $TOTAL_LIMIT -eq $LIMIT ] || - error "(user) limit:$TOTAL_LIMIT, expect:$LIMIT, failed!" - resetquota -u $TSTUSR + wait_ost_reint $QTYPE || error "reintegration failed" - # test for group - $LFS setquota -g $TSTUSR -b 0 -B $LIMIT -i 0 -I 0 $DIR || - error "set group quota failed" - TOTAL_LIMIT=$(getquota -g $TSTUSR global bhardlimit) - [ $TOTAL_LIMIT -eq $LIMIT ] || - error "(group) limits:$TOTAL_LIMIT, expect:$LIMIT, failed!" - resetquota -g $TSTUSR + # hardlimit should be cleared on slave during reintegration + $RUNAS $DD of=$TESTFILE count=$((LIMIT + 1)) oflag=sync || + quota_error u $TSTUSR "write error, but expect success" } -run_test 15 "Set over 4T block quota" +run_test 7a "Quota reintegration (global index)" -test_17sub() { - local err_code=$1 - local BLKS=1 # 1M less than limit +# quota reintegration (slave index) +test_7b() { + local limit=100000 # MB local TESTFILE=$DIR/$tdir/$tfile setup_quota_test || error "setup quota failed with $?" - trap cleanup_quota_test EXIT # make sure the system is clean local USED=$(getquota -u $TSTUSR global curspace) [ $USED -ne 0 ] && error "Used space($USED) for user $TSTUSR isn't 0." - set_ost_qtype "ug" || error "enable ost quota failed" - # make sure no granted quota on ost + # make sure no granted quota on ost1 + set_ost_qtype $QTYPE || error "enable ost quota failed" resetquota -u $TSTUSR - $LFS setquota -u $TSTUSR -b 0 -B 10M -i 0 -I 0 $DIR || - error "set quota failed" + set_ost_qtype "none" || error "disable ost quota failed" - quota_show_check b u $TSTUSR + local OSTUUID=$(ostuuid_from_index 0) + USED=$(getquota -u $TSTUSR $OSTUUID bhardlimit) + [ $USED -ne 0 ] && + error "limit($USED) on $OSTUUID for user $TSTUSR isn't 0" - #define OBD_FAIL_QUOTA_RECOVERABLE_ERR 0xa04 - lustre_fail mds 0xa04 $err_code + # create test file + $LFS setstripe $TESTFILE -c 1 -i 0 || error "setstripe $TESTFILE failed" + chown $TSTUSR.$TSTUSR $TESTFILE || error "chown $TESTFILE failed" - # write in background - $RUNAS $DD of=$TESTFILE count=$BLKS oflag=direct & - local DDPID=$! + # consume some space to make sure the granted space will not + # be released during reconciliation + $RUNAS $DD of=$TESTFILE count=1 oflag=sync || + error "consume space failure, expect success" - sleep 2 - # write should be blocked and never finished - if ! ps -p $DDPID > /dev/null 2>&1; then - lustre_fail mds 0 0 - quota_error u $TSTUSR "write finished incorrectly!" - fi + # define OBD_FAIL_QUOTA_EDQUOT 0xa02 + lustre_fail mds 0xa02 - lustre_fail mds 0 0 + set_ost_qtype $QTYPE || error "enable ost quota failed" + $LFS setquota -u $TSTUSR -b 0 -B ${limit}M -i 0 -I 0 $DIR || + error "set quota failed" - local count=0 - local timeout=30 - while [ true ]; do - if ! ps -p ${DDPID} > /dev/null 2>&1; then break; fi - count=$((count+1)) - if [ $count -gt $timeout ]; then - quota_error u $TSTUSR "dd is not finished!" - fi - sleep 1 - done + # ignore the write error + $RUNAS $DD of=$TESTFILE count=1 seek=1 oflag=sync conv=notrunc - sync; sync_all_data || true + local old_used=$(getquota -u $TSTUSR $OSTUUID bhardlimit) - USED=$(getquota -u $TSTUSR global curspace) - [ $USED -ge $((BLKS * 1024)) ] || quota_error u $TSTUSR \ - "Used space(${USED}K) is less than ${BLKS}M" + lustre_fail mds 0 + + echo "Restart ost to trigger reintegration..." + stop ost1 + start ost1 $(ostdevname 1) $OST_MOUNT_OPTS || error "start ost1 failed" + quota_init + + wait_ost_reint $QTYPE || error "reintegration failed" + + USED=$(getquota -u $TSTUSR $OSTUUID bhardlimit) + [ $USED -gt $old_used ] || error "limit on $OSTUUID $USED <= $old_used" cleanup_quota_test + $SHOW_QUOTA_USER } +run_test 7b "Quota reintegration (slave index)" -# DQACQ return recoverable error -test_17() { - echo "DQACQ return -ENOLCK" - #define ENOLCK 37 - test_17sub 37 || error "Handle -ENOLCK failed" +# quota reintegration (restart mds during reintegration) +test_7c() { + local LIMIT=20 # MB + local TESTFILE=$DIR/$tdir/$tfile - echo "DQACQ return -EAGAIN" - #define EAGAIN 11 - test_17sub 11 || error "Handle -EAGAIN failed" + [ "$SLOW" = "no" ] && LIMIT=5 - echo "DQACQ return -ETIMEDOUT" - #define ETIMEDOUT 110 - test_17sub 110 || error "Handle -ETIMEDOUT failed" + setup_quota_test || error "setup quota failed with $?" - echo "DQACQ return -ENOTCONN" - #define ENOTCONN 107 - test_17sub 107 || error "Handle -ENOTCONN failed" -} + # make sure the system is clean + local USED=$(getquota -u $TSTUSR global curspace) + [ $USED -ne 0 ] && error "Used space($USED) for user $TSTUSR isn't 0." -run_test 17 "DQACQ return recoverable error" + set_ost_qtype "none" || error "disable ost quota failed" + $LFS setquota -u $TSTUSR -b 0 -B ${LIMIT}M -i 0 -I 0 $DIR || + error "set quota failed" -test_18_sub () { - local io_type=$1 - local blimit="200m" # 200M - local TESTFILE="$DIR/$tdir/$tfile" + # define OBD_FAIL_QUOTA_DELAY_REINT 0xa03 + lustre_fail ost 0xa03 - setup_quota_test || error "setup quota failed with $?" - trap cleanup_quota_test EXIT + # enable ost quota + set_ost_qtype $QTYPE || error "enable ost quota failed" + # trigger reintegration + local procf="osd-$ost1_FSTYPE.$FSNAME-OST*." + procf=${procf}quota_slave.force_reint + do_facet ost1 $LCTL set_param $procf=1 || + error "force reintegration failed" - set_ost_qtype "u" || error "enable ost quota failed" - log "User quota (limit: $blimit)" - $LFS setquota -u $TSTUSR -b 0 -B $blimit -i 0 -I 0 $MOUNT || - error "set quota failed" - quota_show_check b u $TSTUSR + echo "Stop mds..." + stop mds1 - $LFS setstripe $TESTFILE -i 0 -c 1 || error "setstripe $TESTFILE failed" - chown $TSTUSR.$TSTUSR $TESTFILE || error "chown $TESTFILE failed" + lustre_fail ost 0 - local timeout=$(sysctl -n lustre.timeout) + echo "Start mds..." + start mds1 $(mdsdevname 1) $MDS_MOUNT_OPTS + quota_init - if [ $io_type = "directio" ]; then - log "Write 100M (directio) ..." - $RUNAS $DD of=$TESTFILE count=100 oflag=direct & - else - log "Write 100M (buffered) ..." - $RUNAS $DD of=$TESTFILE count=100 & - fi - local DDPID=$! + # wait longer than usual to make sure the reintegration + # is triggered by quota wb thread. + wait_ost_reint $QTYPE 200 || error "reintegration failed" - replay_barrier $SINGLEMDS - log "Fail mds for $((2 * timeout)) seconds" - fail $SINGLEMDS $((2 * timeout)) + # hardlimit should have been fetched by slave during global + # reintegration, write will exceed quota + $RUNAS $DD of=$TESTFILE count=$((LIMIT + 1)) oflag=sync && + quota_error u $TSTUSR "write success, but expect EDQUOT" + return 0 +} +run_test 7c "Quota reintegration (restart mds during reintegration)" - local count=0 - if at_is_enabled; then - timeout=$(at_max_get mds) - else - timeout=$(lctl get_param -n timeout) - fi +# Quota reintegration (Transfer index in multiple bulks) +test_7d(){ + local TESTFILE=$DIR/$tdir/$tfile + local TESTFILE1="$DIR/$tdir/$tfile"-1 + local limit=20 # MB - while [ true ]; do - if ! ps -p ${DDPID} > /dev/null 2>&1; then break; fi - if [ $((++count % (2 * timeout) )) -eq 0 ]; then - log "it took $count second" - fi - sleep 1 - done + setup_quota_test || error "setup quota failed with $?" - log "(dd_pid=$DDPID, time=$count, timeout=$timeout)" - sync - cancel_lru_locks mdc - cancel_lru_locks osc - $SHOW_QUOTA_USER + set_ost_qtype "none" || error "disable ost quota failed" + $LFS setquota -u $TSTUSR -B ${limit}M $DIR || + error "set quota for $TSTUSR failed" + $LFS setquota -u $TSTUSR2 -B ${limit}M $DIR || + error "set quota for $TSTUSR2 failed" - local testfile_size=$(stat -c %s $TESTFILE) - if [ $testfile_size -ne $((BLK_SZ * 1024 * 100)) ] ; then - quota_error u $TSTUSR "expect $((BLK_SZ * 1024 * 100))," \ - "got ${testfile_size}. Verifying file failed!" - fi - cleanup_quota_test -} + #define OBD_FAIL_OBD_IDX_READ_BREAK 0x608 + lustre_fail mds 0x608 0 -# test when mds does failover, the ost still could work well -# this test shouldn't trigger watchdog b=14840 -test_18() { - # Clear dmesg so watchdog is not triggered by previous - # test output - do_facet ost1 dmesg -c > /dev/null + # enable quota to tirgger reintegration + set_ost_qtype "u" || error "enable ost quota failed" + wait_ost_reint "u" || error "reintegration failed" - test_18_sub normal - test_18_sub directio + lustre_fail mds 0 - # check if watchdog is triggered - do_facet ost1 dmesg > $TMP/lustre-log-${TESTNAME}.log - local watchdog=$(awk '/Service thread pid/ && /was inactive/ \ - { print; }' $TMP/lustre-log-${TESTNAME}.log) - [ -z "$watchdog" ] || error "$watchdog" - rm -f $TMP/lustre-log-${TESTNAME}.log + # hardlimit should have been fetched by slave during global + # reintegration, write will exceed quota + $RUNAS $DD of=$TESTFILE count=$((limit + 1)) oflag=sync && + quota_error u $TSTUSR "$TSTUSR write success, expect EDQUOT" + + $RUNAS2 $DD of=$TESTFILE1 count=$((limit + 1)) oflag=sync && + quota_error u $TSTUSR2 "$TSTUSR2 write success, expect EDQUOT" + return 0 } -run_test 18 "MDS failover while writing, no watchdog triggered (b14840)" +run_test 7d "Quota reintegration (Transfer index in multiple bulks)" -test_19() { - local blimit=5 # 5M - local TESTFILE=$DIR/$tdir/$tfile +# quota reintegration (inode limits) +test_7e() { + [ "$MDSCOUNT" -lt "2" ] && skip "needs >= 2 MDTs" + + # LU-2435: skip this quota test if underlying zfs version has not + # supported native dnode accounting + [ "$mds1_FSTYPE" == zfs ] && { + local F="feature@userobj_accounting" + local pool=$(zpool_name mds1) + local feature=$(do_facet mds1 $ZPOOL get -H $F $pool) + + [[ "$feature" != *" active "* ]] && + skip "requires zpool with active userobj_accounting" + } + + local ilimit=$((1024 * 2)) # inodes + local TESTFILE=$DIR/${tdir}-1/$tfile setup_quota_test || error "setup quota failed with $?" - trap cleanup_quota_test EXIT - set_ost_qtype $QTYPE || error "enable ost quota failed" + # make sure the system is clean + local USED=$(getquota -u $TSTUSR global curinodes) + [ $USED -ne 0 ] && error "Used inode($USED) for user $TSTUSR isn't 0." - # bind file to a single OST - $LFS setstripe -c 1 $TESTFILE || error "setstripe $TESTFILE failed" - chown $TSTUSR.$TSTUSR $TESTFILE || error "chown $TESTFILE failed" + # make sure no granted quota on mdt1 + set_mdt_qtype $QTYPE || error "enable mdt quota failed" + resetquota -u $TSTUSR + set_mdt_qtype "none" || error "disable mdt quota failed" - echo "Set user quota (limit: ${blimit}M)" - $LFS setquota -u $TSTUSR -b 0 -B "$blimit"M -i 0 -I 0 $MOUNT || - error "set user quota failed" - quota_show_check b u $TSTUSR - echo "Update quota limits" - $LFS setquota -u $TSTUSR -b 0 -B "$blimit"M -i 0 -I 0 $MOUNT || - error "set group quota failed" - quota_show_check b u $TSTUSR + local MDTUUID=$(mdtuuid_from_index $((MDSCOUNT - 1))) + USED=$(getquota -u $TSTUSR $MDTUUID ihardlimit) + [ $USED -ne 0 ] && error "limit($USED) on $MDTUUID for user" \ + "$TSTUSR isn't 0." - # first wirte might be cached - $RUNAS $DD of=$TESTFILE count=$((blimit + 1)) - cancel_lru_locks osc - $SHOW_QUOTA_USER - $RUNAS $DD of=$TESTFILE count=$((blimit + 1)) seek=$((blimit + 1)) && - quota_error u $TSTUSR "Write success, expect failure" - $SHOW_QUOTA_USER + echo "Stop mds${MDSCOUNT}..." + stop mds${MDSCOUNT} - cleanup_quota_test -} -run_test 19 "Updating admin limits doesn't zero operational limits(b14790)" + echo "Enable quota & set quota limit for $TSTUSR" + set_mdt_qtype $QTYPE || error "enable mdt quota failed" + $LFS setquota -u $TSTUSR -b 0 -B 0 -i 0 -I $ilimit $DIR || + error "set quota failed" -test_20() { # b15754 - local LSTR=(2g 1t 4k 3m) # limits strings - # limits values - local LVAL=($((2*1024*1024)) $((1*1024*1024*1024)) $((4*1024)) \ - $((3*1024*1024))) + echo "Start mds${MDSCOUNT}..." + start mds${MDSCOUNT} $(mdsdevname $MDSCOUNT) $MDS_MOUNT_OPTS + quota_init - resetquota -u $TSTUSR + wait_mdt_reint $QTYPE || error "reintegration failed" - $LFS setquota -u $TSTUSR --block-softlimit ${LSTR[0]} \ - $MOUNT || error "could not set quota limits" - $LFS setquota -u $TSTUSR --block-hardlimit ${LSTR[1]} \ - --inode-softlimit ${LSTR[2]} \ - --inode-hardlimit ${LSTR[3]} \ - $MOUNT || error "could not set quota limits" + echo "create remote dir" + $LFS mkdir -i $((MDSCOUNT - 1)) $DIR/${tdir}-1 || + error "create remote dir failed" + chmod 0777 $DIR/${tdir}-1 - [ "$(getquota -u $TSTUSR global bsoftlimit)" = "${LVAL[0]}" ] || - error "bsoftlimit was not set properly" - [ "$(getquota -u $TSTUSR global bhardlimit)" = "${LVAL[1]}" ] || - error "bhardlimit was not set properly" - [ "$(getquota -u $TSTUSR global isoftlimit)" = "${LVAL[2]}" ] || - error "isoftlimit was not set properly" - [ "$(getquota -u $TSTUSR global ihardlimit)" = "${LVAL[3]}" ] || - error "ihardlimit was not set properly" + # hardlimit should have been fetched by slave during global + # reintegration, create will exceed quota + $RUNAS createmany -m $TESTFILE $((ilimit + 1)) && + quota_error u $TSTUSR "create succeeded, expect EDQUOT" - resetquota -u $TSTUSR -} -run_test 20 "Test if setquota specifiers work properly (b15754)" + $RUNAS unlinkmany $TESTFILE $ilimit || error "unlink files failed" + wait_delete_completed + sync_all_data || true -test_21_sub() { - local testfile=$1 - local blk_number=$2 - local seconds=$3 + echo "Stop mds${MDSCOUNT}..." + stop mds${MDSCOUNT} - local time=$(($(date +%s) + seconds)) - while [ $(date +%s) -lt $time ]; do - $RUNAS $DD of=$testfile count=$blk_number > /dev/null 2>&1 - done + $LFS setquota -u $TSTUSR -b 0 -B 0 -i 0 -I 0 $DIR || + error "clear quota failed" + + echo "Start mds${MDSCOUNT}..." + start mds${MDSCOUNT} $(mdsdevname $MDSCOUNT) $MDS_MOUNT_OPTS + quota_init + + wait_mdt_reint $QTYPE || error "reintegration failed" + + # hardlimit should be cleared on slave during reintegration + $RUNAS createmany -m $TESTFILE $((ilimit + 1)) || + quota_error u $TSTUSR "create failed, expect success" + + $RUNAS unlinkmany $TESTFILE $((ilimit + 1)) || error "unlink failed" + rmdir $DIR/${tdir}-1 || error "unlink remote dir failed" } +run_test 7e "Quota reintegration (inode limits)" -# run for fixing bug16053, setquota shouldn't fail when writing and -# deleting are happening -test_21() { - local TESTFILE="$DIR/$tdir/$tfile" - local BLIMIT=10 # 10G - local ILIMIT=1000000 +# run dbench with quota enabled +test_8() { + local BLK_LIMIT="100g" #100G + local FILE_LIMIT=1000000 setup_quota_test || error "setup quota failed with $?" - trap cleanup_quota_test EXIT - set_ost_qtype $QTYPE || error "Enable ost quota failed" + set_mdt_qtype $QTYPE || error "enable mdt quota failed" + set_ost_qtype $QTYPE || error "enable ost quota failed" - log "Set limit(block:${BLIMIT}G; file:$ILIMIT) for user: $TSTUSR" - $LFS setquota -u $TSTUSR -b 0 -B ${BLIMIT}G -i 0 -I $ILIMIT $MOUNT || + echo "Set enough high limit for user: $TSTUSR" + $LFS setquota -u $TSTUSR -b 0 -B $BLK_LIMIT -i 0 -I $FILE_LIMIT $DIR || error "set user quota failed" - log "Set limit(block:${BLIMIT}G; file:$ILIMIT) for group: $TSTUSR" - $LFS setquota -g $TSTUSR -b 0 -B $BLIMIT -i 0 -I $ILIMIT $MOUNT || + echo "Set enough high limit for group: $TSTUSR" + $LFS setquota -g $TSTUSR -b 0 -B $BLK_LIMIT -i 0 -I $FILE_LIMIT $DIR || error "set group quota failed" if is_project_quota_supported; then - log "Set limit(block:${BLIMIT}G; file:$LIMIT) for " \ - "project: $TSTPRJID" - $LFS setquota -p $TSTPRJID -b 0 -B $BLIMIT -i 0 -I $ILIMIT \ - $MOUNT || error "set project quota failed" + change_project -sp $TSTPRJID $DIR/$tdir + echo "Set enough high limit for project: $TSTPRJID" + $LFS setquota -p $TSTPRJID -b 0 \ + -B $BLK_LIMIT -i 0 -I $FILE_LIMIT $DIR || + error "set project quota failed" fi - # repeat writing on a 1M file - test_21_sub ${TESTFILE}_1 1 30 & - local DDPID1=$! - # repeat writing on a 128M file - test_21_sub ${TESTFILE}_2 128 30 & - local DDPID2=$! - - local time=$(($(date +%s) + 30)) - local i=1 - while [ $(date +%s) -lt $time ]; do - log "Set quota for $i times" - $LFS setquota -u $TSTUSR -b 0 -B "$((BLIMIT + i))G" -i 0 \ - -I $((ILIMIT + i)) $MOUNT || - error "Set user quota failed" - $LFS setquota -g $TSTUSR -b 0 -B "$((BLIMIT + i))G" -i 0 \ - -I $((ILIMIT + i)) $MOUNT || - error "Set group quota failed" - if is_project_quota_supported; then - $LFS setquota -p $TSTPRJID -b 0 -B \ - "$((BLIMIT + i))G" -i 0 -I $((ILIMIT + i)) $MOUNT || - error "Set project quota failed" - fi - i=$((i+1)) - sleep 1 - done - - local count=0 - while [ true ]; do - if ! ps -p ${DDPID1} > /dev/null 2>&1; then break; fi - count=$((count+1)) - if [ $count -gt 60 ]; then - quota_error a $TSTUSR "dd should be finished!" - fi - sleep 1 - done - echo "(dd_pid=$DDPID1, time=$count)successful" - - count=0 - while [ true ]; do - if ! ps -p ${DDPID2} > /dev/null 2>&1; then break; fi - count=$((count+1)) - if [ $count -gt 60 ]; then - quota_error a $TSTUSR "dd should be finished!" - fi - sleep 1 - done - echo "(dd_pid=$DDPID2, time=$count)successful" + local duration="" + [ "$SLOW" = "no" ] && duration=" -t 120" + $RUNAS bash rundbench -D $DIR/$tdir 3 $duration || + quota_error a $TSTUSR "dbench failed!" - cleanup_quota_test + is_project_quota_supported && change_project -C $DIR/$tdir + return 0 } -run_test 21 "Setquota while writing & deleting (b16053)" +run_test 8 "Run dbench with quota enabled" -# enable/disable quota enforcement permanently -test_22() { - echo "Set both mdt & ost quota type as ug" - local qtype="ug" - is_project_quota_supported && qtype=$QTYPE - set_mdt_qtype $qtype || error "enable mdt quota failed" - set_ost_qtype $qtype || error "enable ost quota failed" +# this check is just for test_9 +OST0_MIN=4900000 #4.67G - echo "Restart..." - stopall || error "failed to stopall (1)" - mount - setupall +check_whether_skip () { + local OST0_SIZE=$($LFS df $DIR | awk '/\[OST:0\]/ {print $4}') + log "OST0_SIZE: $OST0_SIZE required: $OST0_MIN" + if [ $OST0_SIZE -lt $OST0_MIN ]; then + echo "WARN: OST0 has less than $OST0_MIN free, skip this test." + return 0 + else + return 1 + fi +} - echo "Verify if quota is enabled" - local qtype1=$(mdt_quota_type) - [ $qtype1 != $qtype ] && error "mdt quota setting is lost" - qtype=$(ost_quota_type) - [ $qtype1 != $qtype ] && error "ost quota setting is lost" +# run for fixing bug10707, it needs a big room. test for 64bit +test_9() { + local filesize=$((1024 * 9 / 2)) # 4.5G - echo "Set both mdt & ost quota type as none" - set_mdt_qtype "none" || error "disable mdt quota failed" - set_ost_qtype "none" || error "disable ost quota failed" + check_whether_skip && return 0 - echo "Restart..." - stopall || error "failed to stopall (2)" - mount - setupall - quota_init + setup_quota_test || error "setup quota failed with $?" - echo "Verify if quota is disabled" - qtype=$(mdt_quota_type) - [ $qtype != "none" ] && error "mdt quota setting is lost" - qtype=$(ost_quota_type) - [ $qtype != "none" ] && error "ost quota setting is lost" + set_ost_qtype "ug" || error "enable ost quota failed" - return 0 -} -run_test 22 "enable/disable quota by 'lctl conf_param/set_param -P'" + local TESTFILE="$DIR/$tdir/$tfile-0" + local BLK_LIMIT=100G #100G + local FILE_LIMIT=1000000 -test_23_sub() { - local TESTFILE="$DIR/$tdir/$tfile" - local LIMIT=$1 + echo "Set block limit $BLK_LIMIT bytes to $TSTUSR.$TSTUSR" - setup_quota_test || error "setup quota failed with $?" - trap cleanup_quota_test EXIT + log "Set enough high limit(block:$BLK_LIMIT; file: $FILE_LIMIT)" \ + "for user: $TSTUSR" + $LFS setquota -u $TSTUSR -b 0 -B $BLK_LIMIT -i 0 -I $FILE_LIMIT $DIR || + error "set user quota failed" - set_ost_qtype $QTYPE || error "Enable ost quota failed" + log "Set enough high limit(block:$BLK_LIMIT; file: $FILE_LIMIT)" \ + "for group: $TSTUSR" + $LFS setquota -g $TSTUSR -b 0 -B $BLK_LIMIT -i 0 -I $FILE_LIMIT $DIR || + error "set group quota failed" - # test for user - log "User quota (limit: $LIMIT MB)" - $LFS setquota -u $TSTUSR -b 0 -B "$LIMIT"M -i 0 -I 0 $DIR || - error "set quota failed" - quota_show_check b u $TSTUSR + quota_show_check a u $TSTUSR + quota_show_check a g $TSTUSR + echo "Create test file" $LFS setstripe $TESTFILE -c 1 -i 0 || error "setstripe $TESTFILE failed" chown $TSTUSR.$TSTUSR $TESTFILE || error "chown $TESTFILE failed" - log "Step1: trigger EDQUOT with O_DIRECT" - log "Write half of file" - $RUNAS $DD of=$TESTFILE count=$((LIMIT/2)) oflag=direct || - quota_error u $TSTUSR "(1) Write failure, expect success." \ - "limit=$LIMIT" - log "Write out of block quota ..." - $RUNAS $DD of=$TESTFILE count=$((LIMIT/2 + 1)) seek=$((LIMIT/2)) \ - oflag=direct conv=notrunc && - quota_error u $TSTUSR "(2) Write success, expect EDQUOT." \ - "limit=$LIMIT" - log "Step1: done" + log "Write the big file of 4.5G ..." + $RUNAS $DD of=$TESTFILE count=$filesize || + quota_error a $TSTUSR "write 4.5G file failure, expect success" - log "Step2: rewrite should succeed" - $RUNAS $DD of=$TESTFILE count=1 oflag=direct conv=notrunc|| - quota_error u $TSTUSR "(3) Write failure, expect success." \ - "limit=$LIMIT" - log "Step2: done" + $SHOW_QUOTA_USER + $SHOW_QUOTA_GROUP cleanup_quota_test - local OST0_UUID=$(ostuuid_from_index 0) - local OST0_QUOTA_USED=$(getquota -u $TSTUSR $OST0_UUID curspace) - [ $OST0_QUOTA_USED -ne 0 ] && - ($SHOW_QUOTA_USER; \ - quota_error u $TSTUSR "quota isn't released") $SHOW_QUOTA_USER + $SHOW_QUOTA_GROUP } +run_test 9 "Block limit larger than 4GB (b10707)" -test_23() { - [ $(facet_fstype ost1) == "zfs" ] && - skip "Overwrite in place is not guaranteed to be " \ - "space neutral on ZFS" - - local OST0_MIN=$((6 * 1024)) # 6MB, extra space for meta blocks. - check_whether_skip && return 0 - log "run for 4MB test file" - test_23_sub 4 +test_10() { + local TESTFILE=$DIR/$tdir/$tfile - OST0_MIN=$((60 * 1024)) # 60MB, extra space for meta blocks. - check_whether_skip && return 0 - log "run for 40MB test file" - test_23_sub 40 -} -run_test 23 "Quota should be honored with directIO (b16125)" + setup_quota_test || error "setup quota failed with $?" -test_24() { - local blimit=5 # 5M - local TESTFILE="$DIR/$tdir/$tfile" + # set limit to root user should fail + $LFS setquota -u root -b 100G -B 500G -i 1K -I 1M $DIR && + error "set limit for root user successfully, expect failure" + $LFS setquota -g root -b 1T -B 10T -i 5K -I 100M $DIR && + error "set limit for root group successfully, expect failure" + $LFS setquota -p 0 -b 1T -B 10T -i 5K -I 100M $DIR && + error "set limit for project 0 successfully, expect failure" - setup_quota_test || error "setup quota failed with $?" - trap cleanup_quota_test EXIT + # root user can overrun quota + set_ost_qtype "ug" || error "enable ost quota failed" - set_ost_qtype $QTYPE || error "enable ost quota failed" + $LFS setquota -u $TSTUSR -b 0 -B 2M -i 0 -I 0 $DIR || + error "set quota failed" + quota_show_check b u $TSTUSR - # bind file to a single OST - $LFS setstripe -c 1 $TESTFILE || error "setstripe $TESTFILE failed" + $LFS setstripe $TESTFILE -c 1 || error "setstripe $TESTFILE failed" chown $TSTUSR.$TSTUSR $TESTFILE || error "chown $TESTFILE failed" - echo "Set user quota (limit: ${blimit}M)" - $LFS setquota -u $TSTUSR -b 0 -B "$blimit"M -i 0 -I 0 $MOUNT || + runas -u 0 -g 0 $DD of=$TESTFILE count=3 oflag=sync || + error "write failure, expect success" +} +run_test 10 "Test quota for root user" + +test_11() { + local TESTFILE=$DIR/$tdir/$tfile + setup_quota_test || error "setup quota failed with $?" + + set_mdt_qtype "ug" || error "enable mdt quota failed" + $LFS setquota -u $TSTUSR -b 0 -B 0 -i 0 -I 1 $DIR || error "set quota failed" - # overrun quota by root user - runas -u 0 -g 0 $DD of=$TESTFILE count=$((blimit + 1)) || - error "write failure, expect success" - cancel_lru_locks osc - sync_all_data || true + touch "$TESTFILE"-0 || error "touch $TESTFILE-0 failed" + touch "$TESTFILE"-1 || error "touch $TESTFILE-0 failed" - $SHOW_QUOTA_USER | grep '*' || error "no matching *" + chown $TSTUSR.$TSTUSR "$TESTFILE"-0 || error "chown $TESTFILE-0 failed" + chown $TSTUSR.$TSTUSR "$TESTFILE"-1 || error "chown $TESTFILE-1 failed" - cleanup_quota_test + $SHOW_QUOTA_USER + local USED=$(getquota -u $TSTUSR global curinodes) + [ $USED -ge 2 ] || error "Used inodes($USED) is less than 2" } -run_test 24 "lfs draws an asterix when limit is reached (b16646)" +run_test 11 "Chown/chgrp ignores quota" -test_27a() { # b19612 - $LFS quota $TSTUSR $DIR && - error "lfs succeeded with no type, but should have failed" - $LFS setquota $TSTUSR $DIR && - error "lfs succeeded with no type, but should have failed" - return 0 -} -run_test 27a "lfs quota/setquota should handle wrong arguments (b19612)" +test_12a() { + [ "$OSTCOUNT" -lt "2" ] && skip "needs >= 2 OSTs" -test_27b() { # b20200 - $LFS setquota -u $TSTID -b 1000 -B 1000 -i 1000 -I 1000 $DIR || - error "lfs setquota failed with uid argument" - $LFS setquota -g $TSTID -b 1000 -B 1000 -i 1000 -I 1000 $DIR || - error "lfs stequota failed with gid argument" - if is_project_quota_supported; then - $LFS setquota -p $TSTPRJID -b 1000 -B 1000 -i 1000 -I \ - 1000 $DIR || error \ - "lfs stequota failed with projid argument" - fi - $SHOW_QUOTA_USERID || error "lfs quota failed with uid argument" - $SHOW_QUOTA_GROUPID || error "lfs quota failed with gid argument" - if is_project_quota_supported; then - $SHOW_QUOTA_PROJID || - error "lfs quota failed with projid argument" - fi - resetquota -u $TSTUSR - resetquota -g $TSTUSR - resetquota -p $TSTPRJID - return 0 -} -run_test 27b "lfs quota/setquota should handle user/group/project ID (b20200)" + local blimit=22 # MB + local blk_cnt=$((blimit - 5)) + local TESTFILE0="$DIR/$tdir/$tfile"-0 + local TESTFILE1="$DIR/$tdir/$tfile"-1 -test_27c() { - local limit + setup_quota_test || error "setup quota failed with $?" - $LFS setquota -u $TSTID -b 30M -B 3T $DIR || - error "lfs setquota failed" + set_ost_qtype "u" || error "enable ost quota failed" + quota_show_check b u $TSTUSR - limit=$($LFS quota -u $TSTID -v -h $DIR | grep $DIR | awk '{print $3}') - [ $limit != "30M" ] && error "softlimit $limit isn't human-readable" - limit=$($LFS quota -u $TSTID -v -h $DIR | grep $DIR | awk '{print $4}') - [ $limit != "3T" ] && error "hardlimit $limit isn't human-readable" + $LFS setquota -u $TSTUSR -b 0 -B ${blimit}M -i 0 -I 0 $DIR || + error "set quota failed" - $LFS setquota -u $TSTID -b 1500M -B 18500G $DIR || - error "lfs setquota for $TSTID failed" + $LFS setstripe $TESTFILE0 -c 1 -i 0 || error "setstripe $TESTFILE0 failed" + $LFS setstripe $TESTFILE1 -c 1 -i 1 || error "setstripe $TESTFILE1 failed" + chown $TSTUSR.$TSTUSR $TESTFILE0 || error "chown $TESTFILE0 failed" + chown $TSTUSR.$TSTUSR $TESTFILE1 || error "chown $TESTFILE1 failed" - limit=$($LFS quota -u $TSTID -v -h $DIR | grep $DIR | awk '{print $3}') - [ $limit != "1.465G" ] && error "wrong softlimit $limit" - limit=$($LFS quota -u $TSTID -v -h $DIR | grep $DIR | awk '{print $4}') - [ $limit != "18.07T" ] && error "wrong hardlimit $limit" + echo "Write to ost0..." + $RUNAS $DD of=$TESTFILE0 count=$blk_cnt oflag=sync || + quota_error a $TSTUSR "dd failed" - $LFS quota -u $TSTID -v -h $DIR | grep -q "Total allocated" || - error "total allocated inode/block limit not printed" + echo "Write to ost1..." + $RUNAS $DD of=$TESTFILE1 count=$blk_cnt oflag=sync && + quota_error a $TSTUSR "dd succeed, expect EDQUOT" - resetquota -u $TSTUSR + echo "Free space from ost0..." + rm -f $TESTFILE0 + wait_delete_completed + sync_all_data || true + + echo "Write to ost1 after space freed from ost0..." + $RUNAS $DD of=$TESTFILE1 count=$blk_cnt oflag=sync || + quota_error a $TSTUSR "rebalancing failed" } -run_test 27c "lfs quota should support human-readable output" +run_test 12a "Block quota rebalancing" -test_27d() { - local softlimit=1.5 - local hardlimit=2.3 - local limit +test_12b() { + [ "$MDSCOUNT" -lt "2" ] && skip "needs >= 2 MDTs" - $LFS setquota -u $TSTID -b ${softlimit}p -B ${hardlimit}P $DIR || - error "set fraction block limit failed" - limit=$($LFS quota -u $TSTID -h $DIR | grep $DIR | awk '{print $3}') - [ $limit == ${softlimit}P ] || error "get fraction softlimit failed" - limit=$($LFS quota -u $TSTID -h $DIR | grep $DIR | awk '{print $4}') - [ $limit == ${hardlimit}P ] || error "get fraction hardlimit failed" + local ilimit=$((1024 * 2)) # inodes + local TESTFILE0=$DIR/$tdir/$tfile + local TESTFILE1=$DIR/${tdir}-1/$tfile - resetquota -u $TSTUSR + setup_quota_test || error "setup quota failed with $?" + + $LFS mkdir -i 1 $DIR/${tdir}-1 || error "create remote dir failed" + chmod 0777 $DIR/${tdir}-1 + + set_mdt_qtype "u" || error "enable mdt quota failed" + quota_show_check f u $TSTUSR + + $LFS setquota -u $TSTUSR -b 0 -B 0 -i 0 -I $ilimit $DIR || + error "set quota failed" + + echo "Create $ilimit files on mdt0..." + $RUNAS createmany -m $TESTFILE0 $ilimit || + quota_error u $TSTUSR "create failed, but expect success" + + echo "Create files on mdt1..." + $RUNAS createmany -m $TESTFILE1 1 && + quota_error a $TSTUSR "create succeeded, expect EDQUOT" + + echo "Free space from mdt0..." + $RUNAS unlinkmany $TESTFILE0 $ilimit || error "unlink mdt0 files failed" + wait_delete_completed + sync_all_data || true + + echo "Create files on mdt1 after space freed from mdt0..." + $RUNAS createmany -m $TESTFILE1 $((ilimit / 2)) || + quota_error a $TSTUSR "rebalancing failed" + + $RUNAS unlinkmany $TESTFILE1 $((ilimit / 2)) || + error "unlink mdt1 files failed" + rmdir $DIR/${tdir}-1 || error "unlink remote dir failed" } -run_test 27d "lfs setquota should support fraction block limit" +run_test 12b "Inode quota rebalancing" -test_30() { - local LIMIT=4 # 4MB - local TESTFILE="$DIR/$tdir/$tfile" - local GRACE=10 +test_13(){ + local TESTFILE=$DIR/$tdir/$tfile + # the name of lwp on ost1 name is MDT0000-lwp-OST0000 + local procf="ldlm.namespaces.*MDT0000-lwp-OST0000.lru_size" setup_quota_test || error "setup quota failed with $?" - trap cleanup_quota_test EXIT set_ost_qtype "u" || error "enable ost quota failed" + quota_show_check b u $TSTUSR - $LFS setstripe $TESTFILE -i 0 -c 1 || error "setstripe $TESTFILE failed" + $LFS setquota -u $TSTUSR -b 0 -B 10M -i 0 -I 0 $DIR || + error "set quota failed" + $LFS setstripe $TESTFILE -c 1 -i 0 || error "setstripe $TESTFILE failed" chown $TSTUSR.$TSTUSR $TESTFILE || error "chown $TESTFILE failed" - $LFS setquota -t -u --block-grace $GRACE --inode-grace \ - $MAX_IQ_TIME $DIR || error "set grace time failed" - $LFS setquota -u $TSTUSR -b ${LIMIT}M -B 0 -i 0 -I 0 $DIR || - error "set quota failed" - $RUNAS $DD of=$TESTFILE count=$((LIMIT * 2)) || true - cancel_lru_locks osc - sleep $GRACE - $LFS setquota -u $TSTUSR -B 0 $DIR || error "clear quota failed" - # over-quota flag has not yet settled since we do not trigger async - # events based on grace time period expiration - $SHOW_QUOTA_USER - $RUNAS $DD of=$TESTFILE conv=notrunc oflag=append count=4 || true - cancel_lru_locks osc - # now over-quota flag should be settled and further writes should fail - $SHOW_QUOTA_USER - $RUNAS $DD of=$TESTFILE conv=notrunc oflag=append count=4 && - error "grace times were reset" - # cleanup - cleanup_quota_test - $LFS setquota -t -u --block-grace $MAX_DQ_TIME --inode-grace \ - $MAX_IQ_TIME $DIR || error "restore grace time failed" + # clear the locks in cache first + do_facet ost1 $LCTL set_param -n $procf=clear + local nlock=$(do_facet ost1 $LCTL get_param -n $procf) + [ $nlock -eq 0 ] || error "$nlock cached locks" + + # write to acquire the per-ID lock + $RUNAS $DD of=$TESTFILE count=1 oflag=sync || + quota_error a $TSTUSR "dd failed" + + nlock=$(do_facet ost1 $LCTL get_param -n $procf) + [ $nlock -eq 1 ] || error "lock count($nlock) isn't 1" + + # clear quota doesn't trigger per-ID lock cancellation + resetquota -u $TSTUSR + nlock=$(do_facet ost1 $LCTL get_param -n $procf) + [ $nlock -eq 1 ] || error "per-ID lock is lost on quota clear" + + # clear the per-ID lock + do_facet ost1 $LCTL set_param -n $procf=clear + nlock=$(do_facet ost1 $LCTL get_param -n $procf) + [ $nlock -eq 0 ] || error "per-ID lock isn't cleared" + + # spare quota should be released + local OSTUUID=$(ostuuid_from_index 0) + local limit=$(getquota -u $TSTUSR $OSTUUID bhardlimit) + local space=$(getquota -u $TSTUSR $OSTUUID curspace) + [ $limit -le $space ] || + error "spare quota isn't released, limit:$limit, space:$space" } -run_test 30 "Hard limit updates should not reset grace times" +run_test 13 "Cancel per-ID lock in the LRU list" -# basic usage tracking for user & group -test_33() { - local INODES=10 # 10 files - local BLK_CNT=2 # of 2M each - local TOTAL_BLKS=$((INODES * BLK_CNT * 1024)) +test_15(){ + local LIMIT=$((24 * 1024 * 1024 * 1024 * 1024)) # 24 TB + + wait_delete_completed + sync_all_data || true + + # test for user + $LFS setquota -u $TSTUSR -b 0 -B $LIMIT -i 0 -I 0 $DIR || + error "set user quota failed" + local TOTAL_LIMIT=$(getquota -u $TSTUSR global bhardlimit) + [ $TOTAL_LIMIT -eq $LIMIT ] || + error "(user) limit:$TOTAL_LIMIT, expect:$LIMIT, failed!" + resetquota -u $TSTUSR + + # test for group + $LFS setquota -g $TSTUSR -b 0 -B $LIMIT -i 0 -I 0 $DIR || + error "set group quota failed" + TOTAL_LIMIT=$(getquota -g $TSTUSR global bhardlimit) + [ $TOTAL_LIMIT -eq $LIMIT ] || + error "(group) limits:$TOTAL_LIMIT, expect:$LIMIT, failed!" + resetquota -g $TSTUSR +} +run_test 15 "Set over 4T block quota" + +test_16a() +{ + (( $CLIENT_VERSION < $(version_code 2.14.55) )) && + skip "Not supported Lustre client before 2.14.55" setup_quota_test || error "setup quota failed with $?" - trap cleanup_quota_test EXIT - # make sure the system is clean - local USED=$(getquota -u $TSTID global curspace) - [ $USED -ne 0 ] && - error "Used space ($USED) for user $TSTID isn't 0." - USED=$(getquota -g $TSTID global curspace) - [ $USED -ne 0 ] && - error "Used space ($USED) for group $TSTID isn't 0." - if is_project_quota_supported; then - USED=$(getquota -p $TSTPRJID global curspace) - [ $USED -ne 0 ] && error \ - "Used space ($USED) for project $TSTPRJID isn't 0." - fi + $LFS setquota -u $TSTUSR -B 500M -I 10K $MOUNT || + error "failed to set quota for user $TSTUSR" + $LFS setquota -g $TSTUSR -B 500M -I 10K $MOUNT || + error "failed to set quota for group $TSTUSR" - echo "Write files..." - for i in $(seq 0 $INODES); do - $RUNAS $DD of=$DIR/$tdir/$tfile-$i count=$BLK_CNT 2>/dev/null || - error "write failed" - is_project_quota_supported && - change_project -p $TSTPRJID $DIR/$tdir/$tfile-$i - echo "Iteration $i/$INODES completed" - done - cancel_lru_locks osc + $RUNAS $DD of=$DIR/$tdir/$tfile bs=1M count=50 || + quota_error u $TSTUSR "write failure" - echo "Wait for setattr on objects finished..." - wait_delete_completed + $LFS quota -u $TSTUSR $MOUNT || + quota_error u $TSTUSR "failed to get quota" - sync; sync_all_data || true + local OSC=$($LCTL dl | grep OST0000-osc-[^M] | awk '{print $4}') - echo "Verify disk usage after write" - USED=$(getquota -u $TSTID global curspace) - [ $USED -lt $TOTAL_BLKS ] && - error "Used space for user $TSTID:$USED, expected:$TOTAL_BLKS" - USED=$(getquota -g $TSTID global curspace) - [ $USED -lt $TOTAL_BLKS ] && - error "Used space for group $TSTID:$USED, expected:$TOTAL_BLKS" - if is_project_quota_supported; then - USED=$(getquota -p $TSTPRJID global curspace) - [ $USED -lt $TOTAL_BLKS ] && error \ - "Used space for project $TSTPRJID:$USED, expected:$TOTAL_BLKS" - fi + $LCTL --device %$OSC deactivate + stack_trap "$LCTL --device %$OSC activate" - echo "Verify inode usage after write" - USED=$(getquota -u $TSTID global curinodes) - [ $USED -lt $INODES ] && - error "Used inode for user $TSTID is $USED, expected $INODES" - USED=$(getquota -g $TSTID global curinodes) - [ $USED -lt $INODES ] && - error "Used inode for group $TSTID is $USED, expected $INODES" - if is_project_quota_supported; then - USED=$(getquota -p $TSTPRJID global curinodes) - [ $USED -lt $INODES ] && error \ - "Used inode for project $TSTPRJID is $USED, expected $INODES" - fi + $LFS quota -v -u $TSTUSR $MOUNT || + quota_error u $TSTUSR "failed to get quota after deactivate OSC" + $LFS quota -v -g $TSTUSR $MOUNT || + quota_error g $TSTUSR "failed to get quota after deactivate OSC" - cleanup_quota_test + (( $MDSCOUNT > 1 )) || return 0 - echo "Verify disk usage after delete" - USED=$(getquota -u $TSTID global curspace) - [ $USED -eq 0 ] || error "Used space for user $TSTID isn't 0. $USED" - USED=$(getquota -u $TSTID global curinodes) - [ $USED -eq 0 ] || error "Used inodes for user $TSTID isn't 0. $USED" - USED=$(getquota -g $TSTID global curspace) - [ $USED -eq 0 ] || error "Used space for group $TSTID isn't 0. $USED" - USED=$(getquota -g $TSTID global curinodes) + local MDC=$($LCTL dl | grep MDT0001-mdc-[^M] | awk '{print $4}') + + $LCTL --device %$MDC deactivate + stack_trap "$LCTL --device %$MDC activate" + + $LFS quota -v -u $TSTUSR $MOUNT || + quota_error u $TSTUSR "failed to get quota after deactivate MDC" + $LFS quota -v -g $TSTUSR $MOUNT || + quota_error g $TSTUSR "failed to get quota after deactivate OSC" +} +run_test 16a "lfs quota should skip the inactive MDT/OST" + +cleanup_16b() +{ + stopall + formatall + setupall +} + +test_16b() +{ + (( $CLIENT_VERSION < $(version_code 2.14.55) )) && + skip "Not supported Lustre client before 2.14.55" + + (( $MDSCOUNT >= 3 )) || skip "needs >= 3 MDTs" + + stopall + if ! combined_mgs_mds ; then + format_mgs + start_mgs + fi + + add mds1 $(mkfs_opts mds1 $(mdsdevname 1)) --index=0 --reformat \ + $(mdsdevname 1) $(mdsvdevname 1) + add mds2 $(mkfs_opts mds2 $(mdsdevname 2)) --index=1 --reformat \ + $(mdsdevname 2) $(mdsvdevname 2) + add mds3 $(mkfs_opts mds3 $(mdsdevname 3)) --index=100 --reformat \ + $(mdsdevname 3) $(mdsvdevname 3) + + add ost1 $(mkfs_opts ost1 $(ostdevname 1)) --index=0 --reformat \ + $(ostdevname 1) $(ostvdevname 1) + add ost2 $(mkfs_opts ost2 $(ostdevname 2)) --index=100 --reformat \ + $(ostdevname 2) $(ostvdevname 2) + + stack_trap cleanup_16b + + start mds1 $(mdsdevname 1) $MDS_MOUNT_OPTS || error "MDT1 start failed" + start mds2 $(mdsdevname 2) $MDS_MOUNT_OPTS || error "MDT2 start failed" + start mds3 $(mdsdevname 3) $MDS_MOUNT_OPTS || error "MDT3 start failed" + start ost1 $(ostdevname 1) $OST_MOUNT_OPTS || error "OST1 start failed" + start ost2 $(ostdevname 2) $OST_MOUNT_OPTS || error "OST2 start failed" + + mount_client $MOUNT || error "Unable to mount client" + + setup_quota_test || error "setup quota failed with $?" + stack_trap cleanup_quota_test EXIT + + $LFS setquota -u $TSTUSR -B 100M -I 10K $MOUNT || + error "failed to set quota for user $TSTUSR" + $LFS setquota -g $TSTUSR -B 100M -I 10K $MOUNT || + error "failed to set quota for group $TSTUSR" + + $RUNAS $DD of=$DIR/$tdir/$tfile bs=1M count=10 || + quota_error u $TSTUSR "write failure" + + cnt=$($LFS quota -v -u $TSTUSR $MOUNT | grep -ce "^$FSNAME-[MD|OS]T*") + [ $cnt -le 5 ] || quota_error u $TSTUSR "failed to get user quota" + cnt=$($LFS quota -v -g $TSTUSR $MOUNT | grep -ce "^$FSNAME-[MD|OS]T*") + [ $cnt -le 5 ] || quota_error g $TSTUSR "failed to get group quota" +} +run_test 16b "lfs quota should skip the nonexistent MDT/OST" + +test_17sub() { + local err_code=$1 + local BLKS=1 # 1M less than limit + local TESTFILE=$DIR/$tdir/$tfile + + setup_quota_test || error "setup quota failed with $?" + + # make sure the system is clean + local USED=$(getquota -u $TSTUSR global curspace) + [ $USED -ne 0 ] && error "Used space($USED) for user $TSTUSR isn't 0." + + set_ost_qtype "ug" || error "enable ost quota failed" + # make sure no granted quota on ost + resetquota -u $TSTUSR + $LFS setquota -u $TSTUSR -b 0 -B 10M -i 0 -I 0 $DIR || + error "set quota failed" + + quota_show_check b u $TSTUSR + + #define OBD_FAIL_QUOTA_RECOVERABLE_ERR 0xa04 + lustre_fail mds 0xa04 $err_code + + # write in background + $RUNAS $DD of=$TESTFILE count=$BLKS oflag=direct & + local DDPID=$! + + sleep 2 + # write should be blocked and never finished + if ! ps -p $DDPID > /dev/null 2>&1; then + lustre_fail mds 0 0 + quota_error u $TSTUSR "write finished incorrectly!" + fi + + lustre_fail mds 0 0 + + local count=0 + local timeout=30 + while [ true ]; do + if ! ps -p ${DDPID} > /dev/null 2>&1; then break; fi + count=$((count+1)) + if [ $count -gt $timeout ]; then + quota_error u $TSTUSR "dd is not finished!" + fi + sleep 1 + done + + sync; sync_all_data || true + + USED=$(getquota -u $TSTUSR global curspace) + [ $USED -ge $((BLKS * 1024)) ] || quota_error u $TSTUSR \ + "Used space(${USED}K) is less than ${BLKS}M" + + cleanup_quota_test +} + +# DQACQ return recoverable error +test_17() { + echo "DQACQ return -ENOLCK" + #define ENOLCK 37 + test_17sub 37 || error "Handle -ENOLCK failed" + + echo "DQACQ return -EAGAIN" + #define EAGAIN 11 + test_17sub 11 || error "Handle -EAGAIN failed" + + echo "DQACQ return -ETIMEDOUT" + #define ETIMEDOUT 110 + test_17sub 110 || error "Handle -ETIMEDOUT failed" + + echo "DQACQ return -ENOTCONN" + #define ENOTCONN 107 + test_17sub 107 || error "Handle -ENOTCONN failed" +} + +run_test 17 "DQACQ return recoverable error" + +test_18_sub () { + local io_type=$1 + local blimit=200 # MB + local TESTFILE="$DIR/$tdir/$tfile" + + setup_quota_test || error "setup quota failed with $?" + + set_ost_qtype "u" || error "enable ost quota failed" + log "User quota (limit: $blimit)" + $LFS setquota -u $TSTUSR -b 0 -B ${blimit}M -i 0 -I 0 $MOUNT || + error "set quota failed" + quota_show_check b u $TSTUSR + + $LFS setstripe $TESTFILE -i 0 -c 1 || error "setstripe $TESTFILE failed" + chown $TSTUSR.$TSTUSR $TESTFILE || error "chown $TESTFILE failed" + + local timeout=$(sysctl -n lustre.timeout) + + if [ $io_type = "directio" ]; then + log "Write 100M (directio) ..." + $RUNAS $DD of=$TESTFILE count=100 oflag=direct & + else + log "Write 100M (buffered) ..." + $RUNAS $DD of=$TESTFILE count=100 & + fi + local DDPID=$! + + replay_barrier $SINGLEMDS + log "Fail mds for $((2 * timeout)) seconds" + fail $SINGLEMDS $((2 * timeout)) + + local count=0 + if at_is_enabled; then + timeout=$(at_max_get mds) + else + timeout=$(lctl get_param -n timeout) + fi + + while [ true ]; do + if ! ps -p ${DDPID} > /dev/null 2>&1; then break; fi + if [ $((++count % (2 * timeout) )) -eq 0 ]; then + log "it took $count second" + fi + sleep 1 + done + + log "(dd_pid=$DDPID, time=$count, timeout=$timeout)" + sync + cancel_lru_locks mdc + cancel_lru_locks osc + $SHOW_QUOTA_USER + + local testfile_size=$(stat -c %s $TESTFILE) + if [ $testfile_size -ne $((BLK_SZ * 1024 * 100)) ] ; then + quota_error u $TSTUSR "expect $((BLK_SZ * 1024 * 100))," \ + "got ${testfile_size}. Verifying file failed!" + fi + cleanup_quota_test +} + +# test when mds does failover, the ost still could work well +# this test shouldn't trigger watchdog b=14840 +test_18() { + # Clear dmesg so watchdog is not triggered by previous + # test output + do_facet ost1 dmesg -c > /dev/null + + test_18_sub normal + test_18_sub directio + + # check if watchdog is triggered + do_facet ost1 dmesg > $TMP/lustre-log-${TESTNAME}.log + local watchdog=$(awk '/[Ss]ervice thread pid/ && /was inactive/ \ + { print; }' $TMP/lustre-log-${TESTNAME}.log) + [ -z "$watchdog" ] || error "$watchdog" + rm -f $TMP/lustre-log-${TESTNAME}.log +} +run_test 18 "MDS failover while writing, no watchdog triggered (b14840)" + +test_19() { + local blimit=5 # MB + local TESTFILE=$DIR/$tdir/$tfile + + setup_quota_test || error "setup quota failed with $?" + + set_ost_qtype $QTYPE || error "enable ost quota failed" + + # bind file to a single OST + $LFS setstripe -c 1 $TESTFILE || error "setstripe $TESTFILE failed" + chown $TSTUSR.$TSTUSR $TESTFILE || error "chown $TESTFILE failed" + + echo "Set user quota (limit: ${blimit}M)" + $LFS setquota -u $TSTUSR -b 0 -B ${blimit}M -i 0 -I 0 $MOUNT || + error "set user quota failed" + quota_show_check b u $TSTUSR + echo "Update quota limits" + $LFS setquota -u $TSTUSR -b 0 -B ${blimit}M -i 0 -I 0 $MOUNT || + error "set group quota failed" + quota_show_check b u $TSTUSR + + # first wirte might be cached + $RUNAS $DD of=$TESTFILE count=$((blimit + 1)) + cancel_lru_locks osc + $SHOW_QUOTA_USER + $RUNAS $DD of=$TESTFILE count=$((blimit + 1)) seek=$((blimit + 1)) && + quota_error u $TSTUSR "Write success, expect failure" + $SHOW_QUOTA_USER +} +run_test 19 "Updating admin limits doesn't zero operational limits(b14790)" + +test_20() { # b15754 + local LSTR=(2g 1t 4k 3m) # limits strings + # limits values + local LVAL=($((2*1024*1024)) $((1*1024*1024*1024)) $((4*1024)) \ + $((3*1024*1024))) + + resetquota -u $TSTUSR + + $LFS setquota -u $TSTUSR --block-softlimit ${LSTR[0]} \ + $MOUNT || error "could not set quota limits" + $LFS setquota -u $TSTUSR --block-hardlimit ${LSTR[1]} \ + --inode-softlimit ${LSTR[2]} \ + --inode-hardlimit ${LSTR[3]} \ + $MOUNT || error "could not set quota limits" + + [ "$(getquota -u $TSTUSR global bsoftlimit)" = "${LVAL[0]}" ] || + error "bsoftlimit was not set properly" + [ "$(getquota -u $TSTUSR global bhardlimit)" = "${LVAL[1]}" ] || + error "bhardlimit was not set properly" + [ "$(getquota -u $TSTUSR global isoftlimit)" = "${LVAL[2]}" ] || + error "isoftlimit was not set properly" + [ "$(getquota -u $TSTUSR global ihardlimit)" = "${LVAL[3]}" ] || + error "ihardlimit was not set properly" + + resetquota -u $TSTUSR +} +run_test 20 "Test if setquota specifiers work properly (b15754)" + +test_21_sub() { + local testfile=$1 + local blk_number=$2 + local seconds=$3 + + local time=$(($(date +%s) + seconds)) + while [ $(date +%s) -lt $time ]; do + $RUNAS $DD of=$testfile count=$blk_number > /dev/null 2>&1 + done +} + +# run for fixing bug16053, setquota shouldn't fail when writing and +# deleting are happening +test_21() { + local TESTFILE="$DIR/$tdir/$tfile" + local BLIMIT=10 # 10G + local ILIMIT=1000000 + + setup_quota_test || error "setup quota failed with $?" + + set_ost_qtype $QTYPE || error "Enable ost quota failed" + + log "Set limit(block:${BLIMIT}G; file:$ILIMIT) for user: $TSTUSR" + $LFS setquota -u $TSTUSR -b 0 -B ${BLIMIT}G -i 0 -I $ILIMIT $MOUNT || + error "set user quota failed" + log "Set limit(block:${BLIMIT}G; file:$ILIMIT) for group: $TSTUSR" + $LFS setquota -g $TSTUSR -b 0 -B $BLIMIT -i 0 -I $ILIMIT $MOUNT || + error "set group quota failed" + if is_project_quota_supported; then + log "Set limit(block:${BLIMIT}G; file:$LIMIT) for " \ + "project: $TSTPRJID" + $LFS setquota -p $TSTPRJID -b 0 -B $BLIMIT -i 0 -I $ILIMIT \ + $MOUNT || error "set project quota failed" + fi + + # repeat writing on a 1M file + test_21_sub ${TESTFILE}_1 1 30 & + local DDPID1=$! + # repeat writing on a 128M file + test_21_sub ${TESTFILE}_2 128 30 & + local DDPID2=$! + + local time=$(($(date +%s) + 30)) + local i=1 + while [ $(date +%s) -lt $time ]; do + log "Set quota for $i times" + $LFS setquota -u $TSTUSR -b 0 -B "$((BLIMIT + i))G" -i 0 \ + -I $((ILIMIT + i)) $MOUNT || + error "Set user quota failed" + $LFS setquota -g $TSTUSR -b 0 -B "$((BLIMIT + i))G" -i 0 \ + -I $((ILIMIT + i)) $MOUNT || + error "Set group quota failed" + if is_project_quota_supported; then + $LFS setquota -p $TSTPRJID -b 0 -B \ + "$((BLIMIT + i))G" -i 0 -I $((ILIMIT + i)) $MOUNT || + error "Set project quota failed" + fi + i=$((i+1)) + sleep 1 + done + + local count=0 + while [ true ]; do + if ! ps -p ${DDPID1} > /dev/null 2>&1; then break; fi + count=$((count+1)) + if [ $count -gt 60 ]; then + quota_error a $TSTUSR "dd should be finished!" + fi + sleep 1 + done + echo "(dd_pid=$DDPID1, time=$count)successful" + + count=0 + while [ true ]; do + if ! ps -p ${DDPID2} > /dev/null 2>&1; then break; fi + count=$((count+1)) + if [ $count -gt 60 ]; then + quota_error a $TSTUSR "dd should be finished!" + fi + sleep 1 + done + echo "(dd_pid=$DDPID2, time=$count)successful" +} +run_test 21 "Setquota while writing & deleting (b16053)" + +# enable/disable quota enforcement permanently +test_22() { + echo "Set both mdt & ost quota type as ug" + local qtype="ug" + is_project_quota_supported && qtype=$QTYPE + set_mdt_qtype $qtype || error "enable mdt quota failed" + set_ost_qtype $qtype || error "enable ost quota failed" + + echo "Restart..." + stopall || error "failed to stopall (1)" + mount + setupall + + echo "Verify if quota is enabled" + local qtype1=$(mdt_quota_type) + [ $qtype1 != $qtype ] && error "mdt quota setting is lost" + qtype=$(ost_quota_type) + [ $qtype1 != $qtype ] && error "ost quota setting is lost" + + echo "Set both mdt & ost quota type as none" + set_mdt_qtype "none" || error "disable mdt quota failed" + set_ost_qtype "none" || error "disable ost quota failed" + + echo "Restart..." + stopall || error "failed to stopall (2)" + mount + setupall + quota_init + + echo "Verify if quota is disabled" + qtype=$(mdt_quota_type) + [ $qtype != "none" ] && error "mdt quota setting is lost" + qtype=$(ost_quota_type) + [ $qtype != "none" ] && error "ost quota setting is lost" + + return 0 +} +run_test 22 "enable/disable quota by 'lctl conf_param/set_param -P'" + +test_23_sub() { + local TESTFILE="$DIR/$tdir/$tfile" + local LIMIT=$1 + + setup_quota_test || error "setup quota failed with $?" + + set_ost_qtype $QTYPE || error "Enable ost quota failed" + + # test for user + log "User quota (limit: $LIMIT MB)" + $LFS setquota -u $TSTUSR -b 0 -B "$LIMIT"M -i 0 -I 0 $DIR || + error "set quota failed" + quota_show_check b u $TSTUSR + + $LFS setstripe $TESTFILE -c 1 -i 0 || error "setstripe $TESTFILE failed" + chown $TSTUSR.$TSTUSR $TESTFILE || error "chown $TESTFILE failed" + + log "Step1: trigger EDQUOT with O_DIRECT" + log "Write half of file" + $RUNAS $DD of=$TESTFILE count=$((LIMIT/2)) oflag=direct || + quota_error u $TSTUSR "(1) Write failure, expect success." \ + "limit=$LIMIT" + log "Write out of block quota ..." + $RUNAS $DD of=$TESTFILE count=$((LIMIT/2 + 1)) seek=$((LIMIT/2)) \ + oflag=direct conv=notrunc && + quota_error u $TSTUSR "(2) Write success, expect EDQUOT." \ + "limit=$LIMIT" + log "Step1: done" + + log "Step2: rewrite should succeed" + $RUNAS $DD of=$TESTFILE count=1 oflag=direct conv=notrunc|| + quota_error u $TSTUSR "(3) Write failure, expect success." \ + "limit=$LIMIT" + log "Step2: done" + + cleanup_quota_test + + local OST0_UUID=$(ostuuid_from_index 0) + local OST0_QUOTA_USED=$(getquota -u $TSTUSR $OST0_UUID curspace) + [ $OST0_QUOTA_USED -ne 0 ] && + ($SHOW_QUOTA_USER; \ + quota_error u $TSTUSR "quota isn't released") + $SHOW_QUOTA_USER +} + +test_23() { + [ "$ost1_FSTYPE" == zfs ] && + skip "Overwrite in place is not guaranteed to be " \ + "space neutral on ZFS" + + local OST0_MIN=$((6 * 1024)) # 6MB, extra space for meta blocks. + check_whether_skip && return 0 + log "run for 4MB test file" + test_23_sub 4 + + OST0_MIN=$((60 * 1024)) # 60MB, extra space for meta blocks. + check_whether_skip && return 0 + log "run for 40MB test file" + test_23_sub 40 +} +run_test 23 "Quota should be honored with directIO (b16125)" + +test_24() { + local blimit=5 # MB + local TESTFILE="$DIR/$tdir/$tfile" + + setup_quota_test || error "setup quota failed with $?" + + set_ost_qtype $QTYPE || error "enable ost quota failed" + + # bind file to a single OST + $LFS setstripe -c 1 $TESTFILE || error "setstripe $TESTFILE failed" + chown $TSTUSR.$TSTUSR $TESTFILE || error "chown $TESTFILE failed" + + echo "Set user quota (limit: ${blimit}M)" + $LFS setquota -u $TSTUSR -b 0 -B "$blimit"M -i 0 -I 0 $MOUNT || + error "set quota failed" + + # overrun quota by root user + runas -u 0 -g 0 $DD of=$TESTFILE count=$((blimit + 1)) || + error "write failure, expect success" + cancel_lru_locks osc + sync_all_data || true + + $SHOW_QUOTA_USER | grep '*' || error "no matching *" +} +run_test 24 "lfs draws an asterix when limit is reached (b16646)" + +test_27a() { # b19612 + $LFS quota $TSTUSR $DIR && + error "lfs succeeded with no type, but should have failed" + $LFS setquota $TSTUSR $DIR && + error "lfs succeeded with no type, but should have failed" + return 0 +} +run_test 27a "lfs quota/setquota should handle wrong arguments (b19612)" + +test_27b() { # b20200 + $LFS setquota -u $TSTID -b 1000 -B 1000 -i 1000 -I 1000 $DIR || + error "lfs setquota failed with uid argument" + $LFS setquota -g $TSTID -b 1000 -B 1000 -i 1000 -I 1000 $DIR || + error "lfs stequota failed with gid argument" + if is_project_quota_supported; then + $LFS setquota -p $TSTPRJID -b 1000 -B 1000 -i 1000 -I \ + 1000 $DIR || error \ + "lfs stequota failed with projid argument" + fi + $SHOW_QUOTA_USERID || error "lfs quota failed with uid argument" + $SHOW_QUOTA_GROUPID || error "lfs quota failed with gid argument" + if is_project_quota_supported; then + $SHOW_QUOTA_PROJID || + error "lfs quota failed with projid argument" + fi + resetquota -u $TSTID + resetquota -g $TSTID + resetquota -p $TSTPRJID + return 0 +} +run_test 27b "lfs quota/setquota should handle user/group/project ID (b20200)" + +test_27c() { + local limit + + $LFS setquota -u $TSTID -b 30M -B 3T $DIR || + error "lfs setquota failed" + + limit=$($LFS quota -u $TSTID -v -h $DIR | grep $DIR | awk '{print $3}') + [ $limit != "30M" ] && error "softlimit $limit isn't human-readable" + limit=$($LFS quota -u $TSTID -v -h $DIR | grep $DIR | awk '{print $4}') + [ $limit != "3T" ] && error "hardlimit $limit isn't human-readable" + + $LFS setquota -u $TSTID -b 1500M -B 18500G $DIR || + error "lfs setquota for $TSTID failed" + + limit=$($LFS quota -u $TSTID -v -h $DIR | grep $DIR | awk '{print $3}') + [ $limit != "1.465G" ] && error "wrong softlimit $limit" + limit=$($LFS quota -u $TSTID -v -h $DIR | grep $DIR | awk '{print $4}') + [ $limit != "18.07T" ] && error "wrong hardlimit $limit" + + $LFS quota -u $TSTID -v -h $DIR | grep -q "Total allocated" || + error "total allocated inode/block limit not printed" + + resetquota -u $TSTUSR +} +run_test 27c "lfs quota should support human-readable output" + +test_27d() { + local softlimit=1.5 + local hardlimit=2.3 + local limit + + $LFS setquota -u $TSTID -b ${softlimit}p -B ${hardlimit}P $DIR || + error "set fraction block limit failed" + limit=$($LFS quota -u $TSTID -h $DIR | grep $DIR | awk '{print $3}') + [ $limit == ${softlimit}P ] || error "get fraction softlimit failed" + limit=$($LFS quota -u $TSTID -h $DIR | grep $DIR | awk '{print $4}') + [ $limit == ${hardlimit}P ] || error "get fraction hardlimit failed" + + resetquota -u $TSTUSR +} +run_test 27d "lfs setquota should support fraction block limit" + +test_30() { + local LIMIT=4 # MB + local TESTFILE="$DIR/$tdir/$tfile" + local GRACE=10 + + setup_quota_test || error "setup quota failed with $?" + + set_ost_qtype "u" || error "enable ost quota failed" + + $LFS setstripe $TESTFILE -i 0 -c 1 || error "setstripe $TESTFILE failed" + chown $TSTUSR.$TSTUSR $TESTFILE || error "chown $TESTFILE failed" + + $LFS setquota -t -u --block-grace $GRACE --inode-grace \ + $MAX_IQ_TIME $DIR || error "set grace time failed" + $LFS setquota -u $TSTUSR -b ${LIMIT}M -B 0 -i 0 -I 0 $DIR || + error "set quota failed" + $RUNAS $DD of=$TESTFILE count=$((LIMIT * 2)) || true + cancel_lru_locks osc + sleep $GRACE + $LFS setquota -u $TSTUSR -B 0 $DIR || error "clear quota failed" + # over-quota flag has not yet settled since we do not trigger async + # events based on grace time period expiration + $SHOW_QUOTA_USER + $RUNAS $DD of=$TESTFILE conv=notrunc oflag=append count=4 || true + cancel_lru_locks osc + # now over-quota flag should be settled and further writes should fail + $SHOW_QUOTA_USER + $RUNAS $DD of=$TESTFILE conv=notrunc oflag=append count=4 && + error "grace times were reset" + $LFS setquota -t -u --block-grace $MAX_DQ_TIME --inode-grace \ + $MAX_IQ_TIME $DIR || error "restore grace time failed" +} +run_test 30 "Hard limit updates should not reset grace times" + +# basic usage tracking for user & group +test_33() { + local INODES=10 # files + local BLK_CNT=2 # MB each + local TOTAL_BLKS=$((INODES * BLK_CNT * 1024)) + + setup_quota_test || error "setup quota failed with $?" + + # make sure the system is clean + local USED=$(getquota -u $TSTID global curspace) + [ $USED -ne 0 ] && + error "Used space ($USED) for user $TSTID isn't 0." + USED=$(getquota -g $TSTID global curspace) + [ $USED -ne 0 ] && + error "Used space ($USED) for group $TSTID isn't 0." + if is_project_quota_supported; then + USED=$(getquota -p $TSTPRJID global curspace) + [ $USED -ne 0 ] && error \ + "Used space ($USED) for project $TSTPRJID isn't 0." + fi + + echo "Write files..." + for i in $(seq 0 $INODES); do + $RUNAS $DD of=$DIR/$tdir/$tfile-$i count=$BLK_CNT 2>/dev/null || + error "write failed" + is_project_quota_supported && + change_project -p $TSTPRJID $DIR/$tdir/$tfile-$i + echo "Iteration $i/$INODES completed" + done + cancel_lru_locks osc + + echo "Wait for setattr on objects finished..." + wait_delete_completed + + sync; sync_all_data || true + + echo "Verify disk usage after write" + USED=$(getquota -u $TSTID global curspace) + [ $USED -lt $TOTAL_BLKS ] && + error "Used space for user $TSTID:$USED, expected:$TOTAL_BLKS" + USED=$(getquota -g $TSTID global curspace) + [ $USED -lt $TOTAL_BLKS ] && + error "Used space for group $TSTID:$USED, expected:$TOTAL_BLKS" + if is_project_quota_supported; then + USED=$(getquota -p $TSTPRJID global curspace) + [ $USED -lt $TOTAL_BLKS ] && error \ + "Used space for project $TSTPRJID:$USED, expected:$TOTAL_BLKS" + fi + + echo "Verify inode usage after write" + USED=$(getquota -u $TSTID global curinodes) + [ $USED -lt $INODES ] && + error "Used inode for user $TSTID is $USED, expected $INODES" + USED=$(getquota -g $TSTID global curinodes) + [ $USED -lt $INODES ] && + error "Used inode for group $TSTID is $USED, expected $INODES" + if is_project_quota_supported; then + USED=$(getquota -p $TSTPRJID global curinodes) + [ $USED -lt $INODES ] && error \ + "Used inode for project $TSTPRJID is $USED, expected $INODES" + fi + + cleanup_quota_test + + echo "Verify disk usage after delete" + USED=$(getquota -u $TSTID global curspace) + [ $USED -eq 0 ] || error "Used space for user $TSTID isn't 0. $USED" + USED=$(getquota -u $TSTID global curinodes) + [ $USED -eq 0 ] || error "Used inodes for user $TSTID isn't 0. $USED" + USED=$(getquota -g $TSTID global curspace) + [ $USED -eq 0 ] || error "Used space for group $TSTID isn't 0. $USED" + USED=$(getquota -g $TSTID global curinodes) [ $USED -eq 0 ] || error "Used inodes for group $TSTID isn't 0. $USED" if is_project_quota_supported; then USED=$(getquota -p $TSTPRJID global curspace) - [ $USED -eq 0 ] || - error "Used space for project $TSTPRJID isn't 0. $USED" + [ $USED -eq 0 ] || + error "Used space for project $TSTPRJID isn't 0. $USED" + USED=$(getquota -p $TSTPRJID global curinodes) + [ $USED -eq 0 ] || + error "Used inodes for project $TSTPRJID isn't 0. $USED" + fi +} +run_test 33 "Basic usage tracking for user & group & project" + +# usage transfer test for user & group & project +test_34() { + local BLK_CNT=2 # MB + local project_supported="no" + + is_project_quota_supported && project_supported="yes" + setup_quota_test || error "setup quota failed with $?" + + # make sure the system is clean + local USED=$(getquota -u $TSTID global curspace) + [ $USED -ne 0 ] && error "Used space ($USED) for user $TSTID isn't 0." + USED=$(getquota -g $TSTID global curspace) + [ $USED -ne 0 ] && error "Used space ($USED) for group $TSTID isn't 0." + + local USED=$(getquota -u $TSTID2 global curspace) + [ $USED -ne 0 ] && error "Used space ($USED) for user $TSTID2 isn't 0." + if [ $project_supported == "yes" ]; then + USED=$(getquota -p $TSTPRJID global curspace) + [ $USED -ne 0 ] && error \ + "Used space ($USED) for Project $TSTPRJID isn't 0." + fi + + echo "Write file..." + $DD of=$DIR/$tdir/$tfile count=$BLK_CNT 2>/dev/null || + error "write failed" + cancel_lru_locks osc + sync; sync_all_data || true + + echo "chown the file to user $TSTID" + chown $TSTID $DIR/$tdir/$tfile || error "chown failed" + + echo "Wait for setattr on objects finished..." + wait_delete_completed + + BLK_CNT=$((BLK_CNT * 1024)) + + echo "Verify disk usage for user $TSTID" + USED=$(getquota -u $TSTID global curspace) + [ $USED -lt $BLK_CNT ] && + error "Used space for user $TSTID is ${USED}, expected $BLK_CNT" + USED=$(getquota -u $TSTID global curinodes) + [ $USED -ne 1 ] && + error "Used inodes for user $TSTID is $USED, expected 1" + + echo "chgrp the file to group $TSTID" + chgrp $TSTID $DIR/$tdir/$tfile || error "chgrp failed" + + echo "Wait for setattr on objects finished..." + wait_delete_completed + + echo "Verify disk usage for group $TSTID" + USED=$(getquota -g $TSTID global curspace) + [ $USED -ge $BLK_CNT ] || + error "Used space for group $TSTID is $USED, expected $BLK_CNT" + USED=$(getquota -g $TSTID global curinodes) + [ $USED -eq 1 ] || + error "Used inodes for group $TSTID is $USED, expected 1" + + # chown won't change the ost object group. LU-4345 */ + echo "chown the file to user $TSTID2" + chown $TSTID2 $DIR/$tdir/$tfile || error "chown to $TSTID2 failed" + + echo "Wait for setattr on objects finished..." + wait_delete_completed + + echo "change_project project id to $TSTPRJID" + [ $project_supported == "yes" ] && + change_project -p $TSTPRJID $DIR/$tdir/$tfile + echo "Wait for setattr on objects finished..." + wait_delete_completed + + echo "Verify disk usage for user $TSTID2/$TSTID and group $TSTID" + USED=$(getquota -u $TSTID2 global curspace) + [ $USED -lt $BLK_CNT ] && + error "Used space for user $TSTID2 is $USED, expected $BLK_CNT" + USED=$(getquota -u $TSTID global curspace) + [ $USED -ne 0 ] && + error "Used space for user $TSTID is $USED, expected 0" + USED=$(getquota -g $TSTID global curspace) + [ $USED -lt $BLK_CNT ] && + error "Used space for group $TSTID is $USED, expected $BLK_CNT" + if [ $project_supported == "yes" ]; then + USED=$(getquota -p $TSTPRJID global curspace) + [ $USED -lt $BLK_CNT ] && error \ + "Used space for group $TSTPRJID is $USED, expected $BLK_CNT" + fi + return 0 +} +run_test 34 "Usage transfer for user & group & project" + +# usage is still accessible across restart +test_35() { + local BLK_CNT=2 # MB + + setup_quota_test || error "setup quota failed with $?" + + echo "Write file..." + $RUNAS $DD of=$DIR/$tdir/$tfile count=$BLK_CNT 2>/dev/null || + error "write failed" + is_project_quota_supported && + change_project -p $TSTPRJID $DIR/$tdir/$tfile + cancel_lru_locks osc + + echo "Wait for setattr on objects finished..." + wait_delete_completed + + sync; sync_all_data || true + + echo "Save disk usage before restart" + local ORIG_USR_SPACE=$(getquota -u $TSTID global curspace) + [ $ORIG_USR_SPACE -eq 0 ] && + error "Used space for user $TSTID is 0, expected ${BLK_CNT}M" + local ORIG_USR_INODES=$(getquota -u $TSTID global curinodes) + [ $ORIG_USR_INODES -eq 0 ] && + error "Used inodes for user $TSTID is 0, expected 1" + echo "User $TSTID: ${ORIG_USR_SPACE}KB $ORIG_USR_INODES inodes" + local ORIG_GRP_SPACE=$(getquota -g $TSTID global curspace) + [ $ORIG_GRP_SPACE -eq 0 ] && + error "Used space for group $TSTID is 0, expected ${BLK_CNT}M" + local ORIG_GRP_INODES=$(getquota -g $TSTID global curinodes) + [ $ORIG_GRP_INODES -eq 0 ] && + error "Used inodes for group $TSTID is 0, expected 1" + echo "Group $TSTID: ${ORIG_GRP_SPACE}KB $ORIG_GRP_INODES inodes" + + if is_project_quota_supported; then + local ORIG_PRJ_SPACE=$(getquota -p $TSTPRJID global curspace) + [ $ORIG_PRJ_SPACE -eq 0 ] && error \ + "Used space for project $TSTPRJID is 0, expected ${BLK_CNT}M" + local ORIG_PRJ_INODES=$(getquota -p $TSTPRJID global curinodes) + [ $ORIG_PRJ_INODES -eq 0 ] && error \ + "Used inodes for project $TSTPRJID is 0, expected 1" + echo "Project $TSTPRJID: ${ORIG_PRJ_SPACE}KB $ORIG_PRJ_INODES inodes" + fi + + log "Restart..." + stopall + setupall + quota_init + + echo "Verify disk usage after restart" + local USED=$(getquota -u $TSTID global curspace) + [ $USED -eq $ORIG_USR_SPACE ] || + error "Used space for user $TSTID changed from " \ + "$ORIG_USR_SPACE to $USED" + USED=$(getquota -u $TSTID global curinodes) + [ $USED -eq $ORIG_USR_INODES ] || + error "Used inodes for user $TSTID changed from " \ + "$ORIG_USR_INODES to $USED" + USED=$(getquota -g $TSTID global curspace) + [ $USED -eq $ORIG_GRP_SPACE ] || + error "Used space for group $TSTID changed from " \ + "$ORIG_GRP_SPACE to $USED" + USED=$(getquota -g $TSTID global curinodes) + [ $USED -eq $ORIG_GRP_INODES ] || + error "Used inodes for group $TSTID changed from " \ + "$ORIG_GRP_INODES to $USED" + if [ $project_supported == "yes" ]; then USED=$(getquota -p $TSTPRJID global curinodes) - [ $USED -eq 0 ] || - error "Used inodes for project $TSTPRJID isn't 0. $USED" + [ $USED -eq $ORIG_PRJ_INODES ] || + error "Used inodes for project $TSTPRJID " \ + "changed from $ORIG_PRJ_INODES to $USED" + USED=$(getquota -p $TSTPRJID global curspace) + [ $USED -eq $ORIG_PRJ_SPACE ] || + error "Used space for project $TSTPRJID "\ + "changed from $ORIG_PRJ_SPACE to $USED" + fi + + # check if the vfs_dq_init() is called before writing + echo "Append to the same file..." + $RUNAS $DD of=$DIR/$tdir/$tfile count=$BLK_CNT seek=1 2>/dev/null || + error "write failed" + cancel_lru_locks osc + sync; sync_all_data || true + + echo "Verify space usage is increased" + USED=$(getquota -u $TSTID global curspace) + [ $USED -gt $ORIG_USR_SPACE ] || + error "Used space for user $TSTID isn't increased" \ + "orig:$ORIG_USR_SPACE, now:$USED" + USED=$(getquota -g $TSTID global curspace) + [ $USED -gt $ORIG_GRP_SPACE ] || + error "Used space for group $TSTID isn't increased" \ + "orig:$ORIG_GRP_SPACE, now:$USED" + if [ $project_supported == "yes" ]; then + USED=$(getquota -p $TSTPRJID global curspace) + [ $USED -gt $ORIG_PRJ_SPACE ] || + error "Used space for project $TSTPRJID isn't " \ + "increased orig:$ORIG_PRJ_SPACE, now:$USED" + fi +} +run_test 35 "Usage is still accessible across reboot" + +# chown/chgrp to the file created with MDS_OPEN_DELAY_CREATE +# LU-5006 +test_37() { + [ "$MDS1_VERSION" -lt $(version_code 2.6.93) ] && + skip "Old server doesn't have LU-5006 fix." + + setup_quota_test || error "setup quota failed with $?" + + # make sure the system is clean + local USED=$(getquota -u $TSTID global curspace) + [ $USED -ne 0 ] && + error "Used space ($USED) for user $TSTID isn't 0." + + # create file with MDS_OPEN_DELAY_CREATE flag + $LFS setstripe -c 1 -i 0 $DIR/$tdir/$tfile || + error "Create file failed" + # write to file + dd if=/dev/zero of=$DIR/$tdir/$tfile bs=1M count=1 conv=notrunc \ + oflag=sync || error "Write file failed" + # chown to the file + chown $TSTID $DIR/$tdir/$tfile || error "Chown to file failed" + + # wait for setattr on objects finished..." + wait_delete_completed + + USED=$(getquota -u $TSTID global curspace) + [ $USED -ne 0 ] || quota_error u $TSTUSR "Used space is 0" +} +run_test 37 "Quota accounted properly for file created by 'lfs setstripe'" + +# LU-8801 +test_38() { + [ "$MDS1_VERSION" -lt $(version_code 2.8.60) ] && + skip "Old server doesn't have LU-8801 fix." + + [ "$UID" != 0 ] && skip_env "must run as root" && return + + setup_quota_test || error "setup quota failed with $?" + + # make sure the system is clean + local USED=$(getquota -u $TSTID global curspace) + [ $USED -ne 0 ] && + error "Used space ($USED) for user $TSTID isn't 0." + USED=$(getquota -u $TSTID2 global curspace) + [ $USED -ne 0 ] && + error "Used space ($USED) for user $TSTID2 isn't 0." + + local TESTFILE="$DIR/$tdir/$tfile" + local file_cnt=10000 + + # Generate id entries in accounting file + echo "Create $file_cnt files..." + for i in `seq $file_cnt`; do + touch $TESTFILE-$i + chown $((file_cnt - i)):$((file_cnt - i)) $TESTFILE-$i || + error "failed to chown $TESTFILE-$i" + done + cancel_lru_locks osc + sync; sync_all_data || true + + local procf="osd-$mds1_FSTYPE.$FSNAME-MDT0000" + procf=${procf}.quota_slave.acct_user + local acct_cnt + + acct_cnt=$(do_facet mds1 $LCTL get_param $procf | grep "id:" | \ + awk '{if ($3 < 10000) {print $3}}' | wc -l) + echo "Found $acct_cnt id entries" + + [ $file_cnt -eq $acct_cnt ] || { + do_facet mds1 $LCTL get_param $procf + error "skipped id entries" + } +} +run_test 38 "Quota accounting iterator doesn't skip id entries" + +test_39() { + local TESTFILE="$DIR/$tdir/project" + ! is_project_quota_supported && + skip "Project quota is not supported" + + setup_quota_test || error "setup quota failed with $?" + + touch $TESTFILE + projectid=$(lfs project $TESTFILE | awk '{print $1}') + [ $projectid -ne 0 ] && + error "Project id should be 0 not $projectid" + change_project -p 1024 $TESTFILE + projectid=$(lfs project $TESTFILE | awk '{print $1}') + [ $projectid -ne 1024 ] && + error "Project id should be 1024 not $projectid" + + stopall || error "failed to stopall (1)" + mount + setupall + projectid=$(lfs project $TESTFILE | awk '{print $1}') + [ $projectid -eq 1024 ] || + error "Project id should be 1024 not $projectid" +} +run_test 39 "Project ID interface works correctly" + +test_40a() { + ! is_project_quota_supported && + skip "Project quota is not supported" + local dir1="$DIR/$tdir/dir1" + local dir2="$DIR/$tdir/dir2" + + setup_quota_test || error "setup quota failed with $?" + + mkdir -p $dir1 $dir2 + change_project -sp 1 $dir1 && touch $dir1/1 + change_project -sp 2 $dir2 + + ln $dir1/1 $dir2/1_link && + error "Hard link across different project quota should fail" + return 0 +} +run_test 40a "Hard link across different project ID" + +test_40b() { + ! is_project_quota_supported && + skip "Project quota is not supported" + local dir1="$DIR/$tdir/dir1" + local dir2="$DIR/$tdir/dir2" + + setup_quota_test || error "setup quota failed with $?" + mkdir -p $dir1 $dir2 + change_project -sp 1 $dir1 && touch $dir1/1 + change_project -sp 2 $dir2 + + mv $dir1/1 $dir2/2 || error "mv failed $?" + local projid=$(lfs project $dir2/2 | awk '{print $1}') + [ "$projid" -eq 2 ] || error "project id expected 2 not $projid" +} +run_test 40b "Mv across different project ID" + +test_40c() { + [ "$MDSCOUNT" -lt "2" ] && skip "needs >= 2 MDTs" + ! is_project_quota_supported && + skip "Project quota is not supported" + + setup_quota_test || error "setup quota failed with $?" + local dir="$DIR/$tdir/dir" + + mkdir -p $dir && change_project -sp 1 $dir + $LFS mkdir -i 1 $dir/remote_dir || error "create remote dir failed" + local projid=$(lfs project -d $dir/remote_dir | awk '{print $1}') + [ "$projid" != "1" ] && error "projid id expected 1 not $projid" + touch $dir/remote_dir/file + #verify inherit works file for remote dir. + local projid=$(lfs project -d $dir/remote_dir/file | awk '{print $1}') + [ "$projid" != "1" ] && + error "file under remote dir expected 1 not $projid" + + #Agent inode should be ignored for project quota + local used=$(getquota -p 1 global curinodes) + [ $used -eq 3 ] || + error "file count expected 3 got $used" +} +run_test 40c "Remote child Dir inherit project quota properly" + +test_40d() { + [ "$MDSCOUNT" -lt "2" ] && skip_env "needs >= 2 MDTs" + is_project_quota_supported || skip "Project quota is not supported" + + setup_quota_test || error "setup quota failed with $?" + local dir="$DIR/$tdir/dir" + + mkdir -p $dir + $LFS setdirstripe -D -c 2 -i -1 $dir || error "setdirstripe failed" + change_project -sp $TSTPRJID $dir || + error "change project on $dir failed" + for i in $(seq 5); do + mkdir -p $dir/d$i/d$i || + error "mkdir $dir/d$i/d$i failed" + local projid=$($LFS project -d $dir/d$i/d$i | + awk '{print $1}') + [ "$projid" == "$TSTPRJID" ] || + error "projid id expected $TSTPRJID not $projid" + touch $dir/d$i/d$i/file + #verify inherit works file for stripe dir. + local projid=$($LFS project -d $dir/d$i/d$i/file | awk '{print $1}') + [ "$projid" == "$TSTPRJID" ] || + error "file under remote dir expected 1 not $projid" + done + + # account should be 1 + (2 + 1) *10 + 1 * 5 + local used=$(getquota -p $TSTPRJID global curinodes) + [ $used -eq 36 ] || + error "file count expected 36 got $used" +} +run_test 40d "Stripe Directory inherit project quota properly" + +test_41() { + is_project_quota_supported || + skip "Project quota is not supported" + setup_quota_test || error "setup quota failed with $?" + local dir="$DIR/$tdir/dir" + local blimit=102400 + local ilimit=4096 + local projid=$((testnum * 1000)) + + quota_init + + # enable mdt/ost quota + set_mdt_qtype ugp || error "enable mdt quota failed" + set_ost_qtype ugp || error "enable ost quota failed" + + test_mkdir -p $dir && change_project -sp $projid $dir + $LFS setquota -p $projid -b 0 -B ${blimit}K -i 0 -I $ilimit $dir || + error "set project quota failed" + + sync; sync_all_data + sleep_maxage + + # check if df output works as expected + echo "== global statfs: $MOUNT ==" + df -kP $MOUNT; df -iP $MOUNT; $LFS quota -p $projid $dir + echo + echo "== project statfs (prjid=$projid): $dir ==" + df -kP $dir; df -iP $dir + local bused=$(getquota -p $projid global curspace) + local iused=$(getquota -p $projid global curinodes) + # note trailing space to match double printf from awk + local expected="$blimit $bused $ilimit $iused " + + wait_update $HOSTNAME \ + "{ df -kP $dir; df -iP $dir; } | + awk '/$FSNAME/ { printf \\\"%d %d \\\", \\\$2,\\\$3 }'" \ + "$expected" || + error "failed to get correct statfs for project quota" +} +run_test 41 "df should return projid-specific values" + +test_delete_qid() +{ + local qslv_file=$1 + local qtype_file=$2 + local qtype=$3 + local qid=$4 + local osd="osd-ldiskfs" + + [ "$ost1_FSTYPE" = zfs ] && osd="osd-zfs" + + rm -f $DIR/$tdir/$tfile + $LFS setstripe -i 0 -c 1 $DIR/$tdir/$tfile + chmod a+rw $DIR/$tdir/$tfile + + $LFS setquota $qtype $qid -B 300M $MOUNT + $RUNAS dd if=/dev/zero of=$DIR/$tdir/$tfile bs=1M count=1 || + error "failed to dd" + + do_facet $SINGLEMDS \ + "cat /proc/fs/lustre/qmt/$FSNAME-QMT0000/dt-0x0/$qtype_file | + grep -E 'id: *$qid'" || error "QMT: no qid $qid is found" + echo $osd + do_facet ost1 \ + "cat /proc/fs/lustre/$osd/$FSNAME-OST0000/$qslv_file | + grep -E 'id: *$qid'" || error "QSD: no qid $qid is found" + + $LFS setquota $qtype $qid --delete $MOUNT + do_facet $SINGLEMDS \ + "cat /proc/fs/lustre/qmt/$FSNAME-QMT0000/dt-0x0/$qtype_file | + grep -E 'id: *$qid'" && error "QMT: qid $qid is not deleted" + sleep 5 + do_facet ost1 \ + "cat /proc/fs/lustre/$osd/$FSNAME-OST0000/$qslv_file | + grep -E 'id: *$qid'" && error "QSD: qid $qid is not deleted" + + $LFS setquota $qtype $qid -B 500M $MOUNT + $RUNAS dd if=/dev/zero of=$DIR/$tdir/$tfile bs=1M count=1 || + error "failed to dd" + do_facet $SINGLEMDS \ + "cat /proc/fs/lustre/qmt/$FSNAME-QMT0000/dt-0x0/$qtype_file | + grep -E 'id: *$qid'" || error "QMT: qid $pid is not recreated" + cat /proc/fs/lustre/$osd/$FSNAME-OST0000/$qslv_file + do_facet ost1 \ + "cat /proc/fs/lustre/$osd/$FSNAME-OST0000/$qslv_file | + grep -E 'id: *$qid'" || error "QSD: qid $qid is not recreated" +} + +test_48() +{ + setup_quota_test || error "setup quota failed with $?" + set_ost_qtype $QTYPE || error "enable ost quota failed" + quota_init + + test_delete_qid "quota_slave/limit_user" "glb-usr" "-u" $TSTID + test_delete_qid "quota_slave/limit_group" "glb-grp" "-g" $TSTID + is_project_quota_supported && + test_delete_qid "quota_slave/limit_project" "glb-prj" "-p" "10000" + + cleanup_quota_test +} +run_test 48 "lfs quota --delete should delete quota project ID" + +test_50() { + ! is_project_quota_supported && + skip "Project quota is not supported" + + setup_quota_test || error "setup quota failed with $?" + local dir1="$DIR/$tdir/dir1" + local dir2="$DIR/$tdir/dir2" + + mkdir -p $dir1 && change_project -sp 1 $dir1 + mkdir -p $dir2 && change_project -sp 2 $dir2 + for num in $(seq 1 10); do + touch $dir1/file_$num $dir2/file_$num + ln -s $dir1/file_$num $dir1/file_$num"_link" + ln -s $dir2/file_$num $dir2/file_$num"_link" + done + + count=$($LFS find --projid 1 $DIR | wc -l) + [ "$count" != 21 ] && error "expected 21 but got $count" + + # 1(projid 0 dir) + 1(projid 2 dir) + 20(projid 2 files) + count=$($LFS find ! --projid 1 $DIR/$tdir | wc -l) + [ $count -eq 22 ] || error "expected 22 but got $count" +} +run_test 50 "Test if lfs find --projid works" + +test_51() { + ! is_project_quota_supported && + skip "Project quota is not supported" + setup_quota_test || error "setup quota failed with $?" + local dir="$DIR/$tdir/dir" + + mkdir $dir && change_project -sp 1 $dir + local used=$(getquota -p 1 global curinodes) + [ $used != "1" ] && error "expected 1 got $used" + + touch $dir/1 + touch $dir/2 + cp $dir/2 $dir/3 + used=$(getquota -p 1 global curinodes) + [ $used != "4" ] && error "expected 4 got $used" + + $DD if=/dev/zero of=$DIR/$tdir/6 bs=1M count=1 + #try cp to dir + cp $DIR/$tdir/6 $dir/6 + used=$(getquota -p 1 global curinodes) + [ $used != "5" ] && error "expected 5 got $used" + + #try mv to dir + mv $DIR/$tdir/6 $dir/7 + used=$(getquota -p 1 global curinodes) + [ $used -eq 6 ] || error "expected 6 got $used" +} +run_test 51 "Test project accounting with mv/cp" + +test_52() { + ! is_project_quota_supported && + skip "Project quota is not supported" + + (( MDS1_VERSION >= $(version_code 2.14.55) )) || + skip "Need MDS version at least 2.14.55" + + setup_quota_test || error "setup quota failed with $?" + + local dir1=$DIR/$tdir/t52_dir1 + local dir2=$DIR/$tdir/t52_dir2 + + mkdir $dir1 || error "failed to mkdir $dir1" + mkdir $dir2 || error "failed to mkdir $dir2" + + $LFS project -sp 1000 $dir1 || error "fail to set project on $dir1" + $LFS project -sp 1001 $dir2 || error "fail to set project on $dir2" + + $DD if=/dev/zero of=/$dir1/$tfile bs=1M count=100 || + error "failed to create and write $tdir1/$tfile" + + cancel_lru_locks osc + sync; sync_all_data || true + + local attrs=($(lsattr -p $dir1/$tfile)) + (( ${attrs[0]} == 1000 )) || + error "project ID on $dir1/$tfile is not inherited" + + $LFS quota -p 1000 $DIR + $LFS quota -p 1001 $DIR + + local prev_used=$(getquota -p 1000 global curspace) + local prev_used2=$(getquota -p 1001 global curspace) + + mrename $dir1 $dir2/tdir || log "rename directory return $?" + + local inum_before=$(ls -i $dir1/$tfile | awk '{print $1}') + mrename $dir1/$tfile $dir2/$tfile || error "failed to rename file" + local inum_after=$(ls -i $dir2/$tfile | awk '{print $1}') + + attrs=($(lsattr -p $dir2/$tfile)) + (( ${attrs[0]} == 1001 )) || + error "project ID is not updated after rename" + + (( $inum_before == $inum_after )) || + error "inode is changed after rename: $inum_before, $inum_after" + + sync_all_data || true + + $LFS quota -p 1000 $DIR + $LFS quota -p 1001 $DIR + + local new_used=$(getquota -p 1000 global curspace) + local new_used2=$(getquota -p 1001 global curspace) + + (( $prev_used >= $new_used + 102400 )) || + error "quota is not deducted from old project ID" + (( $prev_used2 <= $new_used2 - 102400 )) || + error "quota is not added for the new project ID" +} +run_test 52 "Rename normal file across project ID" + +test_53() { + ! is_project_quota_supported && + skip "Project quota is not supported" + setup_quota_test || error "setup quota failed with $?" + local dir="$DIR/$tdir/dir" + mkdir $dir && change_project -s $dir + [[ $($LFS project -d $dir) =~ " P " ]] || + error "inherit attribute should be set" + + change_project -C $dir + [[ $($LFS project -d $dir) =~ " - " ]] || + error "inherit attribute should be cleared" +} +run_test 53 "Project inherit attribute could be cleared" + +test_54() { + ! is_project_quota_supported && + skip "Project quota is not supported" + setup_quota_test || error "setup quota failed with $?" + local testfile="$DIR/$tdir/$tfile-0" + + #set project ID/inherit attribute + change_project -sp $TSTPRJID $DIR/$tdir + $RUNAS createmany -m ${testfile} 100 || + error "create many files failed" + + local proj_count=$(lfs project -r $DIR/$tdir | wc -l) + # one more count for directory itself */ + ((proj_count++)) + + #check project + local proj_count1=$(lfs project -rcp $TSTPRJID $DIR/$tdir | wc -l) + [ $proj_count1 -eq 0 ] || error "c1: expected 0 got $proj_count1" + + proj_count1=$(lfs project -rcp $((TSTPRJID+1)) $DIR/$tdir | wc -l) + [ $proj_count1 -eq $proj_count ] || + error "c2: expected $proj_count got $proj_count1" + + #clear project but with kept projid + change_project -rCk $DIR/$tdir + proj_count1=$(lfs project -rcp $TSTPRJID $DIR/$tdir | wc -l) + [ $proj_count1 -eq 1 ] || + error "c3: expected 1 got $proj_count1" + + #verify projid untouched. + proj_count1=$(lfs project -r $DIR/$tdir | grep -c $TSTPRJID) + ((proj_count1++)) + [ $proj_count1 -eq $proj_count ] || + error "c4: expected $proj_count got $proj_count1" + + # test -0 option + lfs project $DIR/$tdir -cr -0 | xargs -0 lfs project -s + proj_count1=$(lfs project -rcp $TSTPRJID $DIR/$tdir | wc -l) + [ $proj_count1 -eq 0 ] || error "c5: expected 0 got $proj_count1" + + #this time clear all + change_project -rC $DIR/$tdir + proj_count1=$(lfs project -r $DIR/$tdir | grep -c $TSTPRJID) + [ $proj_count1 -eq 0 ] || + error "c6: expected 0 got $proj_count1" + #cleanup + unlinkmany ${testfile} 100 || + error "unlink many files failed" +} +run_test 54 "basic lfs project interface test" + +test_55() { + [ "$MDS1_VERSION" -lt $(version_code 2.10.58) ] && + skip "Not supported before 2.10.58." + setup_quota_test || error "setup quota failed with $?" + + set_ost_qtype $QTYPE || error "enable ost quota failed" + quota_init + + #add second group to TSTUSR + usermod -G $TSTUSR,$TSTUSR2 $TSTUSR + + #prepare test file + $RUNAS dd if=/dev/zero of=$DIR/$tdir/$tfile bs=1024 count=100000 || + error "failed to dd" + + cancel_lru_locks osc + sync; sync_all_data || true + + $LFS setquota -g $TSTUSR2 -b 0 -B 50M $DIR || + error "failed to setquota on group $TSTUSR2" + + $LFS quota -v -g $TSTUSR2 $DIR + + runas -u $TSTUSR -g $TSTUSR2 chgrp $TSTUSR2 $DIR/$tdir/$tfile && + error "chgrp should failed with -EDQUOT" + + USED=$(getquota -g $TSTUSR2 global curspace) + echo "$USED" + + $LFS setquota -g $TSTUSR2 -b 0 -B 300M $DIR || + error "failed to setquota on group $TSTUSR2" + + $LFS quota -v -g $TSTUSR2 $DIR + + runas -u $TSTUSR -g $TSTUSR2 chgrp $TSTUSR2 $DIR/$tdir/$tfile || + error "chgrp should succeed" + + $LFS quota -v -g $TSTUSR2 $DIR +} +run_test 55 "Chgrp should be affected by group quota" + +test_56() { + setup_quota_test || error "setup quota failed with $?" + + set_ost_qtype $QTYPE || error "enable ost quota failed" + quota_init + + $LFS setquota -t -u -b 10 -i 10 $DIR || + erro "failed to set grace time for usr quota" + grace_time=$($LFS quota -t -u $DIR | grep "Block grace time:" | + awk '{print $4 $8}') + if [ "x$grace_time" != "x10s;10s" ]; then + $LFS quota -t -u $DIR + error "expected grace time: 10s;10s, got:$grace_time" + fi +} +run_test 56 "lfs quota -t should work well" + +test_57() { + setup_quota_test || error "setup quota failed with $?" + + local dir="$DIR/$tdir/dir" + mkdir -p $dir + mkfifo $dir/pipe + #command can process further if it hit some errors + $LFS project -sp 1 $dir/pipe + touch $dir/aaa $dir/bbb + mkdir $dir/subdir -p + touch $dir/subdir/aaa $dir/subdir/bbb + #create one invalid link file + ln -s $dir/not_exist_file $dir/ccc + local cnt=$(lfs project -r $dir 2>/dev/null | wc -l) + [ $cnt -eq 7 ] || error "expected 7 got $cnt" +} +run_test 57 "lfs project could tolerate errors" + +test_59() { + [ "$mds1_FSTYPE" != ldiskfs ] && + skip "ldiskfs only test" + disable_project_quota + setup_quota_test || error "setup quota failed with $?" + quota_init + + local testfile="$DIR/$tdir/$tfile-0" + #make sure it did not crash kernel + touch $testfile && lfs project -sp 1 $testfile + + enable_project_quota +} +run_test 59 "lfs project dosen't crash kernel with project disabled" + +test_60() { + [ $MDS1_VERSION -lt $(version_code 2.11.53) ] && + skip "Needs MDS version 2.11.53 or later." + setup_quota_test || error "setup quota failed with $?" + + local testfile=$DIR/$tdir/$tfile + local limit=100 + + set_mdt_qtype "ug" || error "enable mdt quota failed" + + $LFS setquota -g $TSTUSR -b 0 -B 0 -i 0 -I $limit $DIR || + error "set quota failed" + quota_show_check a g $TSTUSR + + chown $TSTUSR.$TSTUSR $DIR/$tdir || error "chown $DIR/$tdir failed" + chmod g+s $DIR/$tdir || error "chmod g+s failed" + $RUNAS createmany -m ${testfile} $((limit-1)) || + error "create many files failed" + + $RUNAS touch $DIR/$tdir/foo && error "regular user should fail" + + # root user can overrun quota + runas -u 0 -g 0 touch $DIR/$tdir/foo || + error "root user should succeed" +} +run_test 60 "Test quota for root with setgid" + +# test default quota +test_default_quota() { + [ "$MDS1_VERSION" -lt $(version_code 2.11.51) ] && + skip "Not supported before 2.11.51." + + local qtype=$1 + local qres_type=$2 + local qid=$TSTUSR + local qprjid=$TSTPRJID + local qdtype="-U" + local qs="-b" + local qh="-B" + local LIMIT=20480 #20M disk space + local TESTFILE="$DIR/$tdir/$tfile-0" + local $qpool_cmd + + [ $qtype == "-p" ] && ! is_project_quota_supported && + echo "Project quota is not supported" && return 0 + + [ $qtype == "-u" ] && qdtype="-U" + [ $qtype == "-g" ] && qdtype="-G" + [ $qtype == "-p" ] && { + qdtype="-P" + qid=$qprjid + } + + [ $qres_type == "meta" ] && { + LIMIT=10240 #10K inodes + qs="-i" + qh="-I" + } + [ ! -z "$3" ] && { + qpool_cmd="--pool $3" + # pool quotas don't work properly without global limit + $LFS setquota $qtype $qid -B1T -b1T $DIR || + error "set global limit failed" + } + + setup_quota_test || error "setup quota failed with $?" + + quota_init + + # enable mdt/ost quota + set_mdt_qtype $QTYPE || error "enable mdt quota failed" + set_ost_qtype $QTYPE || error "enable ost quota failed" + + log "set to use default quota" + $LFS setquota $qtype $qid -d $qpool_cmd $DIR || + error "set $qid to use default quota failed" + + log "set default quota" + $LFS setquota $qdtype $qpool_cmd $qs ${LIMIT} $qh ${LIMIT} $DIR || + error "set $qid default quota failed" + + log "get default quota" + $LFS quota $qdtype $DIR || error "get default quota failed" + + if [ $qres_type == "data" ]; then + local SLIMIT=$($LFS quota $qpool_cmd $qdtype $DIR | \ + grep "$MOUNT" | awk '{print $2}') + [ $SLIMIT -eq $LIMIT ] || + error "the returned default quota is wrong" + else + local SLIMIT=$($LFS quota $qdtype $DIR | grep "$MOUNT" | \ + awk '{print $5}') + [ $SLIMIT -eq $LIMIT ] || + error "the returned default quota is wrong" + fi + + # make sure the system is clean + local USED=$(getquota $qtype $qid global curspace) + [ $USED -ne 0 ] && error "Used space for $qid isn't 0." + + $LFS setstripe $TESTFILE -c 1 $qpool_cmd || + error "setstripe $TESTFILE failed" + chown $TSTUSR.$TSTUSR $TESTFILE || error "chown $TESTFILE failed" + + [ $qtype == "-p" ] && change_project -sp $TSTPRJID $DIR/$tdir + + log "Test not out of quota" + if [ $qres_type == "data" ]; then + $RUNAS $DD of=$TESTFILE count=$((LIMIT/2 >> 10)) oflag=sync || + quota_error $qtype $qid "write failed, expect succeed" + else + $RUNAS createmany -m $TESTFILE $((LIMIT/2)) || + quota_error $qtype $qid "create failed, expect succeed" + + unlinkmany $TESTFILE $((LIMIT/2)) + fi + + log "Test out of quota" + # flush cache, ensure noquota flag is set on client + cancel_lru_locks osc + cancel_lru_locks mdc + sync; sync_all_data || true + if [ $qres_type == "data" ]; then + $RUNAS $DD of=$TESTFILE count=$((LIMIT*2 >> 10)) oflag=sync && + quota_error $qtype $qid "write succeed, expect EDQUOT" + else + $RUNAS createmany -m $TESTFILE $((LIMIT*2)) && + quota_error $qtype $qid "create succeed, expect EDQUOT" + + unlinkmany $TESTFILE $((LIMIT*2)) + fi + + rm -f $TESTFILE + $LFS setstripe $TESTFILE -c 1 $qpool_cmd || + error "setstripe $TESTFILE failed" + chown $TSTUSR.$TSTUSR $TESTFILE || error "chown $TESTFILE failed" + + log "Increase default quota" + + # LU-4505: sleep 5 seconds to enable quota acquire + sleep 5 + + # increase default quota + $LFS setquota $qdtype $qpool_cmd $qs $((LIMIT*3)) \ + $qh $((LIMIT*3)) $DIR || error "set default quota failed" + + cancel_lru_locks osc + cancel_lru_locks mdc + sync; sync_all_data || true + if [ $qres_type == "data" ]; then + $RUNAS $DD of=$TESTFILE count=$((LIMIT*2 >> 10)) oflag=sync || + quota_error $qtype $qid "write failed, expect succeed" + else + $RUNAS createmany -m $TESTFILE $((LIMIT*2)) || + quota_error $qtype $qid "create failed, expect succeed" + + unlinkmany $TESTFILE $((LIMIT*2)) + fi + + log "Set quota to override default quota" + $LFS setquota $qtype $qid $qpool_cmd $qs ${LIMIT} $qh ${LIMIT} $DIR || + error "set $qid quota failed" + + cancel_lru_locks osc + cancel_lru_locks mdc + sync; sync_all_data || true + if [ $qres_type == "data" ]; then + $RUNAS $DD of=$TESTFILE count=$((LIMIT*2 >> 10)) oflag=sync && + quota_error $qtype $qid "write succeed, expect EQUOT" + else + $RUNAS createmany -m $TESTFILE $((LIMIT*2)) && + quota_error $qtype $qid "create succeed, expect EQUOT" + + unlinkmany $TESTFILE $((LIMIT*2)) + fi + + log "Set to use default quota again" + + # LU-4505: sleep 5 seconds to enable quota acquire + sleep 5 + + $LFS setquota $qtype $qid -d $qpool_cmd $DIR || + error "set $qid to use default quota failed" + + cancel_lru_locks osc + cancel_lru_locks mdc + sync; sync_all_data || true + if [ $qres_type == "data" ]; then + $RUNAS $DD of=$TESTFILE count=$((LIMIT*2 >> 10)) oflag=sync || + quota_error $qtype $qid "write failed, expect succeed" + else + $RUNAS createmany -m $TESTFILE $((LIMIT*2)) || + quota_error $qtype $qid "create failed, expect succeed" + + unlinkmany $TESTFILE $((LIMIT*2)) fi + + log "Cleanup" + rm -f $TESTFILE + wait_delete_completed || error "wait_delete_completed failed" + sync_all_data || true + + $LFS setquota $qdtype $qpool_cmd $qs 0 $qh 0 $DIR || + error "reset default quota failed" + $LFS setquota $qtype $qid $qpool_cmd $qs 0 $qh 0 $DIR || + error "reset quota failed" + cleanup_quota_test +} + +test_61() { + test_default_quota "-u" "data" + test_default_quota "-u" "meta" + test_default_quota "-g" "data" + test_default_quota "-g" "meta" + test_default_quota "-p" "data" + test_default_quota "-p" "meta" +} +run_test 61 "default quota tests" + +test_62() { + ! is_project_quota_supported && + skip "Project quota is not supported" + [[ "$(chattr -h 2>&1)" =~ "project" || + "$(chattr -h 2>&1)" =~ "pRVf" ]] || + skip "chattr did not support project quota" + setup_quota_test || error "setup quota failed with $?" + local testdir=$DIR/$tdir/ + + $RUNAS mkdir -p $testdir || error "failed to mkdir" + change_project -s $testdir + [[ $($LFS project -d $testdir) =~ "P" ]] || + error "inherit attribute should be set" + # chattr used FS_IOC_SETFLAGS ioctl + $RUNAS chattr -P $testdir && + error "regular user clear inherit should fail" + [[ $($LFS project -d $testdir) =~ "P" ]] || + error "inherit attribute should still be set" + chattr -P $testdir || error "root failed to clear inherit" + [[ $($LFS project -d $testdir) =~ "P" ]] && + error "inherit attribute should be cleared" + return 0 } -run_test 33 "Basic usage tracking for user & group & project" +run_test 62 "Project inherit should be only changed by root" -# usage transfer test for user & group & project -test_34() { - local BLK_CNT=2 # 2MB - local project_supported="no" +test_dom() { + [ "$MDS1_VERSION" -lt $(version_code 2.11.55) ] && + skip "Not supported before 2.11.55" - is_project_quota_supported && project_supported="yes" - setup_quota_test || error "setup quota failed with $?" - trap cleanup_quota_test EXIT + local qtype=$1 + local qid=$TSTUSR + local dd_failed=false + local tdir_dom=${tdir}_dom + local LIMIT=20480 #20M - # make sure the system is clean - local USED=$(getquota -u $TSTID global curspace) - [ $USED -ne 0 ] && error "Used space ($USED) for user $TSTID isn't 0." - USED=$(getquota -g $TSTID global curspace) - [ $USED -ne 0 ] && error "Used space ($USED) for group $TSTID isn't 0." + [ $qtype == "p" ] && ! is_project_quota_supported && + echo "Project quota is not supported" && return 0 - local USED=$(getquota -u $TSTID2 global curspace) - [ $USED -ne 0 ] && error "Used space ($USED) for user $TSTID2 isn't 0." - if [ $project_supported == "yes" ]; then - USED=$(getquota -p $TSTPRJID global curspace) - [ $USED -ne 0 ] && error \ - "Used space ($USED) for Project $TSTPRJID isn't 0." - fi + [ $qtype == "p" ] && qid=$TSTPRJID - echo "Write file..." - $DD of=$DIR/$tdir/$tfile count=$BLK_CNT 2>/dev/null || - error "write failed" - cancel_lru_locks osc - sync; sync_all_data || true + setup_quota_test || error "setup quota failed with $?" - echo "chown the file to user $TSTID" - chown $TSTID $DIR/$tdir/$tfile || error "chown failed" + quota_init - echo "Wait for setattr on objects finished..." - wait_delete_completed + # enable mdt/ost quota + set_mdt_qtype $QTYPE || error "enable mdt quota failed" + set_ost_qtype $QTYPE || error "enable ost quota failed" - BLK_CNT=$((BLK_CNT * 1024)) + # make sure the system is clean + local USED=$(getquota -$qtype $qid global curspace) + [ $USED -ne 0 ] && error "Used space for $qid isn't 0." - echo "Verify disk usage for user $TSTID" - USED=$(getquota -u $TSTID global curspace) - [ $USED -lt $BLK_CNT ] && - error "Used space for user $TSTID is ${USED}, expected $BLK_CNT" - USED=$(getquota -u $TSTID global curinodes) - [ $USED -ne 1 ] && - error "Used inodes for user $TSTID is $USED, expected 1" + chown $TSTUSR.$TSTUSR $DIR/$tdir || error "chown $tdir failed" - echo "chgrp the file to group $TSTID" - chgrp $TSTID $DIR/$tdir/$tfile || error "chgrp failed" + mkdir $DIR/$tdir_dom || error "mkdir $tdir_dom failed" + $LFS setstripe -E 1M -L mdt $DIR/$tdir_dom || + error "setstripe $tdir_dom failed" + chown $TSTUSR.$TSTUSR $DIR/$tdir_dom || error "chown $tdir_dom failed" - echo "Wait for setattr on objects finished..." - wait_delete_completed + [ $qtype == "p" ] && { + change_project -sp $TSTPRJID $DIR/$tdir + change_project -sp $TSTPRJID $DIR/$tdir_dom + } - echo "Verify disk usage for group $TSTID" - USED=$(getquota -g $TSTID global curspace) - [ $USED -ge $BLK_CNT ] || - error "Used space for group $TSTID is $USED, expected $BLK_CNT" - USED=$(getquota -g $TSTID global curinodes) - [ $USED -eq 1 ] || - error "Used inodes for group $TSTID is $USED, expected 1" + $LFS setquota -$qtype $qid -b $LIMIT -B $LIMIT $DIR || + error "set $qid quota failed" - # chown won't change the ost object group. LU-4345 */ - echo "chown the file to user $TSTID2" - chown $TSTID2 $DIR/$tdir/$tfile || error "chown to $TSTID2 failed" + for ((i = 0; i < $((LIMIT/2048)); i++)); do + $RUNAS $DD of=$DIR/$tdir_dom/$tfile-$i count=1 oflag=sync || + dd_failed=true + done - echo "Wait for setattr on objects finished..." - wait_delete_completed + $dd_failed && quota_error $qtype $qid "write failed, expect succeed" - echo "change_project project id to $TSTPRJID" - [ $project_supported == "yes" ] && - change_project -p $TSTPRJID $DIR/$tdir/$tfile - echo "Wait for setattr on objects finished..." - wait_delete_completed + for ((i = $((LIMIT/2048)); i < $((LIMIT/1024 + 10)); i++)); do + $RUNAS $DD of=$DIR/$tdir_dom/$tfile-$i count=1 oflag=sync || + dd_failed=true + done - echo "Verify disk usage for user $TSTID2/$TSTID and group $TSTID" - USED=$(getquota -u $TSTID2 global curspace) - [ $USED -lt $BLK_CNT ] && - error "Used space for user $TSTID2 is $USED, expected $BLK_CNT" - USED=$(getquota -u $TSTID global curspace) - [ $USED -ne 0 ] && - error "Used space for user $TSTID is $USED, expected 0" - USED=$(getquota -g $TSTID global curspace) - [ $USED -lt $BLK_CNT ] && - error "Used space for group $TSTID is $USED, expected $BLK_CNT" - if [ $project_supported == "yes" ]; then - USED=$(getquota -p $TSTPRJID global curspace) - [ $USED -lt $BLK_CNT ] && error \ - "Used space for group $TSTPRJID is $USED, expected $BLK_CNT" - fi + $dd_failed || quota_error $qtype $qid "write succeed, expect EDQUOT" - cleanup_quota_test -} -run_test 34 "Usage transfer for user & group & project" + rm -f $DIR/$tdir_dom/* -# usage is still accessible across restart -test_35() { - local BLK_CNT=2 # 2 MB + # flush cache, ensure noquota flag is set on client + cancel_lru_locks osc + cancel_lru_locks mdc + sync; sync_all_data || true - setup_quota_test || error "setup quota failed with $?" - trap cleanup_quota_test EXIT + dd_failed=false - echo "Write file..." - $RUNAS $DD of=$DIR/$tdir/$tfile count=$BLK_CNT 2>/dev/null || - error "write failed" - is_project_quota_supported && - change_project -p $TSTPRJID $DIR/$tdir/$tfile - cancel_lru_locks osc + $RUNAS $DD of=$DIR/$tdir/file count=$((LIMIT/2048)) oflag=sync || + quota_error $qtype $qid "write failed, expect succeed" - echo "Wait for setattr on objects finished..." - wait_delete_completed + for ((i = 0; i < $((LIMIT/2048 + 10)); i++)); do + $RUNAS $DD of=$DIR/$tdir_dom/$tfile-$i count=1 oflag=sync || + dd_failed=true + done + + $dd_failed || quota_error $qtype $TSTID "write succeed, expect EDQUOT" + rm -f $DIR/$tdir/* + rm -f $DIR/$tdir_dom/* + + # flush cache, ensure noquota flag is set on client + cancel_lru_locks osc + cancel_lru_locks mdc sync; sync_all_data || true - echo "Save disk usage before restart" - local ORIG_USR_SPACE=$(getquota -u $TSTID global curspace) - [ $ORIG_USR_SPACE -eq 0 ] && - error "Used space for user $TSTID is 0, expected ${BLK_CNT}M" - local ORIG_USR_INODES=$(getquota -u $TSTID global curinodes) - [ $ORIG_USR_INODES -eq 0 ] && - error "Used inodes for user $TSTID is 0, expected 1" - echo "User $TSTID: ${ORIG_USR_SPACE}KB $ORIG_USR_INODES inodes" - local ORIG_GRP_SPACE=$(getquota -g $TSTID global curspace) - [ $ORIG_GRP_SPACE -eq 0 ] && - error "Used space for group $TSTID is 0, expected ${BLK_CNT}M" - local ORIG_GRP_INODES=$(getquota -g $TSTID global curinodes) - [ $ORIG_GRP_INODES -eq 0 ] && - error "Used inodes for group $TSTID is 0, expected 1" - echo "Group $TSTID: ${ORIG_GRP_SPACE}KB $ORIG_GRP_INODES inodes" + dd_failed=false - if is_project_quota_supported; then - local ORIG_PRJ_SPACE=$(getquota -p $TSTPRJID global curspace) - [ $ORIG_PRJ_SPACE -eq 0 ] && error \ - "Used space for project $TSTPRJID is 0, expected ${BLK_CNT}M" - local ORIG_PRJ_INODES=$(getquota -p $TSTPRJID global curinodes) - [ $ORIG_PRJ_INODES -eq 0 ] && error \ - "Used inodes for project $TSTPRJID is 0, expected 1" - echo "Project $TSTPRJID: ${ORIG_PRJ_SPACE}KB $ORIG_PRJ_INODES inodes" - fi + for ((i = 0; i < $((LIMIT/2048)); i++)); do + $RUNAS $DD of=$DIR/$tdir_dom/$tfile-$i count=1 oflag=sync || + dd_failed=true + done - log "Restart..." - stopall - setupall - quota_init + $dd_failed && quota_error $qtype $qid "write failed, expect succeed" - echo "Verify disk usage after restart" - local USED=$(getquota -u $TSTID global curspace) - [ $USED -eq $ORIG_USR_SPACE ] || - error "Used space for user $TSTID changed from " \ - "$ORIG_USR_SPACE to $USED" - USED=$(getquota -u $TSTID global curinodes) - [ $USED -eq $ORIG_USR_INODES ] || - error "Used inodes for user $TSTID changed from " \ - "$ORIG_USR_INODES to $USED" - USED=$(getquota -g $TSTID global curspace) - [ $USED -eq $ORIG_GRP_SPACE ] || - error "Used space for group $TSTID changed from " \ - "$ORIG_GRP_SPACE to $USED" - USED=$(getquota -g $TSTID global curinodes) - [ $USED -eq $ORIG_GRP_INODES ] || - error "Used inodes for group $TSTID changed from " \ - "$ORIG_GRP_INODES to $USED" - if [ $project_supported == "yes" ]; then - USED=$(getquota -p $TSTPRJID global curinodes) - [ $USED -eq $ORIG_PRJ_INODES ] || - error "Used inodes for project $TSTPRJID " \ - "changed from $ORIG_PRJ_INODES to $USED" - USED=$(getquota -p $TSTPRJID global curspace) - [ $USED -eq $ORIG_PRJ_SPACE ] || - error "Used space for project $TSTPRJID "\ - "changed from $ORIG_PRJ_SPACE to $USED" - fi + $RUNAS $DD of=$DIR/$tdir/file count=$((LIMIT/2048 + 10)) oflag=sync && + quota_error $qtype $qid "write succeed, expect EDQUOT" - # check if the vfs_dq_init() is called before writing - echo "Append to the same file..." - $RUNAS $DD of=$DIR/$tdir/$tfile count=$BLK_CNT seek=1 2>/dev/null || - error "write failed" - cancel_lru_locks osc - sync; sync_all_data || true + rm -fr $DIR/$tdir + rm -fr $DIR/$tdir_dom - echo "Verify space usage is increased" - USED=$(getquota -u $TSTID global curspace) - [ $USED -gt $ORIG_USR_SPACE ] || - error "Used space for user $TSTID isn't increased" \ - "orig:$ORIG_USR_SPACE, now:$USED" - USED=$(getquota -g $TSTID global curspace) - [ $USED -gt $ORIG_GRP_SPACE ] || - error "Used space for group $TSTID isn't increased" \ - "orig:$ORIG_GRP_SPACE, now:$USED" - if [ $project_supported == "yes" ]; then - USED=$(getquota -p $TSTPRJID global curspace) - [ $USED -gt $ORIG_PRJ_SPACE ] || - error "Used space for project $TSTPRJID isn't " \ - "increased orig:$ORIG_PRJ_SPACE, now:$USED" - fi + $LFS setquota -u $TSTUSR -b 0 -B 0 -i 0 -I 0 $DIR || + error "reset usr quota failed" +} - cleanup_quota_test +test_63() { + test_dom "u" + test_dom "g" + test_dom "p" } -run_test 35 "Usage is still accessible across reboot" +run_test 63 "quota on DoM tests" -# chown/chgrp to the file created with MDS_OPEN_DELAY_CREATE -# LU-5006 -test_37() { - [ $(lustre_version_code $SINGLEMDS) -lt $(version_code 2.6.93) ] && - skip "Old server doesn't have LU-5006 fix." +test_64() { + ! is_project_quota_supported && + skip "Project quota is not supported" + setup_quota_test || error "setup quota failed with $?" + local dir1="$DIR/$tdir/" + + touch $dir1/file + ln -s $dir1/file $dir1/file_link + mkfifo $dir1/fifo - setup_quota_test || error "setup quota failed with $?" - trap cleanup_quota_test EXIT + $LFS project -srp $TSTPRJID $dir1 >&/dev/null || + error "set project should succeed" - # make sure the system is clean - local USED=$(getquota -u $TSTID global curspace) - [ $USED -ne 0 ] && - error "Used space ($USED) for user $TSTID isn't 0." + used=$(getquota -p $TSTPRJID global curinodes) + [ $used -eq 4 ] || error "expected 4 got $used" + $LFS project -rC $dir1 >&/dev/null || + error "clear project should succeed" - # create file with MDS_OPEN_DELAY_CREATE flag - $LFS setstripe -c 1 -i 0 $DIR/$tdir/$tfile || - error "Create file failed" - # write to file - dd if=/dev/zero of=$DIR/$tdir/$tfile bs=1M count=1 conv=notrunc \ - oflag=sync || error "Write file failed" - # chown to the file - chown $TSTID $DIR/$tdir/$tfile || error "Chown to file failed" + used=$(getquota -p $TSTPRJID global curinodes) + [ $used -eq 0 ] || error "expected 0 got $used" +} +run_test 64 "lfs project on non dir/files should succeed" - # wait for setattr on objects finished..." - wait_delete_completed +test_65() { + local SIZE=10 # MB + local TESTFILE="$DIR/$tdir/$tfile-0" - USED=$(getquota -u $TSTID global curspace) - [ $USED -ne 0 ] || quota_error u $TSTUSR "Used space is 0" + setup_quota_test || error "setup quota failed with $?" + set_ost_qtype $QTYPE || error "enable ost quota failed" + quota_init - cleanup_quota_test -} -run_test 37 "Quota accounted properly for file created by 'lfs setstripe'" + echo "Write..." + $RUNAS $DD of=$TESTFILE count=$SIZE || + error "failed to write" + # flush cache, ensure noquota flag is set on client + cancel_lru_locks osc + sync; sync_all_data || true -# LU-8801 -test_38() { - [ $(lustre_version_code $SINGLEMDS) -lt $(version_code 2.8.60) ] && - skip "Old server doesn't have LU-8801 fix." + local quota_u=$($LFS quota -u $TSTUSR $DIR) + local quota_g=$($LFS quota -g $TSTUSR $DIR) + local quota_all=$($RUNAS $LFS quota $DIR) - [ "$UID" != 0 ] && skip_env "must run as root" && return + [ "$(echo "$quota_all" | head -n3)" == "$quota_u" ] || + error "usr quota not match" + [ "$(echo "$quota_all" | tail -n3)" == "$quota_g" ] || + error "grp quota not match" +} +run_test 65 "Check lfs quota result" +test_66() { + ! is_project_quota_supported && + skip "Project quota is not supported" + [ "$MDS1_VERSION" -lt $(version_code 2.12.4) ] && + skip "Not supported before 2.12.4" setup_quota_test || error "setup quota failed with $?" - trap cleanup_quota_test EXIT + local old=$(do_facet mds1 $LCTL get_param -n \ + mdt.*.enable_chprojid_gid | head -1) + local testdir=$DIR/$tdir/foo - # make sure the system is clean - local USED=$(getquota -u $TSTID global curspace) - [ $USED -ne 0 ] && - error "Used space ($USED) for user $TSTID isn't 0." - USED=$(getquota -u $TSTID2 global curspace) - [ $USED -ne 0 ] && - error "Used space ($USED) for user $TSTID2 isn't 0." + do_facet mds1 $LCTL set_param mdt.*.enable_chprojid_gid=0 + stack_trap "do_facet mds1 $LCTL \ + set_param mdt.*.enable_chprojid_gid=$old" EXIT - local TESTFILE="$DIR/$tdir/$tfile" - local file_cnt=10000 + mkdir_on_mdt0 $testdir || error "failed to mkdir" + chown -R $TSTID:$TSTID $testdir + change_project -sp $TSTPRJID $testdir + $RUNAS mkdir $testdir/foo || error "failed to mkdir foo" - # Generate id entries in accounting file - echo "Create $file_cnt files..." - for i in `seq $file_cnt`; do - touch $TESTFILE-$i - chown $((file_cnt - i)):$((file_cnt - i)) $TESTFILE-$i || - error "failed to chown $TESTFILE-$i" - done - cancel_lru_locks osc - sync; sync_all_data || true + $RUNAS lfs project -p 0 $testdir/foo && + error "nonroot user should fail to set projid" - local procf="osd-$(facet_fstype $SINGLEMDS).$FSNAME-MDT0000" - procf=${procf}.quota_slave.acct_user - local accnt_cnt + $RUNAS lfs project -C $testdir/foo && + error "nonroot user should fail to clear projid" - acct_cnt=$(do_facet mds1 $LCTL get_param $procf | grep "id:" | \ - awk '{if ($3 < 10000) {print $3}}' | wc -l) - echo "Found $acct_cnt id entries" + change_project -C $testdir/foo || error "failed to clear project" - [ $file_cnt -eq $acct_cnt ] || { - do_facet mds1 $LCTL get_param $procf - error "skipped id entries" - } + do_facet mds1 $LCTL set_param mdt.*.enable_chprojid_gid=-1 + $RUNAS lfs project -p $TSTPRJID $testdir/foo || error \ + "failed to set projid with normal user when enable_chprojid_gid=-1" - cleanup_quota_test + $RUNAS lfs project -rC $testdir/ || error \ +"failed to clear project state with normal user when enable_chprojid_gid=-1" + + touch $testdir/bar || error "failed touch $testdir/bar" + $RUNAS lfs project -p $TSTPRJID $testdir/bar && error \ + "normal user should not be able to set projid on root owned file" + + change_project -p $TSTPRJID $testdir/bar || error \ + "root should be able to change its own file's projid" } -run_test 38 "Quota accounting iterator doesn't skip id entries" +run_test 66 "nonroot user can not change project state in default" -test_39() { - local TESTFILE="$DIR/$tdir/project" - ! is_project_quota_supported && - skip "Project quota is not supported" +test_67_write() { + local file="$1" + local qtype="$2" + local size=$3 + local _runas="" + local short_qtype=${qtype:0:1} - setup_quota_test || error "setup quota failed with $?" + echo "file "$file + echo "0 $0 1 $1 2 $2 3 $3 4 $4" + case "$4" in + quota_usr) _runas=$RUNAS;; + quota_2usr) _runas=$RUNAS2;; + *) error "unknown quota parameter $4";; + esac - touch $TESTFILE - projectid=$(lfs project $TESTFILE | awk '{print $1}') - [ $projectid -ne 0 ] && - error "Project id should be 0 not $projectid" - change_project -p 1024 $TESTFILE - projectid=$(lfs project $TESTFILE | awk '{print $1}') - [ $projectid -ne 1024 ] && - error "Project id should be 1024 not $projectid" + log "Write..." + date + $_runas $DD of=$file count=$size || + quota_error $short_qtype $TSTUSR \ + "$qtype write failure, but expect success" + date + cancel_lru_locks osc + date + sync; sync_all_data || true + date +} - stopall || error "failed to stopall (1)" - mount - setupall - projectid=$(lfs project $TESTFILE | awk '{print $1}') - [ $projectid -ne 1024 ] && - error "Project id should be 1024 not $projectid" +getgranted() { + local pool=$1 + local ptype=$2 + local userid=$3 + local qtype=$4 + local param=qmt.$FSNAME-QMT0000.$ptype-$pool.glb-$qtype - cleanup_quota_test + do_facet mds1 $LCTL get_param $param | + grep -A2 $userid | awk -F'[, ]*' 'NR==2{print $9}' } -run_test 39 "Project ID interface works correctly" -test_40a() { - ! is_project_quota_supported && - skip "Project quota is not supported" - local dir1="$DIR/$tdir/dir1" - local dir2="$DIR/$tdir/dir2" +test_67() { + local limit=20 # MB + local testfile="$DIR/$tdir/$tfile-0" + local testfile2="$DIR/$tdir/$tfile-1" + local testfile3="$DIR/$tdir/$tfile-2" + local qpool="qpool1" + local used + local granted + local granted_mb + + mds_supports_qp + [ "$ost1_FSTYPE" == zfs ] && + skip "ZFS grants some block space together with inode" setup_quota_test || error "setup quota failed with $?" - mkdir -p $dir1 $dir2 - change_project -sp 1 $dir1 && touch $dir1/1 - change_project -sp 2 $dir2 + # enable ost quota + set_ost_qtype $QTYPE || error "enable ost quota failed" - ln $dir1/1 $dir2/1_link && - error "Hard link across different project quota should fail" - rm -rf $dir1 $dir2 + # test for user + log "User quota (block hardlimit:$limit MB)" + $LFS setquota -u $TSTUSR -b 0 -B ${limit}M -i 0 -I 0 $DIR || + error "set user quota failed" - cleanup_quota_test + # make sure the system is clean + used=$(getquota -u $TSTUSR global curspace) + [ $used -ne 0 ] && error "Used space($used) for user $TSTUSR isn't 0." + + granted=$(getgranted "0x0" "dt" $TSTID "usr") + echo "granted 0x0 before write $granted" + + # trigger reintegration + local procf="osd-$(facet_fstype ost1).$FSNAME-OST*." + procf=${procf}quota_slave.force_reint + do_facet ost1 $LCTL set_param $procf=1 || + error "force reintegration failed" + wait_ost_reint "u" || error "reintegration failed" + granted=$(getgranted "0x0" "dt" $TSTID "usr") + [ $granted -ne 0 ] && + error "Granted($granted) for $TSTUSR in $qpool isn't 0." + + $LFS setstripe $testfile -c 1 -i 0 || error "setstripe $testfile failed" + chown $TSTUSR.$TSTUSR $testfile || error "chown $testfile failed" + + # write 10 MB to testfile + test_67_write "$testfile" "user" 10 "quota_usr" + + # create qpool and add OST1 + pool_add $qpool || error "pool_add failed" + pool_add_targets $qpool 1 1 || error "pool_add_targets failed" + # as quota_usr hasn't limits, lqe may absent. But it should be + # created after the 1st direct qmt_get. + used=$(getquota -u $TSTUSR global bhardlimit $qpool) + + # check granted - should be 0, as testfile is located only on OST0 + granted=$(getgranted "0x0" "dt" $TSTID "usr") + echo "global granted $granted" + granted=$(getgranted $qpool "dt" $TSTID "usr") + echo "$qpool granted $granted" + [ $granted -ne 0 ] && + error "Granted($granted) for $TSTUSR in $qpool isn't 0." + + # add OST0 to qpool and check granted space + pool_add_targets $qpool 0 1 || + error "pool_add_targets failed" + granted_mb=$(($(getgranted $qpool "dt" $TSTID "usr")/1024)) + echo "Granted $granted_mb MB" + #should be 10M + qunit for each OST + [ $granted_mb -ge 10 -a $granted_mb -lt $limit ] || + error "Granted($granted_mb) for $TSTUSR in $qpool is wrong." + + $LFS setstripe $testfile2 -c 1 -i 1 || + error "setstripe $testfile2 failed" + chown $TSTUSR2.$TSTUSR2 $testfile2 || error "chown $testfile2 failed" + # Write from another user and check that qpool1 + # shows correct granted, despite quota_2usr hasn't limits in qpool1. + test_67_write "$testfile2" "user" 10 "quota_2usr" + used=$(getquota -u $TSTUSR2 global curspace $qpool) + granted=$(getgranted $qpool "dt" $TSTID2 "usr") + [ $granted -ne 0 ] && + error "Granted($granted) for $TSTUSR2 in $qpool isn't 0." + + # Granted space for quota_2usr in qpool1 should appear only + # when global lqe for this user becomes enforced. + $LFS setquota -u $TSTUSR2 -B ${limit}M $DIR || + error "set user quota failed" + granted_mb=$(($(getgranted $qpool "dt" $TSTID2 "usr")/1024)) + echo "granted_mb $granted_mb" + [ $granted_mb -ge 10 -a $granted_mb -lt $limit ] || + error "Granted($granted) for $TSTUSR in $qpool is wrong." + + $LFS setstripe $testfile3 -c 1 -i 0 || + error "setstripe $testfile3 failed" + chown $TSTUSR2.$TSTUSR2 $testfile3 || error "chown $testfile3 failed" + test_67_write "$testfile3" "user" 10 "quota_2usr" + granted_mb=$(($(getgranted $qpool "dt" $TSTID2 "usr")/1024)) + echo "$testfile3 granted_mb $granted_mb" + [ $granted_mb -eq $limit ] || + error "Granted($granted_mb) for $TSTUSR2 is not equal to 20M" + + # remove OST1 from the qpool1 and check granted space + # should be 0 for TSTUSR and 10M for TSTUSR2 + pool_remove_target $qpool 0 + granted_mb=$(($(getgranted $qpool "dt" $TSTID "usr")/1024)) + [ $granted_mb -eq 0 ] || + error "Granted($granted_mb) for $TSTUSR in $qpool != 0." + granted_mb=$(($(getgranted $qpool "dt" $TSTID2 "usr")/1024)) + [ $granted_mb -eq 10 ] || + error "Granted($granted_mb) for $TSTUSR2 is not equal to 10M" + + rm -f $testfile + wait_delete_completed || error "wait_delete_completed failed" + sync_all_data || true + used=$(getquota -u $TSTUSR global curspace) + [ $used -eq 0 ] || quota_error u $TSTUSR \ + "user quota isn't released after deletion" } -run_test 40a "Hard link across different project ID" +run_test 67 "quota pools recalculation" -test_40b() { - ! is_project_quota_supported && - skip "Project quota is not supported" - local dir1="$DIR/$tdir/dir1" - local dir2="$DIR/$tdir/dir2" +get_slave_nr() { + local pool=$1 + local qtype=$2 + local nr - setup_quota_test || error "setup quota failed with $?" - mkdir -p $dir1 $dir2 - change_project -sp 1 $dir1 && touch $dir1/1 - change_project -sp 2 $dir2 + wait_update_facet mds1 \ + "$LCTL get_param -n qmt.$FSNAME-QMT0000.dt-$pool.info \ + >/dev/null 2>&1 || echo foo" "" || + error "mds1: failed to create quota pool $pool" - mv $dir1/1 $dir2/2 || error "mv failed $?" - local projid=$(lfs project $dir2/2 | awk '{print $1}') - if [ "$projid" != "2" ]; then - error "project id expected 2 not $projid" - fi - rm -rf $dir1 $dir2 - cleanup_quota_test + do_facet mds1 $LCTL get_param -n qmt.$FSNAME-QMT0000.dt-$pool.info | + awk '/usr/ {getline; print $2}' } -run_test 40b "Mv across different project ID" -test_40c() { - [ "$MDSCOUNT" -lt "2" ] && skip "needs >= 2 MDTs" - ! is_project_quota_supported && - skip "Project quota is not supported" +test_68() +{ + local qpool="qpool1" + mds_supports_qp setup_quota_test || error "setup quota failed with $?" - local dir="$DIR/$tdir/dir" - - mkdir -p $dir && change_project -sp 1 $dir - $LFS mkdir -i 1 $dir/remote_dir || error "create remote dir failed" - local projid=$(lfs project -d $dir/remote_dir | awk '{print $1}') - [ "$projid" != "1" ] && error "projid id expected 1 not $projid" - touch $dir/remote_dir/file - #verify inherit works file for remote dir. - local projid=$(lfs project -d $dir/remote_dir/file | awk '{print $1}') - [ "$projid" != "1" ] && - error "file under remote dir expected 1 not $projid" - #Agent inode should be ignored for project quota - USED=$(getquota -p 1 global curinodes) - [ "$USED" != "3" ] && - error "file count expected 3 got $USED" + # enable ost quota + set_ost_qtype $QTYPE || error "enable ost quota failed" - rm -rf $dir - cleanup_quota_test - return 0 + # check slave number for glbal pool + local nr=$(get_slave_nr "0x0" "usr") + echo "nr result $nr" + [[ $nr != $((OSTCOUNT + MDSCOUNT)) ]] && + error "Slave_nr $nr for global pool != ($OSTCOUNT + $MDSCOUNT)" + + # create qpool and add OST1 + pool_add $qpool || error "pool_add failed" + nr=$(get_slave_nr $qpool "usr") + [[ $nr != 0 ]] && error "Slave number $nr for $qpool != 0" + + # add OST1 to qpool + pool_add_targets $qpool 1 1 || error "pool_add_targets failed" + nr=$(get_slave_nr $qpool "usr") + [[ $nr != 1 ]] && error "Slave number $nr for $qpool != 1" + + # add OST0 to qpool + pool_add_targets $qpool 0 1 || error "pool_add_targets failed" + nr=$(get_slave_nr $qpool "usr") + [[ $nr != 2 ]] && error "Slave number $nr for $qpool != 2" + + # remove OST0 + pool_remove_target $qpool 0 + nr=$(get_slave_nr $qpool "usr") + [[ $nr != 1 ]] && error "Slave number $nr for $qpool != 1" + + # remove OST1 + pool_remove_target $qpool 1 + nr=$(get_slave_nr $qpool "usr") + [[ $nr != 0 ]] && error "Slave number $nr for $qpool != 0" + + # Check again that all is fine with global pool + nr=$(get_slave_nr "0x0" "usr") + [[ $nr == $((OSTCOUNT + MDSCOUNT)) ]] || + error "Slave_nr $nr for global pool != ($OSTCOUNT + $MDSCOUNT)" } -run_test 40c "Remote child Dir inherit project quota properly" +run_test 68 "slave number in quota pool changed after each add/remove OST" -test_50() { - ! is_project_quota_supported && - skip "Project quota is not supported" +test_69() +{ + local global_limit=200 # MB + local limit=10 # MB + local testfile="$DIR/$tdir/$tfile-0" + local dom0="$DIR/$tdir/dom0" + local qpool="qpool1" + mds_supports_qp setup_quota_test || error "setup quota failed with $?" - local dir1="$DIR/$tdir/dir1" - local dir2="$DIR/$tdir/dir2" - mkdir -p $dir1 && change_project -sp 1 $dir1 - mkdir -p $dir2 && change_project -sp 2 $dir2 - for num in $(seq 1 10); do - touch $dir1/file_$num $dir2/file_$num - ln -s $dir1/file_$num $dir1/file_$num"_link" - ln -s $dir2/file_$num $dir2/file_$num"_link" - done + # enable ost quota + set_ost_qtype $QTYPE || error "enable ost quota failed" + set_mdt_qtype $QTYPE || error "enable mdt quota failed" - count=$($LFS find --projid 1 $DIR | wc -l) - [ "$count" != 21 ] && error "expected 21 but got $count" + # Save DOM only at MDT0 + $LFS setdirstripe -c 1 -i 0 $dom0 || error "cannot create $dom0" + $LFS setstripe -E 1M $dom0 -L mdt || error "setstripe to $dom0 failed" + chmod 0777 $dom0 + $LFS setstripe -c 1 -i 0 "$DIR/$tdir/" - # 1(projid 0 dir) + 1(projid 2 dir) + 20(projid 2 files) - count=$($LFS find ! --projid 1 $DIR/$tdir | wc -l) - [ "$count" != 22 ] && error "expected 22 but got $count" + # create qpool and add OST0 + pool_add $qpool || error "pool_add failed" + pool_add_targets $qpool 0 0 || error "pool_add_targets failed" - rm -rf $dir1 $dir2 - cleanup_quota_test -} -run_test 50 "Test if lfs find --projid works" + log "User quota (block hardlimit:$global_limit MB)" + $LFS setquota -u $TSTUSR -b 0 -B ${global_limit}M -i 0 -I 0 $DIR || + error "set user quota failed" -test_51() { - ! is_project_quota_supported && - skip "Project quota is not supported" - setup_quota_test || error "setup quota failed with $?" - local dir="$DIR/$tdir/dir" + log "User quota (block hardlimit:$limit MB)" + $LFS setquota -u $TSTUSR -B ${limit}M --pool $qpool $DIR || + error "set user quota failed" - mkdir $dir && change_project -sp 1 $dir - local used=$(getquota -p 1 global curinodes) - [ $used != "1" ] && error "expected 1 got $used" + $RUNAS dd if=/dev/zero of="$dom0/f1" bs=1K count=512 oflag=sync || + quota_error u $TSTUSR "write failed" - touch $dir/1 - touch $dir/2 - cp $dir/2 $dir/3 - used=$(getquota -p 1 global curinodes) - [ $used != "4" ] && error "expected 4 got $used" + $RUNAS dd if=/dev/zero of="$dom0/f1" bs=1K count=512 seek=512 \ + oflag=sync || quota_error u $TSTUSR "write failed" - $DD if=/dev/zero of=$DIR/$tdir/6 bs=1M count=1 - #try cp to dir - cp $DIR/$tdir/6 $dir/6 - used=$(getquota -p 1 global curinodes) - [ $used != "5" ] && error "expected 5 got $used" + $RUNAS $DD of=$testfile count=$limit || true - #try mv to dir - mv $DIR/$tdir/6 $dir/7 - used=$(getquota -p 1 global curinodes) - [ $used != "6" ] && error "expected 6 got $used" + # flush cache, ensure noquota flag is set on client + cancel_lru_locks osc + sync; sync_all_data || true - rm -rf $dir - cleanup_quota_test -} -run_test 51 "Test project accounting with mv/cp" + # MDT0 shouldn't get EDQUOT with glimpse. + $RUNAS $DD of=$testfile count=$limit seek=$limit && + quota_error u $TSTUSR \ + "user write success, but expect EDQUOT" -test_52() { - ! is_project_quota_supported && - skip "Project quota is not supported" - setup_quota_test || error "setup quota failed with $?" - local dir="$DIR/$tdir/dir" - mkdir $dir && change_project -sp 1 $dir + # Now all members of qpool1 should get EDQUOT. Expect success + # when write to DOM on MDT0, as it belongs to global pool. + $RUNAS dd if=/dev/zero of="$dom0/f1" bs=1K count=512 \ + oflag=sync || quota_error u $TSTUSR "write failed" - touch $DIR/$tdir/file - #Try renaming a file into the project. This should fail. - for num in $(seq 1 2000); do - mrename $DIR/$tdir/file $dir/file >&/dev/null && - error "rename should fail" - done - rm -rf $dir - cleanup_quota_test + $RUNAS dd if=/dev/zero of="$dom0/f1" bs=1K count=512 seek=512 \ + oflag=sync || quota_error u $TSTUSR "write failed" } -run_test 52 "Rename across different project ID" - -test_53() { - ! is_project_quota_supported && - skip "Project quota is not supported" - setup_quota_test || error "setup quota failed with $?" - local dir="$DIR/$tdir/dir" - mkdir $dir && change_project -s $dir - lfs project -d $dir | grep P || error "inherit attribute should be set" +run_test 69 "EDQUOT at one of pools shouldn't affect DOM" - change_project -C $dir - lfs project -d $dir | grep P && - error "inherit attribute should be cleared" +test_70a() +{ + local qpool="qpool1" + local limit=20 # MB + local err=0 + local bhard - rm -rf $dir - cleanup_quota_test -} -run_test 53 "Project inherit attribute could be cleared" + [[ CLIENT_VERSION -lt $(version_code $VERSION_WITH_QP) ]] && + skip "Needs a client >= $VERSION_WITH_QP" -test_54() { - ! is_project_quota_supported && - skip "Project quota is not supported" setup_quota_test || error "setup quota failed with $?" - trap cleanup_quota_test EXIT - local testfile="$DIR/$tdir/$tfile-0" - #set project ID/inherit attribute - change_project -sp $TSTPRJID $DIR/$tdir - $RUNAS createmany -m ${testfile} 100 || - error "create many files failed" + # MDS returns EFAULT for unsupported quotactl command + [[ $MDS1_VERSION -lt $(version_code $VERSION_WITH_QP) ]] && err=14 - local proj_count=$(lfs project -r $DIR/$tdir | wc -l) - # one more count for directory itself */ - ((proj_count++)) + # create qpool and add OST0 + pool_add $qpool || error "pool_add failed" + pool_add_targets $qpool 0 0 || error "pool_add_targets failed" - #check project - local proj_count1=$(lfs project -rcp $TSTPRJID $DIR/$tdir | wc -l) - [ $proj_count1 -eq 0 ] || error "c1: expected 0 got $proj_count1" + $LFS setquota -u $TSTUSR -B ${limit}M --pool $qpool $DIR + rc=$? + [ $rc -eq $err ] || error "setquota res $rc != $err" - proj_count1=$(lfs project -rcp $((TSTPRJID+1)) $DIR/$tdir | wc -l) - [ $proj_count1 -eq $proj_count ] || - error "c2: expected $proj_count got $proj_count1" + # If MDS supports QP, check that limit was set properly. + if [[ $MDS1_VERSION -ge $(version_code $VERSION_WITH_QP) ]]; then + bhard=$(getquota -u $TSTUSR global bhardlimit $qpool) + echo "hard limit $bhard limit $limit" + [ $bhard -ne $((limit*1024)) ] && + error "bhard:$bhard for $qpool!=$((limit*1024))" + fi - #clear project but with kept projid - change_project -rCk $DIR/$tdir - proj_count1=$(lfs project -rcp $TSTPRJID $DIR/$tdir | wc -l) - [ $proj_count1 -eq 1 ] || - error "c3: expected 1 got $proj_count1" + $LFS quota -u $TSTUSR --pool $qpool $DIR + rc=$? + [ $rc -eq $err ] || error "quota res $rc != $err" +} +run_test 70a "check lfs setquota/quota with a pool option" - #verify projid untouched. - proj_count1=$(lfs project -r $DIR/$tdir | grep -c $TSTPRJID) - ((proj_count1++)) - [ $proj_count1 -eq $proj_count ] || - error "c4: expected $proj_count got $proj_count1" +test_70b() +{ + local glbl_hard=200 # 200M + local glbl_soft=100 # 100M + local pool_hard=10 # 10M + local qpool="qpool1" - # test -0 option - lfs project $DIR/$tdir -cr -0 | xargs -0 lfs project -s - proj_count1=$(lfs project -rcp $TSTPRJID $DIR/$tdir | wc -l) - [ $proj_count1 -eq 0 ] || error "c5: expected 0 got $proj_count1" + pool_add $qpool || error "pool_add failed" + pool_add_targets $qpool 0 1 || error "pool_add_targets failed" - #this time clear all - change_project -rC $DIR/$tdir - proj_count1=$(lfs project -r $DIR/$tdir | grep -c $TSTPRJID) - [ $proj_count1 -eq 0 ] || - error "c6: expected 0 got $proj_count1" - #cleanup - unlinkmany ${testfile} 100 || - error "unlink many files failed" + $LFS setquota -u $TSTUSR -b ${glbl_soft}M -B ${glbl_hard}M $DIR || + error "set user quota failed" + $LFS setquota -u $TSTUSR -B ${pool_hard}M --pool $qpool $DIR || + error "set user quota failed" - cleanup_quota_test + local tmp=$(getquota -u $TSTUSR global bhardlimit $qpool) + [ $tmp -eq $((pool_hard * 1024)) ] || + error "wrong block hard limit $tmp for $qpool" + local tmp=$(getquota -u $TSTUSR global bsoftlimit $qpool) + # soft limit hasn't been set and should be zero + [ $tmp -eq 0 ] || error "wrong soft block limit $tmp for $qpool" } -run_test 54 "basic lfs project interface test" +run_test 70b "lfs setquota pool works properly" -test_55() { - [ $(lustre_version_code $SINGLEMDS) -lt $(version_code 2.10.58) ] && - skip "Not supported before 2.10.58." +test_71a() +{ + local limit=10 # MB + local global_limit=100 # MB + local testfile="$DIR/$tdir/$tfile-0" + local qpool="qpool1" + local qpool2="qpool2" + + [ "$ost1_FSTYPE" == zfs ] && + skip "ZFS grants some block space together with inode" + [[ $OSTCOUNT -lt 2 ]] && skip "need >= 2 OSTs" + mds_supports_qp setup_quota_test || error "setup quota failed with $?" + # enable ost quota set_ost_qtype $QTYPE || error "enable ost quota failed" - quota_init - #add second group to TSTUSR - usermod -G $TSTUSR,$TSTUSR2 $TSTUSR + # test for user + log "User quota (block hardlimit:$global_limit MB)" + $LFS setquota -u $TSTUSR -b 0 -B ${global_limit}M -i 0 -I 0 $DIR || + error "set user quota failed" - #prepare test file - $RUNAS dd if=/dev/zero of=$DIR/$tdir/$tfile bs=1024 count=100000 || - error "failed to dd" + pool_add $qpool || error "pool_add failed" + pool_add_targets $qpool 0 1 || + error "pool_add_targets failed" + + $LFS setquota -u $TSTUSR -B ${limit}M --pool $qpool $DIR || + error "set user quota failed" + + pool_add $qpool2 || error "pool_add failed" + pool_add_targets $qpool2 1 1 || + error "pool_add_targets failed" + + $LFS setquota -u $TSTUSR -B ${limit}M --pool $qpool2 $DIR || + error "set user quota failed" + + # make sure the system is clean + local used=$(getquota -u $TSTUSR global curspace) + + echo "used $used" + [ $used -ne 0 ] && error "Used space($used) for user $TSTUSR isn't 0." + + # create 1st component 1-10M + $LFS setstripe -E 10M -S 1M -c 1 -i 0 $testfile + #create 2nd component 10-30M + $LFS setstripe --component-add -E 30M -c 1 -i 1 $testfile + chown $TSTUSR.$TSTUSR $testfile || error "chown $testfile failed" + + # сheck normal use and out of quota with PFL + # 1st element is in qppol1(OST0), 2nd in qpool2(OST2). + test_1_check_write $testfile "user" $((limit*2)) + rm -f $testfile + wait_delete_completed || error "wait_delete_completed failed" + sync_all_data || true + used=$(getquota -u $TSTUSR global curspace) + [ $used -ne 0 ] && quota_error u $TSTUSR \ + "user quota isn't released after deletion" + + # create 1st component 1-10M + $LFS setstripe -E 10M -S 1M -c 1 -i 0 $testfile + # create 2nd component 10-30M + $LFS setstripe --component-add -E 30M -c 1 -i 1 $testfile + chown $TSTUSR.$TSTUSR $testfile || error "chown $testfile failed" + # write to the 2nd component + $RUNAS $DD of=$testfile count=$limit seek=10 || + quota_error u $TSTUSR \ + "write failure, but expect success" + # this time maybe cache write, ignore it's failure + $RUNAS $DD of=$testfile count=$((2*limit)) seek=10 || true cancel_lru_locks osc sync; sync_all_data || true + # write over limit in qpool2(2nd component 10-30M) + $RUNAS $DD of=$testfile count=1 seek=$((10 + 2*limit)) && + quota_error u $TSTUSR "user write success, but expect EDQUOT" + # write to the 1st component - OST0 is empty + $RUNAS $DD of=$testfile count=$limit seek=0 || + quota_error u $TSTUSR "write failed" +} +run_test 71a "Check PFL with quota pools" - $LFS setquota -g $TSTUSR2 -b 0 -B 50M $DIR || - error "failed to setquota on group $TSTUSR2" +test_71b() +{ + local global_limit=1000 # MB + local limit1=160 # MB + local limit2=10 # MB + local testfile="$DIR/$tdir/$tfile-0" + local qpool="qpool1" + local qpool2="qpool2" - $LFS quota -v -g $TSTUSR2 $DIR + [ "$ost1_FSTYPE" == zfs ] && + skip "ZFS grants some block space together with inode" + [[ $OSTCOUNT -lt 2 ]] && skip "need >= 2 OSTs" && return + mds_supports_qp + setup_quota_test || error "setup quota failed with $?" - runas -u $TSTUSR -g $TSTUSR2 chgrp $TSTUSR2 $DIR/$tdir/$tfile && - error "chgrp should failed with -EDQUOT" + # enable ost quota + set_ost_qtype $QTYPE || error "enable ost quota failed" - USED=$(getquota -g $TSTUSR2 global curspace) - echo "$USED" + # test for user + log "User quota (block hardlimit:$global_limit MB)" + $LFS setquota -u $TSTUSR -b 0 -B ${global_limit}M -i 0 -I 0 $DIR || + error "set user quota failed" - $LFS setquota -g $TSTUSR2 -b 0 -B 300M $DIR || - error "failed to setquota on group $TSTUSR2" + pool_add $qpool || error "pool_add failed" + pool_add_targets $qpool 0 1 || + error "pool_add_targets failed" - $LFS quota -v -g $TSTUSR2 $DIR + $LFS setquota -u $TSTUSR -B ${limit1}M --pool $qpool $DIR || + error "set user quota failed" - runas -u $TSTUSR -g $TSTUSR2 chgrp $TSTUSR2 $DIR/$tdir/$tfile || - error "chgrp should succeed" + pool_add $qpool2 || error "pool_add failed" + pool_add_targets $qpool2 1 1 || + error "pool_add_targets failed" - $LFS quota -v -g $TSTUSR2 $DIR + $LFS setquota -u $TSTUSR -B ${limit2}M --pool $qpool2 $DIR || + error "set user quota failed" - cleanup_quota_test + # make sure the system is clean + local used=$(getquota -u $TSTUSR global curspace) + + echo "used $used" + [ $used -ne 0 ] && error "Used space($used) for user $TSTUSR isn't 0." + + # First component is on OST0, 2nd on OST1 + $LFS setstripe -E 128M -i 0 -z 64M -E -1 -i 1 -z 64M $testfile + chown $TSTUSR.$TSTUSR $testfile || error "chown $testfile failed" + + # fill the 1st component on OST0 + $RUNAS $DD of=$testfile count=128 || + quota_error u $TSTUSR "write failed" + # write to the 2nd cmpnt on OST1 + $RUNAS $DD of=$testfile count=$((limit2/2)) seek=128 || + quota_error u $TSTUSR "write failed" + # this time maybe cache write, ignore it's failure + $RUNAS $DD of=$testfile count=$((limit2/2)) seek=$((128 + limit2/2)) || + true + cancel_lru_locks osc + sync; sync_all_data || true + # write over limit in qpool2 + $RUNAS $DD of=$testfile count=2 seek=$((128 + limit2)) && + quota_error u $TSTUSR "user write success, but expect EDQUOT" + return 0 } -run_test 55 "Chgrp should be affected by group quota" +run_test 71b "Check SEL with quota pools" -test_56() { +test_72() +{ + local limit=10 # MB + local global_limit=50 # MB + local testfile="$DIR/$tdir/$tfile-0" + local qpool="qpool1" + + mds_supports_qp setup_quota_test || error "setup quota failed with $?" + # enable ost quota set_ost_qtype $QTYPE || error "enable ost quota failed" - quota_init - $LFS setquota -t -u -b 10 -i 10 $DIR || - erro "failed to set grace time for usr quota" - grace_time=$($LFS quota -t -u $DIR | grep "Block grace time:" | - awk '{print $4 $8}') - if [ "x$grace_time" != "x10s;10s" ]; then - $LFS quota -t -u $DIR - error "expected grace time: 10s;10s, got:$grace_time" - fi + # test for user + log "User quota (block hardlimit:$global_limit MB)" + $LFS setquota -u $TSTUSR -b 0 -B ${global_limit}M -i 0 -I 0 $DIR || + error "set user quota failed" - cleanup_quota_test + pool_add $qpool || error "pool_add failed" + pool_add_targets $qpool 1 1 || error "pool_add_targets failed" + + $LFS setquota -u $TSTUSR -B ${limit}M --pool $qpool $DIR || + error "set user quota failed" + + # make sure the system is clean + local used=$(getquota -u $TSTUSR global curspace) + echo "used $used" + [ $used -ne 0 ] && error "Used space($used) for user $TSTUSR isn't 0." + + used=$(getquota -u $TSTUSR global bhardlimit $qpool) + + $LFS setstripe $testfile -c 1 -i 1 || error "setstripe $testfile failed" + chown $TSTUSR.$TSTUSR $testfile || error "chown $testfile failed" + test_1_check_write $testfile "user" $limit + used=$(getquota -u $TSTUSR global bhardlimit $qpool) + echo "used $used" + [ $used -ge $limit ] || error "used($used) is less than limit($limit)" + # check that lfs quota -uv --pool prints only OST that + # was added in a pool + lfs quota -v -u quota_usr --pool $qpool $DIR | grep -v "OST0001" | + grep "OST\|MDT" && error "$qpool consists wrong targets" + return 0 } -run_test 56 "lfs quota -t should work well" +run_test 72 "lfs quota --pool prints only pool's OSTs" -test_57() { - setup_quota_test || error "setup quota failed with $?" +test_73a() +{ + local qpool="qpool1" - local dir="$DIR/$tdir/dir" - mkdir -p $dir - mkfifo $dir/pipe - #try to change pipe file should not hang and return failure - wait_update_facet client "$LFS project -sp 1 $dir/pipe 2>&1 | - awk -F ':' '{ print \\\$2 }'" \ - " unable to get xattr for fifo '$dir/pipe'" || return 1 - #command can process further if it hit some errors - touch $dir/aaa $dir/bbb - mkdir $dir/subdir -p - touch $dir/subdir/aaa $dir/subdir/bbb - #create one invalid link file - ln -s $dir/not_exist_file $dir/ccc - local cnt=$(lfs project -r $dir 2>/dev/null | wc -l) - [ $cnt -eq 5 ] || error "expected 5 got $cnt" + mds_supports_qp - cleanup_quota_test + pool_add $qpool || error "pool_add failed" + pool_add_targets $qpool 0 $((OSTCOUNT - 1)) || + error "pool_add_targets failed" + + test_default_quota "-u" "data" "qpool1" } -run_test 57 "lfs project could tolerate errors" +run_test 73a "default limits at OST Pool Quotas" + +test_73b() +{ + local TESTFILE1="$DIR/$tdir/$tfile-1" + local limit=20 #20M + local qpool="qpool1" + + mds_supports_qp -test_59() { - [ "$(facet_fstype $SINGLEMDS)" != "ldiskfs" ] && - skip "ldiskfs only test" - disable_project_quota setup_quota_test || error "setup quota failed with $?" quota_init + set_ost_qtype $QTYPE || error "enable ost quota failed" - local testfile="$DIR/$tdir/$tfile-0" - #make sure it did not crash kernel - touch $testfile && lfs project -sp 1 $testfile + # pool quotas don't work properly without global limit + $LFS setquota -u $TSTUSR -b 0 -B ${limit}M -i 0 -I 0 $DIR || + error "set global limit failed" - enable_project_quota - cleanup_quota_test + pool_add $qpool || error "pool_add failed" + pool_add_targets $qpool 0 $((OSTCOUNT - 1)) || + error "pool_add_targets failed" + + log "set default quota for $qpool" + $LFS setquota -U --pool $qpool -b ${limit}M -B ${limit}M $DIR || + error "set default quota failed" + + log "Write from user that hasn't lqe" + # Check that it doesn't cause a panic or a deadlock + # due to nested lqe lookups that rewrite 1st lqe in qti_lqes array. + # Have to use RUNAS_ID as resetquota creates lqes in + # the beginning for TSTUSR/TSTUSR2 when sets limits to 0. + runas -u $RUNAS_ID -g $RUNAS_GID $DD of=$TESTFILE1 count=10 + + cancel_lru_locks osc + sync; sync_all_data || true } -run_test 59 "lfs project dosen't crash kernel with project disabled" +run_test 73b "default OST Pool Quotas limit for new user" -test_60() { - [ $MDS1_VERSION -lt $(version_code 2.11.53) ] && - skip "Needs MDS version 2.11.53 or later." +test_74() +{ + local global_limit=200 # 200M + local limit=10 # 10M + local limit2=50 # 50M + local qpool="qpool1" + local qpool2="qpool2" + local tmp=0 + + mds_supports_qp setup_quota_test || error "setup quota failed with $?" - trap cleanup_quota_test EXIT - local testfile=$DIR/$tdir/$tfile - local limit=100 + # enable ost quota + set_ost_qtype $QTYPE || error "enable ost quota failed" - set_mdt_qtype "ug" || error "enable mdt quota failed" + $LFS setquota -u $TSTUSR -b 0 -B ${global_limit}M -i 0 -I 0 $DIR || + error "set user quota failed" - $LFS setquota -g $TSTUSR -b 0 -B 0 -i 0 -I $limit $DIR || - error "set quota failed" - quota_show_check a g $TSTUSR + pool_add $qpool || error "pool_add failed" + pool_add_targets $qpool 0 1 || + error "pool_add_targets failed" - chown $TSTUSR.$TSTUSR $DIR/$tdir || error "chown $DIR/$tdir failed" - chmod g+s $DIR/$tdir || error "chmod g+s failed" - $RUNAS createmany -m ${testfile} $((limit-1)) || - error "create many files failed" + $LFS setquota -u $TSTUSR -B ${limit}M --pool $qpool $DIR || + error "set user quota failed" - $RUNAS touch $DIR/$tdir/foo && error "regular user should fail" + pool_add $qpool2 || error "pool_add failed" + pool_add_targets $qpool2 1 1 || + error "pool_add_targets failed" - # root user can overrun quota - runas -u 0 -g 0 touch $DIR/$tdir/foo || - error "root user should succeed" + $LFS setquota -u $TSTUSR -B ${limit2}M --pool $qpool2 $DIR || + error "set user quota failed" - cleanup_quota_test + tmp=$(getquota -u $TSTUSR global bhardlimit) + [ $tmp -eq $((global_limit * 1024)) ] || + error "wrong global limit $global_limit" + + tmp=$(getquota -u $TSTUSR global bhardlimit $qpool) + [ $tmp -eq $((limit * 1024)) ] || error "wrong limit $tmp for $qpool" + + tmp=$(getquota -u $TSTUSR global bhardlimit $qpool2) + [ $tmp -eq $((limit2 * 1024)) ] || error "wrong limit $tmp for $qpool2" + + # check limits in pools + tmp=$($LFS quota -u $TSTUSR --pool $DIR | \ + grep -A4 $qpool | awk 'NR == 4{print $4}') + echo "pool limit for $qpool $tmp" + [ $tmp -eq $((limit * 1024)) ] || error "wrong limit:tmp for $qpool" + tmp=$($LFS quota -u $TSTUSR --pool $DIR | \ + grep -A4 $qpool2 | awk 'NR == 4{print $4}') + echo "pool limit for $qpool2 $tmp" + [ $tmp -eq $((limit2 * 1024)) ] || error "wrong limit:$tmp for $qpool2" } -run_test 60 "Test quota for root with setgid" - -# test default quota -test_default_quota() { - [ $(lustre_version_code $SINGLEMDS) -lt $(version_code 2.11.51) ] && - skip "Not supported before 2.11.51." - - local qtype=$1 - local qpool=$2 - local qid=$TSTUSR - local qprjid=$TSTPRJID - local qdtype="-U" - local qs="-b" - local qh="-B" - local LIMIT=20480 #20M disk space - local TESTFILE="$DIR/$tdir/$tfile-0" +run_test 74 "check quota pools per user" - [ $qtype == "-p" ] && ! is_project_quota_supported && - echo "Project quota is not supported" && return 0 +function cleanup_quota_test_75() +{ + do_facet mgs $LCTL nodemap_modify --name default \ + --property admin --value 1 + do_facet mgs $LCTL nodemap_modify --name default \ + --property trusted --value 1 + do_facet mgs $LCTL nodemap_modify --name default \ + --property squash_uid --value 99 + do_facet mgs $LCTL nodemap_modify --name default \ + --property squash_gid --value 99 - [ $qtype == "-u" ] && qdtype="-U" - [ $qtype == "-g" ] && qdtype="-G" - [ $qtype == "-p" ] && { - qdtype="-P" - qid=$qprjid - } + wait_nm_sync default admin_nodemap + wait_nm_sync default trusted_nodemap - [ $qpool == "meta" ] && { - LIMIT=10240 #10K inodes - qs="-i" - qh="-I" - } + do_facet mgs $LCTL nodemap_activate 0 + wait_nm_sync active - setup_quota_test || error "setup quota failed with $?" - trap cleanup_quota_test EXIT + resetquota -u $TSTUSR +} - quota_init +test_dom_75() { + local dd_failed=false + local LIMIT=20480 #20M + local qid=$TSTID - # enable mdt/ost quota - set_mdt_qtype $QTYPE || error "enable mdt quota failed" - set_ost_qtype $QTYPE || error "enable ost quota failed" + for ((i = 0; i < $((LIMIT/2048-1)); i++)); do + $DD of=$DIR/$tdir_dom/$tfile-$i count=1 \ + oflag=sync || dd_failed=true + done - log "set to use default quota" - $LFS setquota $qtype $qid -d $DIR || - error "set $qid to use default quota failed" + $dd_failed && quota_error u $qid "write failed, expect succeed (1)" - log "set default quota" - $LFS setquota $qdtype $qs ${LIMIT} $qh ${LIMIT} $DIR || - error "set $qid default quota failed" + for ((i = $((LIMIT/2048-1)); i < $((LIMIT/1024 + 10)); i++)); do + $DD of=$DIR/$tdir_dom/$tfile-$i count=1 \ + oflag=sync || dd_failed=true + done - log "get default quota" - $LFS quota $qdtype $DIR || error "get default quota failed" + $dd_failed || quota_error u $qid "write succeed, expect EDQUOT (1)" - if [ $qpool == "data" ]; then - local SLIMIT=$($LFS quota $qdtype $DIR | grep "$MOUNT" | \ - awk '{print $2}') - [ $SLIMIT -eq $LIMIT ] || - error "the returned default quota is wrong" - else - local SLIMIT=$($LFS quota $qdtype $DIR | grep "$MOUNT" | \ - awk '{print $5}') - [ $SLIMIT -eq $LIMIT ] || - error "the returned default quota is wrong" - fi + rm -f $DIR/$tdir_dom/* - # make sure the system is clean - local USED=$(getquota $qtype $qid global curspace) - [ $USED -ne 0 ] && error "Used space for $qid isn't 0." + # flush cache, ensure noquota flag is set on client + cancel_lru_locks + sync; sync_all_data || true - $LFS setstripe $TESTFILE -c 1 || error "setstripe $TESTFILE failed" - chown $TSTUSR.$TSTUSR $TESTFILE || error "chown $TESTFILE failed" + dd_failed=false - [ $qtype == "-p" ] && change_project -sp $TSTPRJID $DIR/$tdir + $DD of=$DIR/$tdir/file count=$((LIMIT/2048-1)) oflag=sync || + quota_error u $qid "write failed, expect succeed (2)" - log "Test not out of quota" - if [ $qpool == "data" ]; then - $RUNAS $DD of=$TESTFILE count=$((LIMIT/2 >> 10)) oflag=sync || - quota_error $qtype $qid "write failed, expect succeed" - else - $RUNAS createmany -m $TESTFILE $((LIMIT/2)) || - quota_error $qtype $qid "create failed, expect succeed" + for ((i = 0; i < $((LIMIT/2048 + 10)); i++)); do + $DD of=$DIR/$tdir_dom/$tfile-$i count=1 \ + oflag=sync || dd_failed=true + done - unlinkmany $TESTFILE $((LIMIT/2)) - fi + $dd_failed || quota_error u $TSTID "write succeed, expect EDQUOT (2)" + + rm -f $DIR/$tdir/* + rm -f $DIR/$tdir_dom/* - log "Test out of quota" # flush cache, ensure noquota flag is set on client - cancel_lru_locks osc - cancel_lru_locks mdc + cancel_lru_locks sync; sync_all_data || true - if [ $qpool == "data" ]; then - $RUNAS $DD of=$TESTFILE count=$((LIMIT*2 >> 10)) oflag=sync && - quota_error $qtype $qid "write succeed, expect EDQUOT" - else - $RUNAS createmany -m $TESTFILE $((LIMIT*2)) && - quota_error $qtype $qid "create succeed, expect EDQUOT" - unlinkmany $TESTFILE $((LIMIT*2)) - fi + dd_failed=false - log "Increase default quota" - # increase default quota - $LFS setquota $qdtype $qs $((LIMIT*3)) $qh $((LIMIT*3)) $DIR || - error "set default quota failed" + for ((i = 0; i < $((LIMIT/2048-1)); i++)); do + $DD of=$DIR/$tdir_dom/$tfile-$i count=1 \ + oflag=sync || dd_failed=true + done - cancel_lru_locks osc - cancel_lru_locks mdc - sync; sync_all_data || true - if [ $qpool == "data" ]; then - $RUNAS $DD of=$TESTFILE count=$((LIMIT*2 >> 10)) oflag=sync || - quota_error $qtype $qid "write failed, expect succeed" - else - $RUNAS createmany -m $TESTFILE $((LIMIT*2)) || - quota_error $qtype $qid "create failed, expect succeed" + $dd_failed && quota_error u $qid "write failed, expect succeed (3)" - unlinkmany $TESTFILE $((LIMIT*2)) + $DD of=$DIR/$tdir/file count=$((LIMIT/2048 + 10)) oflag=sync && + quota_error u $qid "write succeed, expect EDQUOT (3)" + true +} + +test_75() +{ + local soft_limit=10 # MB + local hard_limit=20 # MB + local limit=$soft_limit + local testfile="$DIR/$tdir/$tfile-0" + local grace=20 # seconds + local tdir_dom=${tdir}_dom + + if [ $(facet_fstype $SINGLEMDS) = "zfs" ]; then + grace=60 fi - log "Set quota to override default quota" - $LFS setquota $qtype $qid $qs ${LIMIT} $qh ${LIMIT} $DIR || - error "set $qid quota failed" + setup_quota_test || error "setup quota failed with $?" + stack_trap cleanup_quota_test_75 EXIT - cancel_lru_locks osc - cancel_lru_locks mdc - sync; sync_all_data || true - if [ $qpool == "data" ]; then - $RUNAS $DD of=$TESTFILE count=$((LIMIT*2 >> 10)) oflag=sync && - quota_error $qtype $qid "write succeed, expect EQUOT" - else - $RUNAS createmany -m $TESTFILE $((LIMIT*2)) && - quota_error $qtype $qid "create succeed, expect EQUOT" + # enable ost quota + set_ost_qtype $QTYPE || error "enable ost quota failed" + set_mdt_qtype $QTYPE || error "enable mdt quota failed" - unlinkmany $TESTFILE $((LIMIT*2)) - fi + local used=$(getquota -u $TSTID global curspace) + $LFS setquota -t -u --block-grace $grace --inode-grace \ + $MAX_IQ_TIME $DIR || error "set user grace time failed" + $LFS setquota -u $TSTUSR -b $((soft_limit+used/1024))M \ + -B $((hard_limit+used/1024))M -i 0 -I 0 $DIR || + error "set user quota failed" - log "Set to use default quota again" - $LFS setquota $qtype $qid -d $DIR || - error "set $qid to use default quota failed" + chmod 777 $DIR/$tdir || error "chmod 777 $DIR/$tdir failed" + mkdir $DIR/$tdir_dom + chmod 777 $DIR/$tdir_dom + $LFS setstripe -E 1M -L mdt $DIR/$tdir_dom || + error "setstripe $tdir_dom failed" - cancel_lru_locks osc + do_facet mgs $LCTL nodemap_activate 1 + wait_nm_sync active + do_facet mgs $LCTL nodemap_modify --name default \ + --property admin --value 0 + do_facet mgs $LCTL nodemap_modify --name default \ + --property trusted --value 0 + do_facet mgs $LCTL nodemap_modify --name default \ + --property deny_unknown --value 0 + do_facet mgs $LCTL nodemap_modify --name default \ + --property squash_uid --value $TSTID + do_facet mgs $LCTL nodemap_modify --name default \ + --property squash_gid --value $TSTID cancel_lru_locks mdc - sync; sync_all_data || true - if [ $qpool == "data" ]; then - $RUNAS $DD of=$TESTFILE count=$((LIMIT*2 >> 10)) oflag=sync || - quota_error $qtype $qid "write failed, expect succeed" - else - $RUNAS createmany -m $TESTFILE $((LIMIT*2)) || - quota_error $qtype $qid "create failed, expect succeed" + wait_nm_sync default admin_nodemap + wait_nm_sync default trusted_nodemap + wait_nm_sync default squash_uid + + # mmap write when over soft limit + limit=$soft_limit + $DD of=$testfile count=${limit} || + quota_error a "root write failure, but expect success (1)" + OFFSET=$((limit * 1024)) + cancel_lru_locks osc - unlinkmany $TESTFILE $((LIMIT*2)) - fi + echo "Write to exceed soft limit" + dd if=/dev/zero of=$testfile bs=1K count=10 seek=$OFFSET || + quota_error a $TSTUSR "root write failure, but expect success (2)" + OFFSET=$((OFFSET + 1024)) # make sure we don't write to same block + cancel_lru_locks osc - log "Cleanup" - rm -f $TESTFILE - wait_delete_completed || error "wait_delete_completed failed" + echo "mmap write when over soft limit" + $MULTIOP $testfile.mmap OT40960SMW || + quota_error a $TSTUSR "mmap write failure, but expect success" + cancel_lru_locks osc + rm -f $testfile* + wait_delete_completed || error "wait_delete_completed failed (1)" sync_all_data || true - $LFS setquota $qdtype -b 0 -B 0 -i 0 -I 0 $DIR || - error "reset default quota failed" - $LFS setquota $qtype $qid -b 0 -B 0 -i 0 -I 0 $DIR || - error "reset quota failed" - cleanup_quota_test -} + # test for user hard limit + limit=$hard_limit + log "Write..." + $DD of=$testfile bs=1M count=$((limit/2)) || + quota_error u $TSTID \ + "root write failure, but expect success (3)" -test_61() { - test_default_quota "-u" "data" - test_default_quota "-u" "meta" - test_default_quota "-g" "data" - test_default_quota "-g" "meta" - test_default_quota "-p" "data" - test_default_quota "-p" "meta" + log "Write out of block quota ..." + # possibly a cache write, ignore failure + $DD of=$testfile bs=1M count=$((limit/2)) seek=$((limit/2)) || true + # flush cache, ensure noquota flag is set on client + cancel_lru_locks osc + sync; sync_all_data || true + # sync forced cache flush, but did not guarantee that slave + # got new edquot through glimpse, so wait to make sure + sleep 5 + $DD of=$testfile bs=1M count=1 seek=$limit conv=fsync && + quota_error u $TSTID \ + "user write success, but expect EDQUOT" + rm -f $testfile + wait_delete_completed || error "wait_delete_completed failed (2)" + sync_all_data || true + [ $(getquota -u $TSTUSR global curspace) -eq $used ] || + quota_error u $TSTID "user quota not released after deletion" + + test_dom_75 } -run_test 61 "default quota tests" +run_test 75 "nodemap squashed root respects quota enforcement" -test_62() { +test_76() { ! is_project_quota_supported && - skip "Project quota is not supported" - [[ "$(chattr -h 2>&1)" =~ "project" ]] || - skip "chattr did not support project quota" + skip "skip project quota unsupported" + setup_quota_test || error "setup quota failed with $?" - local testdir=$DIR/$tdir/ + quota_init - $RUNAS mkdir -p $testdir || error "failed to mkdir" - change_project -s $testdir - [[ $($LFS project -d $testdir) =~ "P" ]] || - error "inherit attribute should be set" - # chattr used FS_IOC_SETFLAGS ioctl - $RUNAS chattr -P $testdir && - error "regular user clear inherit should fail" - [[ $($LFS project -d $testdir) =~ "P" ]] || - error "inherit attribute should still be set" - chattr -P $testdir || error "root failed to clear inherit" - [[ $($LFS project -d $testdir) =~ "P" ]] && - error "inherit attribute should be cleared" - cleanup_quota_test + local testfile="$DIR/$tdir/$tfile-0" + + touch $testfile + $LFS project -p 4294967295 $testfile && + error "set project ID should fail" + return 0 } -run_test 62 "Project inherit should be only changed by root" +run_test 76 "project ID 4294967295 should be not allowed" -test_dom() { - [ $(lustre_version_code $SINGLEMDS) -lt $(version_code 2.11.55) ] && - skip "Not supported before 2.11.55" && return +test_77() +{ + mount_client $MOUNT2 "ro" + lfs setquota -u quota_usr -b 100M -B 100M -i 10K -I 10K $MOUNT2 && + error "lfs setquota should fail in read-only Lustre mount" + umount $MOUNT2 +} +run_test 77 "lfs setquota should fail in Lustre mount with 'ro'" - local qtype=$1 - local qid=$TSTUSR - local dd_failed=false - local tdir_dom=${tdir}_dom - local LIMIT=20480 #20M +test_78() +{ + (( $OST1_VERSION >= $(version_code 2.14.55) )) || + skip "need OST at least 2.14.55" + check_set_fallocate_or_skip - [ $qtype == "p" ] && ! is_project_quota_supported && - echo "Project quota is not supported" && return 0 + setup_quota_test || error "setup quota failed with $?" - [ $qtype == "p" ] && qid=$TSTPRJID + # enable ost quota + set_ost_qtype $QTYPE || error "enable ost quota failed" - setup_quota_test || error "setup quota failed with $?" - trap cleanup_quota_test EXIT + mkdir -p $DIR/$tdir || error "failed to create $tdir" + chown $TSTUSR $DIR/$tdir || error "failed to chown $tdir" - quota_init + # setup quota limit + $LFS setquota -u $TSTUSR -b25M -B25M $DIR/$tdir || + error "lfs setquota failed" - # enable mdt/ost quota - set_mdt_qtype $QTYPE || error "enable mdt quota failed" - set_ost_qtype $QTYPE || error "enable ost quota failed" + # call fallocate + runas -u $TSTUSR -g $TSTUSR fallocate -l 204800 $DIR/$tdir/$tfile - # make sure the system is clean - local USED=$(getquota -$qtype $qid global curspace) - [ $USED -ne 0 ] && error "Used space for $qid isn't 0." + kbytes=$(lfs quota -u $TSTUSR $DIR | + awk -v pattern=$DIR 'match($0, pattern) {printf $2}') + echo "kbytes returned:$kbytes" - chown $TSTUSR.$TSTUSR $DIR/$tdir || error "chown $tdir failed" + # For file size of 204800. We should be having roughly 200 kbytes + # returned. Anything alarmingly low (50 taken as arbitrary value) + # would bail out this TC. Also this also avoids $kbytes of 0 + # to be used in calculation below. + (( $kbytes > 50 )) || + error "fallocate did not use quota. kbytes returned:$kbytes" - mkdir $DIR/$tdir_dom || error "mkdir $tdir_dom failed" - $LFS setstripe -E 1M -L mdt $DIR/$tdir_dom || - error "setstripe $tdir_dom failed" - chown $TSTUSR.$TSTUSR $DIR/$tdir_dom || error "chown $tdir_dom failed" + local expect_lo=$(($kbytes * 95 / 100)) # 5% below + local expect_hi=$(($kbytes * 105 / 100)) # 5% above - [ $qtype == "p" ] && { - change_project -sp $TSTPRJID $DIR/$tdir - change_project -sp $TSTPRJID $DIR/$tdir_dom - } + # Verify kbytes is 200 (204800/1024). With a permited 5% drift + (( $kbytes >= $expect_lo && $kbytes <= $expect_hi )) || + error "fallocate did not use quota correctly" +} +run_test 78 "Check fallocate increase quota usage" - $LFS setquota -$qtype $qid -b $LIMIT -B $LIMIT $DIR || - error "set $qid quota failed" +test_78a() +{ + (( $CLIENT_VERSION >= $(version_code 2.15.0) )) || + skip "need client at least 2.15.0" + (( $OST1_VERSION >= $(version_code 2.15.0) )) || + skip "need OST at least 2.15.0" + check_set_fallocate_or_skip - for ((i = 0; i < $((LIMIT/2048)); i++)); do - $RUNAS $DD of=$DIR/$tdir_dom/$tfile-$i count=1 oflag=sync || - dd_failed=true - done + setup_quota_test || error "setup quota failed with $?" - $dd_failed && quota_error $qtype $qid "write failed, expect succeed" + # enable ost quota + set_ost_qtype $QTYPE || error "enable ost quota failed" - for ((i = $((LIMIT/2048)); i < $((LIMIT/1024 + 10)); i++)); do - $RUNAS $DD of=$DIR/$tdir_dom/$tfile-$i count=1 oflag=sync || - dd_failed=true - done + mkdir -p $DIR/$tdir || error "failed to create $tdir" - $dd_failed || quota_error $qtype $qid "write succeed, expect EDQUOT" + local projectid=5200 # Random project id to test - rm -f $DIR/$tdir_dom/* + change_project -sp $projectid $DIR/$tdir - # flush cache, ensure noquota flag is set on client - cancel_lru_locks osc - cancel_lru_locks mdc - sync; sync_all_data || true + # setup quota limit + $LFS setquota -p $projectid -b25M -B25M $DIR/$tdir || + error "lfs setquota project failed" - dd_failed=false + # call fallocate + fallocate -l 204800 $DIR/$tdir/$tfile - $RUNAS $DD of=$DIR/$tdir/file count=$((LIMIT/2048)) oflag=sync || - quota_error $qtype $qid "write failed, expect succeed" + # Get curspace (kbytes) for $projectid + local kbytes=$(getquota -p $projectid global curspace) - for ((i = 0; i < $((LIMIT/2048 + 10)); i++)); do - $RUNAS $DD of=$DIR/$tdir_dom/$tfile-$i count=1 oflag=sync || - dd_failed=true - done + echo "kbytes returned:$kbytes" - $dd_failed || quota_error $qtype $TSTID "write succeed, expect EDQUOT" + # For file size of 204800. We should be having roughly 200 kbytes + # returned. Anything alarmingly low (50 taken as arbitrary value) + # would bail out this TC. Also this also avoids $kbytes of 0 + # to be used in calculation below. + (( $kbytes > 50 )) || + error "fallocate did not use projectid. kbytes returned:$kbytes" - rm -f $DIR/$tdir/* - rm -f $DIR/$tdir_dom/* + local expect_lo=$(($kbytes * 95 / 100)) # 5% below + local expect_hi=$(($kbytes * 105 / 100)) # 5% above - # flush cache, ensure noquota flag is set on client - cancel_lru_locks osc - cancel_lru_locks mdc - sync; sync_all_data || true + # Verify kbytes is 200 (204800/1024). With a permited 5% drift + (( $kbytes >= $expect_lo && $kbytes <= $expect_hi )) || + error "fallocate did not use quota projectid correctly" +} +run_test 78a "Check fallocate increase projectid usage" - dd_failed=false +test_79() +{ + local qpool="qpool1" + local cmd="$LCTL get_param -n qmt.$FSNAME-QMT0000.dt-$qpool.info" + local stopf=$TMP/$tfile + + do_facet mds1 "touch $stopf" + stack_trap "do_facet mds1 'rm -f $stopf'" + do_facet mds1 "while [ -e $stopf ]; do $cmd &>/dev/null; done"& + local pid=$! + pool_add $qpool || error "pool_add failed" + do_facet mds1 "rm $stopf" + wait $pid +} +run_test 79 "access to non-existed dt-pool/info doesn't cause a panic" - for ((i = 0; i < $((LIMIT/2048)); i++)); do - $RUNAS $DD of=$DIR/$tdir_dom/$tfile-$i count=1 oflag=sync || - dd_failed=true - done +test_80() +{ + local dir1="$DIR/$tdir/dir1" + local dir2="$DIR/$tdir/dir2" + local TESTFILE0="$dir1/$tfile-0" + local TESTFILE1="$dir1/$tfile-1" + local TESTFILE2="$dir1/$tfile-2" + local TESTFILE3="$dir2/$tfile-0" + local global_limit=100 # 100M + local limit=10 # 10M + local qpool="qpool1" - $dd_failed && quota_error $qtype $qid "write failed, expect succeed" + [ "$OSTCOUNT" -lt "2" ] && skip "needs >= 2 OSTs" + mds_supports_qp + [ "$ost1_FSTYPE" == zfs ] && + skip "ZFS grants some block space together with inode" + setup_quota_test || error "setup quota failed with $?" + set_ost_qtype $QTYPE || error "enable ost quota failed" - $RUNAS $DD of=$DIR/$tdir/file count=$((LIMIT/2048 + 10)) oflag=sync && - quota_error $qtype $qid "write succeed, expect EDQUOT" + # make sure the system is clean + local used=$(getquota -u $TSTUSR global curspace) + [ $used -ne 0 ] && error "Used space($used) for user $TSTUSR is not 0." - rm -f $DIR/$tdir/* - rm -fr $DIR/$tdir_dom + pool_add $qpool || error "pool_add failed" + pool_add_targets $qpool 0 1 || + error "pool_add_targets failed" - $LFS setquota -u $TSTUSR -b 0 -B 0 -i 0 -I 0 $DIR || - error "reset usr quota failed" + $LFS setquota -u $TSTUSR -b 0 -B ${global_limit}M -i 0 -I 0 $DIR || + error "set user quota failed" - cleanup_quota_test -} + $LFS setquota -u $TSTUSR -B ${global_limit}M --pool $qpool $DIR || + error "set user quota failed" + $LFS setquota -u $TSTUSR -B ${limit}M --pool $qpool $DIR || + error "set user quota failed" -test_63() { - test_dom "u" - test_dom "g" - test_dom "p" + mkdir -p $dir1 || error "failed to mkdir" + chown $TSTUSR.$TSTUSR $dir1 || error "chown $dir1 failed" + mkdir -p $dir2 || error "failed to mkdir" + chown $TSTUSR.$TSTUSR $dir2 || error "chown $dir2 failed" + + $LFS setstripe $dir1 -i 1 -c 1|| error "setstripe $testfile failed" + $LFS setstripe $dir2 -i 0 -c 1|| error "setstripe $testfile failed" + lfs getstripe $dir1 + lfs getstripe $dir2 + sleep 3 + + $LFS quota -uv $TSTUSR $DIR + #define OBD_FAIL_QUOTA_PREACQ 0xA06 + do_facet mds1 $LCTL set_param fail_loc=0xa06 + $RUNAS $DD of=$TESTFILE3 count=3 || + quota_error u $TSTUSR "write failed" + $RUNAS $DD of=$TESTFILE2 count=7 || + quota_error u $TSTUSR "write failed" + $RUNAS $DD of=$TESTFILE1 count=1 oflag=direct || + quota_error u $TSTUSR "write failed" + sync + sleep 3 + $LFS quota -uv --pool $qpool $TSTUSR $DIR + + rm -f $TESTFILE2 + stop ost2 + do_facet mds1 $LCTL set_param fail_loc=0 + start ost2 $(ostdevname 2) $OST_MOUNT_OPTS || error "start ost2 failed" + $LFS quota -uv $TSTUSR --pool $qpool $DIR + # OST0 needs some time to update quota usage after removing TESTFILE2 + sleep 4 + $LFS quota -uv $TSTUSR --pool $qpool $DIR + $RUNAS $DD of=$TESTFILE0 count=2 oflag=direct || + quota_error u $TSTUSR "write failure, but expect success" } -run_test 63 "quota on DoM tests" +run_test 80 "check for EDQUOT after OST failover" -test_64() { - ! is_project_quota_supported && - skip "Project quota is not supported" +test_81() { + local global_limit=20 # 100M + local testfile="$DIR/$tdir/$tfile-0" + local qpool="qpool1" + + mds_supports_qp setup_quota_test || error "setup quota failed with $?" - local dir1="$DIR/$tdir/" - touch $dir1/file - ln -s $dir1/file $dir1/file_link + # enable ost quota + set_ost_qtype $QTYPE || error "enable ost quota failed" - $LFS project -sp $TSTPRJID $dir1/file_link >&/dev/null && - error "set symlink file's project should fail" + # test for user + log "User quota (block hardlimit:$global_limit MB)" + $LFS setquota -u $TSTUSR -B 1G $DIR || error "set user quota failed" - $LFS project $TSTPRJID $dir1/file_link >&/dev/null && - error "get symlink file's project should fail" + pool_add $qpool || error "pool_add failed" + #define OBD_FAIL_QUOTA_RECALC 0xA07 + do_facet mds1 $LCTL set_param fail_loc=0x80000A07 fail_val=30 + # added OST casues to start pool recalculation + pool_add_targets $qpool 0 0 1 + stop mds1 -f || error "MDS umount failed" - cleanup_quota_test + #start mds1 back to destroy created pool + start mds1 $(mdsdevname 1) $MDS_MOUNT_OPTS + clients_up || true } -run_test 64 "lfs project on symlink files should fail" +run_test 81 "Race qmt_start_pool_recalc with qmt_pool_free" -test_65() { - local SIZE=10 #10M - local TESTFILE="$DIR/$tdir/$tfile-0" +test_82() +{ + (( $MDS1_VERSION >= $(version_code 2.14.55) )) || + skip "need MDS 2.14.55 or later" + is_project_quota_supported || + skip "skip project quota unsupported" setup_quota_test || error "setup quota failed with $?" - set_ost_qtype $QTYPE || error "enable ost quota failed" + stack_trap cleanup_quota_test quota_init - echo "Write..." - $RUNAS $DD of=$TESTFILE count=$SIZE || - error "failed to write" - # flush cache, ensure noquota flag is set on client - cancel_lru_locks osc - sync; sync_all_data || true + local parent_dir="$DIR/$tdir.parent" + local child_dir="$parent_dir/child" - local quota_u=$($LFS quota -u $TSTUSR $DIR) - local quota_g=$($LFS quota -g $TSTUSR $DIR) - local quota_all=$($RUNAS $LFS quota $DIR) + mkdir -p $child_dir + stack_trap "chown -R 0:0 $parent_dir" - [ "$(echo "$quota_all" | head -n3)" != "$quota_u" ] && - error "usr quota not match" - [ "$(echo "$quota_all" | tail -n3)" != "$quota_g" ] && - error "grp quota not match" + chown $TSTUSR:$TSTUSR $parent_dir || + error "failed to chown on $parent_dir" + chown $TSTUSR2:$TSTUSRS2 $child_dir || + error "failed to chown on $parent_dir" - rm -f $TESTFILE - # cleanup - cleanup_quota_test + $LFS project -p 1000 $parent_dir || + error "failed to set project id on $parent_dir" + $LFS project -p 1001 $child_dir || + error "failed to set project id on $child_dir" + + rmdir $child_dir || error "cannot remove child dir, test failed" } -run_test 65 "Check lfs quota result" +run_test 82 "verify more than 8 qids for single operation" quota_fini() { - do_nodes $(comma_list $(nodes_list)) "lctl set_param debug=-quota" + do_nodes $(comma_list $(nodes_list)) \ + "lctl set_param -n debug=-quota,trace" if $PQ_CLEANUP; then disable_project_quota fi