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