From 1de321e6260f5b83eb943b6ce2166a3879f42df4 Mon Sep 17 00:00:00 2001 From: Jinshan Xiong Date: Tue, 4 Oct 2016 11:46:10 -0700 Subject: 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 Signed-off-by: Johann Lombardi --- module/zfs/zfs_vfsops.c | 112 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 99 insertions(+), 13 deletions(-) (limited to 'module/zfs/zfs_vfsops.c') diff --git a/module/zfs/zfs_vfsops.c b/module/zfs/zfs_vfsops.c index d8b27461a..63b7f9230 100644 --- a/module/zfs/zfs_vfsops.c +++ b/module/zfs/zfs_vfsops.c @@ -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) -- cgit v1.2.3