Relocate common quota functions to shared code
The quota functions are common to all implementations and can be moved to common code. As a simplification they were moved to the Linux platform code in the initial refactoring. Reviewed-by: Jorgen Lundman <lundman@lundman.net> Reviewed-by: Igor Kozhukhov <igor@dilos.org> Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Signed-off-by: Ryan Moeller <ryan@ixsystems.com> Closes #9710
This commit is contained in:
parent
4bc721965f
commit
957c7aa23c
|
@ -198,18 +198,6 @@ extern int zfs_suspend_fs(zfsvfs_t *zfsvfs);
|
|||
extern int zfs_resume_fs(zfsvfs_t *zfsvfs, struct dsl_dataset *ds);
|
||||
extern int zfs_end_fs(zfsvfs_t *zfsvfs, struct dsl_dataset *ds);
|
||||
extern void zfs_exit_fs(zfsvfs_t *zfsvfs);
|
||||
extern int zfs_userspace_one(zfsvfs_t *zfsvfs, zfs_userquota_prop_t type,
|
||||
const char *domain, uint64_t rid, uint64_t *valuep);
|
||||
extern int zfs_userspace_many(zfsvfs_t *zfsvfs, zfs_userquota_prop_t type,
|
||||
uint64_t *cookiep, void *vbuf, uint64_t *bufsizep);
|
||||
extern int zfs_set_userquota(zfsvfs_t *zfsvfs, zfs_userquota_prop_t type,
|
||||
const char *domain, uint64_t rid, uint64_t quota);
|
||||
extern boolean_t zfs_id_overblockquota(zfsvfs_t *zfsvfs, uint64_t usedobj,
|
||||
uint64_t id);
|
||||
extern boolean_t zfs_id_overobjquota(zfsvfs_t *zfsvfs, uint64_t usedobj,
|
||||
uint64_t id);
|
||||
extern boolean_t zfs_id_overquota(zfsvfs_t *zfsvfs, uint64_t usedobj,
|
||||
uint64_t id);
|
||||
extern int zfs_set_version(zfsvfs_t *zfsvfs, uint64_t newvers);
|
||||
extern int zfsvfs_create(const char *name, boolean_t readony, zfsvfs_t **zfvp);
|
||||
extern int zfsvfs_create_impl(zfsvfs_t **zfvp, zfsvfs_t *zfsvfs, objset_t *os);
|
||||
|
|
|
@ -107,6 +107,7 @@ COMMON_H = \
|
|||
$(top_srcdir)/include/sys/zfs_file.h \
|
||||
$(top_srcdir)/include/sys/zfs_fuid.h \
|
||||
$(top_srcdir)/include/sys/zfs_project.h \
|
||||
$(top_srcdir)/include/sys/zfs_quota.h \
|
||||
$(top_srcdir)/include/sys/zfs_ratelimit.h \
|
||||
$(top_srcdir)/include/sys/zfs_rlock.h \
|
||||
$(top_srcdir)/include/sys/zfs_sa.h \
|
||||
|
|
|
@ -116,6 +116,8 @@ extern int zfs_fuid_find_by_domain(zfsvfs_t *, const char *domain,
|
|||
char **retdomain, boolean_t addok);
|
||||
extern const char *zfs_fuid_find_by_idx(zfsvfs_t *zfsvfs, uint32_t idx);
|
||||
extern void zfs_fuid_txhold(zfsvfs_t *zfsvfs, dmu_tx_t *tx);
|
||||
extern int zfs_id_to_fuidstr(zfsvfs_t *zfsvfs, const char *domain, uid_t rid,
|
||||
char *buf, boolean_t addok);
|
||||
#endif
|
||||
|
||||
char *zfs_fuid_idx_domain(avl_tree_t *, uint32_t);
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* 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 http://www.opensolaris.org/os/licensing.
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifndef _SYS_ZFS_QUOTA_H
|
||||
#define _SYS_ZFS_QUOTA_H
|
||||
|
||||
#include <sys/dmu.h>
|
||||
#include <sys/fs/zfs.h>
|
||||
#include <sys/zfs_vfsops.h>
|
||||
|
||||
extern int zfs_space_delta_cb(dmu_object_type_t bonustype, void *data,
|
||||
uint64_t *userp, uint64_t *groupp, uint64_t *projectp);
|
||||
|
||||
extern int zfs_userspace_one(zfsvfs_t *zfsvfs, zfs_userquota_prop_t type,
|
||||
const char *domain, uint64_t rid, uint64_t *valuep);
|
||||
extern int zfs_userspace_many(zfsvfs_t *zfsvfs, zfs_userquota_prop_t type,
|
||||
uint64_t *cookiep, void *vbuf, uint64_t *bufsizep);
|
||||
extern int zfs_set_userquota(zfsvfs_t *zfsvfs, zfs_userquota_prop_t type,
|
||||
const char *domain, uint64_t rid, uint64_t quota);
|
||||
|
||||
extern boolean_t zfs_id_overobjquota(zfsvfs_t *zfsvfs, uint64_t usedobj,
|
||||
uint64_t id);
|
||||
extern boolean_t zfs_id_overblockquota(zfsvfs_t *zfsvfs, uint64_t usedobj,
|
||||
uint64_t id);
|
||||
extern boolean_t zfs_id_overquota(zfsvfs_t *zfsvfs, uint64_t usedobj,
|
||||
uint64_t id);
|
||||
|
||||
#endif
|
|
@ -42,6 +42,7 @@
|
|||
#include <sys/zfs_fuid.h>
|
||||
#include <sys/zfs_acl.h>
|
||||
#include <sys/zfs_dir.h>
|
||||
#include <sys/zfs_quota.h>
|
||||
#include <sys/zfs_vfsops.h>
|
||||
#include <sys/dmu.h>
|
||||
#include <sys/dnode.h>
|
||||
|
|
|
@ -52,6 +52,7 @@
|
|||
#include <sys/zfs_ioctl.h>
|
||||
#include <sys/zfs_ctldir.h>
|
||||
#include <sys/zfs_fuid.h>
|
||||
#include <sys/zfs_quota.h>
|
||||
#include <sys/sunddi.h>
|
||||
#include <sys/dmu_objset.h>
|
||||
#include <sys/spa_boot.h>
|
||||
|
@ -608,454 +609,6 @@ zfs_get_temporary_prop(dsl_dataset_t *ds, zfs_prop_t zfs_prop, uint64_t *val,
|
|||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
zfs_space_delta_cb(dmu_object_type_t bonustype, void *data,
|
||||
uint64_t *userp, uint64_t *groupp, uint64_t *projectp)
|
||||
{
|
||||
sa_hdr_phys_t sa;
|
||||
sa_hdr_phys_t *sap = data;
|
||||
uint64_t flags;
|
||||
int hdrsize;
|
||||
boolean_t swap = B_FALSE;
|
||||
|
||||
/*
|
||||
* Is it a valid type of object to track?
|
||||
*/
|
||||
if (bonustype != DMU_OT_ZNODE && bonustype != DMU_OT_SA)
|
||||
return (SET_ERROR(ENOENT));
|
||||
|
||||
/*
|
||||
* If we have a NULL data pointer
|
||||
* then assume the id's aren't changing and
|
||||
* return EEXIST to the dmu to let it know to
|
||||
* use the same ids
|
||||
*/
|
||||
if (data == NULL)
|
||||
return (SET_ERROR(EEXIST));
|
||||
|
||||
if (bonustype == DMU_OT_ZNODE) {
|
||||
znode_phys_t *znp = data;
|
||||
*userp = znp->zp_uid;
|
||||
*groupp = znp->zp_gid;
|
||||
*projectp = ZFS_DEFAULT_PROJID;
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (sap->sa_magic == 0) {
|
||||
/*
|
||||
* This should only happen for newly created files
|
||||
* that haven't had the znode data filled in yet.
|
||||
*/
|
||||
*userp = 0;
|
||||
*groupp = 0;
|
||||
*projectp = ZFS_DEFAULT_PROJID;
|
||||
return (0);
|
||||
}
|
||||
|
||||
sa = *sap;
|
||||
if (sa.sa_magic == BSWAP_32(SA_MAGIC)) {
|
||||
sa.sa_magic = SA_MAGIC;
|
||||
sa.sa_layout_info = BSWAP_16(sa.sa_layout_info);
|
||||
swap = B_TRUE;
|
||||
} else {
|
||||
VERIFY3U(sa.sa_magic, ==, SA_MAGIC);
|
||||
}
|
||||
|
||||
hdrsize = sa_hdrsize(&sa);
|
||||
VERIFY3U(hdrsize, >=, sizeof (sa_hdr_phys_t));
|
||||
|
||||
*userp = *((uint64_t *)((uintptr_t)data + hdrsize + SA_UID_OFFSET));
|
||||
*groupp = *((uint64_t *)((uintptr_t)data + hdrsize + SA_GID_OFFSET));
|
||||
flags = *((uint64_t *)((uintptr_t)data + hdrsize + SA_FLAGS_OFFSET));
|
||||
if (swap)
|
||||
flags = BSWAP_64(flags);
|
||||
|
||||
if (flags & ZFS_PROJID)
|
||||
*projectp = *((uint64_t *)((uintptr_t)data + hdrsize +
|
||||
SA_PROJID_OFFSET));
|
||||
else
|
||||
*projectp = ZFS_DEFAULT_PROJID;
|
||||
|
||||
if (swap) {
|
||||
*userp = BSWAP_64(*userp);
|
||||
*groupp = BSWAP_64(*groupp);
|
||||
*projectp = BSWAP_64(*projectp);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
fuidstr_to_sid(zfsvfs_t *zfsvfs, const char *fuidstr,
|
||||
char *domainbuf, int buflen, uid_t *ridp)
|
||||
{
|
||||
uint64_t fuid;
|
||||
const char *domain;
|
||||
|
||||
fuid = zfs_strtonum(fuidstr, NULL);
|
||||
|
||||
domain = zfs_fuid_find_by_idx(zfsvfs, FUID_INDEX(fuid));
|
||||
if (domain)
|
||||
(void) strlcpy(domainbuf, domain, buflen);
|
||||
else
|
||||
domainbuf[0] = '\0';
|
||||
*ridp = FUID_RID(fuid);
|
||||
}
|
||||
|
||||
static uint64_t
|
||||
zfs_userquota_prop_to_obj(zfsvfs_t *zfsvfs, 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_PROJECTUSED:
|
||||
case ZFS_PROP_PROJECTOBJUSED:
|
||||
return (DMU_PROJECTUSED_OBJECT);
|
||||
case ZFS_PROP_USERQUOTA:
|
||||
return (zfsvfs->z_userquota_obj);
|
||||
case ZFS_PROP_GROUPQUOTA:
|
||||
return (zfsvfs->z_groupquota_obj);
|
||||
case ZFS_PROP_USEROBJQUOTA:
|
||||
return (zfsvfs->z_userobjquota_obj);
|
||||
case ZFS_PROP_GROUPOBJQUOTA:
|
||||
return (zfsvfs->z_groupobjquota_obj);
|
||||
case ZFS_PROP_PROJECTQUOTA:
|
||||
return (zfsvfs->z_projectquota_obj);
|
||||
case ZFS_PROP_PROJECTOBJQUOTA:
|
||||
return (zfsvfs->z_projectobjquota_obj);
|
||||
default:
|
||||
return (ZFS_NO_OBJECT);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
zfs_userspace_many(zfsvfs_t *zfsvfs, zfs_userquota_prop_t type,
|
||||
uint64_t *cookiep, void *vbuf, uint64_t *bufsizep)
|
||||
{
|
||||
int error;
|
||||
zap_cursor_t zc;
|
||||
zap_attribute_t za;
|
||||
zfs_useracct_t *buf = vbuf;
|
||||
uint64_t obj;
|
||||
int offset = 0;
|
||||
|
||||
if (!dmu_objset_userspace_present(zfsvfs->z_os))
|
||||
return (SET_ERROR(ENOTSUP));
|
||||
|
||||
if ((type == ZFS_PROP_PROJECTQUOTA || type == ZFS_PROP_PROJECTUSED ||
|
||||
type == ZFS_PROP_PROJECTOBJQUOTA ||
|
||||
type == ZFS_PROP_PROJECTOBJUSED) &&
|
||||
!dmu_objset_projectquota_present(zfsvfs->z_os))
|
||||
return (SET_ERROR(ENOTSUP));
|
||||
|
||||
if ((type == ZFS_PROP_USEROBJUSED || type == ZFS_PROP_GROUPOBJUSED ||
|
||||
type == ZFS_PROP_USEROBJQUOTA || type == ZFS_PROP_GROUPOBJQUOTA ||
|
||||
type == ZFS_PROP_PROJECTOBJUSED ||
|
||||
type == ZFS_PROP_PROJECTOBJQUOTA) &&
|
||||
!dmu_objset_userobjspace_present(zfsvfs->z_os))
|
||||
return (SET_ERROR(ENOTSUP));
|
||||
|
||||
obj = zfs_userquota_prop_to_obj(zfsvfs, type);
|
||||
if (obj == ZFS_NO_OBJECT) {
|
||||
*bufsizep = 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (type == ZFS_PROP_USEROBJUSED || type == ZFS_PROP_GROUPOBJUSED ||
|
||||
type == ZFS_PROP_PROJECTOBJUSED)
|
||||
offset = DMU_OBJACCT_PREFIX_LEN;
|
||||
|
||||
for (zap_cursor_init_serialized(&zc, zfsvfs->z_os, obj, *cookiep);
|
||||
(error = zap_cursor_retrieve(&zc, &za)) == 0;
|
||||
zap_cursor_advance(&zc)) {
|
||||
if ((uintptr_t)buf - (uintptr_t)vbuf + sizeof (zfs_useracct_t) >
|
||||
*bufsizep)
|
||||
break;
|
||||
|
||||
/*
|
||||
* 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(zfsvfs, za.za_name + offset,
|
||||
buf->zu_domain, sizeof (buf->zu_domain), &buf->zu_rid);
|
||||
|
||||
buf->zu_space = za.za_first_integer;
|
||||
buf++;
|
||||
}
|
||||
if (error == ENOENT)
|
||||
error = 0;
|
||||
|
||||
ASSERT3U((uintptr_t)buf - (uintptr_t)vbuf, <=, *bufsizep);
|
||||
*bufsizep = (uintptr_t)buf - (uintptr_t)vbuf;
|
||||
*cookiep = zap_cursor_serialize(&zc);
|
||||
zap_cursor_fini(&zc);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* buf must be big enough (eg, 32 bytes)
|
||||
*/
|
||||
static int
|
||||
id_to_fuidstr(zfsvfs_t *zfsvfs, const char *domain, uid_t rid,
|
||||
char *buf, boolean_t addok)
|
||||
{
|
||||
uint64_t fuid;
|
||||
int domainid = 0;
|
||||
|
||||
if (domain && domain[0]) {
|
||||
domainid = zfs_fuid_find_by_domain(zfsvfs, domain, NULL, addok);
|
||||
if (domainid == -1)
|
||||
return (SET_ERROR(ENOENT));
|
||||
}
|
||||
fuid = FUID_ENCODE(domainid, rid);
|
||||
(void) sprintf(buf, "%llx", (longlong_t)fuid);
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
zfs_userspace_one(zfsvfs_t *zfsvfs, zfs_userquota_prop_t type,
|
||||
const char *domain, uint64_t rid, uint64_t *valp)
|
||||
{
|
||||
char buf[20 + DMU_OBJACCT_PREFIX_LEN];
|
||||
int offset = 0;
|
||||
int err;
|
||||
uint64_t obj;
|
||||
|
||||
*valp = 0;
|
||||
|
||||
if (!dmu_objset_userspace_present(zfsvfs->z_os))
|
||||
return (SET_ERROR(ENOTSUP));
|
||||
|
||||
if ((type == ZFS_PROP_USEROBJUSED || type == ZFS_PROP_GROUPOBJUSED ||
|
||||
type == ZFS_PROP_USEROBJQUOTA || type == ZFS_PROP_GROUPOBJQUOTA ||
|
||||
type == ZFS_PROP_PROJECTOBJUSED ||
|
||||
type == ZFS_PROP_PROJECTOBJQUOTA) &&
|
||||
!dmu_objset_userobjspace_present(zfsvfs->z_os))
|
||||
return (SET_ERROR(ENOTSUP));
|
||||
|
||||
if (type == ZFS_PROP_PROJECTQUOTA || type == ZFS_PROP_PROJECTUSED ||
|
||||
type == ZFS_PROP_PROJECTOBJQUOTA ||
|
||||
type == ZFS_PROP_PROJECTOBJUSED) {
|
||||
if (!dmu_objset_projectquota_present(zfsvfs->z_os))
|
||||
return (SET_ERROR(ENOTSUP));
|
||||
if (!zpl_is_valid_projid(rid))
|
||||
return (SET_ERROR(EINVAL));
|
||||
}
|
||||
|
||||
obj = zfs_userquota_prop_to_obj(zfsvfs, type);
|
||||
if (obj == ZFS_NO_OBJECT)
|
||||
return (0);
|
||||
|
||||
if (type == ZFS_PROP_USEROBJUSED || type == ZFS_PROP_GROUPOBJUSED ||
|
||||
type == ZFS_PROP_PROJECTOBJUSED) {
|
||||
strlcpy(buf, DMU_OBJACCT_PREFIX, DMU_OBJACCT_PREFIX_LEN + 1);
|
||||
offset = DMU_OBJACCT_PREFIX_LEN;
|
||||
}
|
||||
|
||||
err = id_to_fuidstr(zfsvfs, domain, rid, buf + offset, B_FALSE);
|
||||
if (err)
|
||||
return (err);
|
||||
|
||||
err = zap_lookup(zfsvfs->z_os, obj, buf, 8, 1, valp);
|
||||
if (err == ENOENT)
|
||||
err = 0;
|
||||
return (err);
|
||||
}
|
||||
|
||||
int
|
||||
zfs_set_userquota(zfsvfs_t *zfsvfs, zfs_userquota_prop_t type,
|
||||
const char *domain, uint64_t rid, uint64_t quota)
|
||||
{
|
||||
char buf[32];
|
||||
int err;
|
||||
dmu_tx_t *tx;
|
||||
uint64_t *objp;
|
||||
boolean_t fuid_dirtied;
|
||||
|
||||
if (zfsvfs->z_version < ZPL_VERSION_USERSPACE)
|
||||
return (SET_ERROR(ENOTSUP));
|
||||
|
||||
switch (type) {
|
||||
case ZFS_PROP_USERQUOTA:
|
||||
objp = &zfsvfs->z_userquota_obj;
|
||||
break;
|
||||
case ZFS_PROP_GROUPQUOTA:
|
||||
objp = &zfsvfs->z_groupquota_obj;
|
||||
break;
|
||||
case ZFS_PROP_USEROBJQUOTA:
|
||||
objp = &zfsvfs->z_userobjquota_obj;
|
||||
break;
|
||||
case ZFS_PROP_GROUPOBJQUOTA:
|
||||
objp = &zfsvfs->z_groupobjquota_obj;
|
||||
break;
|
||||
case ZFS_PROP_PROJECTQUOTA:
|
||||
if (!dmu_objset_projectquota_enabled(zfsvfs->z_os))
|
||||
return (SET_ERROR(ENOTSUP));
|
||||
if (!zpl_is_valid_projid(rid))
|
||||
return (SET_ERROR(EINVAL));
|
||||
|
||||
objp = &zfsvfs->z_projectquota_obj;
|
||||
break;
|
||||
case ZFS_PROP_PROJECTOBJQUOTA:
|
||||
if (!dmu_objset_projectquota_enabled(zfsvfs->z_os))
|
||||
return (SET_ERROR(ENOTSUP));
|
||||
if (!zpl_is_valid_projid(rid))
|
||||
return (SET_ERROR(EINVAL));
|
||||
|
||||
objp = &zfsvfs->z_projectobjquota_obj;
|
||||
break;
|
||||
default:
|
||||
return (SET_ERROR(EINVAL));
|
||||
}
|
||||
|
||||
err = id_to_fuidstr(zfsvfs, domain, rid, buf, B_TRUE);
|
||||
if (err)
|
||||
return (err);
|
||||
fuid_dirtied = zfsvfs->z_fuid_dirty;
|
||||
|
||||
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,
|
||||
zfs_userquota_prop_prefixes[type]);
|
||||
}
|
||||
if (fuid_dirtied)
|
||||
zfs_fuid_txhold(zfsvfs, tx);
|
||||
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,
|
||||
zfs_userquota_prop_prefixes[type], 8, 1, objp, tx));
|
||||
}
|
||||
mutex_exit(&zfsvfs->z_lock);
|
||||
|
||||
if (quota == 0) {
|
||||
err = zap_remove(zfsvfs->z_os, *objp, buf, tx);
|
||||
if (err == ENOENT)
|
||||
err = 0;
|
||||
} else {
|
||||
err = zap_update(zfsvfs->z_os, *objp, buf, 8, 1, "a, tx);
|
||||
}
|
||||
ASSERT(err == 0);
|
||||
if (fuid_dirtied)
|
||||
zfs_fuid_sync(zfsvfs, tx);
|
||||
dmu_tx_commit(tx);
|
||||
return (err);
|
||||
}
|
||||
|
||||
boolean_t
|
||||
zfs_id_overobjquota(zfsvfs_t *zfsvfs, uint64_t usedobj, uint64_t id)
|
||||
{
|
||||
char buf[20 + DMU_OBJACCT_PREFIX_LEN];
|
||||
uint64_t used, quota, quotaobj;
|
||||
int err;
|
||||
|
||||
if (!dmu_objset_userobjspace_present(zfsvfs->z_os)) {
|
||||
if (dmu_objset_userobjspace_upgradable(zfsvfs->z_os)) {
|
||||
dsl_pool_config_enter(
|
||||
dmu_objset_pool(zfsvfs->z_os), FTAG);
|
||||
dmu_objset_id_quota_upgrade(zfsvfs->z_os);
|
||||
dsl_pool_config_exit(
|
||||
dmu_objset_pool(zfsvfs->z_os), FTAG);
|
||||
}
|
||||
return (B_FALSE);
|
||||
}
|
||||
|
||||
if (usedobj == DMU_PROJECTUSED_OBJECT) {
|
||||
if (!dmu_objset_projectquota_present(zfsvfs->z_os)) {
|
||||
if (dmu_objset_projectquota_upgradable(zfsvfs->z_os)) {
|
||||
dsl_pool_config_enter(
|
||||
dmu_objset_pool(zfsvfs->z_os), FTAG);
|
||||
dmu_objset_id_quota_upgrade(zfsvfs->z_os);
|
||||
dsl_pool_config_exit(
|
||||
dmu_objset_pool(zfsvfs->z_os), FTAG);
|
||||
}
|
||||
return (B_FALSE);
|
||||
}
|
||||
quotaobj = zfsvfs->z_projectobjquota_obj;
|
||||
} else if (usedobj == DMU_USERUSED_OBJECT) {
|
||||
quotaobj = zfsvfs->z_userobjquota_obj;
|
||||
} else if (usedobj == DMU_GROUPUSED_OBJECT) {
|
||||
quotaobj = zfsvfs->z_groupobjquota_obj;
|
||||
} else {
|
||||
return (B_FALSE);
|
||||
}
|
||||
if (quotaobj == 0 || zfsvfs->z_replay)
|
||||
return (B_FALSE);
|
||||
|
||||
(void) sprintf(buf, "%llx", (longlong_t)id);
|
||||
err = zap_lookup(zfsvfs->z_os, quotaobj, buf, 8, 1, "a);
|
||||
if (err != 0)
|
||||
return (B_FALSE);
|
||||
|
||||
(void) sprintf(buf, DMU_OBJACCT_PREFIX "%llx", (longlong_t)id);
|
||||
err = zap_lookup(zfsvfs->z_os, usedobj, buf, 8, 1, &used);
|
||||
if (err != 0)
|
||||
return (B_FALSE);
|
||||
return (used >= quota);
|
||||
}
|
||||
|
||||
boolean_t
|
||||
zfs_id_overblockquota(zfsvfs_t *zfsvfs, uint64_t usedobj, uint64_t id)
|
||||
{
|
||||
char buf[20];
|
||||
uint64_t used, quota, quotaobj;
|
||||
int err;
|
||||
|
||||
if (usedobj == DMU_PROJECTUSED_OBJECT) {
|
||||
if (!dmu_objset_projectquota_present(zfsvfs->z_os)) {
|
||||
if (dmu_objset_projectquota_upgradable(zfsvfs->z_os)) {
|
||||
dsl_pool_config_enter(
|
||||
dmu_objset_pool(zfsvfs->z_os), FTAG);
|
||||
dmu_objset_id_quota_upgrade(zfsvfs->z_os);
|
||||
dsl_pool_config_exit(
|
||||
dmu_objset_pool(zfsvfs->z_os), FTAG);
|
||||
}
|
||||
return (B_FALSE);
|
||||
}
|
||||
quotaobj = zfsvfs->z_projectquota_obj;
|
||||
} else if (usedobj == DMU_USERUSED_OBJECT) {
|
||||
quotaobj = zfsvfs->z_userquota_obj;
|
||||
} else if (usedobj == DMU_GROUPUSED_OBJECT) {
|
||||
quotaobj = zfsvfs->z_groupquota_obj;
|
||||
} else {
|
||||
return (B_FALSE);
|
||||
}
|
||||
if (quotaobj == 0 || zfsvfs->z_replay)
|
||||
return (B_FALSE);
|
||||
|
||||
(void) sprintf(buf, "%llx", (longlong_t)id);
|
||||
err = zap_lookup(zfsvfs->z_os, quotaobj, buf, 8, 1, "a);
|
||||
if (err != 0)
|
||||
return (B_FALSE);
|
||||
|
||||
err = zap_lookup(zfsvfs->z_os, usedobj, buf, 8, 1, &used);
|
||||
if (err != 0)
|
||||
return (B_FALSE);
|
||||
return (used >= quota);
|
||||
}
|
||||
|
||||
boolean_t
|
||||
zfs_id_overquota(zfsvfs_t *zfsvfs, uint64_t usedobj, uint64_t id)
|
||||
{
|
||||
return (zfs_id_overblockquota(zfsvfs, usedobj, id) ||
|
||||
zfs_id_overobjquota(zfsvfs, usedobj, id));
|
||||
}
|
||||
|
||||
/*
|
||||
* Associate this zfsvfs with the given objset, which must be owned.
|
||||
* This will cache a bunch of on-disk state from the objset in the
|
||||
|
@ -1454,7 +1007,8 @@ zfs_statfs_project(zfsvfs_t *zfsvfs, znode_t *zp, struct kstatfs *statp,
|
|||
int err;
|
||||
|
||||
strlcpy(buf, DMU_OBJACCT_PREFIX, DMU_OBJACCT_PREFIX_LEN + 1);
|
||||
err = id_to_fuidstr(zfsvfs, NULL, zp->z_projid, buf + offset, B_FALSE);
|
||||
err = zfs_id_to_fuidstr(zfsvfs, NULL, zp->z_projid, buf + offset,
|
||||
B_FALSE);
|
||||
if (err)
|
||||
return (err);
|
||||
|
||||
|
@ -2575,12 +2129,6 @@ zfs_fini(void)
|
|||
#if defined(_KERNEL)
|
||||
EXPORT_SYMBOL(zfs_suspend_fs);
|
||||
EXPORT_SYMBOL(zfs_resume_fs);
|
||||
EXPORT_SYMBOL(zfs_userspace_one);
|
||||
EXPORT_SYMBOL(zfs_userspace_many);
|
||||
EXPORT_SYMBOL(zfs_set_userquota);
|
||||
EXPORT_SYMBOL(zfs_id_overblockquota);
|
||||
EXPORT_SYMBOL(zfs_id_overobjquota);
|
||||
EXPORT_SYMBOL(zfs_id_overquota);
|
||||
EXPORT_SYMBOL(zfs_set_version);
|
||||
EXPORT_SYMBOL(zfsvfs_create);
|
||||
EXPORT_SYMBOL(zfsvfs_free);
|
||||
|
|
|
@ -61,6 +61,7 @@
|
|||
#include <sys/sid.h>
|
||||
#include <sys/zfs_ctldir.h>
|
||||
#include <sys/zfs_fuid.h>
|
||||
#include <sys/zfs_quota.h>
|
||||
#include <sys/zfs_sa.h>
|
||||
#include <sys/zfs_vnops.h>
|
||||
#include <sys/zfs_rlock.h>
|
||||
|
|
|
@ -115,6 +115,7 @@ $(MODULE)-objs += zfs_fuid.o
|
|||
$(MODULE)-objs += zfs_ioctl.o
|
||||
$(MODULE)-objs += zfs_log.o
|
||||
$(MODULE)-objs += zfs_onexit.o
|
||||
$(MODULE)-objs += zfs_quota.o
|
||||
$(MODULE)-objs += zfs_ratelimit.o
|
||||
$(MODULE)-objs += zfs_replay.o
|
||||
$(MODULE)-objs += zfs_rlock.o
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#include <sys/zvol.h>
|
||||
|
||||
#ifdef _KERNEL
|
||||
#include <sys/zfs_quota.h>
|
||||
#include <sys/zfs_vfsops.h>
|
||||
#endif
|
||||
|
||||
|
|
|
@ -772,4 +772,24 @@ zfs_fuid_txhold(zfsvfs_t *zfsvfs, dmu_tx_t *tx)
|
|||
FUID_SIZE_ESTIMATE(zfsvfs));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* buf must be big enough (eg, 32 bytes)
|
||||
*/
|
||||
int
|
||||
zfs_id_to_fuidstr(zfsvfs_t *zfsvfs, const char *domain, uid_t rid,
|
||||
char *buf, boolean_t addok)
|
||||
{
|
||||
uint64_t fuid;
|
||||
int domainid = 0;
|
||||
|
||||
if (domain && domain[0]) {
|
||||
domainid = zfs_fuid_find_by_domain(zfsvfs, domain, NULL, addok);
|
||||
if (domainid == -1)
|
||||
return (SET_ERROR(ENOENT));
|
||||
}
|
||||
fuid = FUID_ENCODE(domainid, rid);
|
||||
(void) sprintf(buf, "%llx", (longlong_t)fuid);
|
||||
return (0);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -162,6 +162,7 @@
|
|||
#include <sys/cmn_err.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/zfs_ioctl.h>
|
||||
#include <sys/zfs_quota.h>
|
||||
#include <sys/zfs_vfsops.h>
|
||||
#include <sys/zfs_znode.h>
|
||||
#include <sys/zap.h>
|
||||
|
|
|
@ -0,0 +1,475 @@
|
|||
/*
|
||||
* 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 http://www.opensolaris.org/os/licensing.
|
||||
* 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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011 Pawel Jakub Dawidek <pawel@dawidek.net>.
|
||||
* All rights reserved.
|
||||
* Copyright (c) 2012, 2015, 2018 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2014 Integros [integros.com]
|
||||
* Copyright 2016 Nexenta Systems, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
/* Portions Copyright 2010 Robert Milkowski */
|
||||
|
||||
#include <sys/avl.h>
|
||||
#include <sys/dmu_objset.h>
|
||||
#include <sys/sa.h>
|
||||
#include <sys/sa_impl.h>
|
||||
#include <sys/zap.h>
|
||||
#include <sys/zfs_project.h>
|
||||
#include <sys/zfs_quota.h>
|
||||
#include <sys/zfs_znode.h>
|
||||
|
||||
int
|
||||
zfs_space_delta_cb(dmu_object_type_t bonustype, void *data,
|
||||
uint64_t *userp, uint64_t *groupp, uint64_t *projectp)
|
||||
{
|
||||
sa_hdr_phys_t sa;
|
||||
sa_hdr_phys_t *sap = data;
|
||||
uint64_t flags;
|
||||
int hdrsize;
|
||||
boolean_t swap = B_FALSE;
|
||||
|
||||
/*
|
||||
* Is it a valid type of object to track?
|
||||
*/
|
||||
if (bonustype != DMU_OT_ZNODE && bonustype != DMU_OT_SA)
|
||||
return (SET_ERROR(ENOENT));
|
||||
|
||||
/*
|
||||
* If we have a NULL data pointer
|
||||
* then assume the id's aren't changing and
|
||||
* return EEXIST to the dmu to let it know to
|
||||
* use the same ids
|
||||
*/
|
||||
if (data == NULL)
|
||||
return (SET_ERROR(EEXIST));
|
||||
|
||||
if (bonustype == DMU_OT_ZNODE) {
|
||||
znode_phys_t *znp = data;
|
||||
*userp = znp->zp_uid;
|
||||
*groupp = znp->zp_gid;
|
||||
*projectp = ZFS_DEFAULT_PROJID;
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (sap->sa_magic == 0) {
|
||||
/*
|
||||
* This should only happen for newly created files
|
||||
* that haven't had the znode data filled in yet.
|
||||
*/
|
||||
*userp = 0;
|
||||
*groupp = 0;
|
||||
*projectp = ZFS_DEFAULT_PROJID;
|
||||
return (0);
|
||||
}
|
||||
|
||||
sa = *sap;
|
||||
if (sa.sa_magic == BSWAP_32(SA_MAGIC)) {
|
||||
sa.sa_magic = SA_MAGIC;
|
||||
sa.sa_layout_info = BSWAP_16(sa.sa_layout_info);
|
||||
swap = B_TRUE;
|
||||
} else {
|
||||
VERIFY3U(sa.sa_magic, ==, SA_MAGIC);
|
||||
}
|
||||
|
||||
hdrsize = sa_hdrsize(&sa);
|
||||
VERIFY3U(hdrsize, >=, sizeof (sa_hdr_phys_t));
|
||||
|
||||
*userp = *((uint64_t *)((uintptr_t)data + hdrsize + SA_UID_OFFSET));
|
||||
*groupp = *((uint64_t *)((uintptr_t)data + hdrsize + SA_GID_OFFSET));
|
||||
flags = *((uint64_t *)((uintptr_t)data + hdrsize + SA_FLAGS_OFFSET));
|
||||
if (swap)
|
||||
flags = BSWAP_64(flags);
|
||||
|
||||
if (flags & ZFS_PROJID)
|
||||
*projectp = *((uint64_t *)((uintptr_t)data + hdrsize +
|
||||
SA_PROJID_OFFSET));
|
||||
else
|
||||
*projectp = ZFS_DEFAULT_PROJID;
|
||||
|
||||
if (swap) {
|
||||
*userp = BSWAP_64(*userp);
|
||||
*groupp = BSWAP_64(*groupp);
|
||||
*projectp = BSWAP_64(*projectp);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
fuidstr_to_sid(zfsvfs_t *zfsvfs, const char *fuidstr,
|
||||
char *domainbuf, int buflen, uid_t *ridp)
|
||||
{
|
||||
uint64_t fuid;
|
||||
const char *domain;
|
||||
|
||||
fuid = zfs_strtonum(fuidstr, NULL);
|
||||
|
||||
domain = zfs_fuid_find_by_idx(zfsvfs, FUID_INDEX(fuid));
|
||||
if (domain)
|
||||
(void) strlcpy(domainbuf, domain, buflen);
|
||||
else
|
||||
domainbuf[0] = '\0';
|
||||
*ridp = FUID_RID(fuid);
|
||||
}
|
||||
|
||||
static uint64_t
|
||||
zfs_userquota_prop_to_obj(zfsvfs_t *zfsvfs, 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_PROJECTUSED:
|
||||
case ZFS_PROP_PROJECTOBJUSED:
|
||||
return (DMU_PROJECTUSED_OBJECT);
|
||||
case ZFS_PROP_USERQUOTA:
|
||||
return (zfsvfs->z_userquota_obj);
|
||||
case ZFS_PROP_GROUPQUOTA:
|
||||
return (zfsvfs->z_groupquota_obj);
|
||||
case ZFS_PROP_USEROBJQUOTA:
|
||||
return (zfsvfs->z_userobjquota_obj);
|
||||
case ZFS_PROP_GROUPOBJQUOTA:
|
||||
return (zfsvfs->z_groupobjquota_obj);
|
||||
case ZFS_PROP_PROJECTQUOTA:
|
||||
return (zfsvfs->z_projectquota_obj);
|
||||
case ZFS_PROP_PROJECTOBJQUOTA:
|
||||
return (zfsvfs->z_projectobjquota_obj);
|
||||
default:
|
||||
return (ZFS_NO_OBJECT);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
zfs_userspace_many(zfsvfs_t *zfsvfs, zfs_userquota_prop_t type,
|
||||
uint64_t *cookiep, void *vbuf, uint64_t *bufsizep)
|
||||
{
|
||||
int error;
|
||||
zap_cursor_t zc;
|
||||
zap_attribute_t za;
|
||||
zfs_useracct_t *buf = vbuf;
|
||||
uint64_t obj;
|
||||
int offset = 0;
|
||||
|
||||
if (!dmu_objset_userspace_present(zfsvfs->z_os))
|
||||
return (SET_ERROR(ENOTSUP));
|
||||
|
||||
if ((type == ZFS_PROP_PROJECTQUOTA || type == ZFS_PROP_PROJECTUSED ||
|
||||
type == ZFS_PROP_PROJECTOBJQUOTA ||
|
||||
type == ZFS_PROP_PROJECTOBJUSED) &&
|
||||
!dmu_objset_projectquota_present(zfsvfs->z_os))
|
||||
return (SET_ERROR(ENOTSUP));
|
||||
|
||||
if ((type == ZFS_PROP_USEROBJUSED || type == ZFS_PROP_GROUPOBJUSED ||
|
||||
type == ZFS_PROP_USEROBJQUOTA || type == ZFS_PROP_GROUPOBJQUOTA ||
|
||||
type == ZFS_PROP_PROJECTOBJUSED ||
|
||||
type == ZFS_PROP_PROJECTOBJQUOTA) &&
|
||||
!dmu_objset_userobjspace_present(zfsvfs->z_os))
|
||||
return (SET_ERROR(ENOTSUP));
|
||||
|
||||
obj = zfs_userquota_prop_to_obj(zfsvfs, type);
|
||||
if (obj == ZFS_NO_OBJECT) {
|
||||
*bufsizep = 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (type == ZFS_PROP_USEROBJUSED || type == ZFS_PROP_GROUPOBJUSED ||
|
||||
type == ZFS_PROP_PROJECTOBJUSED)
|
||||
offset = DMU_OBJACCT_PREFIX_LEN;
|
||||
|
||||
for (zap_cursor_init_serialized(&zc, zfsvfs->z_os, obj, *cookiep);
|
||||
(error = zap_cursor_retrieve(&zc, &za)) == 0;
|
||||
zap_cursor_advance(&zc)) {
|
||||
if ((uintptr_t)buf - (uintptr_t)vbuf + sizeof (zfs_useracct_t) >
|
||||
*bufsizep)
|
||||
break;
|
||||
|
||||
/*
|
||||
* 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(zfsvfs, za.za_name + offset,
|
||||
buf->zu_domain, sizeof (buf->zu_domain), &buf->zu_rid);
|
||||
|
||||
buf->zu_space = za.za_first_integer;
|
||||
buf++;
|
||||
}
|
||||
if (error == ENOENT)
|
||||
error = 0;
|
||||
|
||||
ASSERT3U((uintptr_t)buf - (uintptr_t)vbuf, <=, *bufsizep);
|
||||
*bufsizep = (uintptr_t)buf - (uintptr_t)vbuf;
|
||||
*cookiep = zap_cursor_serialize(&zc);
|
||||
zap_cursor_fini(&zc);
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
zfs_userspace_one(zfsvfs_t *zfsvfs, zfs_userquota_prop_t type,
|
||||
const char *domain, uint64_t rid, uint64_t *valp)
|
||||
{
|
||||
char buf[20 + DMU_OBJACCT_PREFIX_LEN];
|
||||
int offset = 0;
|
||||
int err;
|
||||
uint64_t obj;
|
||||
|
||||
*valp = 0;
|
||||
|
||||
if (!dmu_objset_userspace_present(zfsvfs->z_os))
|
||||
return (SET_ERROR(ENOTSUP));
|
||||
|
||||
if ((type == ZFS_PROP_USEROBJUSED || type == ZFS_PROP_GROUPOBJUSED ||
|
||||
type == ZFS_PROP_USEROBJQUOTA || type == ZFS_PROP_GROUPOBJQUOTA ||
|
||||
type == ZFS_PROP_PROJECTOBJUSED ||
|
||||
type == ZFS_PROP_PROJECTOBJQUOTA) &&
|
||||
!dmu_objset_userobjspace_present(zfsvfs->z_os))
|
||||
return (SET_ERROR(ENOTSUP));
|
||||
|
||||
if (type == ZFS_PROP_PROJECTQUOTA || type == ZFS_PROP_PROJECTUSED ||
|
||||
type == ZFS_PROP_PROJECTOBJQUOTA ||
|
||||
type == ZFS_PROP_PROJECTOBJUSED) {
|
||||
if (!dmu_objset_projectquota_present(zfsvfs->z_os))
|
||||
return (SET_ERROR(ENOTSUP));
|
||||
if (!zpl_is_valid_projid(rid))
|
||||
return (SET_ERROR(EINVAL));
|
||||
}
|
||||
|
||||
obj = zfs_userquota_prop_to_obj(zfsvfs, type);
|
||||
if (obj == ZFS_NO_OBJECT)
|
||||
return (0);
|
||||
|
||||
if (type == ZFS_PROP_USEROBJUSED || type == ZFS_PROP_GROUPOBJUSED ||
|
||||
type == ZFS_PROP_PROJECTOBJUSED) {
|
||||
strlcpy(buf, DMU_OBJACCT_PREFIX, DMU_OBJACCT_PREFIX_LEN + 1);
|
||||
offset = DMU_OBJACCT_PREFIX_LEN;
|
||||
}
|
||||
|
||||
err = zfs_id_to_fuidstr(zfsvfs, domain, rid, buf + offset, B_FALSE);
|
||||
if (err)
|
||||
return (err);
|
||||
|
||||
err = zap_lookup(zfsvfs->z_os, obj, buf, 8, 1, valp);
|
||||
if (err == ENOENT)
|
||||
err = 0;
|
||||
return (err);
|
||||
}
|
||||
|
||||
int
|
||||
zfs_set_userquota(zfsvfs_t *zfsvfs, zfs_userquota_prop_t type,
|
||||
const char *domain, uint64_t rid, uint64_t quota)
|
||||
{
|
||||
char buf[32];
|
||||
int err;
|
||||
dmu_tx_t *tx;
|
||||
uint64_t *objp;
|
||||
boolean_t fuid_dirtied;
|
||||
|
||||
if (zfsvfs->z_version < ZPL_VERSION_USERSPACE)
|
||||
return (SET_ERROR(ENOTSUP));
|
||||
|
||||
switch (type) {
|
||||
case ZFS_PROP_USERQUOTA:
|
||||
objp = &zfsvfs->z_userquota_obj;
|
||||
break;
|
||||
case ZFS_PROP_GROUPQUOTA:
|
||||
objp = &zfsvfs->z_groupquota_obj;
|
||||
break;
|
||||
case ZFS_PROP_USEROBJQUOTA:
|
||||
objp = &zfsvfs->z_userobjquota_obj;
|
||||
break;
|
||||
case ZFS_PROP_GROUPOBJQUOTA:
|
||||
objp = &zfsvfs->z_groupobjquota_obj;
|
||||
break;
|
||||
case ZFS_PROP_PROJECTQUOTA:
|
||||
if (!dmu_objset_projectquota_enabled(zfsvfs->z_os))
|
||||
return (SET_ERROR(ENOTSUP));
|
||||
if (!zpl_is_valid_projid(rid))
|
||||
return (SET_ERROR(EINVAL));
|
||||
|
||||
objp = &zfsvfs->z_projectquota_obj;
|
||||
break;
|
||||
case ZFS_PROP_PROJECTOBJQUOTA:
|
||||
if (!dmu_objset_projectquota_enabled(zfsvfs->z_os))
|
||||
return (SET_ERROR(ENOTSUP));
|
||||
if (!zpl_is_valid_projid(rid))
|
||||
return (SET_ERROR(EINVAL));
|
||||
|
||||
objp = &zfsvfs->z_projectobjquota_obj;
|
||||
break;
|
||||
default:
|
||||
return (SET_ERROR(EINVAL));
|
||||
}
|
||||
|
||||
err = zfs_id_to_fuidstr(zfsvfs, domain, rid, buf, B_TRUE);
|
||||
if (err)
|
||||
return (err);
|
||||
fuid_dirtied = zfsvfs->z_fuid_dirty;
|
||||
|
||||
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,
|
||||
zfs_userquota_prop_prefixes[type]);
|
||||
}
|
||||
if (fuid_dirtied)
|
||||
zfs_fuid_txhold(zfsvfs, tx);
|
||||
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,
|
||||
zfs_userquota_prop_prefixes[type], 8, 1, objp, tx));
|
||||
}
|
||||
mutex_exit(&zfsvfs->z_lock);
|
||||
|
||||
if (quota == 0) {
|
||||
err = zap_remove(zfsvfs->z_os, *objp, buf, tx);
|
||||
if (err == ENOENT)
|
||||
err = 0;
|
||||
} else {
|
||||
err = zap_update(zfsvfs->z_os, *objp, buf, 8, 1, "a, tx);
|
||||
}
|
||||
ASSERT(err == 0);
|
||||
if (fuid_dirtied)
|
||||
zfs_fuid_sync(zfsvfs, tx);
|
||||
dmu_tx_commit(tx);
|
||||
return (err);
|
||||
}
|
||||
|
||||
boolean_t
|
||||
zfs_id_overobjquota(zfsvfs_t *zfsvfs, uint64_t usedobj, uint64_t id)
|
||||
{
|
||||
char buf[20 + DMU_OBJACCT_PREFIX_LEN];
|
||||
uint64_t used, quota, quotaobj;
|
||||
int err;
|
||||
|
||||
if (!dmu_objset_userobjspace_present(zfsvfs->z_os)) {
|
||||
if (dmu_objset_userobjspace_upgradable(zfsvfs->z_os)) {
|
||||
dsl_pool_config_enter(
|
||||
dmu_objset_pool(zfsvfs->z_os), FTAG);
|
||||
dmu_objset_id_quota_upgrade(zfsvfs->z_os);
|
||||
dsl_pool_config_exit(
|
||||
dmu_objset_pool(zfsvfs->z_os), FTAG);
|
||||
}
|
||||
return (B_FALSE);
|
||||
}
|
||||
|
||||
if (usedobj == DMU_PROJECTUSED_OBJECT) {
|
||||
if (!dmu_objset_projectquota_present(zfsvfs->z_os)) {
|
||||
if (dmu_objset_projectquota_upgradable(zfsvfs->z_os)) {
|
||||
dsl_pool_config_enter(
|
||||
dmu_objset_pool(zfsvfs->z_os), FTAG);
|
||||
dmu_objset_id_quota_upgrade(zfsvfs->z_os);
|
||||
dsl_pool_config_exit(
|
||||
dmu_objset_pool(zfsvfs->z_os), FTAG);
|
||||
}
|
||||
return (B_FALSE);
|
||||
}
|
||||
quotaobj = zfsvfs->z_projectobjquota_obj;
|
||||
} else if (usedobj == DMU_USERUSED_OBJECT) {
|
||||
quotaobj = zfsvfs->z_userobjquota_obj;
|
||||
} else if (usedobj == DMU_GROUPUSED_OBJECT) {
|
||||
quotaobj = zfsvfs->z_groupobjquota_obj;
|
||||
} else {
|
||||
return (B_FALSE);
|
||||
}
|
||||
if (quotaobj == 0 || zfsvfs->z_replay)
|
||||
return (B_FALSE);
|
||||
|
||||
(void) sprintf(buf, "%llx", (longlong_t)id);
|
||||
err = zap_lookup(zfsvfs->z_os, quotaobj, buf, 8, 1, "a);
|
||||
if (err != 0)
|
||||
return (B_FALSE);
|
||||
|
||||
(void) sprintf(buf, DMU_OBJACCT_PREFIX "%llx", (longlong_t)id);
|
||||
err = zap_lookup(zfsvfs->z_os, usedobj, buf, 8, 1, &used);
|
||||
if (err != 0)
|
||||
return (B_FALSE);
|
||||
return (used >= quota);
|
||||
}
|
||||
|
||||
boolean_t
|
||||
zfs_id_overblockquota(zfsvfs_t *zfsvfs, uint64_t usedobj, uint64_t id)
|
||||
{
|
||||
char buf[20];
|
||||
uint64_t used, quota, quotaobj;
|
||||
int err;
|
||||
|
||||
if (usedobj == DMU_PROJECTUSED_OBJECT) {
|
||||
if (!dmu_objset_projectquota_present(zfsvfs->z_os)) {
|
||||
if (dmu_objset_projectquota_upgradable(zfsvfs->z_os)) {
|
||||
dsl_pool_config_enter(
|
||||
dmu_objset_pool(zfsvfs->z_os), FTAG);
|
||||
dmu_objset_id_quota_upgrade(zfsvfs->z_os);
|
||||
dsl_pool_config_exit(
|
||||
dmu_objset_pool(zfsvfs->z_os), FTAG);
|
||||
}
|
||||
return (B_FALSE);
|
||||
}
|
||||
quotaobj = zfsvfs->z_projectquota_obj;
|
||||
} else if (usedobj == DMU_USERUSED_OBJECT) {
|
||||
quotaobj = zfsvfs->z_userquota_obj;
|
||||
} else if (usedobj == DMU_GROUPUSED_OBJECT) {
|
||||
quotaobj = zfsvfs->z_groupquota_obj;
|
||||
} else {
|
||||
return (B_FALSE);
|
||||
}
|
||||
if (quotaobj == 0 || zfsvfs->z_replay)
|
||||
return (B_FALSE);
|
||||
|
||||
(void) sprintf(buf, "%llx", (longlong_t)id);
|
||||
err = zap_lookup(zfsvfs->z_os, quotaobj, buf, 8, 1, "a);
|
||||
if (err != 0)
|
||||
return (B_FALSE);
|
||||
|
||||
err = zap_lookup(zfsvfs->z_os, usedobj, buf, 8, 1, &used);
|
||||
if (err != 0)
|
||||
return (B_FALSE);
|
||||
return (used >= quota);
|
||||
}
|
||||
|
||||
boolean_t
|
||||
zfs_id_overquota(zfsvfs_t *zfsvfs, uint64_t usedobj, uint64_t id)
|
||||
{
|
||||
return (zfs_id_overblockquota(zfsvfs, usedobj, id) ||
|
||||
zfs_id_overobjquota(zfsvfs, usedobj, id));
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(zfs_space_delta_cb);
|
||||
EXPORT_SYMBOL(zfs_userspace_one);
|
||||
EXPORT_SYMBOL(zfs_userspace_many);
|
||||
EXPORT_SYMBOL(zfs_set_userquota);
|
||||
EXPORT_SYMBOL(zfs_id_overblockquota);
|
||||
EXPORT_SYMBOL(zfs_id_overobjquota);
|
||||
EXPORT_SYMBOL(zfs_id_overquota);
|
Loading…
Reference in New Issue