FreeBSD ZFS
The Zettabyte File System
|
00001 /* 00002 * CDDL HEADER START 00003 * 00004 * The contents of this file are subject to the terms of the 00005 * Common Development and Distribution License (the "License"). 00006 * You may not use this file except in compliance with the License. 00007 * 00008 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 00009 * or http://www.opensolaris.org/os/licensing. 00010 * See the License for the specific language governing permissions 00011 * and limitations under the License. 00012 * 00013 * When distributing Covered Code, include this CDDL HEADER in each 00014 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 00015 * If applicable, add the following below this CDDL HEADER, with the 00016 * fields enclosed by brackets "[]" replaced with your own identifying 00017 * information: Portions Copyright [yyyy] [name of copyright owner] 00018 * 00019 * CDDL HEADER END 00020 */ 00021 /* 00022 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 00023 * Copyright (c) 2012 by Delphix. All rights reserved. 00024 */ 00025 00072 #include <sys/dmu.h> 00073 #include <sys/dmu_objset.h> 00074 #include <sys/dmu_tx.h> 00075 #include <sys/dsl_dataset.h> 00076 #include <sys/dsl_dir.h> 00077 #include <sys/dsl_prop.h> 00078 #include <sys/dsl_synctask.h> 00079 #include <sys/dsl_deleg.h> 00080 #include <sys/spa.h> 00081 #include <sys/zap.h> 00082 #include <sys/fs/zfs.h> 00083 #include <sys/cred.h> 00084 #include <sys/sunddi.h> 00085 00086 #include "zfs_deleg.h" 00087 00094 int 00095 dsl_deleg_can_allow(char *ddname, nvlist_t *nvp, cred_t *cr) 00096 { 00097 nvpair_t *whopair = NULL; 00098 int error; 00099 00100 if ((error = dsl_deleg_access(ddname, ZFS_DELEG_PERM_ALLOW, cr)) != 0) 00101 return (error); 00102 00103 while (whopair = nvlist_next_nvpair(nvp, whopair)) { 00104 nvlist_t *perms; 00105 nvpair_t *permpair = NULL; 00106 00107 VERIFY(nvpair_value_nvlist(whopair, &perms) == 0); 00108 00109 while (permpair = nvlist_next_nvpair(perms, permpair)) { 00110 const char *perm = nvpair_name(permpair); 00111 00112 if (strcmp(perm, ZFS_DELEG_PERM_ALLOW) == 0) 00113 return (EPERM); 00114 00115 if ((error = dsl_deleg_access(ddname, perm, cr)) != 0) 00116 return (error); 00117 } 00118 } 00119 return (0); 00120 } 00121 00127 int 00128 dsl_deleg_can_unallow(char *ddname, nvlist_t *nvp, cred_t *cr) 00129 { 00130 nvpair_t *whopair = NULL; 00131 int error; 00132 char idstr[32]; 00133 00134 if ((error = dsl_deleg_access(ddname, ZFS_DELEG_PERM_ALLOW, cr)) != 0) 00135 return (error); 00136 00137 (void) snprintf(idstr, sizeof (idstr), "%lld", 00138 (longlong_t)crgetuid(cr)); 00139 00140 while (whopair = nvlist_next_nvpair(nvp, whopair)) { 00141 zfs_deleg_who_type_t type = nvpair_name(whopair)[0]; 00142 00143 if (type != ZFS_DELEG_USER && 00144 type != ZFS_DELEG_USER_SETS) 00145 return (EPERM); 00146 00147 if (strcmp(idstr, &nvpair_name(whopair)[3]) != 0) 00148 return (EPERM); 00149 } 00150 return (0); 00151 } 00152 00153 static void 00154 dsl_deleg_set_sync(void *arg1, void *arg2, dmu_tx_t *tx) 00155 { 00156 dsl_dir_t *dd = arg1; 00157 nvlist_t *nvp = arg2; 00158 objset_t *mos = dd->dd_pool->dp_meta_objset; 00159 nvpair_t *whopair = NULL; 00160 uint64_t zapobj = dd->dd_phys->dd_deleg_zapobj; 00161 00162 if (zapobj == 0) { 00163 dmu_buf_will_dirty(dd->dd_dbuf, tx); 00164 zapobj = dd->dd_phys->dd_deleg_zapobj = zap_create(mos, 00165 DMU_OT_DSL_PERMS, DMU_OT_NONE, 0, tx); 00166 } 00167 00168 while (whopair = nvlist_next_nvpair(nvp, whopair)) { 00169 const char *whokey = nvpair_name(whopair); 00170 nvlist_t *perms; 00171 nvpair_t *permpair = NULL; 00172 uint64_t jumpobj; 00173 00174 VERIFY(nvpair_value_nvlist(whopair, &perms) == 0); 00175 00176 if (zap_lookup(mos, zapobj, whokey, 8, 1, &jumpobj) != 0) { 00177 jumpobj = zap_create_link(mos, DMU_OT_DSL_PERMS, 00178 zapobj, whokey, tx); 00179 } 00180 00181 while (permpair = nvlist_next_nvpair(perms, permpair)) { 00182 const char *perm = nvpair_name(permpair); 00183 uint64_t n = 0; 00184 00185 VERIFY(zap_update(mos, jumpobj, 00186 perm, 8, 1, &n, tx) == 0); 00187 spa_history_log_internal(LOG_DS_PERM_UPDATE, 00188 dd->dd_pool->dp_spa, tx, 00189 "%s %s dataset = %llu", whokey, perm, 00190 dd->dd_phys->dd_head_dataset_obj); 00191 } 00192 } 00193 } 00194 00195 static void 00196 dsl_deleg_unset_sync(void *arg1, void *arg2, dmu_tx_t *tx) 00197 { 00198 dsl_dir_t *dd = arg1; 00199 nvlist_t *nvp = arg2; 00200 objset_t *mos = dd->dd_pool->dp_meta_objset; 00201 nvpair_t *whopair = NULL; 00202 uint64_t zapobj = dd->dd_phys->dd_deleg_zapobj; 00203 00204 if (zapobj == 0) 00205 return; 00206 00207 while (whopair = nvlist_next_nvpair(nvp, whopair)) { 00208 const char *whokey = nvpair_name(whopair); 00209 nvlist_t *perms; 00210 nvpair_t *permpair = NULL; 00211 uint64_t jumpobj; 00212 00213 if (nvpair_value_nvlist(whopair, &perms) != 0) { 00214 if (zap_lookup(mos, zapobj, whokey, 8, 00215 1, &jumpobj) == 0) { 00216 (void) zap_remove(mos, zapobj, whokey, tx); 00217 VERIFY(0 == zap_destroy(mos, jumpobj, tx)); 00218 } 00219 spa_history_log_internal(LOG_DS_PERM_WHO_REMOVE, 00220 dd->dd_pool->dp_spa, tx, 00221 "%s dataset = %llu", whokey, 00222 dd->dd_phys->dd_head_dataset_obj); 00223 continue; 00224 } 00225 00226 if (zap_lookup(mos, zapobj, whokey, 8, 1, &jumpobj) != 0) 00227 continue; 00228 00229 while (permpair = nvlist_next_nvpair(perms, permpair)) { 00230 const char *perm = nvpair_name(permpair); 00231 uint64_t n = 0; 00232 00233 (void) zap_remove(mos, jumpobj, perm, tx); 00234 if (zap_count(mos, jumpobj, &n) == 0 && n == 0) { 00235 (void) zap_remove(mos, zapobj, 00236 whokey, tx); 00237 VERIFY(0 == zap_destroy(mos, 00238 jumpobj, tx)); 00239 } 00240 spa_history_log_internal(LOG_DS_PERM_REMOVE, 00241 dd->dd_pool->dp_spa, tx, 00242 "%s %s dataset = %llu", whokey, perm, 00243 dd->dd_phys->dd_head_dataset_obj); 00244 } 00245 } 00246 } 00247 00248 int 00249 dsl_deleg_set(const char *ddname, nvlist_t *nvp, boolean_t unset) 00250 { 00251 dsl_dir_t *dd; 00252 int error; 00253 nvpair_t *whopair = NULL; 00254 int blocks_modified = 0; 00255 00256 error = dsl_dir_open(ddname, FTAG, &dd, NULL); 00257 if (error) 00258 return (error); 00259 00260 if (spa_version(dmu_objset_spa(dd->dd_pool->dp_meta_objset)) < 00261 SPA_VERSION_DELEGATED_PERMS) { 00262 dsl_dir_close(dd, FTAG); 00263 return (ENOTSUP); 00264 } 00265 00266 while (whopair = nvlist_next_nvpair(nvp, whopair)) 00267 blocks_modified++; 00268 00269 error = dsl_sync_task_do(dd->dd_pool, NULL, 00270 unset ? dsl_deleg_unset_sync : dsl_deleg_set_sync, 00271 dd, nvp, blocks_modified); 00272 dsl_dir_close(dd, FTAG); 00273 00274 return (error); 00275 } 00276 00294 int 00295 dsl_deleg_get(const char *ddname, nvlist_t **nvp) 00296 { 00297 dsl_dir_t *dd, *startdd; 00298 dsl_pool_t *dp; 00299 int error; 00300 objset_t *mos; 00301 00302 error = dsl_dir_open(ddname, FTAG, &startdd, NULL); 00303 if (error) 00304 return (error); 00305 00306 dp = startdd->dd_pool; 00307 mos = dp->dp_meta_objset; 00308 00309 VERIFY(nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP) == 0); 00310 00311 rw_enter(&dp->dp_config_rwlock, RW_READER); 00312 for (dd = startdd; dd != NULL; dd = dd->dd_parent) { 00313 zap_cursor_t basezc; 00314 zap_attribute_t baseza; 00315 nvlist_t *sp_nvp; 00316 uint64_t n; 00317 char source[MAXNAMELEN]; 00318 00319 if (dd->dd_phys->dd_deleg_zapobj && 00320 (zap_count(mos, dd->dd_phys->dd_deleg_zapobj, 00321 &n) == 0) && n) { 00322 VERIFY(nvlist_alloc(&sp_nvp, 00323 NV_UNIQUE_NAME, KM_SLEEP) == 0); 00324 } else { 00325 continue; 00326 } 00327 00328 for (zap_cursor_init(&basezc, mos, 00329 dd->dd_phys->dd_deleg_zapobj); 00330 zap_cursor_retrieve(&basezc, &baseza) == 0; 00331 zap_cursor_advance(&basezc)) { 00332 zap_cursor_t zc; 00333 zap_attribute_t za; 00334 nvlist_t *perms_nvp; 00335 00336 ASSERT(baseza.za_integer_length == 8); 00337 ASSERT(baseza.za_num_integers == 1); 00338 00339 VERIFY(nvlist_alloc(&perms_nvp, 00340 NV_UNIQUE_NAME, KM_SLEEP) == 0); 00341 for (zap_cursor_init(&zc, mos, baseza.za_first_integer); 00342 zap_cursor_retrieve(&zc, &za) == 0; 00343 zap_cursor_advance(&zc)) { 00344 VERIFY(nvlist_add_boolean(perms_nvp, 00345 za.za_name) == 0); 00346 } 00347 zap_cursor_fini(&zc); 00348 VERIFY(nvlist_add_nvlist(sp_nvp, baseza.za_name, 00349 perms_nvp) == 0); 00350 nvlist_free(perms_nvp); 00351 } 00352 00353 zap_cursor_fini(&basezc); 00354 00355 dsl_dir_name(dd, source); 00356 VERIFY(nvlist_add_nvlist(*nvp, source, sp_nvp) == 0); 00357 nvlist_free(sp_nvp); 00358 } 00359 rw_exit(&dp->dp_config_rwlock); 00360 00361 dsl_dir_close(startdd, FTAG); 00362 return (0); 00363 } 00364 00368 typedef struct perm_set { 00369 avl_node_t p_node; 00370 boolean_t p_matched; 00371 char p_setname[ZFS_MAX_DELEG_NAME]; 00372 } perm_set_t; 00373 00374 static int 00375 perm_set_compare(const void *arg1, const void *arg2) 00376 { 00377 const perm_set_t *node1 = arg1; 00378 const perm_set_t *node2 = arg2; 00379 int val; 00380 00381 val = strcmp(node1->p_setname, node2->p_setname); 00382 if (val == 0) 00383 return (0); 00384 return (val > 0 ? 1 : -1); 00385 } 00386 00397 static int 00398 dsl_check_access(objset_t *mos, uint64_t zapobj, 00399 char type, char checkflag, void *valp, const char *perm) 00400 { 00401 int error; 00402 uint64_t jumpobj, zero; 00403 char whokey[ZFS_MAX_DELEG_NAME]; 00404 00405 zfs_deleg_whokey(whokey, type, checkflag, valp); 00406 error = zap_lookup(mos, zapobj, whokey, 8, 1, &jumpobj); 00407 if (error == 0) { 00408 error = zap_lookup(mos, jumpobj, perm, 8, 1, &zero); 00409 if (error == ENOENT) 00410 error = EPERM; 00411 } 00412 return (error); 00413 } 00414 00418 static int 00419 dsl_check_user_access(objset_t *mos, uint64_t zapobj, const char *perm, 00420 int checkflag, cred_t *cr) 00421 { 00422 const gid_t *gids; 00423 int ngids; 00424 int i; 00425 uint64_t id; 00426 00427 /* check for user */ 00428 id = crgetuid(cr); 00429 if (dsl_check_access(mos, zapobj, 00430 ZFS_DELEG_USER, checkflag, &id, perm) == 0) 00431 return (0); 00432 00433 /* check for users primary group */ 00434 id = crgetgid(cr); 00435 if (dsl_check_access(mos, zapobj, 00436 ZFS_DELEG_GROUP, checkflag, &id, perm) == 0) 00437 return (0); 00438 00439 /* check for everyone entry */ 00440 id = -1; 00441 if (dsl_check_access(mos, zapobj, 00442 ZFS_DELEG_EVERYONE, checkflag, &id, perm) == 0) 00443 return (0); 00444 00445 /* check each supplemental group user is a member of */ 00446 ngids = crgetngroups(cr); 00447 gids = crgetgroups(cr); 00448 for (i = 0; i != ngids; i++) { 00449 id = gids[i]; 00450 if (dsl_check_access(mos, zapobj, 00451 ZFS_DELEG_GROUP, checkflag, &id, perm) == 0) 00452 return (0); 00453 } 00454 00455 return (EPERM); 00456 } 00457 00462 static int 00463 dsl_load_sets(objset_t *mos, uint64_t zapobj, 00464 char type, char checkflag, void *valp, avl_tree_t *avl) 00465 { 00466 zap_cursor_t zc; 00467 zap_attribute_t za; 00468 perm_set_t *permnode; 00469 avl_index_t idx; 00470 uint64_t jumpobj; 00471 int error; 00472 char whokey[ZFS_MAX_DELEG_NAME]; 00473 00474 zfs_deleg_whokey(whokey, type, checkflag, valp); 00475 00476 error = zap_lookup(mos, zapobj, whokey, 8, 1, &jumpobj); 00477 if (error != 0) 00478 return (error); 00479 00480 for (zap_cursor_init(&zc, mos, jumpobj); 00481 zap_cursor_retrieve(&zc, &za) == 0; 00482 zap_cursor_advance(&zc)) { 00483 permnode = kmem_alloc(sizeof (perm_set_t), KM_SLEEP); 00484 (void) strlcpy(permnode->p_setname, za.za_name, 00485 sizeof (permnode->p_setname)); 00486 permnode->p_matched = B_FALSE; 00487 00488 if (avl_find(avl, permnode, &idx) == NULL) { 00489 avl_insert(avl, permnode, idx); 00490 } else { 00491 kmem_free(permnode, sizeof (perm_set_t)); 00492 } 00493 } 00494 zap_cursor_fini(&zc); 00495 return (0); 00496 } 00497 00501 static void 00502 dsl_load_user_sets(objset_t *mos, uint64_t zapobj, avl_tree_t *avl, 00503 char checkflag, cred_t *cr) 00504 { 00505 const gid_t *gids; 00506 int ngids, i; 00507 uint64_t id; 00508 00509 id = crgetuid(cr); 00510 (void) dsl_load_sets(mos, zapobj, 00511 ZFS_DELEG_USER_SETS, checkflag, &id, avl); 00512 00513 id = crgetgid(cr); 00514 (void) dsl_load_sets(mos, zapobj, 00515 ZFS_DELEG_GROUP_SETS, checkflag, &id, avl); 00516 00517 (void) dsl_load_sets(mos, zapobj, 00518 ZFS_DELEG_EVERYONE_SETS, checkflag, NULL, avl); 00519 00520 ngids = crgetngroups(cr); 00521 gids = crgetgroups(cr); 00522 for (i = 0; i != ngids; i++) { 00523 id = gids[i]; 00524 (void) dsl_load_sets(mos, zapobj, 00525 ZFS_DELEG_GROUP_SETS, checkflag, &id, avl); 00526 } 00527 } 00528 00533 int 00534 dsl_deleg_access_impl(dsl_dataset_t *ds, boolean_t descendent, const char *perm, 00535 cred_t *cr) 00536 { 00537 dsl_dir_t *dd; 00538 dsl_pool_t *dp; 00539 void *cookie; 00540 int error; 00541 char checkflag; 00542 objset_t *mos; 00543 avl_tree_t permsets; 00544 perm_set_t *setnode; 00545 00546 dp = ds->ds_dir->dd_pool; 00547 mos = dp->dp_meta_objset; 00548 00549 if (dsl_delegation_on(mos) == B_FALSE) 00550 return (ECANCELED); 00551 00552 if (spa_version(dmu_objset_spa(dp->dp_meta_objset)) < 00553 SPA_VERSION_DELEGATED_PERMS) 00554 return (EPERM); 00555 00556 if (dsl_dataset_is_snapshot(ds) || descendent) { 00557 /* 00558 * Snapshots are treated as descendents only, 00559 * local permissions do not apply. 00560 */ 00561 checkflag = ZFS_DELEG_DESCENDENT; 00562 } else { 00563 checkflag = ZFS_DELEG_LOCAL; 00564 } 00565 00566 avl_create(&permsets, perm_set_compare, sizeof (perm_set_t), 00567 offsetof(perm_set_t, p_node)); 00568 00569 rw_enter(&dp->dp_config_rwlock, RW_READER); 00570 for (dd = ds->ds_dir; dd != NULL; dd = dd->dd_parent, 00571 checkflag = ZFS_DELEG_DESCENDENT) { 00572 uint64_t zapobj; 00573 boolean_t expanded; 00574 00575 /* 00576 * If not in global zone then make sure 00577 * the zoned property is set 00578 */ 00579 if (!INGLOBALZONE(curthread)) { 00580 uint64_t zoned; 00581 00582 if (dsl_prop_get_dd(dd, 00583 zfs_prop_to_name(ZFS_PROP_ZONED), 00584 8, 1, &zoned, NULL, B_FALSE) != 0) 00585 break; 00586 if (!zoned) 00587 break; 00588 } 00589 zapobj = dd->dd_phys->dd_deleg_zapobj; 00590 00591 if (zapobj == 0) 00592 continue; 00593 00594 dsl_load_user_sets(mos, zapobj, &permsets, checkflag, cr); 00595 again: 00596 expanded = B_FALSE; 00597 for (setnode = avl_first(&permsets); setnode; 00598 setnode = AVL_NEXT(&permsets, setnode)) { 00599 if (setnode->p_matched == B_TRUE) 00600 continue; 00601 00602 /* See if this set directly grants this permission */ 00603 error = dsl_check_access(mos, zapobj, 00604 ZFS_DELEG_NAMED_SET, 0, setnode->p_setname, perm); 00605 if (error == 0) 00606 goto success; 00607 if (error == EPERM) 00608 setnode->p_matched = B_TRUE; 00609 00610 /* See if this set includes other sets */ 00611 error = dsl_load_sets(mos, zapobj, 00612 ZFS_DELEG_NAMED_SET_SETS, 0, 00613 setnode->p_setname, &permsets); 00614 if (error == 0) 00615 setnode->p_matched = expanded = B_TRUE; 00616 } 00617 /* 00618 * If we expanded any sets, that will define more sets, 00619 * which we need to check. 00620 */ 00621 if (expanded) 00622 goto again; 00623 00624 error = dsl_check_user_access(mos, zapobj, perm, checkflag, cr); 00625 if (error == 0) 00626 goto success; 00627 } 00628 error = EPERM; 00629 success: 00630 rw_exit(&dp->dp_config_rwlock); 00631 00632 cookie = NULL; 00633 while ((setnode = avl_destroy_nodes(&permsets, &cookie)) != NULL) 00634 kmem_free(setnode, sizeof (perm_set_t)); 00635 00636 return (error); 00637 } 00638 00639 int 00640 dsl_deleg_access(const char *dsname, const char *perm, cred_t *cr) 00641 { 00642 dsl_dataset_t *ds; 00643 int error; 00644 00645 error = dsl_dataset_hold(dsname, FTAG, &ds); 00646 if (error) 00647 return (error); 00648 00649 error = dsl_deleg_access_impl(ds, B_FALSE, perm, cr); 00650 dsl_dataset_rele(ds, FTAG); 00651 00652 return (error); 00653 } 00654 00655 /* 00656 * Other routines. 00657 */ 00658 00659 static void 00660 copy_create_perms(dsl_dir_t *dd, uint64_t pzapobj, 00661 boolean_t dosets, uint64_t uid, dmu_tx_t *tx) 00662 { 00663 objset_t *mos = dd->dd_pool->dp_meta_objset; 00664 uint64_t jumpobj, pjumpobj; 00665 uint64_t zapobj = dd->dd_phys->dd_deleg_zapobj; 00666 zap_cursor_t zc; 00667 zap_attribute_t za; 00668 char whokey[ZFS_MAX_DELEG_NAME]; 00669 00670 zfs_deleg_whokey(whokey, 00671 dosets ? ZFS_DELEG_CREATE_SETS : ZFS_DELEG_CREATE, 00672 ZFS_DELEG_LOCAL, NULL); 00673 if (zap_lookup(mos, pzapobj, whokey, 8, 1, &pjumpobj) != 0) 00674 return; 00675 00676 if (zapobj == 0) { 00677 dmu_buf_will_dirty(dd->dd_dbuf, tx); 00678 zapobj = dd->dd_phys->dd_deleg_zapobj = zap_create(mos, 00679 DMU_OT_DSL_PERMS, DMU_OT_NONE, 0, tx); 00680 } 00681 00682 zfs_deleg_whokey(whokey, 00683 dosets ? ZFS_DELEG_USER_SETS : ZFS_DELEG_USER, 00684 ZFS_DELEG_LOCAL, &uid); 00685 if (zap_lookup(mos, zapobj, whokey, 8, 1, &jumpobj) == ENOENT) { 00686 jumpobj = zap_create(mos, DMU_OT_DSL_PERMS, DMU_OT_NONE, 0, tx); 00687 VERIFY(zap_add(mos, zapobj, whokey, 8, 1, &jumpobj, tx) == 0); 00688 } 00689 00690 for (zap_cursor_init(&zc, mos, pjumpobj); 00691 zap_cursor_retrieve(&zc, &za) == 0; 00692 zap_cursor_advance(&zc)) { 00693 uint64_t zero = 0; 00694 ASSERT(za.za_integer_length == 8 && za.za_num_integers == 1); 00695 00696 VERIFY(zap_update(mos, jumpobj, za.za_name, 00697 8, 1, &zero, tx) == 0); 00698 } 00699 zap_cursor_fini(&zc); 00700 } 00701 00705 void 00706 dsl_deleg_set_create_perms(dsl_dir_t *sdd, dmu_tx_t *tx, cred_t *cr) 00707 { 00708 dsl_dir_t *dd; 00709 uint64_t uid = crgetuid(cr); 00710 00711 if (spa_version(dmu_objset_spa(sdd->dd_pool->dp_meta_objset)) < 00712 SPA_VERSION_DELEGATED_PERMS) 00713 return; 00714 00715 for (dd = sdd->dd_parent; dd != NULL; dd = dd->dd_parent) { 00716 uint64_t pzapobj = dd->dd_phys->dd_deleg_zapobj; 00717 00718 if (pzapobj == 0) 00719 continue; 00720 00721 copy_create_perms(sdd, pzapobj, B_FALSE, uid, tx); 00722 copy_create_perms(sdd, pzapobj, B_TRUE, uid, tx); 00723 } 00724 } 00725 00726 int 00727 dsl_deleg_destroy(objset_t *mos, uint64_t zapobj, dmu_tx_t *tx) 00728 { 00729 zap_cursor_t zc; 00730 zap_attribute_t za; 00731 00732 if (zapobj == 0) 00733 return (0); 00734 00735 for (zap_cursor_init(&zc, mos, zapobj); 00736 zap_cursor_retrieve(&zc, &za) == 0; 00737 zap_cursor_advance(&zc)) { 00738 ASSERT(za.za_integer_length == 8 && za.za_num_integers == 1); 00739 VERIFY(0 == zap_destroy(mos, za.za_first_integer, tx)); 00740 } 00741 zap_cursor_fini(&zc); 00742 VERIFY(0 == zap_destroy(mos, zapobj, tx)); 00743 return (0); 00744 } 00745 00746 boolean_t 00747 dsl_delegation_on(objset_t *os) 00748 { 00749 return (!!spa_delegation(os->os_spa)); 00750 }