Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement defaultuserquota/defaultgroupquota #16283

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions cmd/zfs/zfs_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -585,6 +585,10 @@ usage(boolean_t requested)
(void) fprintf(fp, "YES NO <size> | none\n");
(void) fprintf(fp, "\t%-15s ", "projectobjquota@...");
(void) fprintf(fp, "YES NO <size> | none\n");
(void) fprintf(fp, "\t%-15s ", "defaultuserquota");
(void) fprintf(fp, "YES NO <size> | none\n");
(void) fprintf(fp, "\t%-15s ", "defaultgroupquota");
(void) fprintf(fp, "YES NO <size> | none\n");
(void) fprintf(fp, "\t%-15s ", "written@<snap>");
(void) fprintf(fp, " NO NO <size>\n");
(void) fprintf(fp, "\t%-15s ", "written#<bookmark>");
Expand Down
2 changes: 2 additions & 0 deletions include/os/freebsd/zfs/sys/zfs_vfsops_os.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,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
Expand Down
2 changes: 2 additions & 0 deletions include/os/linux/zfs/sys/zfs_vfsops_os.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,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 */
Expand Down
2 changes: 2 additions & 0 deletions include/sys/fs/zfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,8 @@ typedef enum {
ZFS_PROP_SNAPSHOTS_CHANGED,
ZFS_PROP_PREFETCH,
ZFS_PROP_VOLTHREADING,
ZFS_PROP_DEFAULTUSERQUOTA,
ZFS_PROP_DEFAULTGROUPQUOTA,
ZFS_NUM_PROPS
} zfs_prop_t;

Expand Down
1 change: 1 addition & 0 deletions include/sys/zfs_quota.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
4 changes: 3 additions & 1 deletion lib/libzfs/libzfs.abi
Original file line number Diff line number Diff line change
Expand Up @@ -1852,7 +1852,9 @@
<enumerator name='ZFS_PROP_SNAPSHOTS_CHANGED' value='95'/>
<enumerator name='ZFS_PROP_PREFETCH' value='96'/>
<enumerator name='ZFS_PROP_VOLTHREADING' value='97'/>
<enumerator name='ZFS_NUM_PROPS' value='98'/>
<enumerator name='ZFS_PROP_DEFAULTUSERQUOTA' value='98'/>
<enumerator name='ZFS_PROP_DEFAULTGROUPQUOTA' value='99'/>
<enumerator name='ZFS_NUM_PROPS' value='100'/>
</enum-decl>
<typedef-decl name='zfs_prop_t' type-id='4b000d60' id='58603c44'/>
<enum-decl name='zprop_source_t' naming-typedef-id='a2256d42' id='5903f80e'>
Expand Down
2 changes: 2 additions & 0 deletions lib/libzfs/libzfs_dataset.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
6 changes: 6 additions & 0 deletions man/man7/zfsprops.7
Original file line number Diff line number Diff line change
Expand Up @@ -1392,6 +1392,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
Expand All @@ -1413,6 +1416,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
Expand Down
16 changes: 16 additions & 0 deletions module/os/freebsd/zfs/zfs_vfsops.c
Original file line number Diff line number Diff line change
Expand Up @@ -924,6 +924,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)
Expand Down
16 changes: 16 additions & 0 deletions module/os/linux/zfs/zfs_vfsops.c
Original file line number Diff line number Diff line change
Expand Up @@ -743,6 +743,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)
Expand Down
6 changes: 6 additions & 0 deletions module/zcommon/zfs_prop.c
Original file line number Diff line number Diff line change
Expand Up @@ -694,6 +694,12 @@ zfs_prop_init(void)
zprop_register_number(ZFS_PROP_SNAPSHOT_LIMIT, "snapshot_limit",
UINT64_MAX, PROP_DEFAULT, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME,
"<count> | none", "SSLIMIT", B_FALSE, sfeatures);
zprop_register_number(ZFS_PROP_DEFAULTUSERQUOTA, "defaultuserquota", 0,
PROP_DEFAULT, ZFS_TYPE_FILESYSTEM, "<size> | none",
"DEFAULTUSERQUOTA", B_FALSE, sfeatures);
zprop_register_number(ZFS_PROP_DEFAULTGROUPQUOTA, "defaultgroupquota",
0, PROP_DEFAULT, ZFS_TYPE_FILESYSTEM, "<size> | none",
"DEFAULTGROUPQUOTA", B_FALSE, sfeatures);

/* inherit number properties */
zprop_register_number(ZFS_PROP_RECORDSIZE, "recordsize",
Expand Down
19 changes: 19 additions & 0 deletions module/zfs/zfs_ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -2567,6 +2567,25 @@ zfs_prop_set_special(const char *dsname, zprop_source_t source,
}
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;
}
Expand Down
89 changes: 84 additions & 5 deletions module/zfs/zfs_quota.c
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,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, &quota, tx);
}

ASSERT(err == 0);
dmu_tx_commit(tx);
return (err);
}

boolean_t
zfs_id_overobjquota(zfsvfs_t *zfsvfs, uint64_t usedobj, uint64_t id)
{
Expand Down Expand Up @@ -423,8 +476,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)) {
Expand All @@ -440,22 +494,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, &quota);
if (err != 0)
derr = zap_lookup(zfsvfs->z_os, defquotaobj, name,
8, 1, &defquota);
uerr = zap_lookup(zfsvfs->z_os, quotaobj, buf, 8, 1, &quota);

/* 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);
}

Expand All @@ -470,6 +548,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);
5 changes: 5 additions & 0 deletions tests/runfiles/common.run
Original file line number Diff line number Diff line change
Expand Up @@ -979,6 +979,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',
Expand Down
10 changes: 10 additions & 0 deletions tests/zfs-tests/tests/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -2037,6 +2037,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 \
Expand Down
Loading
Loading