diff --git a/include/os/freebsd/zfs/sys/zfs_vfsops_os.h b/include/os/freebsd/zfs/sys/zfs_vfsops_os.h index 289b64759..3ed311d49 100644 --- a/include/os/freebsd/zfs/sys/zfs_vfsops_os.h +++ b/include/os/freebsd/zfs/sys/zfs_vfsops_os.h @@ -96,6 +96,12 @@ struct zfsvfs { uint64_t z_groupobjquota_obj; uint64_t z_projectquota_obj; uint64_t z_projectobjquota_obj; + uint64_t z_defaultuserquota; + uint64_t z_defaultgroupquota; + uint64_t z_defaultprojectquota; + uint64_t z_defaultuserobjquota; + uint64_t z_defaultgroupobjquota; + uint64_t z_defaultprojectobjquota; 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 @@ -226,6 +232,8 @@ extern boolean_t zfs_is_readonly(zfsvfs_t *zfsvfs); extern int zfs_get_temporary_prop(struct dsl_dataset *ds, zfs_prop_t zfs_prop, uint64_t *val, char *setpoint); extern int zfs_busy(void); +extern int zfs_set_default_quota(zfsvfs_t *zfsvfs, zfs_prop_t zfs_prop, + uint64_t quota); #ifdef __cplusplus } diff --git a/include/os/linux/zfs/sys/zfs_vfsops_os.h b/include/os/linux/zfs/sys/zfs_vfsops_os.h index 4a73712e9..ab46d5f8c 100644 --- a/include/os/linux/zfs/sys/zfs_vfsops_os.h +++ b/include/os/linux/zfs/sys/zfs_vfsops_os.h @@ -131,6 +131,12 @@ struct zfsvfs { uint64_t z_groupobjquota_obj; uint64_t z_projectquota_obj; uint64_t z_projectobjquota_obj; + uint64_t z_defaultuserquota; + uint64_t z_defaultgroupquota; + uint64_t z_defaultprojectquota; + uint64_t z_defaultuserobjquota; + uint64_t z_defaultgroupobjquota; + uint64_t z_defaultprojectobjquota; 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 */ @@ -250,6 +256,8 @@ extern int zfs_prune(struct super_block *sb, unsigned long nr_to_scan, int *objects); extern int zfs_get_temporary_prop(dsl_dataset_t *ds, zfs_prop_t zfs_prop, uint64_t *val, char *setpoint); +extern int zfs_set_default_quota(zfsvfs_t *zfsvfs, zfs_prop_t zfs_prop, + uint64_t quota); #ifdef __cplusplus } diff --git a/include/sys/fs/zfs.h b/include/sys/fs/zfs.h index 2d27aee21..44d63e870 100644 --- a/include/sys/fs/zfs.h +++ b/include/sys/fs/zfs.h @@ -197,6 +197,12 @@ typedef enum { ZFS_PROP_VOLTHREADING, ZFS_PROP_DIRECT, ZFS_PROP_LONGNAME, + ZFS_PROP_DEFAULTUSERQUOTA, + ZFS_PROP_DEFAULTGROUPQUOTA, + ZFS_PROP_DEFAULTPROJECTQUOTA, + ZFS_PROP_DEFAULTUSEROBJQUOTA, + ZFS_PROP_DEFAULTGROUPOBJQUOTA, + ZFS_PROP_DEFAULTPROJECTOBJQUOTA, ZFS_NUM_PROPS } zfs_prop_t; diff --git a/lib/libzfs/libzfs.abi b/lib/libzfs/libzfs.abi index 1f9fde667..12496b083 100644 --- a/lib/libzfs/libzfs.abi +++ b/lib/libzfs/libzfs.abi @@ -2049,7 +2049,13 @@ - + + + + + + + diff --git a/lib/libzfs/libzfs_dataset.c b/lib/libzfs/libzfs_dataset.c index 8d9639221..f0d8c1953 100644 --- a/lib/libzfs/libzfs_dataset.c +++ b/lib/libzfs/libzfs_dataset.c @@ -2308,6 +2308,12 @@ get_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zprop_source_t *src, case ZFS_PROP_NORMALIZE: case ZFS_PROP_UTF8ONLY: case ZFS_PROP_CASE: + case ZFS_PROP_DEFAULTUSERQUOTA: + case ZFS_PROP_DEFAULTGROUPQUOTA: + case ZFS_PROP_DEFAULTPROJECTQUOTA: + case ZFS_PROP_DEFAULTUSEROBJQUOTA: + case ZFS_PROP_DEFAULTGROUPOBJQUOTA: + case ZFS_PROP_DEFAULTPROJECTOBJQUOTA: zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0); (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); diff --git a/module/os/freebsd/zfs/zfs_vfsops.c b/module/os/freebsd/zfs/zfs_vfsops.c index 547e109db..c192f6834 100644 --- a/module/os/freebsd/zfs/zfs_vfsops.c +++ b/module/os/freebsd/zfs/zfs_vfsops.c @@ -861,6 +861,36 @@ zfsvfs_init(zfsvfs_t *zfsvfs, objset_t *os) zfsvfs->z_xattr_sa = B_TRUE; } + error = zfs_get_zplprop(os, ZFS_PROP_DEFAULTUSERQUOTA, + &zfsvfs->z_defaultuserquota); + if (error != 0) + return (error); + + error = zfs_get_zplprop(os, ZFS_PROP_DEFAULTGROUPQUOTA, + &zfsvfs->z_defaultgroupquota); + if (error != 0) + return (error); + + error = zfs_get_zplprop(os, ZFS_PROP_DEFAULTPROJECTQUOTA, + &zfsvfs->z_defaultprojectquota); + if (error != 0) + return (error); + + error = zfs_get_zplprop(os, ZFS_PROP_DEFAULTUSEROBJQUOTA, + &zfsvfs->z_defaultuserobjquota); + if (error != 0) + return (error); + + error = zfs_get_zplprop(os, ZFS_PROP_DEFAULTGROUPOBJQUOTA, + &zfsvfs->z_defaultgroupobjquota); + if (error != 0) + return (error); + + error = zfs_get_zplprop(os, ZFS_PROP_DEFAULTPROJECTOBJQUOTA, + &zfsvfs->z_defaultprojectobjquota); + if (error != 0) + return (error); + error = sa_setup(os, sa_obj, zfs_attr_table, ZPL_END, &zfsvfs->z_attr_table); if (error != 0) @@ -2241,6 +2271,62 @@ zfs_set_version(zfsvfs_t *zfsvfs, uint64_t newvers) return (0); } +int +zfs_set_default_quota(zfsvfs_t *zfsvfs, zfs_prop_t prop, uint64_t quota) +{ + int error; + objset_t *os = zfsvfs->z_os; + const char *propstr = zfs_prop_to_name(prop); + dmu_tx_t *tx; + + tx = dmu_tx_create(os); + dmu_tx_hold_zap(tx, MASTER_NODE_OBJ, B_FALSE, propstr); + error = dmu_tx_assign(tx, DMU_TX_WAIT); + if (error) { + dmu_tx_abort(tx); + return (error); + } + + if (quota == 0) { + error = zap_remove(os, MASTER_NODE_OBJ, propstr, tx); + if (error == ENOENT) + error = 0; + } else { + error = zap_update(os, MASTER_NODE_OBJ, propstr, 8, 1, + "a, tx); + } + + if (error) + goto out; + + switch (prop) { + case ZFS_PROP_DEFAULTUSERQUOTA: + zfsvfs->z_defaultuserquota = quota; + break; + case ZFS_PROP_DEFAULTGROUPQUOTA: + zfsvfs->z_defaultgroupquota = quota; + break; + case ZFS_PROP_DEFAULTPROJECTQUOTA: + zfsvfs->z_defaultprojectquota = quota; + break; + case ZFS_PROP_DEFAULTUSEROBJQUOTA: + zfsvfs->z_defaultuserobjquota = quota; + break; + case ZFS_PROP_DEFAULTGROUPOBJQUOTA: + zfsvfs->z_defaultgroupobjquota = quota; + break; + case ZFS_PROP_DEFAULTPROJECTOBJQUOTA: + zfsvfs->z_defaultprojectobjquota = quota; + break; + default: + break; + } + +out: + dmu_tx_commit(tx); + return (error); +} + /* * Return true if the corresponding vfs's unmounted flag is set. * Otherwise return false. diff --git a/module/os/linux/zfs/zfs_vfsops.c b/module/os/linux/zfs/zfs_vfsops.c index ca75080d5..ba38d6673 100644 --- a/module/os/linux/zfs/zfs_vfsops.c +++ b/module/os/linux/zfs/zfs_vfsops.c @@ -697,6 +697,36 @@ zfsvfs_init(zfsvfs_t *zfsvfs, objset_t *os) zfsvfs->z_xattr_sa = B_TRUE; } + error = zfs_get_zplprop(os, ZFS_PROP_DEFAULTUSERQUOTA, + &zfsvfs->z_defaultuserquota); + if (error != 0) + return (error); + + error = zfs_get_zplprop(os, ZFS_PROP_DEFAULTGROUPQUOTA, + &zfsvfs->z_defaultgroupquota); + if (error != 0) + return (error); + + error = zfs_get_zplprop(os, ZFS_PROP_DEFAULTPROJECTQUOTA, + &zfsvfs->z_defaultprojectquota); + if (error != 0) + return (error); + + error = zfs_get_zplprop(os, ZFS_PROP_DEFAULTUSEROBJQUOTA, + &zfsvfs->z_defaultuserobjquota); + if (error != 0) + return (error); + + error = zfs_get_zplprop(os, ZFS_PROP_DEFAULTGROUPOBJQUOTA, + &zfsvfs->z_defaultgroupobjquota); + if (error != 0) + return (error); + + error = zfs_get_zplprop(os, ZFS_PROP_DEFAULTPROJECTOBJQUOTA, + &zfsvfs->z_defaultprojectobjquota); + if (error != 0) + return (error); + error = zap_lookup(os, MASTER_NODE_OBJ, ZFS_ROOT_OBJ, 8, 1, &zfsvfs->z_root); if (error != 0) @@ -2005,6 +2035,62 @@ zfs_set_version(zfsvfs_t *zfsvfs, uint64_t newvers) return (0); } +int +zfs_set_default_quota(zfsvfs_t *zfsvfs, zfs_prop_t prop, uint64_t quota) +{ + int error; + objset_t *os = zfsvfs->z_os; + const char *propstr = zfs_prop_to_name(prop); + dmu_tx_t *tx; + + tx = dmu_tx_create(os); + dmu_tx_hold_zap(tx, MASTER_NODE_OBJ, B_FALSE, propstr); + error = dmu_tx_assign(tx, DMU_TX_WAIT); + if (error) { + dmu_tx_abort(tx); + return (error); + } + + if (quota == 0) { + error = zap_remove(os, MASTER_NODE_OBJ, propstr, tx); + if (error == ENOENT) + error = 0; + } else { + error = zap_update(os, MASTER_NODE_OBJ, propstr, 8, 1, + "a, tx); + } + + if (error) + goto out; + + switch (prop) { + case ZFS_PROP_DEFAULTUSERQUOTA: + zfsvfs->z_defaultuserquota = quota; + break; + case ZFS_PROP_DEFAULTGROUPQUOTA: + zfsvfs->z_defaultgroupquota = quota; + break; + case ZFS_PROP_DEFAULTPROJECTQUOTA: + zfsvfs->z_defaultprojectquota = quota; + break; + case ZFS_PROP_DEFAULTUSEROBJQUOTA: + zfsvfs->z_defaultuserobjquota = quota; + break; + case ZFS_PROP_DEFAULTGROUPOBJQUOTA: + zfsvfs->z_defaultgroupobjquota = quota; + break; + case ZFS_PROP_DEFAULTPROJECTOBJQUOTA: + zfsvfs->z_defaultprojectobjquota = quota; + break; + default: + break; + } + +out: + dmu_tx_commit(tx); + return (error); +} + /* * Return true if the corresponding vfs's unmounted flag is set. * Otherwise return false. @@ -2073,4 +2159,5 @@ EXPORT_SYMBOL(zfs_remount); EXPORT_SYMBOL(zfs_statvfs); EXPORT_SYMBOL(zfs_vget); EXPORT_SYMBOL(zfs_prune); +EXPORT_SYMBOL(zfs_set_default_quota); #endif diff --git a/module/zcommon/zfs_prop.c b/module/zcommon/zfs_prop.c index 480c3fcd0..9d02b1f84 100644 --- a/module/zcommon/zfs_prop.c +++ b/module/zcommon/zfs_prop.c @@ -708,6 +708,28 @@ 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 | ZFS_TYPE_SNAPSHOT, + " | none", "DEFAULTUSERQUOTA", B_FALSE, sfeatures); + zprop_register_number(ZFS_PROP_DEFAULTGROUPQUOTA, "defaultgroupquota", + 0, PROP_DEFAULT, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_SNAPSHOT, + " | none", "DEFAULTGROUPQUOTA", B_FALSE, sfeatures); + zprop_register_number(ZFS_PROP_DEFAULTPROJECTQUOTA, + "defaultprojectquota", 0, PROP_DEFAULT, + ZFS_TYPE_FILESYSTEM | ZFS_TYPE_SNAPSHOT, " | none", + "DEFAULTPROJECTQUOTA", B_FALSE, sfeatures); + zprop_register_number(ZFS_PROP_DEFAULTUSEROBJQUOTA, + "defaultuserobjquota", 0, PROP_DEFAULT, + ZFS_TYPE_FILESYSTEM | ZFS_TYPE_SNAPSHOT, " | none", + "DEFAULTUSEROBJQUOTA", B_FALSE, sfeatures); + zprop_register_number(ZFS_PROP_DEFAULTGROUPOBJQUOTA, + "defaultgroupobjquota", 0, PROP_DEFAULT, + ZFS_TYPE_FILESYSTEM | ZFS_TYPE_SNAPSHOT, " | none", + "DEFAULTGROUPOBJQUOTA", B_FALSE, sfeatures); + zprop_register_number(ZFS_PROP_DEFAULTPROJECTOBJQUOTA, + "defaultprojectobjquota", 0, PROP_DEFAULT, + ZFS_TYPE_FILESYSTEM | ZFS_TYPE_SNAPSHOT, " | none", + "DEFAULTPROJECTOBJQUOTA", 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 9266c3c28..bd92025aa 100644 --- a/module/zfs/zfs_ioctl.c +++ b/module/zfs/zfs_ioctl.c @@ -2259,7 +2259,19 @@ zfs_ioc_objset_zplprops(zfs_cmd_t *zc) if ((err = nvl_add_zplprop(os, nv, ZFS_PROP_VERSION)) == 0 && (err = nvl_add_zplprop(os, nv, ZFS_PROP_NORMALIZE)) == 0 && (err = nvl_add_zplprop(os, nv, ZFS_PROP_UTF8ONLY)) == 0 && - (err = nvl_add_zplprop(os, nv, ZFS_PROP_CASE)) == 0) + (err = nvl_add_zplprop(os, nv, ZFS_PROP_CASE)) == 0 && + (err = nvl_add_zplprop(os, nv, + ZFS_PROP_DEFAULTUSERQUOTA)) == 0 && + (err = nvl_add_zplprop(os, nv, + ZFS_PROP_DEFAULTGROUPQUOTA)) == 0 && + (err = nvl_add_zplprop(os, nv, + ZFS_PROP_DEFAULTPROJECTQUOTA)) == 0 && + (err = nvl_add_zplprop(os, nv, + ZFS_PROP_DEFAULTUSEROBJQUOTA)) == 0 && + (err = nvl_add_zplprop(os, nv, + ZFS_PROP_DEFAULTGROUPOBJQUOTA)) == 0 && + (err = nvl_add_zplprop(os, nv, + ZFS_PROP_DEFAULTPROJECTOBJQUOTA)) == 0) err = put_nvlist(zc, nv); nvlist_free(nv); } else { @@ -2642,6 +2654,20 @@ zfs_prop_set_special(const char *dsname, zprop_source_t source, zfsvfs_rele(zfsvfs, FTAG); break; } + case ZFS_PROP_DEFAULTUSERQUOTA: + case ZFS_PROP_DEFAULTGROUPQUOTA: + case ZFS_PROP_DEFAULTPROJECTQUOTA: + case ZFS_PROP_DEFAULTUSEROBJQUOTA: + case ZFS_PROP_DEFAULTGROUPOBJQUOTA: + case ZFS_PROP_DEFAULTPROJECTOBJQUOTA: + { + zfsvfs_t *zfsvfs; + if ((err = zfsvfs_hold(dsname, FTAG, &zfsvfs, B_TRUE)) != 0) + break; + err = zfs_set_default_quota(zfsvfs, prop, intval); + zfsvfs_rele(zfsvfs, FTAG); + break; + } default: err = -1; } @@ -3331,6 +3357,9 @@ zfs_fill_zplprops_impl(objset_t *os, uint64_t zplver, uint64_t sense = ZFS_PROP_UNDEFINED; uint64_t norm = ZFS_PROP_UNDEFINED; uint64_t u8 = ZFS_PROP_UNDEFINED; + uint64_t duq = ZFS_PROP_UNDEFINED, duoq = ZFS_PROP_UNDEFINED; + uint64_t dgq = ZFS_PROP_UNDEFINED, dgoq = ZFS_PROP_UNDEFINED; + uint64_t dpq = ZFS_PROP_UNDEFINED, dpoq = ZFS_PROP_UNDEFINED; int error; ASSERT(zplprops != NULL); @@ -3357,6 +3386,30 @@ zfs_fill_zplprops_impl(objset_t *os, uint64_t zplver, zfs_prop_to_name(ZFS_PROP_CASE), &sense); (void) nvlist_remove_all(createprops, zfs_prop_to_name(ZFS_PROP_CASE)); + (void) nvlist_lookup_uint64(createprops, + zfs_prop_to_name(ZFS_PROP_DEFAULTUSERQUOTA), &duq); + (void) nvlist_remove_all(createprops, + zfs_prop_to_name(ZFS_PROP_DEFAULTUSERQUOTA)); + (void) nvlist_lookup_uint64(createprops, + zfs_prop_to_name(ZFS_PROP_DEFAULTGROUPQUOTA), &dgq); + (void) nvlist_remove_all(createprops, + zfs_prop_to_name(ZFS_PROP_DEFAULTGROUPQUOTA)); + (void) nvlist_lookup_uint64(createprops, + zfs_prop_to_name(ZFS_PROP_DEFAULTPROJECTQUOTA), &dpq); + (void) nvlist_remove_all(createprops, + zfs_prop_to_name(ZFS_PROP_DEFAULTPROJECTQUOTA)); + (void) nvlist_lookup_uint64(createprops, + zfs_prop_to_name(ZFS_PROP_DEFAULTUSEROBJQUOTA), &duoq); + (void) nvlist_remove_all(createprops, + zfs_prop_to_name(ZFS_PROP_DEFAULTUSEROBJQUOTA)); + (void) nvlist_lookup_uint64(createprops, + zfs_prop_to_name(ZFS_PROP_DEFAULTGROUPOBJQUOTA), &dgoq); + (void) nvlist_remove_all(createprops, + zfs_prop_to_name(ZFS_PROP_DEFAULTGROUPOBJQUOTA)); + (void) nvlist_lookup_uint64(createprops, + zfs_prop_to_name(ZFS_PROP_DEFAULTPROJECTOBJQUOTA), &dpoq); + (void) nvlist_remove_all(createprops, + zfs_prop_to_name(ZFS_PROP_DEFAULTPROJECTOBJQUOTA)); } /* @@ -3402,6 +3455,47 @@ zfs_fill_zplprops_impl(objset_t *os, uint64_t zplver, VERIFY(nvlist_add_uint64(zplprops, zfs_prop_to_name(ZFS_PROP_CASE), sense) == 0); + if (duq == ZFS_PROP_UNDEFINED && + (error = zfs_get_zplprop(os, ZFS_PROP_DEFAULTUSERQUOTA, &duq)) != 0) + return (error); + VERIFY(nvlist_add_uint64(zplprops, + zfs_prop_to_name(ZFS_PROP_DEFAULTUSERQUOTA), duq) == 0); + + if (dgq == ZFS_PROP_UNDEFINED && + (error = zfs_get_zplprop(os, ZFS_PROP_DEFAULTGROUPQUOTA, + &dgq)) != 0) + return (error); + VERIFY(nvlist_add_uint64(zplprops, + zfs_prop_to_name(ZFS_PROP_DEFAULTGROUPQUOTA), dgq) == 0); + + if (dpq == ZFS_PROP_UNDEFINED && + (error = zfs_get_zplprop(os, ZFS_PROP_DEFAULTPROJECTQUOTA, + &dpq)) != 0) + return (error); + VERIFY(nvlist_add_uint64(zplprops, + zfs_prop_to_name(ZFS_PROP_DEFAULTPROJECTQUOTA), dpq) == 0); + + if (duoq == ZFS_PROP_UNDEFINED && + (error = zfs_get_zplprop(os, ZFS_PROP_DEFAULTUSEROBJQUOTA, + &duoq)) != 0) + return (error); + VERIFY(nvlist_add_uint64(zplprops, + zfs_prop_to_name(ZFS_PROP_DEFAULTUSEROBJQUOTA), duoq) == 0); + + if (dgoq == ZFS_PROP_UNDEFINED && + (error = zfs_get_zplprop(os, ZFS_PROP_DEFAULTGROUPOBJQUOTA, + &dgoq)) != 0) + return (error); + VERIFY(nvlist_add_uint64(zplprops, + zfs_prop_to_name(ZFS_PROP_DEFAULTGROUPOBJQUOTA), dgoq) == 0); + + if (dpoq == ZFS_PROP_UNDEFINED && + (error = zfs_get_zplprop(os, ZFS_PROP_DEFAULTPROJECTOBJQUOTA, + &dpoq)) != 0) + return (error); + VERIFY(nvlist_add_uint64(zplprops, + zfs_prop_to_name(ZFS_PROP_DEFAULTPROJECTOBJQUOTA), dpoq) == 0); + if (is_ci) *is_ci = (sense == ZFS_CASE_INSENSITIVE); diff --git a/module/zfs/zfs_znode.c b/module/zfs/zfs_znode.c index f3c63984a..861783d79 100644 --- a/module/zfs/zfs_znode.c +++ b/module/zfs/zfs_znode.c @@ -384,6 +384,14 @@ zfs_get_zplprop(objset_t *os, zfs_prop_t prop, uint64_t *value) *value = ZFS_ACLTYPE_OFF; #endif break; + case ZFS_PROP_DEFAULTUSERQUOTA: + case ZFS_PROP_DEFAULTGROUPQUOTA: + case ZFS_PROP_DEFAULTPROJECTQUOTA: + case ZFS_PROP_DEFAULTUSEROBJQUOTA: + case ZFS_PROP_DEFAULTGROUPOBJQUOTA: + case ZFS_PROP_DEFAULTPROJECTOBJQUOTA: + *value = 0; + return (0); default: return (error); }