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