From 55aa9cea4c19a585991ad3e258cc59024c3afb27 Mon Sep 17 00:00:00 2001 From: Todd Seidelmann <18294602+seidelma@users.noreply.github.com> Date: Mon, 17 Jun 2024 00:41:22 -0700 Subject: [PATCH 1/5] Implement default user and group quotas This change adds the 'defaultuserquota' and 'defaultgroupquota' properties to ZFS datasets to apply a quota to users and groups that do not have a specific quota assigned. The default quota checking mechanism works alongside the existing 'userquota' and 'groupquota' checks, only taking effect if no quota is assigned for a particular user/group. This means that it's possible to exceed a default quota by quite a lot before the user/groupused property is updated and further writes are denied, which was already the case for user/groupquota. Default quotas are implemented similarly to 'normal' user quotas, but instead of being user properties that are preserved across snapshots, they default back to none. NB: this is different from the observed Solaris behavior, which is to preserve default quotas across snapshot/clone/promote. For instance, Solaris has: # zfs set defaultuserquota=100M tank/fs # zfs snap tank/fs@snap # zfs clone tank/fs@snap tank/fs-clone # zfs get -H defaultuserquota tank/fs-clone tank/fs-clone defaultuserquota 100M - Whereas this commit does: # zfs set defaultuserquota=100M tank/fs # zfs snap tank/fs@snap # zfs clone tank/fs@snap tank/fs-clone # zfs get -H defaultuserquota tank/fs-clone tank/fs-clone defaultuserquota none default It should also be possible to implement a default project quota using an analogous process, if doing so makes sense. Signed-off-by: Todd Seidelmann --- include/os/linux/zfs/sys/zfs_vfsops_os.h | 2 + include/sys/fs/zfs.h | 2 + include/sys/zfs_quota.h | 1 + lib/libzfs/libzfs_dataset.c | 2 + module/os/linux/zfs/zfs_vfsops.c | 16 +++++ module/zcommon/zfs_prop.c | 6 ++ module/zfs/zfs_ioctl.c | 19 +++++ module/zfs/zfs_quota.c | 89 ++++++++++++++++++++++-- 8 files changed, 132 insertions(+), 5 deletions(-) diff --git a/include/os/linux/zfs/sys/zfs_vfsops_os.h b/include/os/linux/zfs/sys/zfs_vfsops_os.h index 30aa3a103d33..666da89664a1 100644 --- a/include/os/linux/zfs/sys/zfs_vfsops_os.h +++ b/include/os/linux/zfs/sys/zfs_vfsops_os.h @@ -130,6 +130,8 @@ struct zfsvfs { uint64_t z_groupobjquota_obj; uint64_t z_projectquota_obj; uint64_t z_projectobjquota_obj; + uint64_t z_defaultuserquota_obj; + uint64_t z_defaultgroupquota_obj; uint64_t z_replay_eof; /* New end of file - replay only */ sa_attr_type_t *z_attr_table; /* SA attr mapping->id */ uint64_t z_hold_size; /* znode hold array size */ diff --git a/include/sys/fs/zfs.h b/include/sys/fs/zfs.h index 1676020d04d3..f109610ee5d0 100644 --- a/include/sys/fs/zfs.h +++ b/include/sys/fs/zfs.h @@ -197,6 +197,8 @@ typedef enum { ZFS_PROP_VOLTHREADING, ZFS_PROP_DIRECT, ZFS_PROP_LONGNAME, + ZFS_PROP_DEFAULTUSERQUOTA, + ZFS_PROP_DEFAULTGROUPQUOTA, ZFS_NUM_PROPS } zfs_prop_t; diff --git a/include/sys/zfs_quota.h b/include/sys/zfs_quota.h index 4567cc651afb..e184f8945960 100644 --- a/include/sys/zfs_quota.h +++ b/include/sys/zfs_quota.h @@ -37,6 +37,7 @@ extern int zfs_userspace_many(struct zfsvfs *, zfs_userquota_prop_t, uint64_t *, void *, uint64_t *); extern int zfs_set_userquota(struct zfsvfs *, zfs_userquota_prop_t, const char *, uint64_t, uint64_t); +extern int zfs_set_defaultquota(struct zfsvfs *, int, uint64_t); extern boolean_t zfs_id_overobjquota(struct zfsvfs *, uint64_t, uint64_t); extern boolean_t zfs_id_overblockquota(struct zfsvfs *, uint64_t, uint64_t); diff --git a/lib/libzfs/libzfs_dataset.c b/lib/libzfs/libzfs_dataset.c index 231bbbd92dbf..e670379cf4cd 100644 --- a/lib/libzfs/libzfs_dataset.c +++ b/lib/libzfs/libzfs_dataset.c @@ -2811,6 +2811,8 @@ zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen, case ZFS_PROP_REFQUOTA: case ZFS_PROP_RESERVATION: case ZFS_PROP_REFRESERVATION: + case ZFS_PROP_DEFAULTUSERQUOTA: + case ZFS_PROP_DEFAULTGROUPQUOTA: if (get_numeric_property(zhp, prop, src, &source, &val) != 0) return (-1); diff --git a/module/os/linux/zfs/zfs_vfsops.c b/module/os/linux/zfs/zfs_vfsops.c index 3c53a8a315c3..870ecd3507bb 100644 --- a/module/os/linux/zfs/zfs_vfsops.c +++ b/module/os/linux/zfs/zfs_vfsops.c @@ -755,6 +755,22 @@ zfsvfs_init(zfsvfs_t *zfsvfs, objset_t *os) else if (error != 0) return (error); + error = zap_lookup(os, MASTER_NODE_OBJ, + zfs_prop_to_name(ZFS_PROP_DEFAULTUSERQUOTA), + 8, 1, &zfsvfs->z_defaultuserquota_obj); + if (error == ENOENT) + zfsvfs->z_defaultuserquota_obj = 0; + else if (error != 0) + return (error); + + error = zap_lookup(os, MASTER_NODE_OBJ, + zfs_prop_to_name(ZFS_PROP_DEFAULTGROUPQUOTA), + 8, 1, &zfsvfs->z_defaultgroupquota_obj); + if (error == ENOENT) + zfsvfs->z_defaultgroupquota_obj = 0; + else if (error != 0) + return (error); + error = zap_lookup(os, MASTER_NODE_OBJ, ZFS_FUID_TABLES, 8, 1, &zfsvfs->z_fuid_obj); if (error == ENOENT) diff --git a/module/zcommon/zfs_prop.c b/module/zcommon/zfs_prop.c index 40254c8d9567..600227f1422a 100644 --- a/module/zcommon/zfs_prop.c +++ b/module/zcommon/zfs_prop.c @@ -707,6 +707,12 @@ zfs_prop_init(void) zprop_register_number(ZFS_PROP_SNAPSHOT_LIMIT, "snapshot_limit", UINT64_MAX, PROP_DEFAULT, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME, " | none", "SSLIMIT", B_FALSE, sfeatures); + zprop_register_number(ZFS_PROP_DEFAULTUSERQUOTA, "defaultuserquota", 0, + PROP_DEFAULT, ZFS_TYPE_FILESYSTEM, " | none", + "DEFAULTUSERQUOTA", B_FALSE, sfeatures); + zprop_register_number(ZFS_PROP_DEFAULTGROUPQUOTA, "defaultgroupquota", + 0, PROP_DEFAULT, ZFS_TYPE_FILESYSTEM, " | none", + "DEFAULTGROUPQUOTA", B_FALSE, sfeatures); /* inherit number properties */ zprop_register_number(ZFS_PROP_RECORDSIZE, "recordsize", diff --git a/module/zfs/zfs_ioctl.c b/module/zfs/zfs_ioctl.c index 8188a9e46865..89410a8be244 100644 --- a/module/zfs/zfs_ioctl.c +++ b/module/zfs/zfs_ioctl.c @@ -2629,6 +2629,25 @@ zfs_prop_set_special(const char *dsname, zprop_source_t source, zfsvfs_rele(zfsvfs, FTAG); break; } + case ZFS_PROP_DEFAULTUSERQUOTA: + case ZFS_PROP_DEFAULTGROUPQUOTA: + { + zfsvfs_t *zfsvfs; + + if ((err = zfsvfs_hold(dsname, FTAG, &zfsvfs, B_TRUE)) != 0) + break; + + err = zfs_set_defaultquota(zfsvfs, prop, intval); + zfsvfs_rele(zfsvfs, FTAG); + + /* + * Set err to -1 to force the zfs_set_prop_nvlist code down the + * default path to set the value in the nvlist. + */ + if (err == 0) + err = -1; + break; + } default: err = -1; } diff --git a/module/zfs/zfs_quota.c b/module/zfs/zfs_quota.c index 0fe152bc4dd8..a25e72702238 100644 --- a/module/zfs/zfs_quota.c +++ b/module/zfs/zfs_quota.c @@ -368,6 +368,59 @@ zfs_set_userquota(zfsvfs_t *zfsvfs, zfs_userquota_prop_t type, return (err); } +int +zfs_set_defaultquota(zfsvfs_t *zfsvfs, int type, uint64_t quota) +{ + int err; + dmu_tx_t *tx; + uint64_t *objp; + const char *name; + + if (type == ZFS_PROP_DEFAULTUSERQUOTA) { + objp = &zfsvfs->z_defaultuserquota_obj; + name = zfs_prop_to_name(ZFS_PROP_DEFAULTUSERQUOTA); + } else if (type == ZFS_PROP_DEFAULTGROUPQUOTA) { + objp = &zfsvfs->z_defaultgroupquota_obj; + name = zfs_prop_to_name(ZFS_PROP_DEFAULTGROUPQUOTA); + } else { + /* defaultprojectquota NYI (does it make sense to do so?) */ + return (SET_ERROR(EINVAL)); + } + + tx = dmu_tx_create(zfsvfs->z_os); + dmu_tx_hold_zap(tx, *objp ? *objp : DMU_NEW_OBJECT, B_TRUE, NULL); + if (*objp == 0) { + dmu_tx_hold_zap(tx, MASTER_NODE_OBJ, B_TRUE, name); + } + err = dmu_tx_assign(tx, TXG_WAIT); + if (err) { + dmu_tx_abort(tx); + return (err); + } + + mutex_enter(&zfsvfs->z_lock); + if (*objp == 0) { + *objp = zap_create(zfsvfs->z_os, DMU_OT_USERGROUP_QUOTA, + DMU_OT_NONE, 0, tx); + VERIFY(0 == zap_add(zfsvfs->z_os, MASTER_NODE_OBJ, name, + 8, 1, objp, tx)); + } + mutex_exit(&zfsvfs->z_lock); + + if (quota == 0) { + err = zap_remove(zfsvfs->z_os, *objp, name, tx); + if (err == ENOENT) + err = 0; + } else { + err = zap_update(zfsvfs->z_os, *objp, name, + 8, 1, "a, tx); + } + + ASSERT(err == 0); + dmu_tx_commit(tx); + return (err); +} + boolean_t zfs_id_overobjquota(zfsvfs_t *zfsvfs, uint64_t usedobj, uint64_t id) { @@ -425,8 +478,9 @@ boolean_t zfs_id_overblockquota(zfsvfs_t *zfsvfs, uint64_t usedobj, uint64_t id) { char buf[20]; - uint64_t used, quota, quotaobj; - int err; + uint64_t used, quota, quotaobj, defquota, defquotaobj; + int err, uerr, derr; + const char *name; if (usedobj == DMU_PROJECTUSED_OBJECT) { if (!dmu_objset_projectquota_present(zfsvfs->z_os)) { @@ -442,22 +496,46 @@ zfs_id_overblockquota(zfsvfs_t *zfsvfs, uint64_t usedobj, uint64_t id) quotaobj = zfsvfs->z_projectquota_obj; } else if (usedobj == DMU_USERUSED_OBJECT) { quotaobj = zfsvfs->z_userquota_obj; + defquotaobj = zfsvfs->z_defaultuserquota_obj; + name = zfs_prop_to_name(ZFS_PROP_DEFAULTUSERQUOTA); } else if (usedobj == DMU_GROUPUSED_OBJECT) { quotaobj = zfsvfs->z_groupquota_obj; + defquotaobj = zfsvfs->z_defaultgroupquota_obj; + name = zfs_prop_to_name(ZFS_PROP_DEFAULTGROUPQUOTA); } else { return (B_FALSE); } - if (quotaobj == 0 || zfsvfs->z_replay) + + /* no quota assigned */ + if (quotaobj == 0 && defquotaobj == 0) { + return (B_FALSE); + } + if (zfsvfs->z_replay) { return (B_FALSE); + } (void) snprintf(buf, sizeof (buf), "%llx", (longlong_t)id); - err = zap_lookup(zfsvfs->z_os, quotaobj, buf, 8, 1, "a); - if (err != 0) + derr = zap_lookup(zfsvfs->z_os, defquotaobj, name, + 8, 1, &defquota); + uerr = zap_lookup(zfsvfs->z_os, quotaobj, buf, 8, 1, "a); + + /* bail if both id-specific && default lookups failed */ + if (uerr != 0 && derr != 0) return (B_FALSE); err = zap_lookup(zfsvfs->z_os, usedobj, buf, 8, 1, &used); if (err != 0) return (B_FALSE); + + /* + * if a user/group has a specific quota assigned, use that. + * if neither quota...we've already returned false (hopefully). + * if a default quota is set, but no user quota is, + * use the default. + */ + if (uerr != 0 && derr == 0 && defquota) + quota = defquota; + return (used >= quota); } @@ -472,6 +550,7 @@ EXPORT_SYMBOL(zpl_get_file_info); EXPORT_SYMBOL(zfs_userspace_one); EXPORT_SYMBOL(zfs_userspace_many); EXPORT_SYMBOL(zfs_set_userquota); +EXPORT_SYMBOL(zfs_set_defaultquota); EXPORT_SYMBOL(zfs_id_overblockquota); EXPORT_SYMBOL(zfs_id_overobjquota); EXPORT_SYMBOL(zfs_id_overquota); From e08cd9723d525aabbd1086101e673be957787d74 Mon Sep 17 00:00:00 2001 From: Todd Seidelmann <18294602+seidelma@users.noreply.github.com> Date: Mon, 17 Jun 2024 00:41:27 -0700 Subject: [PATCH 2/5] Add tests for defaultuserquota/defaultgroupquota feature These are based on the existing userquota tests. Note that because the default{user|group}quota behavior differs from Solaris during snapshot/clone/promote, some of the tests fail by design. Signed-off-by: Todd Seidelmann --- tests/runfiles/common.run | 5 + tests/zfs-tests/tests/Makefile.am | 10 ++ .../userquota/defaultuserquota_001_pos.ksh | 74 ++++++++++ .../userquota/defaultuserquota_002_pos.ksh | 95 +++++++++++++ .../userquota/defaultuserquota_003_pos.ksh | 61 ++++++++ .../userquota/defaultuserquota_004_neg.ksh | 71 ++++++++++ .../userquota/defaultuserquota_005_pos.ksh | 75 ++++++++++ .../userquota/defaultuserquota_006_pos.ksh | 60 ++++++++ .../userquota/defaultuserquota_007_pos.ksh | 89 ++++++++++++ .../userquota/defaultuserquota_008_pos.ksh | 77 ++++++++++ .../userquota/defaultuserquota_009_pos.ksh | 132 ++++++++++++++++++ .../userquota/defaultuserquota_010_neg.ksh | 64 +++++++++ 12 files changed, 813 insertions(+) create mode 100755 tests/zfs-tests/tests/functional/userquota/defaultuserquota_001_pos.ksh create mode 100755 tests/zfs-tests/tests/functional/userquota/defaultuserquota_002_pos.ksh create mode 100755 tests/zfs-tests/tests/functional/userquota/defaultuserquota_003_pos.ksh create mode 100755 tests/zfs-tests/tests/functional/userquota/defaultuserquota_004_neg.ksh create mode 100755 tests/zfs-tests/tests/functional/userquota/defaultuserquota_005_pos.ksh create mode 100755 tests/zfs-tests/tests/functional/userquota/defaultuserquota_006_pos.ksh create mode 100755 tests/zfs-tests/tests/functional/userquota/defaultuserquota_007_pos.ksh create mode 100755 tests/zfs-tests/tests/functional/userquota/defaultuserquota_008_pos.ksh create mode 100755 tests/zfs-tests/tests/functional/userquota/defaultuserquota_009_pos.ksh create mode 100755 tests/zfs-tests/tests/functional/userquota/defaultuserquota_010_neg.ksh diff --git a/tests/runfiles/common.run b/tests/runfiles/common.run index fc4adc42d00a..f47e6f1f6153 100644 --- a/tests/runfiles/common.run +++ b/tests/runfiles/common.run @@ -998,6 +998,11 @@ tags = ['functional', 'upgrade'] [tests/functional/userquota] tests = [ + 'defaultuserquota_001_pos', 'defaultuserquota_002_pos', + 'defaultuserquota_003_pos', 'defaultuserquota_004_neg', + 'defaultuserquota_005_pos', 'defaultuserquota_006_pos', + 'defaultuserquota_007_pos', 'defaultuserquota_008_pos', + 'defaultuserquota_009_pos', 'defaultuserquota_010_neg', 'userquota_001_pos', 'userquota_002_pos', 'userquota_003_pos', 'userquota_004_pos', 'userquota_005_neg', 'userquota_006_pos', 'userquota_007_pos', 'userquota_008_pos', 'userquota_009_pos', diff --git a/tests/zfs-tests/tests/Makefile.am b/tests/zfs-tests/tests/Makefile.am index 7d1551a63f0d..6c1072e4861f 100644 --- a/tests/zfs-tests/tests/Makefile.am +++ b/tests/zfs-tests/tests/Makefile.am @@ -2083,6 +2083,16 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \ functional/userquota/groupspace_002_pos.ksh \ functional/userquota/groupspace_003_pos.ksh \ functional/userquota/setup.ksh \ + functional/userquota/defaultuserquota_001_pos.ksh \ + functional/userquota/defaultuserquota_002_pos.ksh \ + functional/userquota/defaultuserquota_003_pos.ksh \ + functional/userquota/defaultuserquota_004_neg.ksh \ + functional/userquota/defaultuserquota_005_pos.ksh \ + functional/userquota/defaultuserquota_006_pos.ksh \ + functional/userquota/defaultuserquota_007_pos.ksh \ + functional/userquota/defaultuserquota_008_pos.ksh \ + functional/userquota/defaultuserquota_009_pos.ksh \ + functional/userquota/defaultuserquota_010_neg.ksh \ functional/userquota/userquota_001_pos.ksh \ functional/userquota/userquota_002_pos.ksh \ functional/userquota/userquota_003_pos.ksh \ diff --git a/tests/zfs-tests/tests/functional/userquota/defaultuserquota_001_pos.ksh b/tests/zfs-tests/tests/functional/userquota/defaultuserquota_001_pos.ksh new file mode 100755 index 000000000000..9a1a618e34e3 --- /dev/null +++ b/tests/zfs-tests/tests/functional/userquota/defaultuserquota_001_pos.ksh @@ -0,0 +1,74 @@ +#!/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 https://opensource.org/licenses/CDDL-1.0. +# 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) 2013, 2016 by Delphix. All rights reserved. +# +. $STF_SUITE/include/libtest.shlib +. $STF_SUITE/tests/functional/userquota/userquota_common.kshlib + +# +# +# DESCRIPTION: +# Check the basic function of defaultuserquota and defaultgroupquota +# +# +# STRATEGY: +# 1. Set defaultuserquota and exceed the quota size +# 2. The write operation should fail with "Disk quota exceeded" +# 3. Set defaultgroupquota and exceed the quota size +# 4. The write operation should fail with "Disk quota exceeded" +# +# + +function cleanup +{ + cleanup_quota +} + +log_onexit cleanup + +log_assert "If write operation exceeds default{user|group}quota size, it will fail" + +mkmount_writable $QFS +log_note "Check the defaultuserquota" +log_must zfs set defaultuserquota=$UQUOTA_SIZE $QFS +log_must user_run $QUSER1 mkfile $UQUOTA_SIZE $QFILE +sync_pool +log_mustnot user_run $QUSER1 mkfile 1 $OFILE +cleanup_quota + +log_note "Check the defaultgroupquota" +log_must zfs set defaultgroupquota=$GQUOTA_SIZE $QFS +mkmount_writable $QFS +log_must user_run $QUSER1 mkfile $GQUOTA_SIZE $QFILE +sync_pool +log_mustnot user_run $QUSER1 mkfile 1 $OFILE +log_mustnot user_run $QUSER2 mkfile 1 $OFILE +cleanup_quota + +log_pass "Write operation exceeded default{user|group}quota size, failed as expected" diff --git a/tests/zfs-tests/tests/functional/userquota/defaultuserquota_002_pos.ksh b/tests/zfs-tests/tests/functional/userquota/defaultuserquota_002_pos.ksh new file mode 100755 index 000000000000..461a16cdc4e8 --- /dev/null +++ b/tests/zfs-tests/tests/functional/userquota/defaultuserquota_002_pos.ksh @@ -0,0 +1,95 @@ +#!/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 https://opensource.org/licenses/CDDL-1.0. +# 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) 2013, 2016 by Delphix. All rights reserved. +# + +. $STF_SUITE/include/libtest.shlib +. $STF_SUITE/tests/functional/userquota/userquota_common.kshlib + +# +# DESCRIPTION: +# defaultuserquota and defaultgroupquota can be set during zpool or zfs creation" +# +# +# STRATEGY: +# 1. Set defaultuserquota and defaultgroupquota 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 \ + "default{user|group}quota can be set during {zpool|zfs} create" + +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 defaultuserquota=$UQUOTA_SIZE \ + -O defaultgroupquota=$GQUOTA_SIZE \ + $TESTPOOL1 $pool_vdev + +log_must eval "zfs list -r \ + -o defaultuserquota,defaultgroupquota \ + $TESTPOOL1 > /dev/null 2>&1" + +log_must check_quota "defaultuserquota" $TESTPOOL1 "$UQUOTA_SIZE" +log_must check_quota "defaultgroupquota" $TESTPOOL1 "$GQUOTA_SIZE" + +log_must zfs create \ + -o defaultuserquota=$UQUOTA_SIZE \ + -o defaultgroupquota=$GQUOTA_SIZE \ + $TESTPOOL1/fs + +log_must eval "zfs list -r \ + -o defaultuserquota,defaultgroupquota \ + $TESTPOOL1 > /dev/null 2>&1" + +log_must check_quota "defaultuserquota" $TESTPOOL1/fs "$UQUOTA_SIZE" +log_must check_quota "defaultgroupquota" $TESTPOOL1/fs "$GQUOTA_SIZE" + +log_pass \ + "default{user|group}quota can be set during {zpool|zfs} create" diff --git a/tests/zfs-tests/tests/functional/userquota/defaultuserquota_003_pos.ksh b/tests/zfs-tests/tests/functional/userquota/defaultuserquota_003_pos.ksh new file mode 100755 index 000000000000..a09750ed1c8c --- /dev/null +++ b/tests/zfs-tests/tests/functional/userquota/defaultuserquota_003_pos.ksh @@ -0,0 +1,61 @@ +#!/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 https://opensource.org/licenses/CDDL-1.0. +# 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) 2013, 2016 by Delphix. All rights reserved. +# + +. $STF_SUITE/include/libtest.shlib +. $STF_SUITE/tests/functional/userquota/userquota_common.kshlib + +# +# DESCRIPTION: +# Check the basic function of set/get defaultuserquota and defaultgroupquota on fs +# +# +# STRATEGY: +# 1. Set defaultuserquota on fs and check output of zfs get +# 2. Set defaultgroupquota on fs and check output of zfs get +# + +function cleanup +{ + cleanup_quota +} + +log_onexit cleanup + +log_assert "Check the basic function of set/get default{user|group}quota on fs" + +log_note "Check zfs {set|get} default{user|group}quota" +log_must zfs set defaultuserquota=$UQUOTA_SIZE $QFS +log_must check_quota "defaultuserquota" $QFS "$UQUOTA_SIZE" + +log_must zfs set defaultgroupquota=$GQUOTA_SIZE $QFS +log_must check_quota "defaultgroupquota" $QFS "$GQUOTA_SIZE" + +log_pass "Check the basic function of zfs {set|get} default{user|group}quota passed as expected" diff --git a/tests/zfs-tests/tests/functional/userquota/defaultuserquota_004_neg.ksh b/tests/zfs-tests/tests/functional/userquota/defaultuserquota_004_neg.ksh new file mode 100755 index 000000000000..29182bc1e50a --- /dev/null +++ b/tests/zfs-tests/tests/functional/userquota/defaultuserquota_004_neg.ksh @@ -0,0 +1,71 @@ +#!/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 https://opensource.org/licenses/CDDL-1.0. +# 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) 2013, 2016 by Delphix. All rights reserved. +# + +. $STF_SUITE/include/libtest.shlib +. $STF_SUITE/tests/functional/userquota/userquota_common.kshlib + +# +# DESCRIPTION: +# Check invalid parameter handling of zfs set default{user|group}quota +# +# +# STRATEGY: +# 1. try to set invalid values with zfs set default{user|group}quota to fs +# 2. try to set valid values with zfs set default{user|group}quota to snapshots (an invalid operation) +# + +function cleanup +{ + datasetexists $snap_fs && destroy_dataset $snap_fs + + log_must cleanup_quota +} + +log_onexit cleanup + +log_assert "Check invalid values for zfs set default{user|group}quota" +typeset snap_fs=$QFS@snap + +log_must zfs snapshot $snap_fs + +set -A sizes "100mfsd" "m0.12m" "GGM" "-1234-m" "123m-m" + +for size in "${sizes[@]}"; do + log_note "can not set default{user|group}quota with invalid size parameter" + log_mustnot zfs set defaultuserquota=$size $QFS + log_mustnot zfs set defaultgroupquota=$size $QFS +done + +log_note "can not set default{user|group}quota to snapshot $snap_fs" +log_mustnot zfs set defaultuserquota=100m $snap_fs +log_mustnot zfs set defaultgroupquota=100m $snap_fs + +log_pass "Check invalid values for zfs set default{user|group}quota passed as expected" diff --git a/tests/zfs-tests/tests/functional/userquota/defaultuserquota_005_pos.ksh b/tests/zfs-tests/tests/functional/userquota/defaultuserquota_005_pos.ksh new file mode 100755 index 000000000000..0ad9e587baa7 --- /dev/null +++ b/tests/zfs-tests/tests/functional/userquota/defaultuserquota_005_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 https://opensource.org/licenses/CDDL-1.0. +# 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) 2013, 2016 by Delphix. All rights reserved. +# + +. $STF_SUITE/include/libtest.shlib +. $STF_SUITE/tests/functional/userquota/userquota_common.kshlib + +# +# DESCRIPTION: +# +# defaultuserquota/defaultgroupquota can be set beyond the fs quota +# defaultuserquota/defaultgroupquota can be set at a smaller size than its current usage. +# +# STRATEGY: +# 1. set quota to a fs and set a larger size of defaultuserquota and defaultgroupquota +# 2. write some data to the fs and set a smaller defaultuserquota and defaultgroupquota +# + +function cleanup +{ + log_must cleanup_quota + log_must zfs set quota=none $QFS +} + +log_onexit cleanup + +log_assert "Check set default{user|group}quota to larger than the quota size of a fs" + +log_must zfs set quota=200m $QFS +log_must zfs set defaultuserquota="$UQUOTA_SIZE" $QFS +log_must zfs set defaultgroupquota="$GQUOTA_SIZE" $QFS + +log_must check_quota "defaultuserquota" $QFS "$UQUOTA_SIZE" +log_must check_quota "defaultgroupquota" $QFS "$GQUOTA_SIZE" + +log_note "write some data to the $QFS" +mkmount_writable $QFS +log_must user_run $QUSER1 mkfile 100000 $QFILE +sync_all_pools + +log_note "set default{user|group}quota at a smaller size than current usage" +log_must zfs set defaultuserquota=90000 $QFS +log_must zfs set defaultgroupquota=90000 $QFS + +log_must check_quota "defaultuserquota" $QFS 90000 +log_must check_quota "defaultgroupquota" $QFS 90000 + +log_pass "set default{user|group}quota to larger than quota size of a fs passed as expected" diff --git a/tests/zfs-tests/tests/functional/userquota/defaultuserquota_006_pos.ksh b/tests/zfs-tests/tests/functional/userquota/defaultuserquota_006_pos.ksh new file mode 100755 index 000000000000..ec3837492fcc --- /dev/null +++ b/tests/zfs-tests/tests/functional/userquota/defaultuserquota_006_pos.ksh @@ -0,0 +1,60 @@ +#!/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 https://opensource.org/licenses/CDDL-1.0. +# 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) 2013, 2016 by Delphix. All rights reserved. +# + +. $STF_SUITE/include/libtest.shlib +. $STF_SUITE/tests/functional/userquota/userquota_common.kshlib + +# +# DESCRIPTION: +# +# zfs get all does print out defaultuserquota/defaultgroupquota +# +# STRATEGY: +# 1. set defaultuserquota and defaultgroupquota to a fs +# 2. check zfs get all fs +# + +function cleanup +{ + log_must cleanup_quota +} + +log_onexit cleanup + +log_assert "Check zfs get all will print out default{user|group}quota" + +log_must zfs set defaultuserquota=50m $QFS +log_must zfs set defaultgroupquota=100m $QFS + +log_must zfs get all $QFS | grep defaultuserquota +log_must zfs get all $QFS | grep defaultgroupquota + +log_pass "zfs get all will print out default{user|group}quota" diff --git a/tests/zfs-tests/tests/functional/userquota/defaultuserquota_007_pos.ksh b/tests/zfs-tests/tests/functional/userquota/defaultuserquota_007_pos.ksh new file mode 100755 index 000000000000..626129d4bc17 --- /dev/null +++ b/tests/zfs-tests/tests/functional/userquota/defaultuserquota_007_pos.ksh @@ -0,0 +1,89 @@ +#!/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 https://opensource.org/licenses/CDDL-1.0. +# 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) 2013, 2016 by Delphix. All rights reserved. +# + +. $STF_SUITE/include/libtest.shlib +. $STF_SUITE/tests/functional/userquota/userquota_common.kshlib + +# +# DESCRIPTION: +# Check default{user|group}quota to snapshot such that: +# 1) can not set default{user|group}quota to snapshot directly +# 2) snapshot does not inherit the parent fs's default{user|group}quota +# (same behavior as Solaris) +# +# +# STRATEGY: +# 1. create a snapshot of a fs +# 2. set the default{user|group}quota to snapshot and expect fail +# 3. set default{user|group}quota to fs and check the snapshot +# 4. reset default{user|group}quota to fs and check the snapshot's value +# + +function cleanup +{ + datasetexists $snap_fs && destroy_dataset $snap_fs + + log_must cleanup_quota +} + +log_onexit cleanup + +log_assert "Check the snapshot's default{user|group}quota" +typeset snap_fs=$QFS@snap + +log_must zfs set defaultuserquota=$UQUOTA_SIZE $QFS +log_must check_quota "defaultuserquota" $QFS "$UQUOTA_SIZE" + +log_must zfs set defaultgroupquota=$GQUOTA_SIZE $QFS +log_must check_quota "defaultgroupquota" $QFS "$GQUOTA_SIZE" + +log_must zfs snapshot $snap_fs + +log_note "check the snapshot $snap_fs default{user|group}quota" +log_mustnot check_quota "defaultuserquota" $snap_fs "$UQUOTA_SIZE" +log_mustnot check_quota "defaultgroupquota" $snap_fs "$GQUOTA_SIZE" + +log_note "set default{user|group}quota to $snap_fs should fail" +log_mustnot zfs set defaultuserquota=$SNAP_QUOTA $snap_fs +log_mustnot zfs set defaultgroupquota=$SNAP_QUOTA $snap_fs + +log_note "change the parent filesystem's default{user|group}quota" +log_must zfs set defaultuserquota=$TEST_QUOTA $QFS +log_must zfs set defaultgroupquota=$TEST_QUOTA $QFS + +log_must check_quota "defaultuserquota" $QFS $TEST_QUOTA +log_must check_quota "defaultgroupquota" $QFS $TEST_QUOTA + +log_note "check the snapshot $snap_fs default{user|group}quota" +log_mustnot check_quota "defaultuserquota" $snap_fs "$UQUOTA_SIZE" +log_mustnot check_quota "defaultgroupquota" $snap_fs "$GQUOTA_SIZE" + +log_pass "Check the snapshot's default{user|group}quota passed as expected" diff --git a/tests/zfs-tests/tests/functional/userquota/defaultuserquota_008_pos.ksh b/tests/zfs-tests/tests/functional/userquota/defaultuserquota_008_pos.ksh new file mode 100755 index 000000000000..74344a8a1a7c --- /dev/null +++ b/tests/zfs-tests/tests/functional/userquota/defaultuserquota_008_pos.ksh @@ -0,0 +1,77 @@ +#!/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 https://opensource.org/licenses/CDDL-1.0. +# 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) 2013, 2016 by Delphix. All rights reserved. +# + +. $STF_SUITE/include/libtest.shlib +. $STF_SUITE/tests/functional/userquota/userquota_common.kshlib + +# +# DESCRIPTION: +# Check defaultuserquota and defaultgroupquota being exceeded at the same time +# +# +# STRATEGY: +# 1. Set defaultuserquota and defaultgroupquota to a fs +# 2. write to exceed the defaultuserquota size to check the result +# 3. unset defaultuserquota +# 4. write (as a different user) to exceed the defaultgroupquota size to check the result +# + +function cleanup +{ + cleanup_quota +} + +log_onexit cleanup + +log_assert "write in excess of any default{user|group}quota size fails" + +log_note "write to $QFS to make it exceed defaultuserquota ($GQUOTA_SIZE)" +log_must zfs set defaultuserquota=$GQUOTA_SIZE $QFS +log_must zfs set defaultgroupquota=$GQUOTA_SIZE $QFS + +mkmount_writable $QFS +log_must user_run $QUSER1 mkfile $GQUOTA_SIZE $QFILE +sync_pool + +log_must eval "zfs get -p userused@$QUSER1 $QFS >/dev/null 2>&1" +log_must eval "zfs get -p groupused@$GROUPUSED $QFS >/dev/null 2>&1" + +log_mustnot user_run $QUSER1 mkfile 1 $OFILE + +log_must zfs set defaultuserquota=none $QFS + +log_note "write to $QFS as $QUSER2 to make it exceed defaultgroupquota" +log_mustnot user_run $QUSER2 mkfile 1 $QFILE + +log_must eval "zfs get -p userused@$QUSER1 $QFS >/dev/null 2>&1" +log_must eval "zfs get -p userused@$QUSER2 $QFS >/dev/null 2>&1" +log_must eval "zfs get -p groupused@$GROUPUSED $QFS >/dev/null 2>&1" + +log_pass "write in excess of any default{user|group}quota size failed as expected" diff --git a/tests/zfs-tests/tests/functional/userquota/defaultuserquota_009_pos.ksh b/tests/zfs-tests/tests/functional/userquota/defaultuserquota_009_pos.ksh new file mode 100755 index 000000000000..6ca8cdd4a37f --- /dev/null +++ b/tests/zfs-tests/tests/functional/userquota/defaultuserquota_009_pos.ksh @@ -0,0 +1,132 @@ +#!/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 https://opensource.org/licenses/CDDL-1.0. +# 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) 2013, 2016 by Delphix. All rights reserved. +# + +. $STF_SUITE/include/libtest.shlib +. $STF_SUITE/tests/functional/userquota/userquota_common.kshlib + +# +# DESCRIPTION: +# the defaultuserquota and defaultgroupquota will not change during zfs actions, such as +# snapshot,clone,rename,upgrade,send,receive. +# +# +# STRATEGY: +# 1. Create a pool, and create fs with preset default user,group quota +# 2. Check set default user|group quota via zfs snapshot|clone|list -o +# 3. Check the default user|group quota can not change during zfs rename|upgrade|promote +# 4. Check the default user|group quota can not change during zfs clone +# 5. Check the default user|group quota can not change during zfs send/receive +# + +function cleanup +{ + for ds in $TESTPOOL/fs $TESTPOOL/fs-rename $TESTPOOL/fs-clone; do + datasetexists $ds && destroy_dataset $ds -rRf + done +} + +log_onexit cleanup + +log_assert \ + "the default{user|group}quota don't change during zfs actions" + +cleanup + +log_must zfs create \ + -o defaultuserquota=$UQUOTA_SIZE \ + -o defaultgroupquota=$GQUOTA_SIZE \ + $TESTPOOL/fs + +log_must zfs snapshot $TESTPOOL/fs@snap +log_must eval "zfs list -r \ + -o defaultuserquota,defaultgroupquota \ + $TESTPOOL >/dev/null 2>&1" + +log_mustnot check_quota "defaultuserquota" $TESTPOOL/fs@snap "$UQUOTA_SIZE" +log_mustnot check_quota "defaultgroupquota" $TESTPOOL/fs@snap "$GQUOTA_SIZE" + +log_note "clone fs gets its parent's default{user|group}quota initially" +log_must zfs clone \ + $TESTPOOL/fs@snap $TESTPOOL/fs-clone + +log_must eval "zfs list -r \ + -o defaultuserquota,defaultgroupquota \ + $TESTPOOL >/dev/null 2>&1" + +log_must check_quota "defaultuserquota" $TESTPOOL/fs-clone "$UQUOTA_SIZE" +log_must check_quota "defaultgroupquota" $TESTPOOL/fs-clone "$GQUOTA_SIZE" + +log_must eval "zfs list \ + -o defaultuserquota,defaultgroupquota \ + $TESTPOOL/fs-clone >/dev/null 2>&1" + +log_note "zfs promote can not change the previously set default{user|group}quota" +log_must zfs promote $TESTPOOL/fs-clone + +log_must eval "zfs list -r \ + -o defaultuserquota,defaultgroupquota \ + $TESTPOOL >/dev/null 2>&1" + +log_must check_quota "defaultuserquota" $TESTPOOL/fs-clone "$UQUOTA_SIZE" +log_must check_quota "defaultgroupquota" $TESTPOOL/fs-clone "$GQUOTA_SIZE" + +log_note "zfs send receive can not change the previously set default{user|group}quota" +log_must zfs send $TESTPOOL/fs-clone@snap | zfs receive $TESTPOOL/fs-rev + +log_must eval "zfs list -r \ + -o defaultuserquota,defaultgroupquota \ + $TESTPOOL >/dev/null 2>&1" + +log_must check_quota "defaultuserquota" $TESTPOOL/fs-rev "$UQUOTA_SIZE" +log_must check_quota "defaultgroupquota" $TESTPOOL/fs-rev "$GQUOTA_SIZE" + +log_note "zfs rename can not change the previously set default{user|group}quota" +log_must zfs rename $TESTPOOL/fs-rev $TESTPOOL/fs-rename + +log_must eval "zfs list -r \ + -o defaultuserquota,defaultgroupquota \ + $TESTPOOL >/dev/null 2>&1" + +log_must check_quota "defaultuserquota" $TESTPOOL/fs-rename "$UQUOTA_SIZE" +log_must check_quota "defaultgroupquota" $TESTPOOL/fs-rename "$GQUOTA_SIZE" + +log_note "zfs upgrade can not change the previously set default{user|group}quota" +log_must zfs upgrade $TESTPOOL/fs-rename + +log_must eval "zfs list -r \ + -o defaultuserquota,defaultgroupquota \ + $TESTPOOL >/dev/null 2>&1" + +log_must check_quota "defaultuserquota" $TESTPOOL/fs-rename "$UQUOTA_SIZE" +log_must check_quota "defaultgroupquota" $TESTPOOL/fs-rename "$GQUOTA_SIZE" + +log_pass \ + "the default{user|group}quota don't change during zfs actions" diff --git a/tests/zfs-tests/tests/functional/userquota/defaultuserquota_010_neg.ksh b/tests/zfs-tests/tests/functional/userquota/defaultuserquota_010_neg.ksh new file mode 100755 index 000000000000..64296b5fcc66 --- /dev/null +++ b/tests/zfs-tests/tests/functional/userquota/defaultuserquota_010_neg.ksh @@ -0,0 +1,64 @@ +#!/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 https://opensource.org/licenses/CDDL-1.0. +# 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) 2013, 2016 by Delphix. All rights reserved. +# + +. $STF_SUITE/include/libtest.shlib +. $STF_SUITE/tests/functional/userquota/userquota_common.kshlib + +# +# DESCRIPTION: +# defaultuserquota and defaultgroupquota can not be set against snapshot +# +# +# STRATEGY: +# 1. Set defaultuserquota on snap +# 2. Set defaultgroupquota on snap +# + +function cleanup +{ + cleanup_quota + + datasetexists $snap_fs && destroy_dataset $snap_fs +} + +log_onexit cleanup + +typeset snap_fs=$QFS@snap +log_assert "Check setting default{user|group}quota on snapshot" + +log_note "Check can not set default{user|group}quota on snapshot" +log_must zfs snapshot $snap_fs + +log_mustnot zfs set defaultuserquota=$UQUOTA_SIZE $snap_fs + +log_mustnot zfs set defaultgroupquota=$GQUOTA_SIZE $snap_fs + +log_pass "Check setting default{user|group}quota on snapshot fails as expected" From e090fc2e1fbedcbcab1730b060b61eb6da11f5d1 Mon Sep 17 00:00:00 2001 From: Todd Seidelmann <18294602+seidelma@users.noreply.github.com> Date: Mon, 17 Jun 2024 00:41:29 -0700 Subject: [PATCH 3/5] zfsprops.7 manpage changes for default quotas Add defaultuserquota and defaultgroupquota dataset properties to the zfsprops.7 manpage. Signed-off-by: Todd Seidelmann --- man/man7/zfsprops.7 | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/man/man7/zfsprops.7 b/man/man7/zfsprops.7 index 06e2797968ea..8fb13fe37c3c 100644 --- a/man/man7/zfsprops.7 +++ b/man/man7/zfsprops.7 @@ -1444,6 +1444,9 @@ but it limits the number of objects a user can create. Please refer to .Sy userobjused for more information about how objects are counted. +.It Sy defaultuserquota Ns = Ns Ar size Ns | Ns Sy none +Sets a default quota to be applied to each user for whom no user-specific +quota is set. .It Sy groupquota@ Ns Ar group Ns = Ns Ar size Ns | Ns Sy none Limits the amount of space consumed by the specified group. Group space consumption is identified by the @@ -1465,6 +1468,9 @@ but it limits number of objects a group can consume. Please refer to .Sy userobjused for more information about how objects are counted. +.It Sy defaultgroupquota Ns = Ns Ar size Ns | Ns Sy none +Sets a default quota to be applied to each group for whom no group-specific +quota is set. .It Sy projectquota@ Ns Ar project Ns = Ns Ar size Ns | Ns Sy none Limits the amount of space consumed by the specified project. Project space consumption is identified by the From c46cb4b672debc6ca8d0c69946a347582758bb7a Mon Sep 17 00:00:00 2001 From: Todd Seidelmann <18294602+seidelma@users.noreply.github.com> Date: Fri, 2 Aug 2024 17:25:18 -0400 Subject: [PATCH 4/5] Store ABI changes for defaultuserquota/defaultgroupquota Signed-off-by: Todd Seidelmann --- lib/libzfs/libzfs.abi | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/libzfs/libzfs.abi b/lib/libzfs/libzfs.abi index ac9ae233c72d..78feaa58b3a5 100644 --- a/lib/libzfs/libzfs.abi +++ b/lib/libzfs/libzfs.abi @@ -2049,7 +2049,9 @@ - + + + From 0a9157bdbe3599305827f2e7f703f53674f788d7 Mon Sep 17 00:00:00 2001 From: Todd Seidelmann <18294602+seidelma@users.noreply.github.com> Date: Fri, 9 Aug 2024 09:25:05 -0700 Subject: [PATCH 5/5] Implement defaultuserquota/defaultgroupquota on FreeBSD Signed-off-by: Todd Seidelmann --- include/os/freebsd/zfs/sys/zfs_vfsops_os.h | 2 ++ module/os/freebsd/zfs/zfs_vfsops.c | 16 ++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/include/os/freebsd/zfs/sys/zfs_vfsops_os.h b/include/os/freebsd/zfs/sys/zfs_vfsops_os.h index b7cbdc736d21..4c3854c072a2 100644 --- a/include/os/freebsd/zfs/sys/zfs_vfsops_os.h +++ b/include/os/freebsd/zfs/sys/zfs_vfsops_os.h @@ -95,6 +95,8 @@ struct zfsvfs { uint64_t z_groupobjquota_obj; uint64_t z_projectquota_obj; uint64_t z_projectobjquota_obj; + uint64_t z_defaultuserquota_obj; + uint64_t z_defaultgroupquota_obj; uint64_t z_replay_eof; /* New end of file - replay only */ sa_attr_type_t *z_attr_table; /* SA attr mapping->id */ #define ZFS_OBJ_MTX_SZ 64 diff --git a/module/os/freebsd/zfs/zfs_vfsops.c b/module/os/freebsd/zfs/zfs_vfsops.c index a3fac1636981..378aadeeecca 100644 --- a/module/os/freebsd/zfs/zfs_vfsops.c +++ b/module/os/freebsd/zfs/zfs_vfsops.c @@ -925,6 +925,22 @@ zfsvfs_init(zfsvfs_t *zfsvfs, objset_t *os) else if (error != 0) return (error); + error = zap_lookup(os, MASTER_NODE_OBJ, + zfs_prop_to_name(ZFS_PROP_DEFAULTUSERQUOTA), + 8, 1, &zfsvfs->z_defaultuserquota_obj); + if (error == ENOENT) + zfsvfs->z_defaultuserquota_obj = 0; + else if (error != 0) + return (error); + + error = zap_lookup(os, MASTER_NODE_OBJ, + zfs_prop_to_name(ZFS_PROP_DEFAULTGROUPQUOTA), + 8, 1, &zfsvfs->z_defaultgroupquota_obj); + if (error == ENOENT) + zfsvfs->z_defaultgroupquota_obj = 0; + else if (error != 0) + return (error); + error = zap_lookup(os, MASTER_NODE_OBJ, ZFS_FUID_TABLES, 8, 1, &zfsvfs->z_fuid_obj); if (error == ENOENT)