mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2026-05-29 18:24:11 +03:00
Add support for user/group dnode accounting & quota
This patch tracks dnode usage for each user/group in the DMU_USER/GROUPUSED_OBJECT ZAPs. ZAP entries dedicated to dnode accounting have the key prefixed with "obj-" followed by the UID/GID in string format (as done for the block accounting). A new SPA feature has been added for dnode accounting as well as a new ZPL version. The SPA feature must be enabled in the pool before upgrading the zfs filesystem. During the zfs version upgrade, a "quotacheck" will be executed by marking all dnode as dirty. ZoL-bug-id: https://github.com/zfsonlinux/zfs/issues/3500 Signed-off-by: Jinshan Xiong <jinshan.xiong@intel.com> Signed-off-by: Johann Lombardi <johann.lombardi@intel.com>
This commit is contained in:
committed by
Brian Behlendorf
parent
af322debaa
commit
1de321e626
+99
-13
@@ -431,17 +431,22 @@ zfs_userquota_prop_to_obj(zfs_sb_t *zsb, zfs_userquota_prop_t type)
|
||||
{
|
||||
switch (type) {
|
||||
case ZFS_PROP_USERUSED:
|
||||
case ZFS_PROP_USEROBJUSED:
|
||||
return (DMU_USERUSED_OBJECT);
|
||||
case ZFS_PROP_GROUPUSED:
|
||||
case ZFS_PROP_GROUPOBJUSED:
|
||||
return (DMU_GROUPUSED_OBJECT);
|
||||
case ZFS_PROP_USERQUOTA:
|
||||
return (zsb->z_userquota_obj);
|
||||
case ZFS_PROP_GROUPQUOTA:
|
||||
return (zsb->z_groupquota_obj);
|
||||
case ZFS_PROP_USEROBJQUOTA:
|
||||
return (zsb->z_userobjquota_obj);
|
||||
case ZFS_PROP_GROUPOBJQUOTA:
|
||||
return (zsb->z_groupobjquota_obj);
|
||||
default:
|
||||
return (SET_ERROR(ENOTSUP));
|
||||
return (ZFS_NO_OBJECT);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
@@ -453,16 +458,25 @@ zfs_userspace_many(zfs_sb_t *zsb, zfs_userquota_prop_t type,
|
||||
zap_attribute_t za;
|
||||
zfs_useracct_t *buf = vbuf;
|
||||
uint64_t obj;
|
||||
int offset = 0;
|
||||
|
||||
if (!dmu_objset_userspace_present(zsb->z_os))
|
||||
return (SET_ERROR(ENOTSUP));
|
||||
|
||||
if ((type == ZFS_PROP_USEROBJUSED || type == ZFS_PROP_GROUPOBJUSED ||
|
||||
type == ZFS_PROP_USEROBJQUOTA || type == ZFS_PROP_GROUPOBJQUOTA) &&
|
||||
!dmu_objset_userobjspace_present(zsb->z_os))
|
||||
return (SET_ERROR(ENOTSUP));
|
||||
|
||||
obj = zfs_userquota_prop_to_obj(zsb, type);
|
||||
if (obj == 0) {
|
||||
if (obj == ZFS_NO_OBJECT) {
|
||||
*bufsizep = 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (type == ZFS_PROP_USEROBJUSED || type == ZFS_PROP_GROUPOBJUSED)
|
||||
offset = DMU_OBJACCT_PREFIX_LEN;
|
||||
|
||||
for (zap_cursor_init_serialized(&zc, zsb->z_os, obj, *cookiep);
|
||||
(error = zap_cursor_retrieve(&zc, &za)) == 0;
|
||||
zap_cursor_advance(&zc)) {
|
||||
@@ -470,7 +484,15 @@ zfs_userspace_many(zfs_sb_t *zsb, zfs_userquota_prop_t type,
|
||||
*bufsizep)
|
||||
break;
|
||||
|
||||
fuidstr_to_sid(zsb, za.za_name,
|
||||
/*
|
||||
* skip object quota (with zap name prefix DMU_OBJACCT_PREFIX)
|
||||
* when dealing with block quota and vice versa.
|
||||
*/
|
||||
if ((offset > 0) != (strncmp(za.za_name, DMU_OBJACCT_PREFIX,
|
||||
DMU_OBJACCT_PREFIX_LEN) == 0))
|
||||
continue;
|
||||
|
||||
fuidstr_to_sid(zsb, za.za_name + offset,
|
||||
buf->zu_domain, sizeof (buf->zu_domain), &buf->zu_rid);
|
||||
|
||||
buf->zu_space = za.za_first_integer;
|
||||
@@ -511,7 +533,8 @@ int
|
||||
zfs_userspace_one(zfs_sb_t *zsb, zfs_userquota_prop_t type,
|
||||
const char *domain, uint64_t rid, uint64_t *valp)
|
||||
{
|
||||
char buf[32];
|
||||
char buf[20 + DMU_OBJACCT_PREFIX_LEN];
|
||||
int offset = 0;
|
||||
int err;
|
||||
uint64_t obj;
|
||||
|
||||
@@ -520,11 +543,21 @@ zfs_userspace_one(zfs_sb_t *zsb, zfs_userquota_prop_t type,
|
||||
if (!dmu_objset_userspace_present(zsb->z_os))
|
||||
return (SET_ERROR(ENOTSUP));
|
||||
|
||||
if ((type == ZFS_PROP_USEROBJUSED || type == ZFS_PROP_GROUPOBJUSED ||
|
||||
type == ZFS_PROP_USEROBJQUOTA || type == ZFS_PROP_GROUPOBJQUOTA) &&
|
||||
!dmu_objset_userobjspace_present(zsb->z_os))
|
||||
return (SET_ERROR(ENOTSUP));
|
||||
|
||||
obj = zfs_userquota_prop_to_obj(zsb, type);
|
||||
if (obj == 0)
|
||||
if (obj == ZFS_NO_OBJECT)
|
||||
return (0);
|
||||
|
||||
err = id_to_fuidstr(zsb, domain, rid, buf, B_FALSE);
|
||||
if (type == ZFS_PROP_USEROBJUSED || type == ZFS_PROP_GROUPOBJUSED) {
|
||||
strncpy(buf, DMU_OBJACCT_PREFIX, DMU_OBJACCT_PREFIX_LEN);
|
||||
offset = DMU_OBJACCT_PREFIX_LEN;
|
||||
}
|
||||
|
||||
err = id_to_fuidstr(zsb, domain, rid, buf + offset, B_FALSE);
|
||||
if (err)
|
||||
return (err);
|
||||
|
||||
@@ -545,14 +578,25 @@ zfs_set_userquota(zfs_sb_t *zsb, zfs_userquota_prop_t type,
|
||||
uint64_t *objp;
|
||||
boolean_t fuid_dirtied;
|
||||
|
||||
if (type != ZFS_PROP_USERQUOTA && type != ZFS_PROP_GROUPQUOTA)
|
||||
return (SET_ERROR(EINVAL));
|
||||
|
||||
if (zsb->z_version < ZPL_VERSION_USERSPACE)
|
||||
return (SET_ERROR(ENOTSUP));
|
||||
|
||||
objp = (type == ZFS_PROP_USERQUOTA) ? &zsb->z_userquota_obj :
|
||||
&zsb->z_groupquota_obj;
|
||||
switch (type) {
|
||||
case ZFS_PROP_USERQUOTA:
|
||||
objp = &zsb->z_userquota_obj;
|
||||
break;
|
||||
case ZFS_PROP_GROUPQUOTA:
|
||||
objp = &zsb->z_groupquota_obj;
|
||||
break;
|
||||
case ZFS_PROP_USEROBJQUOTA:
|
||||
objp = &zsb->z_userobjquota_obj;
|
||||
break;
|
||||
case ZFS_PROP_GROUPOBJQUOTA:
|
||||
objp = &zsb->z_groupobjquota_obj;
|
||||
break;
|
||||
default:
|
||||
return (SET_ERROR(EINVAL));
|
||||
}
|
||||
|
||||
err = id_to_fuidstr(zsb, domain, rid, buf, B_TRUE);
|
||||
if (err)
|
||||
@@ -597,10 +641,40 @@ zfs_set_userquota(zfs_sb_t *zsb, zfs_userquota_prop_t type,
|
||||
}
|
||||
EXPORT_SYMBOL(zfs_set_userquota);
|
||||
|
||||
boolean_t
|
||||
zfs_fuid_overobjquota(zfs_sb_t *zsb, boolean_t isgroup, uint64_t fuid)
|
||||
{
|
||||
char buf[20 + DMU_OBJACCT_PREFIX_LEN];
|
||||
uint64_t used, quota, usedobj, quotaobj;
|
||||
int err;
|
||||
|
||||
if (!dmu_objset_userobjspace_present(zsb->z_os)) {
|
||||
if (dmu_objset_userobjspace_upgradable(zsb->z_os))
|
||||
dmu_objset_userobjspace_upgrade(zsb->z_os);
|
||||
return (B_FALSE);
|
||||
}
|
||||
|
||||
usedobj = isgroup ? DMU_GROUPUSED_OBJECT : DMU_USERUSED_OBJECT;
|
||||
quotaobj = isgroup ? zsb->z_groupobjquota_obj : zsb->z_userobjquota_obj;
|
||||
if (quotaobj == 0 || zsb->z_replay)
|
||||
return (B_FALSE);
|
||||
|
||||
(void) sprintf(buf, "%llx", (longlong_t)fuid);
|
||||
err = zap_lookup(zsb->z_os, quotaobj, buf, 8, 1, "a);
|
||||
if (err != 0)
|
||||
return (B_FALSE);
|
||||
|
||||
(void) sprintf(buf, DMU_OBJACCT_PREFIX "%llx", (longlong_t)fuid);
|
||||
err = zap_lookup(zsb->z_os, usedobj, buf, 8, 1, &used);
|
||||
if (err != 0)
|
||||
return (B_FALSE);
|
||||
return (used >= quota);
|
||||
}
|
||||
|
||||
boolean_t
|
||||
zfs_fuid_overquota(zfs_sb_t *zsb, boolean_t isgroup, uint64_t fuid)
|
||||
{
|
||||
char buf[32];
|
||||
char buf[20];
|
||||
uint64_t used, quota, usedobj, quotaobj;
|
||||
int err;
|
||||
|
||||
@@ -777,6 +851,18 @@ zfs_sb_create(const char *osname, zfs_mntopts_t *zmo, zfs_sb_t **zsbp)
|
||||
if (error && error != ENOENT)
|
||||
goto out;
|
||||
|
||||
error = zap_lookup(os, MASTER_NODE_OBJ,
|
||||
zfs_userquota_prop_prefixes[ZFS_PROP_USEROBJQUOTA],
|
||||
8, 1, &zsb->z_userobjquota_obj);
|
||||
if (error && error != ENOENT)
|
||||
goto out;
|
||||
|
||||
error = zap_lookup(os, MASTER_NODE_OBJ,
|
||||
zfs_userquota_prop_prefixes[ZFS_PROP_GROUPOBJQUOTA],
|
||||
8, 1, &zsb->z_groupobjquota_obj);
|
||||
if (error && error != ENOENT)
|
||||
goto out;
|
||||
|
||||
error = zap_lookup(os, MASTER_NODE_OBJ, ZFS_FUID_TABLES, 8, 1,
|
||||
&zsb->z_fuid_obj);
|
||||
if (error && error != ENOENT)
|
||||
|
||||
Reference in New Issue
Block a user