xref: /freebsd/sys/contrib/openzfs/module/zfs/zfs_quota.c (revision 6c1e79df8c651b31ca4f656336e6c5ac29a66482)
1eda14cbcSMatt Macy /*
2eda14cbcSMatt Macy  * CDDL HEADER START
3eda14cbcSMatt Macy  *
4eda14cbcSMatt Macy  * The contents of this file are subject to the terms of the
5eda14cbcSMatt Macy  * Common Development and Distribution License (the "License").
6eda14cbcSMatt Macy  * You may not use this file except in compliance with the License.
7eda14cbcSMatt Macy  *
8eda14cbcSMatt Macy  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9271171e0SMartin Matuska  * or https://opensource.org/licenses/CDDL-1.0.
10eda14cbcSMatt Macy  * See the License for the specific language governing permissions
11eda14cbcSMatt Macy  * and limitations under the License.
12eda14cbcSMatt Macy  *
13eda14cbcSMatt Macy  * When distributing Covered Code, include this CDDL HEADER in each
14eda14cbcSMatt Macy  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15eda14cbcSMatt Macy  * If applicable, add the following below this CDDL HEADER, with the
16eda14cbcSMatt Macy  * fields enclosed by brackets "[]" replaced with your own identifying
17eda14cbcSMatt Macy  * information: Portions Copyright [yyyy] [name of copyright owner]
18eda14cbcSMatt Macy  *
19eda14cbcSMatt Macy  * CDDL HEADER END
20eda14cbcSMatt Macy  */
21eda14cbcSMatt Macy /*
22eda14cbcSMatt Macy  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
232a58b312SMartin Matuska  * Copyright (c) 2011 Pawel Jakub Dawidek
24eda14cbcSMatt Macy  * Copyright (c) 2012, 2015, 2018 by Delphix. All rights reserved.
25eda14cbcSMatt Macy  * Copyright (c) 2014 Integros [integros.com]
26eda14cbcSMatt Macy  * Copyright 2016 Nexenta Systems, Inc. All rights reserved.
27eda14cbcSMatt Macy  */
28eda14cbcSMatt Macy 
29eda14cbcSMatt Macy /* Portions Copyright 2010 Robert Milkowski */
30eda14cbcSMatt Macy 
31eda14cbcSMatt Macy #include <sys/avl.h>
32eda14cbcSMatt Macy #include <sys/dmu_objset.h>
33eda14cbcSMatt Macy #include <sys/sa.h>
34eda14cbcSMatt Macy #include <sys/sa_impl.h>
35eda14cbcSMatt Macy #include <sys/zap.h>
36eda14cbcSMatt Macy #include <sys/zfs_project.h>
37eda14cbcSMatt Macy #include <sys/zfs_quota.h>
38eda14cbcSMatt Macy #include <sys/zfs_znode.h>
39eda14cbcSMatt Macy 
40eda14cbcSMatt Macy int
41eda14cbcSMatt Macy zpl_get_file_info(dmu_object_type_t bonustype, const void *data,
42eda14cbcSMatt Macy     zfs_file_info_t *zoi)
43eda14cbcSMatt Macy {
44eda14cbcSMatt Macy 	/*
45eda14cbcSMatt Macy 	 * Is it a valid type of object to track?
46eda14cbcSMatt Macy 	 */
47eda14cbcSMatt Macy 	if (bonustype != DMU_OT_ZNODE && bonustype != DMU_OT_SA)
48eda14cbcSMatt Macy 		return (SET_ERROR(ENOENT));
49eda14cbcSMatt Macy 
50eda14cbcSMatt Macy 	zoi->zfi_project = ZFS_DEFAULT_PROJID;
51eda14cbcSMatt Macy 
52eda14cbcSMatt Macy 	/*
53eda14cbcSMatt Macy 	 * If we have a NULL data pointer
54eda14cbcSMatt Macy 	 * then assume the id's aren't changing and
55eda14cbcSMatt Macy 	 * return EEXIST to the dmu to let it know to
56eda14cbcSMatt Macy 	 * use the same ids
57eda14cbcSMatt Macy 	 */
58eda14cbcSMatt Macy 	if (data == NULL)
59eda14cbcSMatt Macy 		return (SET_ERROR(EEXIST));
60eda14cbcSMatt Macy 
61eda14cbcSMatt Macy 	if (bonustype == DMU_OT_ZNODE) {
62eda14cbcSMatt Macy 		const znode_phys_t *znp = data;
63eda14cbcSMatt Macy 		zoi->zfi_user = znp->zp_uid;
64eda14cbcSMatt Macy 		zoi->zfi_group = znp->zp_gid;
65eda14cbcSMatt Macy 		zoi->zfi_generation = znp->zp_gen;
66eda14cbcSMatt Macy 		return (0);
67eda14cbcSMatt Macy 	}
68eda14cbcSMatt Macy 
69eda14cbcSMatt Macy 	const sa_hdr_phys_t *sap = data;
70eda14cbcSMatt Macy 	if (sap->sa_magic == 0) {
71eda14cbcSMatt Macy 		/*
72eda14cbcSMatt Macy 		 * This should only happen for newly created files
73eda14cbcSMatt Macy 		 * that haven't had the znode data filled in yet.
74eda14cbcSMatt Macy 		 */
75eda14cbcSMatt Macy 		zoi->zfi_user = 0;
76eda14cbcSMatt Macy 		zoi->zfi_group = 0;
77eda14cbcSMatt Macy 		zoi->zfi_generation = 0;
78eda14cbcSMatt Macy 		return (0);
79eda14cbcSMatt Macy 	}
80eda14cbcSMatt Macy 
81eda14cbcSMatt Macy 	sa_hdr_phys_t sa = *sap;
82eda14cbcSMatt Macy 	boolean_t swap = B_FALSE;
83eda14cbcSMatt Macy 	if (sa.sa_magic == BSWAP_32(SA_MAGIC)) {
84eda14cbcSMatt Macy 		sa.sa_magic = SA_MAGIC;
85eda14cbcSMatt Macy 		sa.sa_layout_info = BSWAP_16(sa.sa_layout_info);
86eda14cbcSMatt Macy 		swap = B_TRUE;
87eda14cbcSMatt Macy 	}
88eda14cbcSMatt Macy 	VERIFY3U(sa.sa_magic, ==, SA_MAGIC);
89eda14cbcSMatt Macy 
90eda14cbcSMatt Macy 	int hdrsize = sa_hdrsize(&sa);
91eda14cbcSMatt Macy 	VERIFY3U(hdrsize, >=, sizeof (sa_hdr_phys_t));
92eda14cbcSMatt Macy 
93eda14cbcSMatt Macy 	uintptr_t data_after_hdr = (uintptr_t)data + hdrsize;
94eda14cbcSMatt Macy 	zoi->zfi_user = *((uint64_t *)(data_after_hdr + SA_UID_OFFSET));
95eda14cbcSMatt Macy 	zoi->zfi_group = *((uint64_t *)(data_after_hdr + SA_GID_OFFSET));
96eda14cbcSMatt Macy 	zoi->zfi_generation = *((uint64_t *)(data_after_hdr + SA_GEN_OFFSET));
97eda14cbcSMatt Macy 	uint64_t flags = *((uint64_t *)(data_after_hdr + SA_FLAGS_OFFSET));
98eda14cbcSMatt Macy 	if (swap)
99eda14cbcSMatt Macy 		flags = BSWAP_64(flags);
100eda14cbcSMatt Macy 
101eda14cbcSMatt Macy 	if (flags & ZFS_PROJID) {
102eda14cbcSMatt Macy 		zoi->zfi_project =
103eda14cbcSMatt Macy 		    *((uint64_t *)(data_after_hdr + SA_PROJID_OFFSET));
104eda14cbcSMatt Macy 	}
105eda14cbcSMatt Macy 
106eda14cbcSMatt Macy 	if (swap) {
107eda14cbcSMatt Macy 		zoi->zfi_user = BSWAP_64(zoi->zfi_user);
108eda14cbcSMatt Macy 		zoi->zfi_group = BSWAP_64(zoi->zfi_group);
109eda14cbcSMatt Macy 		zoi->zfi_project = BSWAP_64(zoi->zfi_project);
110eda14cbcSMatt Macy 		zoi->zfi_generation = BSWAP_64(zoi->zfi_generation);
111eda14cbcSMatt Macy 	}
112eda14cbcSMatt Macy 	return (0);
113eda14cbcSMatt Macy }
114eda14cbcSMatt Macy 
115eda14cbcSMatt Macy static void
116eda14cbcSMatt Macy fuidstr_to_sid(zfsvfs_t *zfsvfs, const char *fuidstr,
117eda14cbcSMatt Macy     char *domainbuf, int buflen, uid_t *ridp)
118eda14cbcSMatt Macy {
119eda14cbcSMatt Macy 	uint64_t fuid;
120eda14cbcSMatt Macy 	const char *domain;
121eda14cbcSMatt Macy 
122eda14cbcSMatt Macy 	fuid = zfs_strtonum(fuidstr, NULL);
123eda14cbcSMatt Macy 
124eda14cbcSMatt Macy 	domain = zfs_fuid_find_by_idx(zfsvfs, FUID_INDEX(fuid));
125eda14cbcSMatt Macy 	if (domain)
126eda14cbcSMatt Macy 		(void) strlcpy(domainbuf, domain, buflen);
127eda14cbcSMatt Macy 	else
128eda14cbcSMatt Macy 		domainbuf[0] = '\0';
129eda14cbcSMatt Macy 	*ridp = FUID_RID(fuid);
130eda14cbcSMatt Macy }
131eda14cbcSMatt Macy 
132eda14cbcSMatt Macy static uint64_t
133eda14cbcSMatt Macy zfs_userquota_prop_to_obj(zfsvfs_t *zfsvfs, zfs_userquota_prop_t type)
134eda14cbcSMatt Macy {
135eda14cbcSMatt Macy 	switch (type) {
136eda14cbcSMatt Macy 	case ZFS_PROP_USERUSED:
137eda14cbcSMatt Macy 	case ZFS_PROP_USEROBJUSED:
138eda14cbcSMatt Macy 		return (DMU_USERUSED_OBJECT);
139eda14cbcSMatt Macy 	case ZFS_PROP_GROUPUSED:
140eda14cbcSMatt Macy 	case ZFS_PROP_GROUPOBJUSED:
141eda14cbcSMatt Macy 		return (DMU_GROUPUSED_OBJECT);
142eda14cbcSMatt Macy 	case ZFS_PROP_PROJECTUSED:
143eda14cbcSMatt Macy 	case ZFS_PROP_PROJECTOBJUSED:
144eda14cbcSMatt Macy 		return (DMU_PROJECTUSED_OBJECT);
145eda14cbcSMatt Macy 	case ZFS_PROP_USERQUOTA:
146eda14cbcSMatt Macy 		return (zfsvfs->z_userquota_obj);
147eda14cbcSMatt Macy 	case ZFS_PROP_GROUPQUOTA:
148eda14cbcSMatt Macy 		return (zfsvfs->z_groupquota_obj);
149eda14cbcSMatt Macy 	case ZFS_PROP_USEROBJQUOTA:
150eda14cbcSMatt Macy 		return (zfsvfs->z_userobjquota_obj);
151eda14cbcSMatt Macy 	case ZFS_PROP_GROUPOBJQUOTA:
152eda14cbcSMatt Macy 		return (zfsvfs->z_groupobjquota_obj);
153eda14cbcSMatt Macy 	case ZFS_PROP_PROJECTQUOTA:
154eda14cbcSMatt Macy 		return (zfsvfs->z_projectquota_obj);
155eda14cbcSMatt Macy 	case ZFS_PROP_PROJECTOBJQUOTA:
156eda14cbcSMatt Macy 		return (zfsvfs->z_projectobjquota_obj);
157eda14cbcSMatt Macy 	default:
158eda14cbcSMatt Macy 		return (ZFS_NO_OBJECT);
159eda14cbcSMatt Macy 	}
160eda14cbcSMatt Macy }
161eda14cbcSMatt Macy 
162eda14cbcSMatt Macy int
163eda14cbcSMatt Macy zfs_userspace_many(zfsvfs_t *zfsvfs, zfs_userquota_prop_t type,
164eda14cbcSMatt Macy     uint64_t *cookiep, void *vbuf, uint64_t *bufsizep)
165eda14cbcSMatt Macy {
166eda14cbcSMatt Macy 	int error;
167eda14cbcSMatt Macy 	zap_cursor_t zc;
168eda14cbcSMatt Macy 	zap_attribute_t za;
169eda14cbcSMatt Macy 	zfs_useracct_t *buf = vbuf;
170eda14cbcSMatt Macy 	uint64_t obj;
171eda14cbcSMatt Macy 	int offset = 0;
172eda14cbcSMatt Macy 
173eda14cbcSMatt Macy 	if (!dmu_objset_userspace_present(zfsvfs->z_os))
174eda14cbcSMatt Macy 		return (SET_ERROR(ENOTSUP));
175eda14cbcSMatt Macy 
176eda14cbcSMatt Macy 	if ((type == ZFS_PROP_PROJECTQUOTA || type == ZFS_PROP_PROJECTUSED ||
177eda14cbcSMatt Macy 	    type == ZFS_PROP_PROJECTOBJQUOTA ||
178eda14cbcSMatt Macy 	    type == ZFS_PROP_PROJECTOBJUSED) &&
179eda14cbcSMatt Macy 	    !dmu_objset_projectquota_present(zfsvfs->z_os))
180eda14cbcSMatt Macy 		return (SET_ERROR(ENOTSUP));
181eda14cbcSMatt Macy 
182eda14cbcSMatt Macy 	if ((type == ZFS_PROP_USEROBJUSED || type == ZFS_PROP_GROUPOBJUSED ||
183eda14cbcSMatt Macy 	    type == ZFS_PROP_USEROBJQUOTA || type == ZFS_PROP_GROUPOBJQUOTA ||
184eda14cbcSMatt Macy 	    type == ZFS_PROP_PROJECTOBJUSED ||
185eda14cbcSMatt Macy 	    type == ZFS_PROP_PROJECTOBJQUOTA) &&
186eda14cbcSMatt Macy 	    !dmu_objset_userobjspace_present(zfsvfs->z_os))
187eda14cbcSMatt Macy 		return (SET_ERROR(ENOTSUP));
188eda14cbcSMatt Macy 
189eda14cbcSMatt Macy 	obj = zfs_userquota_prop_to_obj(zfsvfs, type);
190eda14cbcSMatt Macy 	if (obj == ZFS_NO_OBJECT) {
191eda14cbcSMatt Macy 		*bufsizep = 0;
192eda14cbcSMatt Macy 		return (0);
193eda14cbcSMatt Macy 	}
194eda14cbcSMatt Macy 
195eda14cbcSMatt Macy 	if (type == ZFS_PROP_USEROBJUSED || type == ZFS_PROP_GROUPOBJUSED ||
196eda14cbcSMatt Macy 	    type == ZFS_PROP_PROJECTOBJUSED)
197eda14cbcSMatt Macy 		offset = DMU_OBJACCT_PREFIX_LEN;
198eda14cbcSMatt Macy 
199eda14cbcSMatt Macy 	for (zap_cursor_init_serialized(&zc, zfsvfs->z_os, obj, *cookiep);
200eda14cbcSMatt Macy 	    (error = zap_cursor_retrieve(&zc, &za)) == 0;
201eda14cbcSMatt Macy 	    zap_cursor_advance(&zc)) {
202eda14cbcSMatt Macy 		if ((uintptr_t)buf - (uintptr_t)vbuf + sizeof (zfs_useracct_t) >
203eda14cbcSMatt Macy 		    *bufsizep)
204eda14cbcSMatt Macy 			break;
205eda14cbcSMatt Macy 
206eda14cbcSMatt Macy 		/*
207eda14cbcSMatt Macy 		 * skip object quota (with zap name prefix DMU_OBJACCT_PREFIX)
208eda14cbcSMatt Macy 		 * when dealing with block quota and vice versa.
209eda14cbcSMatt Macy 		 */
210eda14cbcSMatt Macy 		if ((offset > 0) != (strncmp(za.za_name, DMU_OBJACCT_PREFIX,
211eda14cbcSMatt Macy 		    DMU_OBJACCT_PREFIX_LEN) == 0))
212eda14cbcSMatt Macy 			continue;
213eda14cbcSMatt Macy 
214eda14cbcSMatt Macy 		fuidstr_to_sid(zfsvfs, za.za_name + offset,
215eda14cbcSMatt Macy 		    buf->zu_domain, sizeof (buf->zu_domain), &buf->zu_rid);
216eda14cbcSMatt Macy 
217eda14cbcSMatt Macy 		buf->zu_space = za.za_first_integer;
218eda14cbcSMatt Macy 		buf++;
219eda14cbcSMatt Macy 	}
220eda14cbcSMatt Macy 	if (error == ENOENT)
221eda14cbcSMatt Macy 		error = 0;
222eda14cbcSMatt Macy 
223eda14cbcSMatt Macy 	ASSERT3U((uintptr_t)buf - (uintptr_t)vbuf, <=, *bufsizep);
224eda14cbcSMatt Macy 	*bufsizep = (uintptr_t)buf - (uintptr_t)vbuf;
225eda14cbcSMatt Macy 	*cookiep = zap_cursor_serialize(&zc);
226eda14cbcSMatt Macy 	zap_cursor_fini(&zc);
227eda14cbcSMatt Macy 	return (error);
228eda14cbcSMatt Macy }
229eda14cbcSMatt Macy 
230eda14cbcSMatt Macy int
231eda14cbcSMatt Macy zfs_userspace_one(zfsvfs_t *zfsvfs, zfs_userquota_prop_t type,
232eda14cbcSMatt Macy     const char *domain, uint64_t rid, uint64_t *valp)
233eda14cbcSMatt Macy {
234eda14cbcSMatt Macy 	char buf[20 + DMU_OBJACCT_PREFIX_LEN];
235eda14cbcSMatt Macy 	int offset = 0;
236eda14cbcSMatt Macy 	int err;
237eda14cbcSMatt Macy 	uint64_t obj;
238eda14cbcSMatt Macy 
239eda14cbcSMatt Macy 	*valp = 0;
240eda14cbcSMatt Macy 
241eda14cbcSMatt Macy 	if (!dmu_objset_userspace_present(zfsvfs->z_os))
242eda14cbcSMatt Macy 		return (SET_ERROR(ENOTSUP));
243eda14cbcSMatt Macy 
244eda14cbcSMatt Macy 	if ((type == ZFS_PROP_USEROBJUSED || type == ZFS_PROP_GROUPOBJUSED ||
245eda14cbcSMatt Macy 	    type == ZFS_PROP_USEROBJQUOTA || type == ZFS_PROP_GROUPOBJQUOTA ||
246eda14cbcSMatt Macy 	    type == ZFS_PROP_PROJECTOBJUSED ||
247eda14cbcSMatt Macy 	    type == ZFS_PROP_PROJECTOBJQUOTA) &&
248eda14cbcSMatt Macy 	    !dmu_objset_userobjspace_present(zfsvfs->z_os))
249eda14cbcSMatt Macy 		return (SET_ERROR(ENOTSUP));
250eda14cbcSMatt Macy 
251eda14cbcSMatt Macy 	if (type == ZFS_PROP_PROJECTQUOTA || type == ZFS_PROP_PROJECTUSED ||
252eda14cbcSMatt Macy 	    type == ZFS_PROP_PROJECTOBJQUOTA ||
253eda14cbcSMatt Macy 	    type == ZFS_PROP_PROJECTOBJUSED) {
254eda14cbcSMatt Macy 		if (!dmu_objset_projectquota_present(zfsvfs->z_os))
255eda14cbcSMatt Macy 			return (SET_ERROR(ENOTSUP));
256eda14cbcSMatt Macy 		if (!zpl_is_valid_projid(rid))
257eda14cbcSMatt Macy 			return (SET_ERROR(EINVAL));
258eda14cbcSMatt Macy 	}
259eda14cbcSMatt Macy 
260eda14cbcSMatt Macy 	obj = zfs_userquota_prop_to_obj(zfsvfs, type);
261eda14cbcSMatt Macy 	if (obj == ZFS_NO_OBJECT)
262eda14cbcSMatt Macy 		return (0);
263eda14cbcSMatt Macy 
264eda14cbcSMatt Macy 	if (type == ZFS_PROP_USEROBJUSED || type == ZFS_PROP_GROUPOBJUSED ||
265eda14cbcSMatt Macy 	    type == ZFS_PROP_PROJECTOBJUSED) {
266eda14cbcSMatt Macy 		strlcpy(buf, DMU_OBJACCT_PREFIX, DMU_OBJACCT_PREFIX_LEN + 1);
267eda14cbcSMatt Macy 		offset = DMU_OBJACCT_PREFIX_LEN;
268eda14cbcSMatt Macy 	}
269eda14cbcSMatt Macy 
270eda14cbcSMatt Macy 	err = zfs_id_to_fuidstr(zfsvfs, domain, rid, buf + offset,
271eda14cbcSMatt Macy 	    sizeof (buf) - offset, B_FALSE);
272eda14cbcSMatt Macy 	if (err)
273eda14cbcSMatt Macy 		return (err);
274eda14cbcSMatt Macy 
275eda14cbcSMatt Macy 	err = zap_lookup(zfsvfs->z_os, obj, buf, 8, 1, valp);
276eda14cbcSMatt Macy 	if (err == ENOENT)
277eda14cbcSMatt Macy 		err = 0;
278eda14cbcSMatt Macy 	return (err);
279eda14cbcSMatt Macy }
280eda14cbcSMatt Macy 
281eda14cbcSMatt Macy int
282eda14cbcSMatt Macy zfs_set_userquota(zfsvfs_t *zfsvfs, zfs_userquota_prop_t type,
283eda14cbcSMatt Macy     const char *domain, uint64_t rid, uint64_t quota)
284eda14cbcSMatt Macy {
285eda14cbcSMatt Macy 	char buf[32];
286eda14cbcSMatt Macy 	int err;
287eda14cbcSMatt Macy 	dmu_tx_t *tx;
288eda14cbcSMatt Macy 	uint64_t *objp;
289eda14cbcSMatt Macy 	boolean_t fuid_dirtied;
290eda14cbcSMatt Macy 
291eda14cbcSMatt Macy 	if (zfsvfs->z_version < ZPL_VERSION_USERSPACE)
292eda14cbcSMatt Macy 		return (SET_ERROR(ENOTSUP));
293eda14cbcSMatt Macy 
294eda14cbcSMatt Macy 	switch (type) {
295eda14cbcSMatt Macy 	case ZFS_PROP_USERQUOTA:
296eda14cbcSMatt Macy 		objp = &zfsvfs->z_userquota_obj;
297eda14cbcSMatt Macy 		break;
298eda14cbcSMatt Macy 	case ZFS_PROP_GROUPQUOTA:
299eda14cbcSMatt Macy 		objp = &zfsvfs->z_groupquota_obj;
300eda14cbcSMatt Macy 		break;
301eda14cbcSMatt Macy 	case ZFS_PROP_USEROBJQUOTA:
302eda14cbcSMatt Macy 		objp = &zfsvfs->z_userobjquota_obj;
303eda14cbcSMatt Macy 		break;
304eda14cbcSMatt Macy 	case ZFS_PROP_GROUPOBJQUOTA:
305eda14cbcSMatt Macy 		objp = &zfsvfs->z_groupobjquota_obj;
306eda14cbcSMatt Macy 		break;
307eda14cbcSMatt Macy 	case ZFS_PROP_PROJECTQUOTA:
308eda14cbcSMatt Macy 		if (!dmu_objset_projectquota_enabled(zfsvfs->z_os))
309eda14cbcSMatt Macy 			return (SET_ERROR(ENOTSUP));
310eda14cbcSMatt Macy 		if (!zpl_is_valid_projid(rid))
311eda14cbcSMatt Macy 			return (SET_ERROR(EINVAL));
312eda14cbcSMatt Macy 
313eda14cbcSMatt Macy 		objp = &zfsvfs->z_projectquota_obj;
314eda14cbcSMatt Macy 		break;
315eda14cbcSMatt Macy 	case ZFS_PROP_PROJECTOBJQUOTA:
316eda14cbcSMatt Macy 		if (!dmu_objset_projectquota_enabled(zfsvfs->z_os))
317eda14cbcSMatt Macy 			return (SET_ERROR(ENOTSUP));
318eda14cbcSMatt Macy 		if (!zpl_is_valid_projid(rid))
319eda14cbcSMatt Macy 			return (SET_ERROR(EINVAL));
320eda14cbcSMatt Macy 
321eda14cbcSMatt Macy 		objp = &zfsvfs->z_projectobjquota_obj;
322eda14cbcSMatt Macy 		break;
323eda14cbcSMatt Macy 	default:
324eda14cbcSMatt Macy 		return (SET_ERROR(EINVAL));
325eda14cbcSMatt Macy 	}
326eda14cbcSMatt Macy 
327eda14cbcSMatt Macy 	err = zfs_id_to_fuidstr(zfsvfs, domain, rid, buf, sizeof (buf), B_TRUE);
328eda14cbcSMatt Macy 	if (err)
329eda14cbcSMatt Macy 		return (err);
330eda14cbcSMatt Macy 	fuid_dirtied = zfsvfs->z_fuid_dirty;
331eda14cbcSMatt Macy 
332eda14cbcSMatt Macy 	tx = dmu_tx_create(zfsvfs->z_os);
333eda14cbcSMatt Macy 	dmu_tx_hold_zap(tx, *objp ? *objp : DMU_NEW_OBJECT, B_TRUE, NULL);
334eda14cbcSMatt Macy 	if (*objp == 0) {
335eda14cbcSMatt Macy 		dmu_tx_hold_zap(tx, MASTER_NODE_OBJ, B_TRUE,
336eda14cbcSMatt Macy 		    zfs_userquota_prop_prefixes[type]);
337eda14cbcSMatt Macy 	}
338eda14cbcSMatt Macy 	if (fuid_dirtied)
339eda14cbcSMatt Macy 		zfs_fuid_txhold(zfsvfs, tx);
340eda14cbcSMatt Macy 	err = dmu_tx_assign(tx, TXG_WAIT);
341eda14cbcSMatt Macy 	if (err) {
342eda14cbcSMatt Macy 		dmu_tx_abort(tx);
343eda14cbcSMatt Macy 		return (err);
344eda14cbcSMatt Macy 	}
345eda14cbcSMatt Macy 
346eda14cbcSMatt Macy 	mutex_enter(&zfsvfs->z_lock);
347eda14cbcSMatt Macy 	if (*objp == 0) {
348eda14cbcSMatt Macy 		*objp = zap_create(zfsvfs->z_os, DMU_OT_USERGROUP_QUOTA,
349eda14cbcSMatt Macy 		    DMU_OT_NONE, 0, tx);
350*6c1e79dfSMartin Matuska 		VERIFY(0 == zap_add(zfsvfs->z_os, MASTER_NODE_OBJ,
351eda14cbcSMatt Macy 		    zfs_userquota_prop_prefixes[type], 8, 1, objp, tx));
352eda14cbcSMatt Macy 	}
353*6c1e79dfSMartin Matuska 	mutex_exit(&zfsvfs->z_lock);
354eda14cbcSMatt Macy 
355eda14cbcSMatt Macy 	if (quota == 0) {
356eda14cbcSMatt Macy 		err = zap_remove(zfsvfs->z_os, *objp, buf, tx);
357eda14cbcSMatt Macy 		if (err == ENOENT)
358eda14cbcSMatt Macy 			err = 0;
359eda14cbcSMatt Macy 	} else {
360eda14cbcSMatt Macy 		err = zap_update(zfsvfs->z_os, *objp, buf, 8, 1, &quota, tx);
361eda14cbcSMatt Macy 	}
362eda14cbcSMatt Macy 	ASSERT(err == 0);
363eda14cbcSMatt Macy 	if (fuid_dirtied)
364eda14cbcSMatt Macy 		zfs_fuid_sync(zfsvfs, tx);
365eda14cbcSMatt Macy 	dmu_tx_commit(tx);
366eda14cbcSMatt Macy 	return (err);
367eda14cbcSMatt Macy }
368eda14cbcSMatt Macy 
369eda14cbcSMatt Macy boolean_t
370eda14cbcSMatt Macy zfs_id_overobjquota(zfsvfs_t *zfsvfs, uint64_t usedobj, uint64_t id)
371eda14cbcSMatt Macy {
372eda14cbcSMatt Macy 	char buf[20 + DMU_OBJACCT_PREFIX_LEN];
373eda14cbcSMatt Macy 	uint64_t used, quota, quotaobj;
374eda14cbcSMatt Macy 	int err;
375eda14cbcSMatt Macy 
376eda14cbcSMatt Macy 	if (!dmu_objset_userobjspace_present(zfsvfs->z_os)) {
377eda14cbcSMatt Macy 		if (dmu_objset_userobjspace_upgradable(zfsvfs->z_os)) {
378eda14cbcSMatt Macy 			dsl_pool_config_enter(
379eda14cbcSMatt Macy 			    dmu_objset_pool(zfsvfs->z_os), FTAG);
380eda14cbcSMatt Macy 			dmu_objset_id_quota_upgrade(zfsvfs->z_os);
381eda14cbcSMatt Macy 			dsl_pool_config_exit(
382eda14cbcSMatt Macy 			    dmu_objset_pool(zfsvfs->z_os), FTAG);
383eda14cbcSMatt Macy 		}
384eda14cbcSMatt Macy 		return (B_FALSE);
385eda14cbcSMatt Macy 	}
386eda14cbcSMatt Macy 
387eda14cbcSMatt Macy 	if (usedobj == DMU_PROJECTUSED_OBJECT) {
388eda14cbcSMatt Macy 		if (!dmu_objset_projectquota_present(zfsvfs->z_os)) {
389eda14cbcSMatt Macy 			if (dmu_objset_projectquota_upgradable(zfsvfs->z_os)) {
390eda14cbcSMatt Macy 				dsl_pool_config_enter(
391eda14cbcSMatt Macy 				    dmu_objset_pool(zfsvfs->z_os), FTAG);
392eda14cbcSMatt Macy 				dmu_objset_id_quota_upgrade(zfsvfs->z_os);
393eda14cbcSMatt Macy 				dsl_pool_config_exit(
394eda14cbcSMatt Macy 				    dmu_objset_pool(zfsvfs->z_os), FTAG);
395eda14cbcSMatt Macy 			}
396eda14cbcSMatt Macy 			return (B_FALSE);
397eda14cbcSMatt Macy 		}
398eda14cbcSMatt Macy 		quotaobj = zfsvfs->z_projectobjquota_obj;
399eda14cbcSMatt Macy 	} else if (usedobj == DMU_USERUSED_OBJECT) {
400eda14cbcSMatt Macy 		quotaobj = zfsvfs->z_userobjquota_obj;
401eda14cbcSMatt Macy 	} else if (usedobj == DMU_GROUPUSED_OBJECT) {
402eda14cbcSMatt Macy 		quotaobj = zfsvfs->z_groupobjquota_obj;
403eda14cbcSMatt Macy 	} else {
404eda14cbcSMatt Macy 		return (B_FALSE);
405eda14cbcSMatt Macy 	}
406eda14cbcSMatt Macy 	if (quotaobj == 0 || zfsvfs->z_replay)
407eda14cbcSMatt Macy 		return (B_FALSE);
408eda14cbcSMatt Macy 
409eda14cbcSMatt Macy 	(void) snprintf(buf, sizeof (buf), "%llx", (longlong_t)id);
410eda14cbcSMatt Macy 	err = zap_lookup(zfsvfs->z_os, quotaobj, buf, 8, 1, &quota);
411eda14cbcSMatt Macy 	if (err != 0)
412eda14cbcSMatt Macy 		return (B_FALSE);
413eda14cbcSMatt Macy 
414eda14cbcSMatt Macy 	(void) snprintf(buf, sizeof (buf), DMU_OBJACCT_PREFIX "%llx",
415eda14cbcSMatt Macy 	    (longlong_t)id);
416eda14cbcSMatt Macy 	err = zap_lookup(zfsvfs->z_os, usedobj, buf, 8, 1, &used);
417eda14cbcSMatt Macy 	if (err != 0)
418eda14cbcSMatt Macy 		return (B_FALSE);
419eda14cbcSMatt Macy 	return (used >= quota);
420eda14cbcSMatt Macy }
421eda14cbcSMatt Macy 
422eda14cbcSMatt Macy boolean_t
423eda14cbcSMatt Macy zfs_id_overblockquota(zfsvfs_t *zfsvfs, uint64_t usedobj, uint64_t id)
424eda14cbcSMatt Macy {
425eda14cbcSMatt Macy 	char buf[20];
426eda14cbcSMatt Macy 	uint64_t used, quota, quotaobj;
427eda14cbcSMatt Macy 	int err;
428eda14cbcSMatt Macy 
429eda14cbcSMatt Macy 	if (usedobj == DMU_PROJECTUSED_OBJECT) {
430eda14cbcSMatt Macy 		if (!dmu_objset_projectquota_present(zfsvfs->z_os)) {
431eda14cbcSMatt Macy 			if (dmu_objset_projectquota_upgradable(zfsvfs->z_os)) {
432eda14cbcSMatt Macy 				dsl_pool_config_enter(
433eda14cbcSMatt Macy 				    dmu_objset_pool(zfsvfs->z_os), FTAG);
434eda14cbcSMatt Macy 				dmu_objset_id_quota_upgrade(zfsvfs->z_os);
435eda14cbcSMatt Macy 				dsl_pool_config_exit(
436eda14cbcSMatt Macy 				    dmu_objset_pool(zfsvfs->z_os), FTAG);
437eda14cbcSMatt Macy 			}
438eda14cbcSMatt Macy 			return (B_FALSE);
439eda14cbcSMatt Macy 		}
440eda14cbcSMatt Macy 		quotaobj = zfsvfs->z_projectquota_obj;
441eda14cbcSMatt Macy 	} else if (usedobj == DMU_USERUSED_OBJECT) {
442eda14cbcSMatt Macy 		quotaobj = zfsvfs->z_userquota_obj;
443eda14cbcSMatt Macy 	} else if (usedobj == DMU_GROUPUSED_OBJECT) {
444eda14cbcSMatt Macy 		quotaobj = zfsvfs->z_groupquota_obj;
445eda14cbcSMatt Macy 	} else {
446eda14cbcSMatt Macy 		return (B_FALSE);
447eda14cbcSMatt Macy 	}
448eda14cbcSMatt Macy 	if (quotaobj == 0 || zfsvfs->z_replay)
449eda14cbcSMatt Macy 		return (B_FALSE);
450eda14cbcSMatt Macy 
451eda14cbcSMatt Macy 	(void) snprintf(buf, sizeof (buf), "%llx", (longlong_t)id);
452eda14cbcSMatt Macy 	err = zap_lookup(zfsvfs->z_os, quotaobj, buf, 8, 1, &quota);
453eda14cbcSMatt Macy 	if (err != 0)
454eda14cbcSMatt Macy 		return (B_FALSE);
455eda14cbcSMatt Macy 
456eda14cbcSMatt Macy 	err = zap_lookup(zfsvfs->z_os, usedobj, buf, 8, 1, &used);
457eda14cbcSMatt Macy 	if (err != 0)
458eda14cbcSMatt Macy 		return (B_FALSE);
459eda14cbcSMatt Macy 	return (used >= quota);
460eda14cbcSMatt Macy }
461eda14cbcSMatt Macy 
462eda14cbcSMatt Macy boolean_t
463eda14cbcSMatt Macy zfs_id_overquota(zfsvfs_t *zfsvfs, uint64_t usedobj, uint64_t id)
464eda14cbcSMatt Macy {
465eda14cbcSMatt Macy 	return (zfs_id_overblockquota(zfsvfs, usedobj, id) ||
466eda14cbcSMatt Macy 	    zfs_id_overobjquota(zfsvfs, usedobj, id));
467eda14cbcSMatt Macy }
468eda14cbcSMatt Macy 
469eda14cbcSMatt Macy EXPORT_SYMBOL(zpl_get_file_info);
470eda14cbcSMatt Macy EXPORT_SYMBOL(zfs_userspace_one);
471eda14cbcSMatt Macy EXPORT_SYMBOL(zfs_userspace_many);
472eda14cbcSMatt Macy EXPORT_SYMBOL(zfs_set_userquota);
473eda14cbcSMatt Macy EXPORT_SYMBOL(zfs_id_overblockquota);
474eda14cbcSMatt Macy EXPORT_SYMBOL(zfs_id_overobjquota);
475eda14cbcSMatt Macy EXPORT_SYMBOL(zfs_id_overquota);
476