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 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 static uint64_t 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 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 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 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 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 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 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