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
40int
41zpl_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
115static void
116fuidstr_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
132static uint64_t
133zfs_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
162int
163zfs_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
230int
231zfs_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
281int
282zfs_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
369boolean_t
370zfs_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
422boolean_t
423zfs_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
462boolean_t
463zfs_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
469EXPORT_SYMBOL(zpl_get_file_info);
470EXPORT_SYMBOL(zfs_userspace_one);
471EXPORT_SYMBOL(zfs_userspace_many);
472EXPORT_SYMBOL(zfs_set_userquota);
473EXPORT_SYMBOL(zfs_id_overblockquota);
474EXPORT_SYMBOL(zfs_id_overobjquota);
475EXPORT_SYMBOL(zfs_id_overquota);
476