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