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