aboutsummaryrefslogtreecommitdiff
path: root/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota
diff options
context:
space:
mode:
Diffstat (limited to 'sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota')
-rw-r--r--sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/Makefile.am27
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/cleanup.ksh37
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projectid_001_pos.ksh113
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projectid_002_pos.ksh88
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projectid_003_pos.ksh81
-rw-r--r--sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projectquota.cfg46
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projectquota_001_pos.ksh88
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projectquota_002_pos.ksh86
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projectquota_003_pos.ksh98
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projectquota_004_neg.ksh87
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projectquota_005_pos.ksh68
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projectquota_006_pos.ksh75
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projectquota_007_pos.ksh58
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projectquota_008_pos.ksh91
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projectquota_009_pos.ksh131
-rw-r--r--sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projectquota_common.kshlib101
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projectspace_001_pos.ksh93
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projectspace_002_pos.ksh85
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projectspace_003_pos.ksh118
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projectspace_004_pos.ksh76
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projecttree_001_pos.ksh108
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projecttree_002_pos.ksh120
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projecttree_003_neg.ksh103
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/setup.ksh56
24 files changed, 2034 insertions, 0 deletions
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/Makefile.am b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/Makefile.am
new file mode 100644
index 000000000000..e98c8672802e
--- /dev/null
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/Makefile.am
@@ -0,0 +1,27 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/projectquota
+dist_pkgdata_SCRIPTS = \
+ setup.ksh \
+ cleanup.ksh \
+ projectid_001_pos.ksh \
+ projectid_002_pos.ksh \
+ projectid_003_pos.ksh \
+ projectquota_001_pos.ksh \
+ projectquota_002_pos.ksh \
+ projectquota_003_pos.ksh \
+ projectquota_004_neg.ksh \
+ projectquota_005_pos.ksh \
+ projectquota_006_pos.ksh \
+ projectquota_007_pos.ksh \
+ projectquota_008_pos.ksh \
+ projectquota_009_pos.ksh \
+ projectspace_001_pos.ksh \
+ projectspace_002_pos.ksh \
+ projectspace_003_pos.ksh \
+ projectspace_004_pos.ksh \
+ projecttree_001_pos.ksh \
+ projecttree_002_pos.ksh \
+ projecttree_003_neg.ksh
+
+dist_pkgdata_DATA = \
+ projectquota.cfg \
+ projectquota_common.kshlib
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/cleanup.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/cleanup.ksh
new file mode 100755
index 000000000000..0440e3d8af8c
--- /dev/null
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/cleanup.ksh
@@ -0,0 +1,37 @@
+#!/bin/ksh -p
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2017 by Fan Yong. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/projectquota/projectquota_common.kshlib
+
+log_must cleanup_projectquota
+log_must del_user $PUSER
+log_must del_group $PGROUP
+default_cleanup
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projectid_001_pos.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projectid_001_pos.ksh
new file mode 100755
index 000000000000..46e79062a0e2
--- /dev/null
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projectid_001_pos.ksh
@@ -0,0 +1,113 @@
+#!/bin/ksh -p
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2017 by Fan Yong. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/projectquota/projectquota_common.kshlib
+
+#
+#
+# DESCRIPTION:
+# Check project ID/flags can be set/inherited properly
+#
+#
+# STRATEGY:
+# 1. Create a regular file and a directory.
+# 2. Set project ID on both directory and regular file.
+# 3. New created subdir or regular file should inherit its parent's
+# project ID if its parent has project inherit flag.
+# 4. New created subdir should inherit its parent project's inherit flag.
+#
+
+function cleanup
+{
+ log_must rm -f $PRJFILE
+ log_must rm -rf $PRJDIR
+}
+
+if ! lsattr -pd > /dev/null 2>&1; then
+ log_unsupported "Current e2fsprogs does not support set/show project ID"
+fi
+
+#
+# e2fsprogs-1.44.4 incorrectly reports verity 'V' bit when the project 'P'
+# bit is set. Skip this test when 1.44.4 is installed to prevent failures.
+#
+# https://github.com/tytso/e2fsprogs/commit/7e5a95e3d
+#
+if lsattr -V 2>&1 | grep "lsattr 1.44.4"; then
+ log_unsupported "Current e2fsprogs incorrectly reports 'V' verity bit"
+fi
+
+log_onexit cleanup
+
+log_assert "Check project ID/flags can be set/inherited properly"
+
+log_must touch $PRJFILE
+log_must mkdir $PRJDIR
+
+log_must chattr -p $PRJID1 $PRJFILE
+log_must eval "lsattr -p $PRJFILE | grep $PRJID1 | grep -v '\-P[- ]* '"
+log_must chattr -p $PRJID1 $PRJDIR
+log_must eval "lsattr -pd $PRJDIR | grep $PRJID1 | grep -v '\-P[- ]* '"
+
+log_must chattr +P $PRJDIR
+log_must eval "lsattr -pd $PRJDIR | grep $PRJID1 | grep '\-P[- ]* '"
+
+# "-1" is invalid project ID, should be denied
+log_mustnot chattr -p -1 $PRJFILE
+log_must eval "lsattr -p $PRJFILE | grep $PRJID1 | grep -v '\-P[- ]* '"
+
+log_must mkdir $PRJDIR/dchild
+log_must eval "lsattr -pd $PRJDIR/dchild | grep $PRJID1 | grep '\-P[- ]* '"
+log_must touch $PRJDIR/fchild
+log_must eval "lsattr -p $PRJDIR/fchild | grep $PRJID1"
+
+log_must touch $PRJDIR/dchild/foo
+log_must eval "lsattr -p $PRJDIR/dchild/foo | grep $PRJID1"
+
+# not support project ID/flag on symlink
+log_must ln -s $PRJDIR/dchild/foo $PRJDIR/dchild/s_foo
+log_mustnot lsattr -p $PRJDIR/dchild/s_foo
+log_mustnot chattr -p 123 $PRJDIR/dchild/s_foo
+log_mustnot chattr +P $PRJDIR/dchild/s_foo
+
+# not support project ID/flag on block special file
+log_must mknod $PRJDIR/dchild/b_foo b 124 124
+log_mustnot lsattr -p $PRJDIR/dchild/b_foo
+log_mustnot chattr -p 123 $PRJDIR/dchild/b_foo
+log_mustnot chattr +P $PRJDIR/dchild/b_foo
+
+# not support project ID/flag on character special file
+log_must mknod $PRJDIR/dchild/c_foo c 125 125
+log_mustnot lsattr -p $PRJDIR/dchild/c_foo
+log_mustnot chattr -p 123 $PRJDIR/dchild/c_foo
+log_mustnot chattr +P $PRJDIR/dchild/c_foo
+
+log_pass "Check project ID/flags can be set/inherited properly"
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projectid_002_pos.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projectid_002_pos.ksh
new file mode 100755
index 000000000000..e382f464046b
--- /dev/null
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projectid_002_pos.ksh
@@ -0,0 +1,88 @@
+#!/bin/ksh -p
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2017 by Fan Yong. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/projectquota/projectquota_common.kshlib
+
+#
+#
+# DESCRIPTION:
+# Project ID affects POSIX behavior
+#
+#
+# STRATEGY:
+# 1. Create three directories
+# 2. Set tdir1 and tdir3 project ID as PRJID1,
+# set tdir2 project ID as PRJID2.
+# 3. Create regular file under tdir1. It inherits tdir1 project ID.
+# 4. Hardlink from tdir1's child to tdir2 should be denied,
+# move tdir1's child to tdir2 will be object recreated.
+# 5. Hardlink from tdir1's child to tdir3 should succeed.
+#
+
+function cleanup
+{
+ log_must rm -rf $PRJDIR1
+ log_must rm -rf $PRJDIR2
+ log_must rm -rf $PRJDIR3
+}
+
+if ! lsattr -pd > /dev/null 2>&1; then
+ log_unsupported "Current e2fsprogs does not support set/show project ID"
+fi
+
+log_onexit cleanup
+
+log_assert "Project ID affects POSIX behavior"
+
+log_must mkdir $PRJDIR1
+log_must mkdir $PRJDIR2
+log_must mkdir $PRJDIR3
+log_must mkdir $PRJDIR3/dir
+
+log_must chattr +P -p $PRJID1 $PRJDIR1
+log_must chattr +P -p $PRJID2 $PRJDIR2
+
+log_must touch $PRJDIR1/tfile1
+log_must touch $PRJDIR1/tfile2
+log_must eval "lsattr -p $PRJDIR1/tfile1 | grep $PRJID1"
+
+log_mustnot ln $PRJDIR1/tfile1 $PRJDIR2/tfile2
+
+log_must mv $PRJDIR1/tfile1 $PRJDIR2/tfile2
+log_must eval "lsattr -p $PRJDIR2/tfile2 | grep $PRJID2"
+
+log_must mv $PRJDIR3/dir $PRJDIR2/
+log_must eval "lsattr -dp $PRJDIR2/dir | grep $PRJID2"
+
+log_must chattr +P -p $PRJID1 $PRJDIR3
+log_must ln $PRJDIR1/tfile2 $PRJDIR3/tfile3
+
+log_pass "Project ID affects POSIX behavior"
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projectid_003_pos.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projectid_003_pos.ksh
new file mode 100755
index 000000000000..d6dbaafc217a
--- /dev/null
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projectid_003_pos.ksh
@@ -0,0 +1,81 @@
+#!/bin/ksh -p
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2017 by Fan Yong. Fan rights reserved.
+#
+
+. $STF_SUITE/tests/functional/projectquota/projectquota_common.kshlib
+
+#
+# DESCRIPTION:
+# Check changing project ID for the file with directory-based
+# extended attributes.
+#
+#
+# STRATEGY:
+# 1. create new file with default project ID
+# 2. set non-ACL extended attributes on the file
+# 3. use zfs projectspace to check the object usage
+# 4. change the file's project ID
+# 5. use zfs projectspace to check the object usage again
+#
+
+function cleanup
+{
+ log_must rm -f $PRJGUARD
+ log_must rm -f $PRJFILE
+}
+
+if ! lsattr -pd > /dev/null 2>&1; then
+ log_unsupported "Current e2fsprogs does not support set/show project ID"
+fi
+
+log_onexit cleanup
+
+log_assert "Check changing project ID with directory-based extended attributes"
+
+log_must zfs set xattr=on $QFS
+
+log_must touch $PRJGUARD
+log_must chattr -p $PRJID1 $PRJGUARD
+log_must touch $PRJFILE
+log_must setfattr -n trusted.ea1 -v val1 $PRJFILE
+log_must setfattr -n trusted.ea2 -v val2 $PRJFILE
+log_must setfattr -n trusted.ea3 -v val3 $PRJFILE
+
+sync_pool
+typeset prj_bef=$(project_obj_count $QFS $PRJID1)
+
+log_must chattr -p $PRJID1 $PRJFILE
+sync_pool
+typeset prj_aft=$(project_obj_count $QFS $PRJID1)
+
+[[ $prj_aft -ge $((prj_bef + 5)) ]] ||
+ log_fail "new value ($prj_aft) is NOT 5 largr than old one ($prj_bef)"
+
+log_pass "Changing project ID with directory-based extended attributes pass"
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projectquota.cfg b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projectquota.cfg
new file mode 100644
index 000000000000..564ab3ef9698
--- /dev/null
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projectquota.cfg
@@ -0,0 +1,46 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2017 by Fan Yong. All rights reserved.
+#
+
+export PUSER=puser
+export PGROUP=pgroup
+
+export PRJID1=1001
+export PRJID2=1002
+
+export QFS=$TESTPOOL/$TESTFS
+export PRJFILE=$TESTDIR/tfile
+export PRJGUARD=$TESTDIR/guard
+export PRJDIR=$TESTDIR/tdir
+export PRJDIR1=$TESTDIR/tdir1
+export PRJDIR2=$TESTDIR/tdir2
+export PRJDIR3=$TESTDIR/tdir3
+
+export PQUOTA_LIMIT=1000000
+export PQUOTA_OBJLIMIT=1000
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projectquota_001_pos.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projectquota_001_pos.ksh
new file mode 100755
index 000000000000..3f8c3d68ce3e
--- /dev/null
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projectquota_001_pos.ksh
@@ -0,0 +1,88 @@
+#!/bin/ksh -p
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2017 by Fan Yong. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/projectquota/projectquota_common.kshlib
+
+#
+#
+# DESCRIPTION:
+# Check the basic function of the project{obj}quota
+#
+#
+# STRATEGY:
+# 1. Set projectquota and overwrite the quota size.
+# 2. The write operation should fail with Disc quota exceeded
+# 3. Set projectobjquota and overcreate the quota size.
+# 4. More create should fail with Disc quota exceeded
+# 5. More chattr to such project should fail with Disc quota exceeded
+#
+
+function cleanup
+{
+ cleanup_projectquota
+}
+
+if ! lsattr -pd > /dev/null 2>&1; then
+ log_unsupported "Current e2fsprogs does not support set/show project ID"
+fi
+
+log_onexit cleanup
+
+log_assert "If operation overwrite project{obj}quota size, it will fail"
+
+mkmount_writable $QFS
+
+log_note "Check the projectquota@$PRJID1"
+log_must user_run $PUSER mkdir $PRJDIR
+log_must chattr +P -p $PRJID1 $PRJDIR
+
+log_must zfs set projectquota@$PRJID1=$PQUOTA_LIMIT $QFS
+log_must user_run $PUSER mkfile $PQUOTA_LIMIT $PRJDIR/qf
+sync_pool
+log_mustnot user_run $PUSER mkfile 1 $PRJDIR/of
+
+log_must rm -rf $PRJDIR
+
+log_note "Check the projectobjquota@$PRJID2"
+log_must zfs set xattr=sa $QFS
+log_must user_run $PUSER mkdir $PRJDIR
+log_must chattr +P -p $PRJID2 $PRJDIR
+
+log_must zfs set projectobjquota@$PRJID2=$PQUOTA_OBJLIMIT $QFS
+log_must user_run $PUSER mkfiles $PRJDIR/qf_ $((PQUOTA_OBJLIMIT - 1))
+sync_pool
+log_mustnot user_run $PUSER mkfile 1 $PRJDIR/of
+
+log_must user_run $PUSER touch $PRJFILE
+log_must user_run $PUSER chattr -p 123 $PRJFILE
+log_mustnot user_run $PUSER chattr -p $PRJID2 $PRJFILE
+
+log_pass "Operation overwrite project{obj}quota size failed as expect"
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projectquota_002_pos.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projectquota_002_pos.ksh
new file mode 100755
index 000000000000..66cd1fb9ef71
--- /dev/null
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projectquota_002_pos.ksh
@@ -0,0 +1,86 @@
+#!/bin/ksh -p
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2017 by Fan Yong. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/projectquota/projectquota_common.kshlib
+
+#
+# DESCRIPTION:
+# The project{obj}quota can be set during zpool or zfs creation
+#
+#
+# STRATEGY:
+# 1. Set project{obj}quota via "zpool -O or zfs create -o"
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+ if poolexists $TESTPOOL1; then
+ log_must zpool destroy $TESTPOOL1
+ fi
+
+ if [[ -f $pool_vdev ]]; then
+ rm -f $pool_vdev
+ fi
+}
+
+log_onexit cleanup
+
+log_assert "The project{obj}quota can be set during zpool,zfs creation"
+
+typeset pool_vdev=$TEST_BASE_DIR/pool_dev.$$
+
+log_must mkfile 500m $pool_vdev
+
+if poolexists $TESTPOOL1; then
+ zpool destroy $TESTPOOL1
+fi
+
+log_must zpool create -O projectquota@$PRJID1=$PQUOTA_LIMIT \
+ -O projectobjquota@$PRJID2=$PQUOTA_OBJLIMIT $TESTPOOL1 $pool_vdev
+
+log_must eval "zfs list -r -o projectquota@$PRJID1,projectobjquota@$PRJID2 \
+ $TESTPOOL1 > /dev/null 2>&1"
+
+log_must check_quota "projectquota@$PRJID1" $TESTPOOL1 "$PQUOTA_LIMIT"
+log_must check_quota "projectobjquota@$PRJID2" $TESTPOOL1 "$PQUOTA_OBJLIMIT"
+
+log_must zfs create -o projectquota@$PRJID1=$PQUOTA_LIMIT \
+ -o projectobjquota@$PRJID2=$PQUOTA_OBJLIMIT $TESTPOOL1/fs
+
+log_must eval "zfs list -r -o projectquota@$PRJID1,projectobjquota@$PRJID2 \
+ $TESTPOOL1 > /dev/null 2>&1"
+
+log_must check_quota "projectquota@$PRJID1" $TESTPOOL1/fs "$PQUOTA_LIMIT"
+log_must check_quota "projectobjquota@$PRJID2" $TESTPOOL1/fs "$PQUOTA_OBJLIMIT"
+
+log_pass "The project{obj}quota can be set during zpool,zfs creation"
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projectquota_003_pos.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projectquota_003_pos.ksh
new file mode 100755
index 000000000000..06f360d30b2b
--- /dev/null
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projectquota_003_pos.ksh
@@ -0,0 +1,98 @@
+#!/bin/ksh -p
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2017 by Fan Yong. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/projectquota/projectquota_common.kshlib
+
+#
+# DESCRIPTION:
+# Check the basic function project{obj}used
+#
+#
+# STRATEGY:
+# 1. Write data to fs with some project then check the project{obj}used
+#
+
+function cleanup
+{
+ cleanup_projectquota
+}
+
+if ! lsattr -pd > /dev/null 2>&1; then
+ log_unsupported "Current e2fsprogs does not support set/show project ID"
+fi
+
+log_onexit cleanup
+
+log_assert "Check the basic function of project{obj}used"
+
+sync_pool
+typeset project_used=$(get_value "projectused@$PRJID1" $QFS)
+typeset file_size='10m'
+
+if [[ $project_used != 0 ]]; then
+ log_fail "FAIL: projectused is $project_used, should be 0"
+fi
+
+mkmount_writable $QFS
+log_must user_run $PUSER mkdir $PRJDIR
+log_must chattr +P -p $PRJID1 $PRJDIR
+log_must user_run $PUSER mkfile $file_size $PRJDIR/qf
+sync_pool
+project_used=$(get_value "projectused@$PRJID1" $QFS)
+# get_value() reads the exact byte value which is slightly more than 10m
+if [[ "$(($project_used/1024/1024))m" != "$file_size" ]]; then
+ log_note "project $PRJID1 used is $project_used"
+ log_fail "projectused for project $PRJID1 expected to be $file_size, " \
+ "not $project_used"
+fi
+
+log_must rm -rf $PRJDIR
+typeset project_obj_used=$(get_value "projectobjused@$PRJID2" $QFS)
+typeset file_count=100
+
+if [[ $project_obj_used != 0 ]]; then
+ log_fail "FAIL: projectobjused is $project_obj_used, should be 0"
+fi
+
+log_must zfs set xattr=sa $QFS
+log_must user_run $PUSER mkdir $PRJDIR
+log_must chattr +P -p $PRJID2 $PRJDIR
+# $PRJDIR has already used one object with the $PRJID2
+log_must user_run $PUSER mkfiles $PRJDIR/qf_ $((file_count - 1))
+sync_pool
+project_obj_used=$(get_value "projectobjused@$PRJID2" $QFS)
+if [[ $project_obj_used != $file_count ]]; then
+ log_note "project $PRJID2 used is $project_obj_used"
+ log_fail "projectobjused for project $PRJID2 expected to be " \
+ "$file_count, not $project_obj_used"
+fi
+
+log_pass "Check the basic function of project{obj}used pass as expect"
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projectquota_004_neg.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projectquota_004_neg.ksh
new file mode 100755
index 000000000000..a975d2a19f0c
--- /dev/null
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projectquota_004_neg.ksh
@@ -0,0 +1,87 @@
+#!/bin/ksh -p
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2017 by Fan Yong. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/projectquota/projectquota_common.kshlib
+
+#
+# DESCRIPTION:
+# Check the invalid parameter of zfs set project{obj}quota
+#
+#
+# STRATEGY:
+# 1. check the invalid zfs set project{obj}quota to fs
+# 2. check the valid zfs set project{obj}quota to snapshots
+#
+
+function cleanup
+{
+ if datasetexists $snap_fs; then
+ log_must zfs destroy $snap_fs
+ fi
+
+ log_must cleanup_projectquota
+}
+
+log_onexit cleanup
+
+log_assert "Check the invalid parameter of zfs set project{obj}quota"
+typeset snap_fs=$QFS@snap
+
+log_must zfs snapshot $snap_fs
+
+set -A no_prjs "mms1234" "ss@#" "root-122" "-1"
+for prj in "${no_prjs[@]}"; do
+ log_mustnot zfs set projectquota@$prj=100m $QFS
+done
+
+log_note "can set all numeric id even if that id does not exist"
+log_must zfs set projectquota@12345678=100m $QFS
+
+set -A sizes "100mfsd" "m0.12m" "GGM" "-1234-m" "123m-m"
+for size in "${sizes[@]}"; do
+ log_note "can not set projectquota with invalid size parameter"
+ log_mustnot zfs set projectquota@$PRJID1=$size $QFS
+done
+
+log_note "can not set projectquota to snapshot $snap_fs"
+log_mustnot zfs set projectquota@$PRJID1=100m $snap_fs
+
+for prj in "${no_prjs[@]}"; do
+ log_mustnot zfs set projectobjquota@$prj=100 $QFS
+done
+
+log_note "can not set projectobjquota with invalid size parameter"
+log_mustnot zfs set projectobjquota@$PRJID2=100msfsd $QFS
+
+log_note "can not set projectobjquota to snapshot $snap_fs"
+log_mustnot zfs set projectobjquota@$PRJID2=100m $snap_fs
+
+log_pass "Check the invalid parameter of zfs set project{obj}quota"
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projectquota_005_pos.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projectquota_005_pos.ksh
new file mode 100755
index 000000000000..b52f302f7892
--- /dev/null
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projectquota_005_pos.ksh
@@ -0,0 +1,68 @@
+#!/bin/ksh -p
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2017 by Fan Yong. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/projectquota/projectquota_common.kshlib
+
+#
+# DESCRIPTION:
+# Check the invalid parameter of zfs get project{obj}quota
+#
+#
+# STRATEGY:
+# 1. check the invalid zfs get project{obj}quota to fs
+# 2. check the valid zfs get project{obj}quota to snapshots
+#
+
+function cleanup
+{
+ if datasetexists $snap_fs; then
+ log_must zfs destroy $snap_fs
+ fi
+
+ log_must cleanup_projectquota
+}
+
+log_onexit cleanup
+
+log_assert "Check the invalid parameter of zfs get project{obj}quota"
+typeset snap_fs=$QFS@snap
+
+log_must zfs snapshot $snap_fs
+
+set -A no_prjs "mms1234" "ss@#" "root-122"
+for prj in "${no_prjs[@]}"; do
+ log_must eval "zfs get projectquota@$prj $QFS >/dev/null 2>&1"
+ log_must eval "zfs get projectquota@$prj $snap_fs >/dev/null 2>&1"
+ log_must eval "zfs get projectobjquota@$prj $QFS >/dev/null 2>&1"
+ log_must eval "zfs get projectobjquota@$prj $snap_fs >/dev/null 2>&1"
+done
+
+log_pass "Check the invalid parameter of zfs get project{obj}quota"
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projectquota_006_pos.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projectquota_006_pos.ksh
new file mode 100755
index 000000000000..6b375d407e23
--- /dev/null
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projectquota_006_pos.ksh
@@ -0,0 +1,75 @@
+#!/bin/ksh -p
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2017 by Fan Yong. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/projectquota/projectquota_common.kshlib
+
+#
+# DESCRIPTION:
+# Projectquota can be set beyond the fs quota.
+# Pprojectquota can be set at a smaller size than its current usage.
+#
+# STRATEGY:
+# 1. set quota to a fs and set a larger size of projectquota
+# 2. write some data to the fs and set a smaller projectquota
+#
+
+function cleanup
+{
+ log_must cleanup_projectquota
+ log_must zfs set quota=none $QFS
+}
+
+if ! lsattr -pd > /dev/null 2>&1; then
+ log_unsupported "Current e2fsprogs does not support set/show project ID"
+fi
+
+log_onexit cleanup
+
+log_assert "Check set projectquota to larger than the quota size of a fs"
+
+log_must zfs set quota=200m $QFS
+log_must zfs set projectquota@$PRJID1=500m $QFS
+
+log_must zfs get projectquota@$PRJID1 $QFS
+
+log_note "write some data to the $QFS"
+mkmount_writable $QFS
+log_must user_run $PUSER mkdir $PRJDIR
+log_must chattr +P -p $PRJID1 $PRJDIR
+log_must user_run $PUSER mkfile 100m $PRJDIR/qf
+sync
+
+log_note "set projectquota at a smaller size than it current usage"
+log_must zfs set projectquota@$PRJID1=90m $QFS
+
+log_must zfs get projectquota@$PRJID1 $QFS
+
+log_pass "set projectquota to larger than quota size of a fs"
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projectquota_007_pos.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projectquota_007_pos.ksh
new file mode 100755
index 000000000000..3572e0118f45
--- /dev/null
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projectquota_007_pos.ksh
@@ -0,0 +1,58 @@
+#!/bin/ksh -p
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2017 by Fan Yong. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/projectquota/projectquota_common.kshlib
+
+#
+# DESCRIPTION:
+# zfs get all <fs> does not print out project{obj}quota
+#
+# STRATEGY:
+# 1. set project{obj}quota to a fs
+# 2. check zfs get all fs
+#
+
+function cleanup
+{
+ log_must cleanup_projectquota
+}
+
+log_onexit cleanup
+
+log_assert "Check zfs get all will not print out project{obj}quota"
+
+log_must zfs set projectquota@$PRJID1=50m $QFS
+log_must zfs set projectobjquota@$PRJID2=100 $QFS
+
+log_mustnot eval "zfs get all $QFS | grep projectquota"
+log_mustnot eval "zfs get all $QFS | grep projectobjquota"
+
+log_pass "zfs get all will not print out project{obj}quota"
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projectquota_008_pos.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projectquota_008_pos.ksh
new file mode 100755
index 000000000000..365b5627e801
--- /dev/null
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projectquota_008_pos.ksh
@@ -0,0 +1,91 @@
+#!/bin/ksh -p
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2017 by Fan Yong. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/projectquota/projectquota_common.kshlib
+
+#
+# DESCRIPTION:
+# Check project{obj}quota to snapshot that:
+# 1) can not set project{obj}quota to snapshot directly
+# 2) snapshot can inherit the parent fs's project{obj}quota
+# 3) the project{obj}quota will not change even the parent quota changed.
+#
+#
+# STRATEGY:
+# 1. create a snapshot of a fs
+# 2. set the project{obj}quota to snapshot and expect fail
+# 3. set project{obj}quota to fs and check the snapshot
+# 4. re-set project{obj}quota to fs and check the snapshot's value
+#
+
+function cleanup
+{
+ if datasetexists $snap_fs; then
+ log_must zfs destroy $snap_fs
+ fi
+
+ log_must cleanup_projectquota
+}
+
+log_onexit cleanup
+
+log_assert "Check the snapshot's project{obj}quota"
+typeset snap_fs=$QFS@snap
+
+
+log_must zfs set projectquota@$PRJID1=$PQUOTA_LIMIT $QFS
+log_must check_quota "projectquota@$PRJID1" $QFS "$PQUOTA_LIMIT"
+
+log_must zfs set projectobjquota@$PRJID2=$PQUOTA_OBJLIMIT $QFS
+log_must check_quota "projectobjquota@$PRJID2" $QFS "$PQUOTA_OBJLIMIT"
+
+log_must zfs snapshot $snap_fs
+
+log_note "check the snapshot $snap_fs project{obj}quota"
+log_must check_quota "projectquota@$PRJID1" $snap_fs "$PQUOTA_LIMIT"
+log_must check_quota "projectobjquota@$PRJID2" $snap_fs "$PQUOTA_OBJLIMIT"
+
+log_note "set project{obj}quota to $snap_fs which will fail"
+log_mustnot zfs set projectquota@$PRJID1=100m $snap_fs
+log_mustnot zfs set projectobjquota@$PRJID2=100 $snap_fs
+
+log_note "change the parent's project{obj}quota"
+log_must zfs set projectquota@$PRJID1=$((PQUOTA_LIMIT * 2)) $QFS
+log_must zfs set projectobjquota@$PRJID2=50 $QFS
+
+log_must check_quota "projectquota@$PRJID1" $QFS $((PQUOTA_LIMIT * 2))
+log_must check_quota "projectobjquota@$PRJID2" $QFS 50
+
+log_note "check the snapshot $snap_fs project{obj}quota"
+log_must check_quota "projectquota@$PRJID1" $snap_fs "$PQUOTA_LIMIT"
+log_must check_quota "projectobjquota@$PRJID2" $snap_fs "$PQUOTA_OBJLIMIT"
+
+log_pass "Check the snapshot's project{obj}quota"
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projectquota_009_pos.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projectquota_009_pos.ksh
new file mode 100755
index 000000000000..a867b538c120
--- /dev/null
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projectquota_009_pos.ksh
@@ -0,0 +1,131 @@
+#!/bin/ksh -p
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2017 by Fan Yong. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/projectquota/projectquota_common.kshlib
+
+#
+# DESCRIPTION:
+# The project{obj}quota will not change during zfs actions, such as
+# snapshot,clone,rename,upgrade,send,receive.
+#
+#
+# STRATEGY:
+# 1. Create a pool, and create fs with preset project{obj}quota
+# 2. Check set project{obj}quota via zfs snapshot|clone|list -o
+# 3. Check the project{obj}quota can not change during zfs
+# rename|upgrade|promote
+# 4. Check the project{obj}quota can not change during zfs clone
+# 5. Check the project{obj}quota can not change during zfs send/receive
+#
+
+function cleanup
+{
+ for ds in $TESTPOOL/fs $TESTPOOL/fs-rename $TESTPOOL/fs-clone; do
+ if datasetexists $ds; then
+ log_must zfs destroy -rRf $ds
+ fi
+ done
+}
+
+log_onexit cleanup
+
+log_assert "the project{obj}quota can't change during zfs actions"
+
+cleanup
+
+log_must zfs create -o projectquota@$PRJID1=$PQUOTA_LIMIT \
+ -o projectobjquota@$PRJID2=$PQUOTA_OBJLIMIT $TESTPOOL/fs
+
+log_must zfs snapshot $TESTPOOL/fs@snap
+log_must eval "zfs list -r -o projectquota@$PRJID1,projectobjquota@$PRJID2 \
+ $TESTPOOL >/dev/null 2>&1"
+
+log_must check_quota "projectquota@$PRJID1" $TESTPOOL/fs@snap "$PQUOTA_LIMIT"
+log_must check_quota "projectobjquota@$PRJID2" $TESTPOOL/fs@snap \
+ "$PQUOTA_OBJLIMIT"
+
+
+log_note "clone fs gets its parent's project{obj}quota initially"
+log_must zfs clone -o projectquota@$PRJID1=$PQUOTA_LIMIT \
+ -o projectobjquota@$PRJID2=$PQUOTA_OBJLIMIT \
+ $TESTPOOL/fs@snap $TESTPOOL/fs-clone
+
+log_must eval "zfs list -r -o projectquota@$PRJID1,projectobjquota@$PRJID2 \
+ $TESTPOOL >/dev/null 2>&1"
+
+log_must check_quota "projectquota@$PRJID1" $TESTPOOL/fs-clone "$PQUOTA_LIMIT"
+log_must check_quota "projectobjquota@$PRJID2" $TESTPOOL/fs-clone \
+ "$PQUOTA_OBJLIMIT"
+
+log_must eval "zfs list -o projectquota@$PRJID1,projectobjquota@$PRJID2 \
+ $TESTPOOL/fs-clone >/dev/null 2>&1"
+
+log_note "zfs promote can not change the previously set project{obj}quota"
+log_must zfs promote $TESTPOOL/fs-clone
+
+log_must eval "zfs list -r -o projectquota@$PRJID1,projectobjquota@$PRJID2 \
+ $TESTPOOL >/dev/null 2>&1"
+
+log_must check_quota "projectquota@$PRJID1" $TESTPOOL/fs-clone "$PQUOTA_LIMIT"
+log_must check_quota "projectobjquota@$PRJID2" $TESTPOOL/fs-clone \
+ "$PQUOTA_OBJLIMIT"
+
+log_note "zfs send receive can not change the previously set project{obj}quota"
+log_must zfs send $TESTPOOL/fs-clone@snap | zfs receive $TESTPOOL/fs-rev
+
+log_must eval "zfs list -r -o projectquota@$PRJID1,projectobjquota@$PRJID2 \
+ $TESTPOOL >/dev/null 2>&1"
+
+log_must check_quota "projectquota@$PRJID1" $TESTPOOL/fs-rev "$PQUOTA_LIMIT"
+log_must check_quota "projectobjquota@$PRJID2" $TESTPOOL/fs-rev \
+ "$PQUOTA_OBJLIMIT"
+
+log_note "zfs rename can not change the previously set project{obj}quota"
+log_must zfs rename $TESTPOOL/fs-rev $TESTPOOL/fs-rename
+
+log_must eval "zfs list -r -o projectquota@$PRJID1,projectobjquota@$PRJID2 \
+ $TESTPOOL >/dev/null 2>&1"
+
+log_must check_quota "projectquota@$PRJID1" $TESTPOOL/fs-rename "$PQUOTA_LIMIT"
+log_must check_quota "projectobjquota@$PRJID2" $TESTPOOL/fs-rename \
+ "$PQUOTA_OBJLIMIT"
+
+log_note "zfs upgrade can not change the previously set project{obj}quota"
+log_must zfs upgrade $TESTPOOL/fs-rename
+
+log_must eval "zfs list -r -o projectquota@$PRJID1,projectobjquota@$PRJID2 \
+ $TESTPOOL >/dev/null 2>&1"
+
+log_must check_quota "projectquota@$PRJID1" $TESTPOOL/fs-rename "$PQUOTA_LIMIT"
+log_must check_quota "projectobjquota@$PRJID2" $TESTPOOL/fs-rename \
+ "$PQUOTA_OBJLIMIT"
+
+log_pass "the project{obj}quota can't change during zfs actions"
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projectquota_common.kshlib b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projectquota_common.kshlib
new file mode 100644
index 000000000000..23f7c2a50663
--- /dev/null
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projectquota_common.kshlib
@@ -0,0 +1,101 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2017 by Fan Yong. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/projectquota/projectquota.cfg
+
+#
+# reset the projectquota and delete temporary files
+#
+function cleanup_projectquota
+{
+ if datasetexists $QFS; then
+ typeset mntp=$(get_prop mountpoint $QFS)
+
+ log_must zfs set projectquota@$PRJID1=none $QFS
+ log_must zfs set projectobjquota@$PRJID1=none $QFS
+ log_must zfs set projectquota@$PRJID2=none $QFS
+ log_must zfs set projectobjquota@$PRJID2=none $QFS
+ log_must chmod 0755 $mntp
+ fi
+
+ [[ -f $PRJFILE ]] && log_must rm -f $PRJFILE
+ [[ -d $PRJDIR ]] && log_must rm -rf $PRJDIR
+ [[ -d $PRJDIR1 ]] && log_must rm -rf $PRJDIR1
+ [[ -d $PRJDIR2 ]] && log_must rm -rf $PRJDIR2
+ [[ -d $PRJDIR3 ]] && log_must rm -rf $PRJDIR3
+ sync
+
+ return 0
+}
+
+function mkmount_writable
+{
+ typeset fs=$1
+ typeset mntp=$(get_prop mountpoint $fs)
+ log_must chmod 0777 $mntp
+}
+
+function check_quota
+{
+ typeset fs=$2
+ typeset prop=$1
+ typeset expected=$3
+ typeset value=$(get_prop $prop $fs)
+
+ if (($value != $expected)); then
+ return 1
+ fi
+}
+
+function get_value
+{
+ typeset prop_val
+ typeset prop=$1
+ typeset dataset=$2
+
+ prop_val=$(zfs get -H -p -o value $prop $dataset 2>/dev/null)
+ if [[ $? -ne 0 ]]; then
+ log_note "Unable to get $prop property for dataset $dataset"
+ return 1
+ fi
+
+ echo $prop_val
+}
+
+function project_obj_count
+{
+ typeset fs=$1
+ typeset prj=$2
+ typeset cnt=$(zfs projectspace -oname,objused $fs |
+ awk /$prj/'{print $2}')
+ [[ "$cnt" == "-" ]] && cnt=0 || true
+ echo $cnt
+}
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projectspace_001_pos.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projectspace_001_pos.ksh
new file mode 100755
index 000000000000..a84ff9f89a0d
--- /dev/null
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projectspace_001_pos.ksh
@@ -0,0 +1,93 @@
+#!/bin/ksh -p
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2017 by Fan Yong. Fan rights reserved.
+#
+
+. $STF_SUITE/tests/functional/projectquota/projectquota_common.kshlib
+
+#
+# DESCRIPTION:
+# Check the zfs projectspace with kinds of parameters
+#
+#
+# STRATEGY:
+# 1. set zfs projectspace to a fs
+# 2. write some data to the fs with specified project ID
+# 3. use zfs projectspace with all possible parameters to check the result
+# 4. use zfs projectspace with some bad parameters to check the result
+#
+
+function cleanup
+{
+ if datasetexists $snap_fs; then
+ log_must zfs destroy $snap_fs
+ fi
+
+ log_must cleanup_projectquota
+}
+
+if ! lsattr -pd > /dev/null 2>&1; then
+ log_unsupported "Current e2fsprogs does not support set/show project ID"
+fi
+
+log_onexit cleanup
+
+log_assert "Check the zfs projectspace with all possible parameters"
+
+set -A good_params -- "-H" "-p" "-o type,name,used,quota" "-o name,used,quota" \
+ "-o used,quota" "-o objused" "-o quota" "-s type" "-s name" "-s used" \
+ "-s quota" "-S type" "-S name" "-S used" "-S quota"
+
+typeset snap_fs=$QFS@snap
+
+log_must zfs set projectquota@$PRJID1=100m $QFS
+log_must zfs set projectobjquota@$PRJID1=100 $QFS
+mkmount_writable $QFS
+log_must user_run $PUSER mkdir $PRJDIR
+log_must chattr +P -p $PRJID1 $PRJDIR
+log_must user_run $PUSER mkfile 50m $PRJDIR/qf
+sync
+
+log_must zfs snapshot $snap_fs
+
+for param in "${good_params[@]}"; do
+ log_must eval "zfs projectspace $param $QFS >/dev/null 2>&1"
+ log_must eval "zfs projectspace $param $snap_fs >/dev/null 2>&1"
+done
+
+log_assert "Check the zfs projectspace with some bad parameters"
+
+set -A bad_params -- "-i" "-n" "-P" "-t posixuser"
+
+for param in "${bad_params[@]}"; do
+ log_mustnot eval "zfs projectspace $param $QFS >/dev/null 2>&1"
+ log_mustnot eval "zfs projectspace $param $snap_fs >/dev/null 2>&1"
+done
+
+log_pass "zfs projectspace with kinds of parameters pass"
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projectspace_002_pos.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projectspace_002_pos.ksh
new file mode 100755
index 000000000000..216855e94dc9
--- /dev/null
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projectspace_002_pos.ksh
@@ -0,0 +1,85 @@
+#!/bin/ksh -p
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2017 by Fan Yong. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/projectquota/projectquota_common.kshlib
+
+#
+# DESCRIPTION:
+# Check the project used size and quota in zfs projectspace
+#
+#
+# STRATEGY:
+# 1. set zfs projectquota to a fs
+# 2. write some data to the fs with specified project and size
+# 3. use zfs projectspace to check the used size and quota size
+#
+
+function cleanup
+{
+ if datasetexists $snapfs; then
+ log_must zfs destroy $snapfs
+ fi
+
+ log_must cleanup_projectquota
+}
+
+if ! lsattr -pd > /dev/null 2>&1; then
+ log_unsupported "Current e2fsprogs does not support set/show project ID"
+fi
+
+log_onexit cleanup
+
+log_assert "Check the zfs projectspace used and quota"
+
+log_must zfs set projectquota@$PRJID1=100m $QFS
+
+mkmount_writable $QFS
+log_must user_run $PUSER mkdir $PRJDIR
+log_must chattr +P -p $PRJID1 $PRJDIR
+log_must user_run $PUSER mkfile 50m $PRJDIR/qf
+sync
+
+typeset snapfs=$QFS@snap
+
+log_must zfs snapshot $snapfs
+
+log_must eval "zfs projectspace $QFS >/dev/null 2>&1"
+log_must eval "zfs projectspace $snapfs >/dev/null 2>&1"
+
+for fs in "$QFS" "$snapfs"; do
+ log_note "check the quota size in zfs projectspace $fs"
+ log_must eval "zfs projectspace $fs | grep $PRJID1 | grep 100M"
+
+ log_note "check the project used size in zfs projectspace $fs"
+ log_must eval "zfs projectspace $fs | grep $PRJID1 | grep 50\\.\*M"
+done
+
+log_pass "Check the zfs projectspace used and quota"
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projectspace_003_pos.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projectspace_003_pos.ksh
new file mode 100755
index 000000000000..629b3b3e57e2
--- /dev/null
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projectspace_003_pos.ksh
@@ -0,0 +1,118 @@
+#!/bin/ksh -p
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2017 by Fan Yong. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/projectquota/projectquota_common.kshlib
+
+#
+# DESCRIPTION:
+# Check the project used object accounting in zfs projectspace
+#
+#
+# STRATEGY:
+# 1. create a bunch of files by specific project
+# 2. use zfs projectspace to check the used objects
+# 3. change the project ID of test files and verify object count
+# 4. delete files and verify object count
+#
+
+function cleanup
+{
+ if datasetexists $snapfs; then
+ log_must zfs destroy $snapfs
+ fi
+
+ log_must cleanup_projectquota
+}
+
+if ! lsattr -pd > /dev/null 2>&1; then
+ log_unsupported "Current e2fsprogs does not support set/show project ID"
+fi
+
+log_onexit cleanup
+
+log_assert "Check the zfs projectspace object used"
+
+mkmount_writable $QFS
+log_must zfs set xattr=sa $QFS
+log_must user_run $PUSER mkdir $PRJDIR1
+log_must user_run $PUSER mkdir $PRJDIR2
+log_must chattr +P -p $PRJID1 $PRJDIR1
+log_must chattr +P -p $PRJID2 $PRJDIR2
+
+((prj_cnt1 = RANDOM % 100 + 2))
+((prj_cnt2 = RANDOM % 100 + 2))
+
+log_must user_run $PUSER mkfiles $PRJDIR1/qf $((prj_cnt1 - 1))
+log_must user_run $PUSER mkfiles $PRJDIR2/qf $((prj_cnt2 - 1))
+sync_pool
+
+typeset snapfs=$QFS@snap
+
+log_must zfs snapshot $snapfs
+
+log_must eval "zfs projectspace $QFS >/dev/null 2>&1"
+log_must eval "zfs projectspace $snapfs >/dev/null 2>&1"
+
+for fs in "$QFS" "$snapfs"; do
+ log_note "check the project used objects in zfs projectspace $fs"
+ prjused=$(project_obj_count $fs $PRJID1)
+ [[ $prjused -eq $prj_cnt1 ]] ||
+ log_fail "($PRJID1) expected $prj_cnt1, got $prjused"
+ prjused=$(project_obj_count $fs $PRJID2)
+ [[ $prjused -eq $prj_cnt2 ]] ||
+ log_fail "($PRJID2) expected $prj_cnt2, got $prjused"
+done
+
+log_note "change the project of files"
+log_must chattr -p $PRJID2 $PRJDIR1/qf*
+sync_pool
+
+prjused=$(project_obj_count $QFS $PRJID1)
+[[ $prjused -eq 1 ]] ||
+ log_fail "expected 1 for project $PRJID1, got $prjused"
+
+prjused=$(project_obj_count $snapfs $PRJID1)
+[[ $prjused -eq $prj_cnt1 ]] ||
+ log_fail "expected $prj_cnt1 for $PRJID1 in snapfs, got $prjused"
+
+prjused=$(project_obj_count $QFS $PRJID2)
+[[ $prjused -eq $((prj_cnt1 + prj_cnt2 - 1)) ]] ||
+ log_fail "($PRJID2) expected $((prj_cnt1 + prj_cnt2 - 1)), got $prjused"
+
+log_note "file removal"
+log_must rm -rf $PRJDIR1
+sync_pool
+
+prjused=$(project_obj_count $QFS $PRJID1)
+[[ $prjused -eq 0 ]] || log_fail "expected 0 for $PRJID1, got $prjused"
+
+cleanup
+log_pass "Check the zfs projectspace object used"
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projectspace_004_pos.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projectspace_004_pos.ksh
new file mode 100755
index 000000000000..ec299e0e7f93
--- /dev/null
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projectspace_004_pos.ksh
@@ -0,0 +1,76 @@
+#!/bin/ksh -p
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2017 by Fan Yong. Fan rights reserved.
+#
+
+. $STF_SUITE/tests/functional/projectquota/projectquota_common.kshlib
+
+#
+# DESCRIPTION:
+# Check 'df' command on the directory with INHERIT (project ID) flag
+#
+#
+# STRATEGY:
+# 1. set project [obj]quota on the directory
+# 2. set project ID and inherit flag on the directory
+# 3. run 'df [-i]' on the directory and check the result
+#
+
+function cleanup
+{
+ if datasetexists $snap_fs; then
+ log_must zfs destroy $snap_fs
+ fi
+
+ log_must cleanup_projectquota
+}
+
+if ! lsattr -pd > /dev/null 2>&1; then
+ log_unsupported "Current e2fsprogs does not support set/show project ID"
+fi
+
+log_onexit cleanup
+
+log_assert "Check 'df' on dir with inherit project shows the project quota/used"
+
+log_must zfs set projectquota@$PRJID1=100m $QFS
+log_must zfs set projectobjquota@$PRJID1=100 $QFS
+mkmount_writable $QFS
+log_must user_run $PUSER mkdir $PRJDIR
+log_must chattr +P -p $PRJID1 $PRJDIR
+log_must user_run $PUSER mkfile 50m $PRJDIR/qf
+sync_pool
+
+total=$(df $PRJDIR | tail -n 1 | awk '{ print $2 }')
+[[ $total -eq 102400 ]] || log_fail "expect '102400' resource, but got '$total'"
+
+used=$(df -i $PRJDIR | tail -n 1 | awk '{ print $5 }')
+[[ "$used" == "2%" ]] || log_fail "expect '2%' used, but got '$used'"
+
+log_pass "'df' on the directory with inherit project ID flag pass as expect"
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projecttree_001_pos.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projecttree_001_pos.ksh
new file mode 100755
index 000000000000..0402e345df2a
--- /dev/null
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projecttree_001_pos.ksh
@@ -0,0 +1,108 @@
+#!/bin/ksh -p
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2017 by Fan Yong. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/projectquota/projectquota_common.kshlib
+
+#
+#
+# DESCRIPTION:
+# Check 'zfs project' is compatible with chattr/lsattr
+#
+#
+# STRATEGY:
+# Verify the following:
+# 1. "zfs project -p" behaviours the same as "chattr -p"
+# 2. "zfs project" behaviours the same as "lsattr -p"
+# 3. "zfs project -d" behaviours the same as "lsattr -p -d"
+# 4. "zfs project -s" behaviours the same as "chattr +P"
+# 5. "zfs project -s -p" behaviours the same as "chattr +P -p"
+# 6. "zfs project -C" behaviours the same as "chattr -P"
+#
+
+function cleanup
+{
+ log_must rm -rf $PRJDIR
+}
+
+if ! lsattr -pd > /dev/null 2>&1; then
+ log_unsupported "Current e2fsprogs does not support set/show project ID"
+fi
+
+#
+# e2fsprogs-1.44.4 incorrectly reports verity 'V' bit when the project 'P'
+# bit is set. Skip this test when 1.44.4 is installed to prevent failures.
+#
+# https://github.com/tytso/e2fsprogs/commit/7e5a95e3d
+#
+if lsattr -V 2>&1 | grep "lsattr 1.44.4"; then
+ log_unsupported "Current e2fsprogs incorrectly reports 'V' verity bit"
+fi
+
+log_onexit cleanup
+
+log_assert "Check 'zfs project' is compatible with chattr/lsattr"
+
+log_must mkdir $PRJDIR
+log_must mkdir $PRJDIR/a1
+log_must mkdir $PRJDIR/a2
+log_must touch $PRJDIR/a3
+
+log_must chattr -p $PRJID1 $PRJDIR/a3
+log_must eval "zfs project $PRJDIR/a3 | grep '$PRJID1 \-'"
+
+log_must zfs project -p $PRJID2 $PRJDIR/a3
+log_must eval "lsattr -p $PRJDIR/a3 | grep $PRJID2 | grep -v '\-P[- ]* '"
+
+log_must chattr -p $PRJID1 $PRJDIR/a1
+log_must eval "zfs project -d $PRJDIR/a1 | grep '$PRJID1 \-'"
+
+log_must zfs project -p $PRJID2 $PRJDIR/a1
+log_must eval "lsattr -pd $PRJDIR/a1 | grep $PRJID2 | grep -v '\-P[- ]* '"
+
+log_must chattr +P $PRJDIR/a2
+log_must eval "zfs project -d $PRJDIR/a2 | grep '0 P'"
+
+log_must zfs project -s $PRJDIR/a2
+log_must eval "lsattr -pd $PRJDIR/a2 | grep 0 | grep '\-P[- ]* '"
+
+log_must chattr +P -p $PRJID1 $PRJDIR/a1
+log_must eval "zfs project -d $PRJDIR/a1 | grep '$PRJID1 P'"
+
+log_must zfs project -s -p $PRJID2 $PRJDIR/a2
+log_must eval "lsattr -pd $PRJDIR/a2 | grep $PRJID2 | grep '\-P[- ]* '"
+
+log_must chattr -P $PRJDIR/a1
+log_must eval "zfs project -d $PRJDIR/a1 | grep '$PRJID1 \-'"
+
+log_must zfs project -C -k $PRJDIR/a2
+log_must eval "lsattr -pd $PRJDIR/a2 | grep $PRJID2 | grep -v '\-P[- ]* '"
+
+log_pass "Check 'zfs project' is compatible with chattr/lsattr"
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projecttree_002_pos.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projecttree_002_pos.ksh
new file mode 100755
index 000000000000..d61019242703
--- /dev/null
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projecttree_002_pos.ksh
@@ -0,0 +1,120 @@
+#!/bin/ksh -p
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2017 by Fan Yong. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/projectquota/projectquota_common.kshlib
+
+#
+#
+# DESCRIPTION:
+# Check project ID/flag can be operated via "zfs project"
+#
+#
+# STRATEGY:
+# 1. Create a tree with 4 level directories.
+# 2. Set project ID on both directory and regular file via
+# "zfs project -p".
+# 3. Check the project ID via "zfs project".
+# 4. Set project inherit flag on kinds of level directories (and its
+# descendants for some)) via "zfs project -s [-r]".
+# 5. Check the project ID and inherit flag via "zfs project -r".
+# 6. Clear the project inherit flag from some directories (and its
+# descendants for some) via "zfs project -C [-r]".
+# 7. Check the project ID and inherit flag via "zfs project -r".
+#
+
+function cleanup
+{
+ log_must rm -rf $PRJDIR
+}
+
+log_onexit cleanup
+
+log_assert "Check project ID/flag can be operated via 'zfs project'"
+
+log_must mkdir $PRJDIR
+
+log_must mkdir $PRJDIR/a1
+log_must mkdir $PRJDIR/b1
+log_must touch $PRJDIR/c1
+
+log_must mkdir $PRJDIR/a1/a2
+log_must mkdir $PRJDIR/a1/b2
+log_must touch $PRJDIR/a1/c2
+
+log_must mkdir $PRJDIR/b1/a2
+log_must mkdir $PRJDIR/b1/b2
+log_must touch $PRJDIR/b1/c2
+
+log_must mkdir $PRJDIR/a1/a2/a3
+log_must mkdir $PRJDIR/a1/a2/b3
+log_must touch $PRJDIR/a1/a2/c3
+
+log_must mkdir $PRJDIR/b1/a2/a3
+
+log_must touch $PRJDIR/a1/a2/a3/c4
+log_must touch $PRJDIR/a1/a2/a3/d4
+
+log_must zfs project -p $PRJID1 $PRJDIR/a1/c2
+log_must eval "zfs project $PRJDIR/a1/c2 | grep $PRJID1"
+
+log_must zfs project -p $PRJID2 $PRJDIR/a1/a2/a3
+log_must eval "zfs project -d $PRJDIR/a1/a2/a3 | grep $PRJID2"
+
+log_must zfs project -s $PRJDIR/b1/a2
+log_must eval "zfs project -d $PRJDIR/b1/a2 | grep ' P '"
+log_must eval "zfs project -d $PRJDIR/b1/a2/a3 | grep ' \- '"
+
+log_must zfs project -s -r -p $PRJID2 $PRJDIR/a1/a2
+log_must zfs project -c -r $PRJDIR/a1/a2
+log_must eval "zfs project -d $PRJDIR/a1/a2/a3 | grep ' P '"
+log_must eval "zfs project $PRJDIR/a1/a2/a3/c4 | grep $PRJID2"
+
+log_must zfs project -C $PRJDIR/a1/a2/a3
+log_must eval "zfs project -cr $PRJDIR/a1/a2 | grep 'inherit flag is not set'"
+log_must eval "zfs project $PRJDIR/a1/a2/a3/c4 | grep $PRJID2 | grep -v not"
+log_must zfs project -p 123 $PRJDIR/a1/a2/a3/c4
+log_must eval "zfs project -c -r $PRJDIR/a1/a2 | grep 123 | grep 'not set'"
+log_mustnot eval "zfs project -cr -p 123 $PRJDIR/a1/a2 | grep c4 | grep -v not"
+
+log_must zfs project -C -r $PRJDIR/a1/a2/a3
+log_must eval "zfs project -cr $PRJDIR/a1/a2 | grep a3 | grep 'not set'"
+log_must eval "zfs project -cr $PRJDIR/a1/a2 | grep d4 | grep 'not set'"
+log_must eval "zfs project $PRJDIR/a1/a2/a3/d4 | grep '0 \-'"
+
+log_must eval \
+ "zfs project -cr -0 $PRJDIR/a1/a2 | xargs -0 zfs project -s -p $PRJID2"
+log_mustnot eval "zfs project -cr $PRJDIR/a1/a2 | grep a3 | grep 'not set'"
+log_mustnot eval "zfs project -cr $PRJDIR/a1/a2 | grep d4 | grep 'not set'"
+
+log_must zfs project -C -r -k $PRJDIR/a1/a2
+log_must eval "zfs project -d $PRJDIR/a1/a2/b3 | grep '$PRJID2 \- '"
+
+log_pass "Check project ID/flag can be operated via 'zfs project'"
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projecttree_003_neg.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projecttree_003_neg.ksh
new file mode 100755
index 000000000000..cbc45857f779
--- /dev/null
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/projecttree_003_neg.ksh
@@ -0,0 +1,103 @@
+#!/bin/ksh -p
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2017 by Fan Yong. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/projectquota/projectquota_common.kshlib
+
+#
+#
+# DESCRIPTION:
+# Check 'zfs project' invalid options combinations
+#
+#
+# STRATEGY:
+# Verify the following:
+# 1. "-c" only supports "-d", "-p", "-r" and "-0".
+# 2. "-C" only supports "-r" and "-k".
+# 3. "-s" only supports "-r" and "-p".
+# 4. "-c", "-C" and "-s" can NOT be specified together.
+# 5. "-d" can overwrite former "-r".
+# 6. "-r" can overwrite former "-d".
+# 7. "-0" must be together with "-c".
+# 8. "-d" must be on directory.
+# 9. "-r" must be on directory.
+# 10. "-p" must be together with "-c -r" or "-s".
+#
+
+function cleanup
+{
+ log_must rm -rf $PRJDIR
+}
+
+log_onexit cleanup
+
+log_assert "Check 'zfs project' invalid options combinations"
+
+log_must mkdir $PRJDIR
+log_must mkdir $PRJDIR/a1
+log_must touch $PRJDIR/a2
+
+log_mustnot zfs project -c
+log_mustnot zfs project -c -k $PRJDIR/a1
+log_mustnot zfs project -c -C $PRJDIR/a1
+log_mustnot zfs project -c -s $PRJDIR/a1
+log_must zfs project -c -d -r $PRJDIR/a1
+log_must zfs project -c -r -d $PRJDIR/a1
+log_mustnot zfs project -c -d $PRJDIR/a2
+log_mustnot zfs project -c -r $PRJDIR/a2
+
+log_mustnot zfs project -C
+log_mustnot zfs project -C -c $PRJDIR/a1
+log_mustnot zfs project -C -d $PRJDIR/a1
+log_mustnot zfs project -C -p 100 $PRJDIR/a1
+log_mustnot zfs project -C -s $PRJDIR/a1
+log_mustnot zfs project -C -r -0 $PRJDIR/a1
+log_mustnot zfs project -C -0 $PRJDIR/a1
+
+log_mustnot zfs project -s
+log_mustnot zfs project -s -d $PRJDIR/a1
+log_mustnot zfs project -s -k $PRJDIR/a1
+log_mustnot zfs project -s -r -0 $PRJDIR/a1
+log_mustnot zfs project -s -0 $PRJDIR/a1
+log_mustnot zfs project -s -r $PRJDIR/a2
+
+log_mustnot zfs project -p 100
+log_mustnot zfs project -p -1 $PRJDIR/a2
+log_mustnot zfs project -p 100 -d $PRJDIR/a1
+log_mustnot zfs project -p 100 -k $PRJDIR/a1
+log_mustnot zfs project -p 100 -0 $PRJDIR/a1
+log_mustnot zfs project -p 100 -r -0 $PRJDIR/a1
+
+log_mustnot zfs project
+log_mustnot zfs project -0 $PRJDIR/a2
+log_mustnot zfs project -k $PRJDIR/a2
+log_mustnot zfs project -S $PRJDIR/a1
+
+log_pass "Check 'zfs project' invalid options combinations"
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/setup.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/setup.ksh
new file mode 100755
index 000000000000..c81b300e5e96
--- /dev/null
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/projectquota/setup.ksh
@@ -0,0 +1,56 @@
+#!/bin/ksh -p
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2017 by Fan Yong. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/projectquota/projectquota_common.kshlib
+
+verify_runnable "both"
+
+del_user $PUSER
+del_group $PGROUP
+log_must add_group $PGROUP
+log_must add_user $PGROUP $PUSER
+
+#
+# Verify the test user can execute the zfs utilities. This may not
+# be possible due to default permissions on the user home directory.
+# This can be resolved granting group read access.
+#
+# chmod 0750 $HOME
+#
+user_run $PUSER zfs list
+if [ $? -ne 0 ]; then
+ log_unsupported "Test user $PUSER cannot execute zfs utilities"
+fi
+
+DISK=${DISKS%% *}
+default_setup_noexit $DISK
+
+log_pass