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 za = zap_attribute_alloc(); 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 zap_attribute_free(za); 229 return (error); 230 } 231 232 int 233 zfs_userspace_one(zfsvfs_t *zfsvfs, zfs_userquota_prop_t type, 234 const char *domain, uint64_t rid, uint64_t *valp) 235 { 236 char buf[20 + DMU_OBJACCT_PREFIX_LEN]; 237 int offset = 0; 238 int err; 239 uint64_t obj; 240 241 *valp = 0; 242 243 if (!dmu_objset_userspace_present(zfsvfs->z_os)) 244 return (SET_ERROR(ENOTSUP)); 245 246 if ((type == ZFS_PROP_USEROBJUSED || type == ZFS_PROP_GROUPOBJUSED || 247 type == ZFS_PROP_USEROBJQUOTA || type == ZFS_PROP_GROUPOBJQUOTA || 248 type == ZFS_PROP_PROJECTOBJUSED || 249 type == ZFS_PROP_PROJECTOBJQUOTA) && 250 !dmu_objset_userobjspace_present(zfsvfs->z_os)) 251 return (SET_ERROR(ENOTSUP)); 252 253 if (type == ZFS_PROP_PROJECTQUOTA || type == ZFS_PROP_PROJECTUSED || 254 type == ZFS_PROP_PROJECTOBJQUOTA || 255 type == ZFS_PROP_PROJECTOBJUSED) { 256 if (!dmu_objset_projectquota_present(zfsvfs->z_os)) 257 return (SET_ERROR(ENOTSUP)); 258 if (!zpl_is_valid_projid(rid)) 259 return (SET_ERROR(EINVAL)); 260 } 261 262 obj = zfs_userquota_prop_to_obj(zfsvfs, type); 263 if (obj == ZFS_NO_OBJECT) 264 return (0); 265 266 if (type == ZFS_PROP_USEROBJUSED || type == ZFS_PROP_GROUPOBJUSED || 267 type == ZFS_PROP_PROJECTOBJUSED) { 268 strlcpy(buf, DMU_OBJACCT_PREFIX, DMU_OBJACCT_PREFIX_LEN + 1); 269 offset = DMU_OBJACCT_PREFIX_LEN; 270 } 271 272 err = zfs_id_to_fuidstr(zfsvfs, domain, rid, buf + offset, 273 sizeof (buf) - offset, B_FALSE); 274 if (err) 275 return (err); 276 277 err = zap_lookup(zfsvfs->z_os, obj, buf, 8, 1, valp); 278 if (err == ENOENT) 279 err = 0; 280 return (err); 281 } 282 283 int 284 zfs_set_userquota(zfsvfs_t *zfsvfs, zfs_userquota_prop_t type, 285 const char *domain, uint64_t rid, uint64_t quota) 286 { 287 char buf[32]; 288 int err; 289 dmu_tx_t *tx; 290 uint64_t *objp; 291 boolean_t fuid_dirtied; 292 293 if (zfsvfs->z_version < ZPL_VERSION_USERSPACE) 294 return (SET_ERROR(ENOTSUP)); 295 296 switch (type) { 297 case ZFS_PROP_USERQUOTA: 298 objp = &zfsvfs->z_userquota_obj; 299 break; 300 case ZFS_PROP_GROUPQUOTA: 301 objp = &zfsvfs->z_groupquota_obj; 302 break; 303 case ZFS_PROP_USEROBJQUOTA: 304 objp = &zfsvfs->z_userobjquota_obj; 305 break; 306 case ZFS_PROP_GROUPOBJQUOTA: 307 objp = &zfsvfs->z_groupobjquota_obj; 308 break; 309 case ZFS_PROP_PROJECTQUOTA: 310 if (!dmu_objset_projectquota_enabled(zfsvfs->z_os)) 311 return (SET_ERROR(ENOTSUP)); 312 if (!zpl_is_valid_projid(rid)) 313 return (SET_ERROR(EINVAL)); 314 315 objp = &zfsvfs->z_projectquota_obj; 316 break; 317 case ZFS_PROP_PROJECTOBJQUOTA: 318 if (!dmu_objset_projectquota_enabled(zfsvfs->z_os)) 319 return (SET_ERROR(ENOTSUP)); 320 if (!zpl_is_valid_projid(rid)) 321 return (SET_ERROR(EINVAL)); 322 323 objp = &zfsvfs->z_projectobjquota_obj; 324 break; 325 default: 326 return (SET_ERROR(EINVAL)); 327 } 328 329 err = zfs_id_to_fuidstr(zfsvfs, domain, rid, buf, sizeof (buf), B_TRUE); 330 if (err) 331 return (err); 332 fuid_dirtied = zfsvfs->z_fuid_dirty; 333 334 tx = dmu_tx_create(zfsvfs->z_os); 335 dmu_tx_hold_zap(tx, *objp ? *objp : DMU_NEW_OBJECT, B_TRUE, NULL); 336 if (*objp == 0) { 337 dmu_tx_hold_zap(tx, MASTER_NODE_OBJ, B_TRUE, 338 zfs_userquota_prop_prefixes[type]); 339 } 340 if (fuid_dirtied) 341 zfs_fuid_txhold(zfsvfs, tx); 342 err = dmu_tx_assign(tx, TXG_WAIT); 343 if (err) { 344 dmu_tx_abort(tx); 345 return (err); 346 } 347 348 mutex_enter(&zfsvfs->z_lock); 349 if (*objp == 0) { 350 *objp = zap_create(zfsvfs->z_os, DMU_OT_USERGROUP_QUOTA, 351 DMU_OT_NONE, 0, tx); 352 VERIFY(0 == zap_add(zfsvfs->z_os, MASTER_NODE_OBJ, 353 zfs_userquota_prop_prefixes[type], 8, 1, objp, tx)); 354 } 355 mutex_exit(&zfsvfs->z_lock); 356 357 if (quota == 0) { 358 err = zap_remove(zfsvfs->z_os, *objp, buf, tx); 359 if (err == ENOENT) 360 err = 0; 361 } else { 362 err = zap_update(zfsvfs->z_os, *objp, buf, 8, 1, "a, tx); 363 } 364 ASSERT(err == 0); 365 if (fuid_dirtied) 366 zfs_fuid_sync(zfsvfs, tx); 367 dmu_tx_commit(tx); 368 return (err); 369 } 370 371 boolean_t 372 zfs_id_overobjquota(zfsvfs_t *zfsvfs, uint64_t usedobj, uint64_t id) 373 { 374 char buf[20 + DMU_OBJACCT_PREFIX_LEN]; 375 uint64_t used, quota, quotaobj; 376 int err; 377 378 if (!dmu_objset_userobjspace_present(zfsvfs->z_os)) { 379 if (dmu_objset_userobjspace_upgradable(zfsvfs->z_os)) { 380 dsl_pool_config_enter( 381 dmu_objset_pool(zfsvfs->z_os), FTAG); 382 dmu_objset_id_quota_upgrade(zfsvfs->z_os); 383 dsl_pool_config_exit( 384 dmu_objset_pool(zfsvfs->z_os), FTAG); 385 } 386 return (B_FALSE); 387 } 388 389 if (usedobj == DMU_PROJECTUSED_OBJECT) { 390 if (!dmu_objset_projectquota_present(zfsvfs->z_os)) { 391 if (dmu_objset_projectquota_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 quotaobj = zfsvfs->z_projectobjquota_obj; 401 } else if (usedobj == DMU_USERUSED_OBJECT) { 402 quotaobj = zfsvfs->z_userobjquota_obj; 403 } else if (usedobj == DMU_GROUPUSED_OBJECT) { 404 quotaobj = zfsvfs->z_groupobjquota_obj; 405 } else { 406 return (B_FALSE); 407 } 408 if (quotaobj == 0 || zfsvfs->z_replay) 409 return (B_FALSE); 410 411 (void) snprintf(buf, sizeof (buf), "%llx", (longlong_t)id); 412 err = zap_lookup(zfsvfs->z_os, quotaobj, buf, 8, 1, "a); 413 if (err != 0) 414 return (B_FALSE); 415 416 (void) snprintf(buf, sizeof (buf), DMU_OBJACCT_PREFIX "%llx", 417 (longlong_t)id); 418 err = zap_lookup(zfsvfs->z_os, usedobj, buf, 8, 1, &used); 419 if (err != 0) 420 return (B_FALSE); 421 return (used >= quota); 422 } 423 424 boolean_t 425 zfs_id_overblockquota(zfsvfs_t *zfsvfs, uint64_t usedobj, uint64_t id) 426 { 427 char buf[20]; 428 uint64_t used, quota, quotaobj; 429 int err; 430 431 if (usedobj == DMU_PROJECTUSED_OBJECT) { 432 if (!dmu_objset_projectquota_present(zfsvfs->z_os)) { 433 if (dmu_objset_projectquota_upgradable(zfsvfs->z_os)) { 434 dsl_pool_config_enter( 435 dmu_objset_pool(zfsvfs->z_os), FTAG); 436 dmu_objset_id_quota_upgrade(zfsvfs->z_os); 437 dsl_pool_config_exit( 438 dmu_objset_pool(zfsvfs->z_os), FTAG); 439 } 440 return (B_FALSE); 441 } 442 quotaobj = zfsvfs->z_projectquota_obj; 443 } else if (usedobj == DMU_USERUSED_OBJECT) { 444 quotaobj = zfsvfs->z_userquota_obj; 445 } else if (usedobj == DMU_GROUPUSED_OBJECT) { 446 quotaobj = zfsvfs->z_groupquota_obj; 447 } else { 448 return (B_FALSE); 449 } 450 if (quotaobj == 0 || zfsvfs->z_replay) 451 return (B_FALSE); 452 453 (void) snprintf(buf, sizeof (buf), "%llx", (longlong_t)id); 454 err = zap_lookup(zfsvfs->z_os, quotaobj, buf, 8, 1, "a); 455 if (err != 0) 456 return (B_FALSE); 457 458 err = zap_lookup(zfsvfs->z_os, usedobj, buf, 8, 1, &used); 459 if (err != 0) 460 return (B_FALSE); 461 return (used >= quota); 462 } 463 464 boolean_t 465 zfs_id_overquota(zfsvfs_t *zfsvfs, uint64_t usedobj, uint64_t id) 466 { 467 return (zfs_id_overblockquota(zfsvfs, usedobj, id) || 468 zfs_id_overobjquota(zfsvfs, usedobj, id)); 469 } 470 471 EXPORT_SYMBOL(zpl_get_file_info); 472 EXPORT_SYMBOL(zfs_userspace_one); 473 EXPORT_SYMBOL(zfs_userspace_many); 474 EXPORT_SYMBOL(zfs_set_userquota); 475 EXPORT_SYMBOL(zfs_id_overblockquota); 476 EXPORT_SYMBOL(zfs_id_overobjquota); 477 EXPORT_SYMBOL(zfs_id_overquota); 478