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 VERIFY0(zap_add(zfsvfs->z_os, MASTER_NODE_OBJ, 351 zfs_userquota_prop_prefixes[type], 8, 1, objp, tx)); 352 } 353 354 if (quota == 0) { 355 err = zap_remove(zfsvfs->z_os, *objp, buf, tx); 356 if (err == ENOENT) 357 err = 0; 358 /* 359 * If the quota contains no more entries after the entry 360 * was removed, destroy the quota zap and remove the 361 * reference from zfsvfs. This will save us unnecessary 362 * zap_lookups for the quota during writes. 363 */ 364 uint64_t zap_nentries; 365 VERIFY0(zap_count(zfsvfs->z_os, *objp, &zap_nentries)); 366 if (zap_nentries == 0) { 367 VERIFY0(zap_remove(zfsvfs->z_os, MASTER_NODE_OBJ, 368 zfs_userquota_prop_prefixes[type], tx)); 369 VERIFY0(zap_destroy(zfsvfs->z_os, *objp, tx)); 370 *objp = 0; 371 } 372 } else { 373 err = zap_update(zfsvfs->z_os, *objp, buf, 8, 1, "a, tx); 374 } 375 mutex_exit(&zfsvfs->z_lock); 376 ASSERT(err == 0); 377 if (fuid_dirtied) 378 zfs_fuid_sync(zfsvfs, tx); 379 dmu_tx_commit(tx); 380 return (err); 381 } 382 383 boolean_t 384 zfs_id_overobjquota(zfsvfs_t *zfsvfs, uint64_t usedobj, uint64_t id) 385 { 386 char buf[20 + DMU_OBJACCT_PREFIX_LEN]; 387 uint64_t used, quota, quotaobj; 388 int err; 389 390 if (!dmu_objset_userobjspace_present(zfsvfs->z_os)) { 391 if (dmu_objset_userobjspace_upgradable(zfsvfs->z_os)) { 392 dsl_pool_config_enter( 393 dmu_objset_pool(zfsvfs->z_os), FTAG); 394 dmu_objset_id_quota_upgrade(zfsvfs->z_os); 395 dsl_pool_config_exit( 396 dmu_objset_pool(zfsvfs->z_os), FTAG); 397 } 398 return (B_FALSE); 399 } 400 401 if (usedobj == DMU_PROJECTUSED_OBJECT) { 402 if (!dmu_objset_projectquota_present(zfsvfs->z_os)) { 403 if (dmu_objset_projectquota_upgradable(zfsvfs->z_os)) { 404 dsl_pool_config_enter( 405 dmu_objset_pool(zfsvfs->z_os), FTAG); 406 dmu_objset_id_quota_upgrade(zfsvfs->z_os); 407 dsl_pool_config_exit( 408 dmu_objset_pool(zfsvfs->z_os), FTAG); 409 } 410 return (B_FALSE); 411 } 412 quotaobj = zfsvfs->z_projectobjquota_obj; 413 } else if (usedobj == DMU_USERUSED_OBJECT) { 414 quotaobj = zfsvfs->z_userobjquota_obj; 415 } else if (usedobj == DMU_GROUPUSED_OBJECT) { 416 quotaobj = zfsvfs->z_groupobjquota_obj; 417 } else { 418 return (B_FALSE); 419 } 420 if (quotaobj == 0 || zfsvfs->z_replay) 421 return (B_FALSE); 422 423 (void) snprintf(buf, sizeof (buf), "%llx", (longlong_t)id); 424 err = zap_lookup(zfsvfs->z_os, quotaobj, buf, 8, 1, "a); 425 if (err != 0) 426 return (B_FALSE); 427 428 (void) snprintf(buf, sizeof (buf), DMU_OBJACCT_PREFIX "%llx", 429 (longlong_t)id); 430 err = zap_lookup(zfsvfs->z_os, usedobj, buf, 8, 1, &used); 431 if (err != 0) 432 return (B_FALSE); 433 return (used >= quota); 434 } 435 436 boolean_t 437 zfs_id_overblockquota(zfsvfs_t *zfsvfs, uint64_t usedobj, uint64_t id) 438 { 439 char buf[20]; 440 uint64_t used, quota, quotaobj; 441 int err; 442 443 if (usedobj == DMU_PROJECTUSED_OBJECT) { 444 if (!dmu_objset_projectquota_present(zfsvfs->z_os)) { 445 if (dmu_objset_projectquota_upgradable(zfsvfs->z_os)) { 446 dsl_pool_config_enter( 447 dmu_objset_pool(zfsvfs->z_os), FTAG); 448 dmu_objset_id_quota_upgrade(zfsvfs->z_os); 449 dsl_pool_config_exit( 450 dmu_objset_pool(zfsvfs->z_os), FTAG); 451 } 452 return (B_FALSE); 453 } 454 quotaobj = zfsvfs->z_projectquota_obj; 455 } else if (usedobj == DMU_USERUSED_OBJECT) { 456 quotaobj = zfsvfs->z_userquota_obj; 457 } else if (usedobj == DMU_GROUPUSED_OBJECT) { 458 quotaobj = zfsvfs->z_groupquota_obj; 459 } else { 460 return (B_FALSE); 461 } 462 if (quotaobj == 0 || zfsvfs->z_replay) 463 return (B_FALSE); 464 465 (void) snprintf(buf, sizeof (buf), "%llx", (longlong_t)id); 466 err = zap_lookup(zfsvfs->z_os, quotaobj, buf, 8, 1, "a); 467 if (err != 0) 468 return (B_FALSE); 469 470 err = zap_lookup(zfsvfs->z_os, usedobj, buf, 8, 1, &used); 471 if (err != 0) 472 return (B_FALSE); 473 return (used >= quota); 474 } 475 476 boolean_t 477 zfs_id_overquota(zfsvfs_t *zfsvfs, uint64_t usedobj, uint64_t id) 478 { 479 return (zfs_id_overblockquota(zfsvfs, usedobj, id) || 480 zfs_id_overobjquota(zfsvfs, usedobj, id)); 481 } 482 483 EXPORT_SYMBOL(zpl_get_file_info); 484 EXPORT_SYMBOL(zfs_userspace_one); 485 EXPORT_SYMBOL(zfs_userspace_many); 486 EXPORT_SYMBOL(zfs_set_userquota); 487 EXPORT_SYMBOL(zfs_id_overblockquota); 488 EXPORT_SYMBOL(zfs_id_overobjquota); 489 EXPORT_SYMBOL(zfs_id_overquota); 490