1 // SPDX-License-Identifier: CDDL-1.0
2 /*
3 * CDDL HEADER START
4 *
5 * The contents of this file are subject to the terms of the
6 * Common Development and Distribution License (the "License").
7 * You may not use this file except in compliance with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or https://opensource.org/licenses/CDDL-1.0.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright (c) 2011 Pawel Jakub Dawidek
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
zpl_get_file_info(dmu_object_type_t bonustype,const void * data,zfs_file_info_t * zoi)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
fuidstr_to_sid(zfsvfs_t * zfsvfs,const char * fuidstr,char * domainbuf,int buflen,uid_t * ridp)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
zfs_userquota_prop_to_obj(zfsvfs_t * zfsvfs,zfs_userquota_prop_t type)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 static uint64_t
zfs_usedquota_prop_to_default(zfsvfs_t * zfsvfs,zfs_userquota_prop_t type)164 zfs_usedquota_prop_to_default(zfsvfs_t *zfsvfs, zfs_userquota_prop_t type)
165 {
166 switch (type) {
167 case ZFS_PROP_USERUSED:
168 return (zfsvfs->z_defaultuserquota);
169 case ZFS_PROP_USEROBJUSED:
170 return (zfsvfs->z_defaultuserobjquota);
171 case ZFS_PROP_GROUPUSED:
172 return (zfsvfs->z_defaultgroupquota);
173 case ZFS_PROP_GROUPOBJUSED:
174 return (zfsvfs->z_defaultgroupobjquota);
175 case ZFS_PROP_PROJECTUSED:
176 return (zfsvfs->z_defaultprojectquota);
177 case ZFS_PROP_PROJECTOBJUSED:
178 return (zfsvfs->z_defaultprojectobjquota);
179 default:
180 return (0);
181 }
182 }
183
184 int
zfs_userspace_many(zfsvfs_t * zfsvfs,zfs_userquota_prop_t type,uint64_t * cookiep,void * vbuf,uint64_t * bufsizep,uint64_t * default_quota)185 zfs_userspace_many(zfsvfs_t *zfsvfs, zfs_userquota_prop_t type,
186 uint64_t *cookiep, void *vbuf, uint64_t *bufsizep,
187 uint64_t *default_quota)
188 {
189 int error;
190 zap_cursor_t zc;
191 zap_attribute_t *za;
192 zfs_useracct_t *buf = vbuf;
193 uint64_t obj;
194 int offset = 0;
195
196 if (!dmu_objset_userspace_present(zfsvfs->z_os))
197 return (SET_ERROR(ENOTSUP));
198
199 if ((type == ZFS_PROP_PROJECTQUOTA || type == ZFS_PROP_PROJECTUSED ||
200 type == ZFS_PROP_PROJECTOBJQUOTA ||
201 type == ZFS_PROP_PROJECTOBJUSED) &&
202 !dmu_objset_projectquota_present(zfsvfs->z_os))
203 return (SET_ERROR(ENOTSUP));
204
205 if ((type == ZFS_PROP_USEROBJUSED || type == ZFS_PROP_GROUPOBJUSED ||
206 type == ZFS_PROP_USEROBJQUOTA || type == ZFS_PROP_GROUPOBJQUOTA ||
207 type == ZFS_PROP_PROJECTOBJUSED ||
208 type == ZFS_PROP_PROJECTOBJQUOTA) &&
209 !dmu_objset_userobjspace_present(zfsvfs->z_os))
210 return (SET_ERROR(ENOTSUP));
211
212 *default_quota = zfs_usedquota_prop_to_default(zfsvfs, type);
213
214 obj = zfs_userquota_prop_to_obj(zfsvfs, type);
215 if (obj == ZFS_NO_OBJECT) {
216 *bufsizep = 0;
217 return (0);
218 }
219
220 if (type == ZFS_PROP_USEROBJUSED || type == ZFS_PROP_GROUPOBJUSED ||
221 type == ZFS_PROP_PROJECTOBJUSED)
222 offset = DMU_OBJACCT_PREFIX_LEN;
223
224 za = zap_attribute_alloc();
225 for (zap_cursor_init_serialized(&zc, zfsvfs->z_os, obj, *cookiep);
226 (error = zap_cursor_retrieve(&zc, za)) == 0;
227 zap_cursor_advance(&zc)) {
228 if ((uintptr_t)buf - (uintptr_t)vbuf + sizeof (zfs_useracct_t) >
229 *bufsizep)
230 break;
231
232 /*
233 * skip object quota (with zap name prefix DMU_OBJACCT_PREFIX)
234 * when dealing with block quota and vice versa.
235 */
236 if ((offset > 0) != (strncmp(za->za_name, DMU_OBJACCT_PREFIX,
237 DMU_OBJACCT_PREFIX_LEN) == 0))
238 continue;
239
240 fuidstr_to_sid(zfsvfs, za->za_name + offset,
241 buf->zu_domain, sizeof (buf->zu_domain), &buf->zu_rid);
242
243 buf->zu_space = za->za_first_integer;
244 buf++;
245 }
246 if (error == ENOENT)
247 error = 0;
248
249 ASSERT3U((uintptr_t)buf - (uintptr_t)vbuf, <=, *bufsizep);
250 *bufsizep = (uintptr_t)buf - (uintptr_t)vbuf;
251 *cookiep = zap_cursor_serialize(&zc);
252 zap_cursor_fini(&zc);
253 zap_attribute_free(za);
254 return (error);
255 }
256
257 int
zfs_userspace_one(zfsvfs_t * zfsvfs,zfs_userquota_prop_t type,const char * domain,uint64_t rid,uint64_t * valp)258 zfs_userspace_one(zfsvfs_t *zfsvfs, zfs_userquota_prop_t type,
259 const char *domain, uint64_t rid, uint64_t *valp)
260 {
261 char buf[20 + DMU_OBJACCT_PREFIX_LEN];
262 int offset = 0;
263 int err;
264 uint64_t obj;
265
266 *valp = 0;
267
268 if (!dmu_objset_userspace_present(zfsvfs->z_os))
269 return (SET_ERROR(ENOTSUP));
270
271 if ((type == ZFS_PROP_USEROBJUSED || type == ZFS_PROP_GROUPOBJUSED ||
272 type == ZFS_PROP_USEROBJQUOTA || type == ZFS_PROP_GROUPOBJQUOTA ||
273 type == ZFS_PROP_PROJECTOBJUSED ||
274 type == ZFS_PROP_PROJECTOBJQUOTA) &&
275 !dmu_objset_userobjspace_present(zfsvfs->z_os))
276 return (SET_ERROR(ENOTSUP));
277
278 if (type == ZFS_PROP_PROJECTQUOTA || type == ZFS_PROP_PROJECTUSED ||
279 type == ZFS_PROP_PROJECTOBJQUOTA ||
280 type == ZFS_PROP_PROJECTOBJUSED) {
281 if (!dmu_objset_projectquota_present(zfsvfs->z_os))
282 return (SET_ERROR(ENOTSUP));
283 if (!zpl_is_valid_projid(rid))
284 return (SET_ERROR(EINVAL));
285 }
286
287 obj = zfs_userquota_prop_to_obj(zfsvfs, type);
288 if (obj == ZFS_NO_OBJECT)
289 return (0);
290
291 if (type == ZFS_PROP_USEROBJUSED || type == ZFS_PROP_GROUPOBJUSED ||
292 type == ZFS_PROP_PROJECTOBJUSED) {
293 strlcpy(buf, DMU_OBJACCT_PREFIX, DMU_OBJACCT_PREFIX_LEN + 1);
294 offset = DMU_OBJACCT_PREFIX_LEN;
295 }
296
297 err = zfs_id_to_fuidstr(zfsvfs, domain, rid, buf + offset,
298 sizeof (buf) - offset, B_FALSE);
299 if (err)
300 return (err);
301
302 err = zap_lookup(zfsvfs->z_os, obj, buf, 8, 1, valp);
303 if (err == ENOENT)
304 err = 0;
305 return (err);
306 }
307
308 int
zfs_set_userquota(zfsvfs_t * zfsvfs,zfs_userquota_prop_t type,const char * domain,uint64_t rid,uint64_t quota)309 zfs_set_userquota(zfsvfs_t *zfsvfs, zfs_userquota_prop_t type,
310 const char *domain, uint64_t rid, uint64_t quota)
311 {
312 char buf[32];
313 int err;
314 dmu_tx_t *tx;
315 uint64_t *objp;
316 boolean_t fuid_dirtied;
317
318 if (zfsvfs->z_version < ZPL_VERSION_USERSPACE)
319 return (SET_ERROR(ENOTSUP));
320
321 switch (type) {
322 case ZFS_PROP_USERQUOTA:
323 objp = &zfsvfs->z_userquota_obj;
324 break;
325 case ZFS_PROP_GROUPQUOTA:
326 objp = &zfsvfs->z_groupquota_obj;
327 break;
328 case ZFS_PROP_USEROBJQUOTA:
329 objp = &zfsvfs->z_userobjquota_obj;
330 break;
331 case ZFS_PROP_GROUPOBJQUOTA:
332 objp = &zfsvfs->z_groupobjquota_obj;
333 break;
334 case ZFS_PROP_PROJECTQUOTA:
335 if (!dmu_objset_projectquota_enabled(zfsvfs->z_os))
336 return (SET_ERROR(ENOTSUP));
337 if (!zpl_is_valid_projid(rid))
338 return (SET_ERROR(EINVAL));
339
340 objp = &zfsvfs->z_projectquota_obj;
341 break;
342 case ZFS_PROP_PROJECTOBJQUOTA:
343 if (!dmu_objset_projectquota_enabled(zfsvfs->z_os))
344 return (SET_ERROR(ENOTSUP));
345 if (!zpl_is_valid_projid(rid))
346 return (SET_ERROR(EINVAL));
347
348 objp = &zfsvfs->z_projectobjquota_obj;
349 break;
350 default:
351 return (SET_ERROR(EINVAL));
352 }
353
354 err = zfs_id_to_fuidstr(zfsvfs, domain, rid, buf, sizeof (buf), B_TRUE);
355 if (err)
356 return (err);
357 fuid_dirtied = zfsvfs->z_fuid_dirty;
358
359 tx = dmu_tx_create(zfsvfs->z_os);
360 dmu_tx_hold_zap(tx, *objp ? *objp : DMU_NEW_OBJECT, B_TRUE, NULL);
361 if (*objp == 0) {
362 dmu_tx_hold_zap(tx, MASTER_NODE_OBJ, B_TRUE,
363 zfs_userquota_prop_prefixes[type]);
364 }
365 if (fuid_dirtied)
366 zfs_fuid_txhold(zfsvfs, tx);
367 err = dmu_tx_assign(tx, DMU_TX_WAIT);
368 if (err) {
369 dmu_tx_abort(tx);
370 return (err);
371 }
372
373 mutex_enter(&zfsvfs->z_lock);
374 if (*objp == 0) {
375 *objp = zap_create(zfsvfs->z_os, DMU_OT_USERGROUP_QUOTA,
376 DMU_OT_NONE, 0, tx);
377 VERIFY(0 == zap_add(zfsvfs->z_os, MASTER_NODE_OBJ,
378 zfs_userquota_prop_prefixes[type], 8, 1, objp, tx));
379 }
380 mutex_exit(&zfsvfs->z_lock);
381
382 if (quota == 0) {
383 err = zap_remove(zfsvfs->z_os, *objp, buf, tx);
384 if (err == ENOENT)
385 err = 0;
386 } else {
387 err = zap_update(zfsvfs->z_os, *objp, buf, 8, 1, "a, tx);
388 }
389 ASSERT(err == 0);
390 if (fuid_dirtied)
391 zfs_fuid_sync(zfsvfs, tx);
392 dmu_tx_commit(tx);
393 return (err);
394 }
395
396 boolean_t
zfs_id_overobjquota(zfsvfs_t * zfsvfs,uint64_t usedobj,uint64_t id)397 zfs_id_overobjquota(zfsvfs_t *zfsvfs, uint64_t usedobj, uint64_t id)
398 {
399 char buf[20 + DMU_OBJACCT_PREFIX_LEN];
400 uint64_t used, quota, quotaobj, default_quota = 0;
401 int err;
402
403 if (!dmu_objset_userobjspace_present(zfsvfs->z_os)) {
404 if (dmu_objset_userobjspace_upgradable(zfsvfs->z_os)) {
405 dsl_pool_config_enter(
406 dmu_objset_pool(zfsvfs->z_os), FTAG);
407 dmu_objset_id_quota_upgrade(zfsvfs->z_os);
408 dsl_pool_config_exit(
409 dmu_objset_pool(zfsvfs->z_os), FTAG);
410 }
411 return (B_FALSE);
412 }
413
414 if (usedobj == DMU_PROJECTUSED_OBJECT) {
415 if (!dmu_objset_projectquota_present(zfsvfs->z_os)) {
416 if (dmu_objset_projectquota_upgradable(zfsvfs->z_os)) {
417 dsl_pool_config_enter(
418 dmu_objset_pool(zfsvfs->z_os), FTAG);
419 dmu_objset_id_quota_upgrade(zfsvfs->z_os);
420 dsl_pool_config_exit(
421 dmu_objset_pool(zfsvfs->z_os), FTAG);
422 }
423 return (B_FALSE);
424 }
425 quotaobj = zfsvfs->z_projectobjquota_obj;
426 default_quota = zfsvfs->z_defaultprojectobjquota;
427 } else if (usedobj == DMU_USERUSED_OBJECT) {
428 quotaobj = zfsvfs->z_userobjquota_obj;
429 default_quota = zfsvfs->z_defaultuserobjquota;
430 } else if (usedobj == DMU_GROUPUSED_OBJECT) {
431 quotaobj = zfsvfs->z_groupobjquota_obj;
432 default_quota = zfsvfs->z_defaultgroupobjquota;
433 } else {
434 return (B_FALSE);
435 }
436 if (zfsvfs->z_replay)
437 return (B_FALSE);
438
439 (void) snprintf(buf, sizeof (buf), "%llx", (longlong_t)id);
440 if (quotaobj == 0) {
441 if (default_quota == 0)
442 return (B_FALSE);
443 quota = default_quota;
444 } else {
445 err = zap_lookup(zfsvfs->z_os, quotaobj, buf, 8, 1, "a);
446 if (err != 0 && ((quota = default_quota) == 0))
447 return (B_FALSE);
448 }
449
450 (void) snprintf(buf, sizeof (buf), DMU_OBJACCT_PREFIX "%llx",
451 (longlong_t)id);
452 err = zap_lookup(zfsvfs->z_os, usedobj, buf, 8, 1, &used);
453 if (err != 0)
454 return (B_FALSE);
455 return (used >= quota);
456 }
457
458 boolean_t
zfs_id_overblockquota(zfsvfs_t * zfsvfs,uint64_t usedobj,uint64_t id)459 zfs_id_overblockquota(zfsvfs_t *zfsvfs, uint64_t usedobj, uint64_t id)
460 {
461 char buf[20];
462 uint64_t used, quota, quotaobj, default_quota = 0;
463 int err;
464
465 if (usedobj == DMU_PROJECTUSED_OBJECT) {
466 if (!dmu_objset_projectquota_present(zfsvfs->z_os)) {
467 if (dmu_objset_projectquota_upgradable(zfsvfs->z_os)) {
468 dsl_pool_config_enter(
469 dmu_objset_pool(zfsvfs->z_os), FTAG);
470 dmu_objset_id_quota_upgrade(zfsvfs->z_os);
471 dsl_pool_config_exit(
472 dmu_objset_pool(zfsvfs->z_os), FTAG);
473 }
474 return (B_FALSE);
475 }
476 quotaobj = zfsvfs->z_projectquota_obj;
477 default_quota = zfsvfs->z_defaultprojectquota;
478 } else if (usedobj == DMU_USERUSED_OBJECT) {
479 quotaobj = zfsvfs->z_userquota_obj;
480 default_quota = zfsvfs->z_defaultuserquota;
481 } else if (usedobj == DMU_GROUPUSED_OBJECT) {
482 quotaobj = zfsvfs->z_groupquota_obj;
483 default_quota = zfsvfs->z_defaultgroupquota;
484 } else {
485 return (B_FALSE);
486 }
487 if (zfsvfs->z_replay)
488 return (B_FALSE);
489
490 (void) snprintf(buf, sizeof (buf), "%llx", (longlong_t)id);
491 if (quotaobj == 0) {
492 if (default_quota == 0)
493 return (B_FALSE);
494 quota = default_quota;
495 } else {
496 err = zap_lookup(zfsvfs->z_os, quotaobj, buf, 8, 1, "a);
497 if (err != 0 && ((quota = default_quota) == 0))
498 return (B_FALSE);
499 }
500
501 err = zap_lookup(zfsvfs->z_os, usedobj, buf, 8, 1, &used);
502 if (err != 0)
503 return (B_FALSE);
504 return (used >= quota);
505 }
506
507 boolean_t
zfs_id_overquota(zfsvfs_t * zfsvfs,uint64_t usedobj,uint64_t id)508 zfs_id_overquota(zfsvfs_t *zfsvfs, uint64_t usedobj, uint64_t id)
509 {
510 return (zfs_id_overblockquota(zfsvfs, usedobj, id) ||
511 zfs_id_overobjquota(zfsvfs, usedobj, id));
512 }
513
514 EXPORT_SYMBOL(zpl_get_file_info);
515 EXPORT_SYMBOL(zfs_userspace_one);
516 EXPORT_SYMBOL(zfs_userspace_many);
517 EXPORT_SYMBOL(zfs_set_userquota);
518 EXPORT_SYMBOL(zfs_id_overblockquota);
519 EXPORT_SYMBOL(zfs_id_overobjquota);
520 EXPORT_SYMBOL(zfs_id_overquota);
521