Whamcloud - gitweb
LU-7991 quota: project quota against ZFS backend
[fs/lustre-release.git] / lustre / tests / sanity-quota.sh
index 8723809..48f8ad6 100755 (executable)
@@ -72,9 +72,21 @@ export QUOTA_AUTO=0
 check_and_setup_lustre
 
 is_project_quota_supported() {
+       lsattr -dp > /dev/null 2>&1 || return 1
+
        [ "$(facet_fstype $SINGLEMDS)" == "ldiskfs" ] &&
-               [ $(lustre_version_code $SINGLEMDS) -gt $(version_code 2.9.55) ] &&
-                       egrep -q "7." /etc/redhat-release
+               [ $(lustre_version_code $SINGLEMDS) -gt \
+               $(version_code 2.9.55) ] &&
+               egrep -q "7." /etc/redhat-release && return 0
+
+       if [ "$(facet_fstype $SINGLEMDS)" == "zfs" ]; then
+               [ $(lustre_version_code $SINGLEMDS) -le \
+                       $(version_code 2.10.53) ] && return 1
+
+               $ZPOOL upgrade -v | grep project_quota && return 0
+       fi
+
+       return 1
 }
 
 SHOW_QUOTA_USER="$LFS quota -v -u $TSTUSR $DIR"
@@ -103,6 +115,12 @@ lustre_fail() {
        do_nodes $NODES "lctl set_param fail_val=$fail_val fail_loc=$fail_loc"
 }
 
+change_project()
+{
+       echo "chattr $*"
+       chattr $* || error "chattr $* failed"
+}
+
 RUNAS="runas -u $TSTID -g $TSTID"
 RUNAS2="runas -u $TSTID2 -g $TSTID2"
 DD="dd if=/dev/zero bs=1M"
@@ -153,9 +171,9 @@ quota_scan() {
        fi
 
        if [ "$local_ugp" == "a" -o "$local_ugp" == "p" ]; then
-               $LFS quota -v -p $local_id $DIR
-               log "Files for project ($local_id):"
-               ($LFS find --projid $local_id $DIR | head -n 4 |
+               $LFS quota -v -p $TSTPRJID $DIR
+               log "Files for project ($TSTPRJID):"
+               ($LFS find --projid $TSTPRJID $DIR | head -n 4 |
                        xargs stat 2>/dev/null)
        fi
 }
@@ -179,6 +197,8 @@ getquota() {
        local spec
        local uuid
 
+       sync_all_data > /dev/null 2>&1 || true
+
        [ "$#" != 4 ] && error "getquota: wrong number of arguments: $#"
        [ "$1" != "-u" -a "$1" != "-g" -a "$1" != "-p" ] &&
                error "getquota: wrong u/g/p specifier $1 passed"
@@ -323,6 +343,7 @@ wait_ost_reint() {
 
 disable_project_quota() {
        is_project_quota_supported || return 0
+       [ "$(facet_fstype $SINGLEMDS)" != "ldiskfs" ] && return 0
        stopall || error "failed to stopall (1)"
 
        for num in $(seq $MDSCOUNT); do
@@ -390,7 +411,8 @@ quota_show_check() {
 }
 
 enable_project_quota() {
-       is_project_quota_supported ||  return 0
+       is_project_quota_supported || return 0
+       [ "$(facet_fstype $SINGLEMDS)" != "ldiskfs" ] && return 0
        stopall || error "failed to stopall (1)"
 
        for num in $(seq $MDSCOUNT); do
@@ -556,13 +578,13 @@ test_1() {
 
        # test for Project
        log "--------------------------------------"
-       log "project quota (block hardlimit:$LIMIT mb)"
+       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"
 
        $SETSTRIPE $TESTFILE -c 1 || error "setstripe $TESTFILE failed"
        chown $TSTUSR:$TSTUSR $TESTFILE || error "chown $TESTFILE failed"
-       chattr -p $TSTPRJID $TESTFILE
+       change_project -p $TSTPRJID $TESTFILE
 
        log "write ..."
        $RUNAS $DD of=$TESTFILE count=$((LIMIT/2)) || quota_error p $TSTPRJID \
@@ -573,7 +595,7 @@ test_1() {
        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"
+               $TSTPRJID "project write success, but expect EDQUOT"
 
        # cleanup
        cleanup_quota_test
@@ -674,16 +696,16 @@ test_2() {
        [ $USED -ne 0 ] &&
                error "Used inodes($USED) for project $TSTPRJID isn't 0"
 
-       chattr +P $DIR/$tdir/
-       chattr -p $TSTPRJID -d $DIR/$tdir
+       change_project +P $DIR/$tdir/
+       change_project -p $TSTPRJID -d $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"
-       chattr -P $DIR/$tdir
-       chattr -p 0 -d $DIR/$tdir
+       change_project -P $DIR/$tdir
+       change_project -p 0 -d $DIR/$tdir
 
        cleanup_quota_test
        USED=$(getquota -p $TSTPRJID global curinodes)
@@ -708,7 +730,7 @@ test_block_soft() {
        $SETSTRIPE $TESTFILE -c 1 -i 0
        chown $TSTUSR.$TSTUSR $TESTFILE
        [ "$qtype" == "p" ] && is_project_quota_supported &&
-               chattr -p $TSTPRJID $TESTFILE
+               change_project -p $TSTPRJID $TESTFILE
 
        echo "Write up to soft limit"
        $RUNAS $DD of=$TESTFILE count=$LIMIT ||
@@ -774,7 +796,7 @@ test_block_soft() {
 
        $SETSTRIPE $TESTFILE -c 1 -i 0
        chown $TSTUSR.$TSTUSR $TESTFILE
-       [ "$qtype" == "p" ] && chattr -p $TSTPRJID $TESTFILE
+       [ "$qtype" == "p" ] && change_project -p $TSTPRJID $TESTFILE
 
        echo "Write ..."
        $RUNAS $DD of=$TESTFILE count=$LIMIT ||
@@ -855,8 +877,8 @@ test_file_soft() {
 
        setup_quota_test
        trap cleanup_quota_test EXIT
-       is_project_quota_supported && chattr +P $DIR/$tdir/ &&
-               chattr -p $TSTPRJID -d $DIR/$tdir
+       is_project_quota_supported && change_project +P $DIR/$tdir/ &&
+               change_project -p $TSTPRJID -d $DIR/$tdir
 
        echo "Create files to exceed soft limit"
        $RUNAS createmany -m ${TESTFILE}_ $((LIMIT + 1)) ||
@@ -1047,6 +1069,9 @@ test_5() {
        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."
@@ -1055,9 +1080,9 @@ test_5() {
        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 [ "$(facet_fstype $singlemds)" == "ldiskfs" ]; then
+       if is_project_quota_supported; then
                touch $DIR/$tdir/$tfile-0_1
-               chattr -p $TSTPRJID $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"
@@ -1399,15 +1424,18 @@ run_test 7d "Quota reintegration (Transfer index in multiple bulks)"
 
 # quota reintegration (inode limits)
 test_7e() {
-       [ "$MDSCOUNT" -lt "2" ] && skip "Required more MDTs" && return
+       [ "$MDSCOUNT" -lt "2" ] && skip "needs >= 2 MDTs" && return
 
        # LU-2435: skip this quota test if underlying zfs version has not
        # supported native dnode accounting
        [ "$(facet_fstype mds1)" == "zfs" ] && {
-               local zfs_version=$(do_facet mds1 cat /sys/module/zfs/version)
+               local F="feature@userobj_accounting"
+               local pool=$(zpool_name mds1)
+               local feature=$(do_facet mds1 $ZPOOL get -H $F $pool)
 
-               [ $(version_code $zfs_version) -lt $(version_code 0.7.0) ] &&
-                       skip "requires zfs version at least 0.7.0" && return
+               [[ "$feature" != *" active "* ]] &&
+                       skip "requires zpool with active userobj_accounting" &&
+                       return
        }
 
        local ilimit=$((1024 * 2)) # 2k inodes
@@ -1472,7 +1500,7 @@ test_7e() {
 
        # hardlimit should be cleared on slave during reintegration
        $RUNAS createmany -m $TESTFILE $((ilimit + 1)) ||
-               quota_error -u $TSTUSR "create failed, expect success"
+               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"
@@ -1500,7 +1528,8 @@ test_8() {
        $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
-               chattr +P $DIR/$tdir && chattr -p $TSTPRJID -d $DIR/$tdir
+               change_project +P $DIR/$tdir && change_project -p \
+                       $TSTPRJID -d $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 ||
@@ -1512,8 +1541,8 @@ test_8() {
        $RUNAS bash rundbench -D $DIR/$tdir 3 $duration ||
                quota_error a $TSTUSR "dbench failed!"
 
-       is_project_quota_supported && chattr -P $DIR/$tdir &&
-       chattr -dp 0 $DIR/$tdir
+       is_project_quota_supported && change_project -P $DIR/$tdir &&
+       change_project -dp 0 $DIR/$tdir
        cleanup_quota_test
        resetquota -u $TSTUSR
        resetquota -g $TSTUSR
@@ -1642,7 +1671,7 @@ test_11() {
 run_test 11 "Chown/chgrp ignores quota"
 
 test_12a() {
-       [ "$OSTCOUNT" -lt "2" ] && skip "skipping rebalancing test" && return
+       [ "$OSTCOUNT" -lt "2" ] && skip "needs >= 2 OSTs" && return
 
        local blimit=22 # 22M
        local blk_cnt=$((blimit - 5))
@@ -1686,7 +1715,7 @@ test_12a() {
 run_test 12a "Block quota rebalancing"
 
 test_12b() {
-       [ "$MDSCOUNT" -lt "2" ] && skip "skipping rebalancing test" && return
+       [ "$MDSCOUNT" -lt "2" ] && skip "needs >= 2 MDTs" && return
 
        local ilimit=$((1024 * 2)) # 2k inodes
        local TESTFILE0=$DIR/$tdir/$tfile
@@ -2388,10 +2417,14 @@ test_33() {
                $RUNAS $DD of=$DIR/$tdir/$tfile-$i count=$BLK_CNT 2>/dev/null ||
                        error "write failed"
                        is_project_quota_supported &&
-                               chattr -p $TSTPRJID $DIR/$tdir/$tfile-$i
+                               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"
@@ -2432,6 +2465,9 @@ test_33() {
        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=$(getquota -p $TSTPRJID global curinodes)
                [ $USED -eq 0 ] ||
                        error "Used inodes for project $TSTPRJID isn't 0. $USED"
@@ -2505,9 +2541,9 @@ test_34() {
        echo "Wait for setattr on objects finished..."
        wait_delete_completed
 
-       echo "chattr project id to $TSTPRJID"
+       echo "change_project project id to $TSTPRJID"
        [ $project_supported == "yes" ] &&
-               chattr -p $TSTPRJID $DIR/$tdir/$tfile
+               change_project -p $TSTPRJID $DIR/$tdir/$tfile
        echo "Wait for setattr on objects finished..."
        wait_delete_completed
 
@@ -2542,8 +2578,12 @@ test_35() {
        $RUNAS $DD of=$DIR/$tdir/$tfile count=$BLK_CNT 2>/dev/null ||
                error "write failed"
        is_project_quota_supported &&
-               chattr -p $TSTPRJID $DIR/$tdir/$tfile
+               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"
@@ -2721,7 +2761,7 @@ test_39() {
        projectid=$(lsattr -p $TESTFILE | awk '{print $1}')
        [ $projectid -ne 0 ] &&
                error "Project id should be 0 not $projectid"
-       chattr -p 1024 $TESTFILE
+       change_project -p 1024 $TESTFILE
        projectid=$(lsattr -p $TESTFILE | awk '{print $1}')
        [ $projectid -ne 1024 ] &&
                error "Project id should be 1024 not $projectid"
@@ -2746,8 +2786,8 @@ test_40a() {
        setup_quota_test || error "setup quota failed with $?"
 
        mkdir -p $dir1 $dir2
-       chattr +P $dir1 && chattr -p 1 -d $dir1 && touch $dir1/1
-       chattr +P $dir2 && chattr -p 2 -d $dir2
+       change_project +P $dir1 && change_project -p 1 -d $dir1 && touch $dir1/1
+       change_project +P $dir2 && change_project -p 2 -d $dir2
 
        ln $dir1/1 $dir2/1_link &&
                error "Hard link across different project quota should fail"
@@ -2765,8 +2805,8 @@ test_40b() {
 
        setup_quota_test || error "setup quota failed with $?"
        mkdir -p $dir1 $dir2
-       chattr +P $dir1 && chattr -p 1 -d $dir1 && touch $dir1/1
-       chattr +P $dir2 && chattr -p 2 -d $dir2
+       change_project +P $dir1 && change_project -p 1 -d $dir1 && touch $dir1/1
+       change_project +P $dir2 && change_project -p 2 -d $dir2
 
        mv $dir1/1 $dir2/2 || error "mv failed $?"
        local projid=$(lsattr -p $dir2/2 | awk '{print $1}')
@@ -2779,14 +2819,14 @@ test_40b() {
 run_test 40b "Mv across different project ID"
 
 test_40c() {
-       [ "$MDSCOUNT" -lt "2" ] && skip "Required more MDTs" && return
+       [ "$MDSCOUNT" -lt "2" ] && skip "needs >= 2 MDTs" && return
                ! is_project_quota_supported &&
                        skip "Project quota is not supported" && return 0
 
        setup_quota_test || error "setup quota failed with $?"
        local dir="$DIR/$tdir/dir"
 
-       mkdir -p $dir && chattr +P $dir && chattr -dp 1 $dir
+       mkdir -p $dir && change_project +P $dir && change_project -dp 1 $dir
        $LFS mkdir -i 1 $dir/remote_dir || error "create remote dir failed"
        local projid=$(lsattr -dp $dir/remote_dir | awk '{print $1}')
        [ "$projid" != "1" ] && error "projid id expected 1 not $projid"
@@ -2814,7 +2854,7 @@ test_50() {
        setup_quota_test || error "setup quota failed with $?"
        local dir="$DIR/$tdir/dir"
 
-       mkdir $dir && chattr -dp 1 $dir
+       mkdir $dir && change_project -dp 1 $dir
        count=$($LFS find --projid 1 $DIR | wc -l)
        [ "$count" != 1 ] && error "expected 1 but got $count"
 
@@ -2829,26 +2869,26 @@ test_51() {
        setup_quota_test || error "setup quota failed with $?"
        local dir="$DIR/$tdir/dir"
 
-       mkdir $dir && chattr -dp 1 $dir && chattr +P $dir
+       mkdir $dir && change_project -dp 1 $dir && change_project +P $dir
        local used=$(getquota -p 1 global curinodes)
-       [ $used != "1" ] &&  error "expected 1 got $used"
+       [ $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"
+       [ $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"
+       [ $used != "5" ] && error "expected 5 got $used"
 
        #try mv to dir
        mv $DIR/$tdir/6 $dir/7
        used=$(getquota -p 1 global curinodes)
-       [ $used != "6" ] &&  error "expected 6 got $used"
+       [ $used != "6" ] && error "expected 6 got $used"
 
        rm -rf $dir
        cleanup_quota_test
@@ -2860,7 +2900,7 @@ test_52() {
                skip "Project quota is not supported" && return 0
        setup_quota_test || error "setup quota failed with $?"
        local dir="$DIR/$tdir/dir"
-       mkdir $dir && chattr -dp 1 $dir && chattr +P $dir
+       mkdir $dir && change_project -dp 1 $dir && change_project +P $dir
 
        touch $DIR/$tdir/file
        #Try renaming a file into the project.  This should fail.
@@ -2873,6 +2913,22 @@ test_52() {
 }
 run_test 52 "Rename across different project ID"
 
+test_53() {
+       ! is_project_quota_supported &&
+               skip "Project quota is not supported" && return 0
+       setup_quota_test || error "setup quota failed with $?"
+       local dir="$DIR/$tdir/dir"
+       mkdir $dir && change_project +P $dir
+       lsattr -pd $dir | grep P || error "inherit attribute should be set"
+
+       change_project -Pd $dir
+       lsattr -pd $dir | grep P && error "inherit attribute should be cleared"
+
+       rm -rf $dir
+       cleanup_quota_test
+}
+run_test 53 "Project inherit attribute could be cleared"
+
 quota_fini()
 {
        do_nodes $(comma_list $(nodes_list)) "lctl set_param debug=-quota"