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 /* 00023 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 00024 * Portions Copyright 2011 iXsystems, Inc 00025 * Copyright (c) 2012 by Delphix. All rights reserved. 00026 */ 00027 00028 #include <sys/zfs_context.h> 00029 #include <sys/types.h> 00030 #include <sys/param.h> 00031 #include <sys/systm.h> 00032 #include <sys/sysmacros.h> 00033 #include <sys/dmu.h> 00034 #include <sys/dmu_impl.h> 00035 #include <sys/dmu_objset.h> 00036 #include <sys/dbuf.h> 00037 #include <sys/dnode.h> 00038 #include <sys/zap.h> 00039 #include <sys/sa.h> 00040 #include <sys/sunddi.h> 00041 #include <sys/sa_impl.h> 00042 #include <sys/dnode.h> 00043 #include <sys/errno.h> 00044 #include <sys/zfs_context.h> 00045 00128 typedef void (sa_iterfunc_t)(void *hdr, void *addr, sa_attr_type_t, 00129 uint16_t length, int length_idx, boolean_t, void *userp); 00130 00131 static int sa_build_index(sa_handle_t *hdl, sa_buf_type_t buftype); 00132 static void sa_idx_tab_hold(objset_t *os, sa_idx_tab_t *idx_tab); 00133 static void *sa_find_idx_tab(objset_t *os, dmu_object_type_t bonustype, 00134 void *data); 00135 static void sa_idx_tab_rele(objset_t *os, void *arg); 00136 static void sa_copy_data(sa_data_locator_t *func, void *start, void *target, 00137 int buflen); 00138 static int sa_modify_attrs(sa_handle_t *hdl, sa_attr_type_t newattr, 00139 sa_data_op_t action, sa_data_locator_t *locator, void *datastart, 00140 uint16_t buflen, dmu_tx_t *tx); 00141 00142 arc_byteswap_func_t *sa_bswap_table[] = { 00143 byteswap_uint64_array, 00144 byteswap_uint32_array, 00145 byteswap_uint16_array, 00146 byteswap_uint8_array, 00147 zfs_acl_byteswap, 00148 }; 00149 00150 #define SA_COPY_DATA(f, s, t, l) \ 00151 { \ 00152 if (f == NULL) { \ 00153 if (l == 8) { \ 00154 *(uint64_t *)t = *(uint64_t *)s; \ 00155 } else if (l == 16) { \ 00156 *(uint64_t *)t = *(uint64_t *)s; \ 00157 *(uint64_t *)((uintptr_t)t + 8) = \ 00158 *(uint64_t *)((uintptr_t)s + 8); \ 00159 } else { \ 00160 bcopy(s, t, l); \ 00161 } \ 00162 } else \ 00163 sa_copy_data(f, s, t, l); \ 00164 } 00165 00176 sa_attr_reg_t sa_legacy_attrs[] = { 00177 {"ZPL_ATIME", sizeof (uint64_t) * 2, SA_UINT64_ARRAY, 0}, 00178 {"ZPL_MTIME", sizeof (uint64_t) * 2, SA_UINT64_ARRAY, 1}, 00179 {"ZPL_CTIME", sizeof (uint64_t) * 2, SA_UINT64_ARRAY, 2}, 00180 {"ZPL_CRTIME", sizeof (uint64_t) * 2, SA_UINT64_ARRAY, 3}, 00181 {"ZPL_GEN", sizeof (uint64_t), SA_UINT64_ARRAY, 4}, 00182 {"ZPL_MODE", sizeof (uint64_t), SA_UINT64_ARRAY, 5}, 00183 {"ZPL_SIZE", sizeof (uint64_t), SA_UINT64_ARRAY, 6}, 00184 {"ZPL_PARENT", sizeof (uint64_t), SA_UINT64_ARRAY, 7}, 00185 {"ZPL_LINKS", sizeof (uint64_t), SA_UINT64_ARRAY, 8}, 00186 {"ZPL_XATTR", sizeof (uint64_t), SA_UINT64_ARRAY, 9}, 00187 {"ZPL_RDEV", sizeof (uint64_t), SA_UINT64_ARRAY, 10}, 00188 {"ZPL_FLAGS", sizeof (uint64_t), SA_UINT64_ARRAY, 11}, 00189 {"ZPL_UID", sizeof (uint64_t), SA_UINT64_ARRAY, 12}, 00190 {"ZPL_GID", sizeof (uint64_t), SA_UINT64_ARRAY, 13}, 00191 {"ZPL_PAD", sizeof (uint64_t) * 4, SA_UINT64_ARRAY, 14}, 00192 {"ZPL_ZNODE_ACL", 88, SA_UINT8_ARRAY, 15}, 00193 }; 00194 00200 sa_attr_type_t sa_legacy_zpl_layout[] = { 00201 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 00202 }; 00203 00207 sa_attr_type_t sa_dummy_zpl_layout[] = { 0 }; 00208 00209 static int sa_legacy_attr_count = 16; 00210 static kmem_cache_t *sa_cache = NULL; 00211 00212 /*ARGSUSED*/ 00213 static int 00214 sa_cache_constructor(void *buf, void *unused, int kmflag) 00215 { 00216 sa_handle_t *hdl = buf; 00217 00218 hdl->sa_bonus_tab = NULL; 00219 hdl->sa_spill_tab = NULL; 00220 hdl->sa_os = NULL; 00221 hdl->sa_userp = NULL; 00222 hdl->sa_bonus = NULL; 00223 hdl->sa_spill = NULL; 00224 mutex_init(&hdl->sa_lock, NULL, MUTEX_DEFAULT, NULL); 00225 return (0); 00226 } 00227 00228 /*ARGSUSED*/ 00229 static void 00230 sa_cache_destructor(void *buf, void *unused) 00231 { 00232 sa_handle_t *hdl = buf; 00233 mutex_destroy(&hdl->sa_lock); 00234 } 00235 00236 void 00237 sa_cache_init(void) 00238 { 00239 sa_cache = kmem_cache_create("sa_cache", 00240 sizeof (sa_handle_t), 0, sa_cache_constructor, 00241 sa_cache_destructor, NULL, NULL, NULL, 0); 00242 } 00243 00244 void 00245 sa_cache_fini(void) 00246 { 00247 if (sa_cache) 00248 kmem_cache_destroy(sa_cache); 00249 } 00250 00251 static int 00252 layout_num_compare(const void *arg1, const void *arg2) 00253 { 00254 const sa_lot_t *node1 = arg1; 00255 const sa_lot_t *node2 = arg2; 00256 00257 if (node1->lot_num > node2->lot_num) 00258 return (1); 00259 else if (node1->lot_num < node2->lot_num) 00260 return (-1); 00261 return (0); 00262 } 00263 00264 static int 00265 layout_hash_compare(const void *arg1, const void *arg2) 00266 { 00267 const sa_lot_t *node1 = arg1; 00268 const sa_lot_t *node2 = arg2; 00269 00270 if (node1->lot_hash > node2->lot_hash) 00271 return (1); 00272 if (node1->lot_hash < node2->lot_hash) 00273 return (-1); 00274 if (node1->lot_instance > node2->lot_instance) 00275 return (1); 00276 if (node1->lot_instance < node2->lot_instance) 00277 return (-1); 00278 return (0); 00279 } 00280 00281 boolean_t 00282 sa_layout_equal(sa_lot_t *tbf, sa_attr_type_t *attrs, int count) 00283 { 00284 int i; 00285 00286 if (count != tbf->lot_attr_count) 00287 return (1); 00288 00289 for (i = 0; i != count; i++) { 00290 if (attrs[i] != tbf->lot_attrs[i]) 00291 return (1); 00292 } 00293 return (0); 00294 } 00295 00296 #define SA_ATTR_HASH(attr) (zfs_crc64_table[(-1ULL ^ attr) & 0xFF]) 00297 00298 static uint64_t 00299 sa_layout_info_hash(sa_attr_type_t *attrs, int attr_count) 00300 { 00301 int i; 00302 uint64_t crc = -1ULL; 00303 00304 for (i = 0; i != attr_count; i++) 00305 crc ^= SA_ATTR_HASH(attrs[i]); 00306 00307 return (crc); 00308 } 00309 00310 static int 00311 sa_get_spill(sa_handle_t *hdl) 00312 { 00313 int rc; 00314 if (hdl->sa_spill == NULL) { 00315 if ((rc = dmu_spill_hold_existing(hdl->sa_bonus, NULL, 00316 &hdl->sa_spill)) == 0) 00317 VERIFY(0 == sa_build_index(hdl, SA_SPILL)); 00318 } else { 00319 rc = 0; 00320 } 00321 00322 return (rc); 00323 } 00324 00332 int 00333 sa_attr_op(sa_handle_t *hdl, sa_bulk_attr_t *bulk, int count, 00334 sa_data_op_t data_op, dmu_tx_t *tx) 00335 { 00336 sa_os_t *sa = hdl->sa_os->os_sa; 00337 int i; 00338 int error = 0; 00339 sa_buf_type_t buftypes; 00340 00341 buftypes = 0; 00342 00343 ASSERT(count > 0); 00344 for (i = 0; i != count; i++) { 00345 ASSERT(bulk[i].sa_attr <= hdl->sa_os->os_sa->sa_num_attrs); 00346 00347 bulk[i].sa_addr = NULL; 00348 /* First check the bonus buffer */ 00349 00350 if (hdl->sa_bonus_tab && TOC_ATTR_PRESENT( 00351 hdl->sa_bonus_tab->sa_idx_tab[bulk[i].sa_attr])) { 00352 SA_ATTR_INFO(sa, hdl->sa_bonus_tab, 00353 SA_GET_HDR(hdl, SA_BONUS), 00354 bulk[i].sa_attr, bulk[i], SA_BONUS, hdl); 00355 if (tx && !(buftypes & SA_BONUS)) { 00356 dmu_buf_will_dirty(hdl->sa_bonus, tx); 00357 buftypes |= SA_BONUS; 00358 } 00359 } 00360 if (bulk[i].sa_addr == NULL && 00361 ((error = sa_get_spill(hdl)) == 0)) { 00362 if (TOC_ATTR_PRESENT( 00363 hdl->sa_spill_tab->sa_idx_tab[bulk[i].sa_attr])) { 00364 SA_ATTR_INFO(sa, hdl->sa_spill_tab, 00365 SA_GET_HDR(hdl, SA_SPILL), 00366 bulk[i].sa_attr, bulk[i], SA_SPILL, hdl); 00367 if (tx && !(buftypes & SA_SPILL) && 00368 bulk[i].sa_size == bulk[i].sa_length) { 00369 dmu_buf_will_dirty(hdl->sa_spill, tx); 00370 buftypes |= SA_SPILL; 00371 } 00372 } 00373 } 00374 if (error && error != ENOENT) { 00375 return ((error == ECKSUM) ? EIO : error); 00376 } 00377 00378 switch (data_op) { 00379 case SA_LOOKUP: 00380 if (bulk[i].sa_addr == NULL) 00381 return (ENOENT); 00382 if (bulk[i].sa_data) { 00383 SA_COPY_DATA(bulk[i].sa_data_func, 00384 bulk[i].sa_addr, bulk[i].sa_data, 00385 bulk[i].sa_size); 00386 } 00387 continue; 00388 00389 case SA_UPDATE: 00390 /* existing rewrite of attr */ 00391 if (bulk[i].sa_addr && 00392 bulk[i].sa_size == bulk[i].sa_length) { 00393 SA_COPY_DATA(bulk[i].sa_data_func, 00394 bulk[i].sa_data, bulk[i].sa_addr, 00395 bulk[i].sa_length); 00396 continue; 00397 } else if (bulk[i].sa_addr) { /* attr size change */ 00398 error = sa_modify_attrs(hdl, bulk[i].sa_attr, 00399 SA_REPLACE, bulk[i].sa_data_func, 00400 bulk[i].sa_data, bulk[i].sa_length, tx); 00401 } else { /* adding new attribute */ 00402 error = sa_modify_attrs(hdl, bulk[i].sa_attr, 00403 SA_ADD, bulk[i].sa_data_func, 00404 bulk[i].sa_data, bulk[i].sa_length, tx); 00405 } 00406 if (error) 00407 return (error); 00408 break; 00409 } 00410 } 00411 return (error); 00412 } 00413 00414 static sa_lot_t * 00415 sa_add_layout_entry(objset_t *os, sa_attr_type_t *attrs, int attr_count, 00416 uint64_t lot_num, uint64_t hash, boolean_t zapadd, dmu_tx_t *tx) 00417 { 00418 sa_os_t *sa = os->os_sa; 00419 sa_lot_t *tb, *findtb; 00420 int i; 00421 avl_index_t loc; 00422 00423 ASSERT(MUTEX_HELD(&sa->sa_lock)); 00424 tb = kmem_zalloc(sizeof (sa_lot_t), KM_SLEEP); 00425 tb->lot_attr_count = attr_count; 00426 tb->lot_attrs = kmem_alloc(sizeof (sa_attr_type_t) * attr_count, 00427 KM_SLEEP); 00428 bcopy(attrs, tb->lot_attrs, sizeof (sa_attr_type_t) * attr_count); 00429 tb->lot_num = lot_num; 00430 tb->lot_hash = hash; 00431 tb->lot_instance = 0; 00432 00433 if (zapadd) { 00434 char attr_name[8]; 00435 00436 if (sa->sa_layout_attr_obj == 0) { 00437 sa->sa_layout_attr_obj = zap_create_link(os, 00438 DMU_OT_SA_ATTR_LAYOUTS, 00439 sa->sa_master_obj, SA_LAYOUTS, tx); 00440 } 00441 00442 (void) snprintf(attr_name, sizeof (attr_name), 00443 "%d", (int)lot_num); 00444 VERIFY(0 == zap_update(os, os->os_sa->sa_layout_attr_obj, 00445 attr_name, 2, attr_count, attrs, tx)); 00446 } 00447 00448 list_create(&tb->lot_idx_tab, sizeof (sa_idx_tab_t), 00449 offsetof(sa_idx_tab_t, sa_next)); 00450 00451 for (i = 0; i != attr_count; i++) { 00452 if (sa->sa_attr_table[tb->lot_attrs[i]].sa_length == 0) 00453 tb->lot_var_sizes++; 00454 } 00455 00456 avl_add(&sa->sa_layout_num_tree, tb); 00457 00458 /* verify we don't have a hash collision */ 00459 if ((findtb = avl_find(&sa->sa_layout_hash_tree, tb, &loc)) != NULL) { 00460 for (; findtb && findtb->lot_hash == hash; 00461 findtb = AVL_NEXT(&sa->sa_layout_hash_tree, findtb)) { 00462 if (findtb->lot_instance != tb->lot_instance) 00463 break; 00464 tb->lot_instance++; 00465 } 00466 } 00467 avl_add(&sa->sa_layout_hash_tree, tb); 00468 return (tb); 00469 } 00470 00471 static void 00472 sa_find_layout(objset_t *os, uint64_t hash, sa_attr_type_t *attrs, 00473 int count, dmu_tx_t *tx, sa_lot_t **lot) 00474 { 00475 sa_lot_t *tb, tbsearch; 00476 avl_index_t loc; 00477 sa_os_t *sa = os->os_sa; 00478 boolean_t found = B_FALSE; 00479 00480 mutex_enter(&sa->sa_lock); 00481 tbsearch.lot_hash = hash; 00482 tbsearch.lot_instance = 0; 00483 tb = avl_find(&sa->sa_layout_hash_tree, &tbsearch, &loc); 00484 if (tb) { 00485 for (; tb && tb->lot_hash == hash; 00486 tb = AVL_NEXT(&sa->sa_layout_hash_tree, tb)) { 00487 if (sa_layout_equal(tb, attrs, count) == 0) { 00488 found = B_TRUE; 00489 break; 00490 } 00491 } 00492 } 00493 if (!found) { 00494 tb = sa_add_layout_entry(os, attrs, count, 00495 avl_numnodes(&sa->sa_layout_num_tree), hash, B_TRUE, tx); 00496 } 00497 mutex_exit(&sa->sa_lock); 00498 *lot = tb; 00499 } 00500 00501 static int 00502 sa_resize_spill(sa_handle_t *hdl, uint32_t size, dmu_tx_t *tx) 00503 { 00504 int error; 00505 uint32_t blocksize; 00506 00507 if (size == 0) { 00508 blocksize = SPA_MINBLOCKSIZE; 00509 } else if (size > SPA_MAXBLOCKSIZE) { 00510 ASSERT(0); 00511 return (EFBIG); 00512 } else { 00513 blocksize = P2ROUNDUP_TYPED(size, SPA_MINBLOCKSIZE, uint32_t); 00514 } 00515 00516 error = dbuf_spill_set_blksz(hdl->sa_spill, blocksize, tx); 00517 ASSERT(error == 0); 00518 return (error); 00519 } 00520 00521 static void 00522 sa_copy_data(sa_data_locator_t *func, void *datastart, void *target, int buflen) 00523 { 00524 if (func == NULL) { 00525 bcopy(datastart, target, buflen); 00526 } else { 00527 boolean_t start; 00528 int bytes; 00529 void *dataptr; 00530 void *saptr = target; 00531 uint32_t length; 00532 00533 start = B_TRUE; 00534 bytes = 0; 00535 while (bytes < buflen) { 00536 func(&dataptr, &length, buflen, start, datastart); 00537 bcopy(dataptr, saptr, length); 00538 saptr = (void *)((caddr_t)saptr + length); 00539 bytes += length; 00540 start = B_FALSE; 00541 } 00542 } 00543 } 00544 00554 static int 00555 sa_find_sizes(sa_os_t *sa, sa_bulk_attr_t *attr_desc, int attr_count, 00556 dmu_buf_t *db, sa_buf_type_t buftype, int *index, int *total, 00557 boolean_t *will_spill) 00558 { 00559 int var_size = 0; 00560 int i; 00561 int full_space; 00562 int hdrsize; 00563 boolean_t done = B_FALSE; 00564 00565 if (buftype == SA_BONUS && sa->sa_force_spill) { 00566 *total = 0; 00567 *index = 0; 00568 *will_spill = B_TRUE; 00569 return (0); 00570 } 00571 00572 *index = -1; 00573 *total = 0; 00574 00575 if (buftype == SA_BONUS) 00576 *will_spill = B_FALSE; 00577 00578 hdrsize = (SA_BONUSTYPE_FROM_DB(db) == DMU_OT_ZNODE) ? 0 : 00579 sizeof (sa_hdr_phys_t); 00580 00581 full_space = (buftype == SA_BONUS) ? DN_MAX_BONUSLEN : db->db_size; 00582 00583 for (i = 0; i != attr_count; i++) { 00584 boolean_t is_var_sz; 00585 00586 *total += P2ROUNDUP(attr_desc[i].sa_length, 8); 00587 if (done) 00588 goto next; 00589 00590 is_var_sz = (SA_REGISTERED_LEN(sa, attr_desc[i].sa_attr) == 0); 00591 if (is_var_sz) { 00592 var_size++; 00593 } 00594 00595 if (is_var_sz && var_size > 1) { 00596 if (P2ROUNDUP(hdrsize + sizeof (uint16_t), 8) + 00597 *total < full_space) { 00598 hdrsize += sizeof (uint16_t); 00599 } else { 00600 done = B_TRUE; 00601 *index = i; 00602 if (buftype == SA_BONUS) 00603 *will_spill = B_TRUE; 00604 continue; 00605 } 00606 } 00607 00608 /* 00609 * find index of where spill *could* occur. 00610 * Then continue to count of remainder attribute 00611 * space. The sum is used later for sizing bonus 00612 * and spill buffer. 00613 */ 00614 if (buftype == SA_BONUS && *index == -1 && 00615 (*total + P2ROUNDUP(hdrsize, 8)) > 00616 (full_space - sizeof (blkptr_t))) { 00617 *index = i; 00618 done = B_TRUE; 00619 } 00620 00621 next: 00622 if ((*total + P2ROUNDUP(hdrsize, 8)) > full_space && 00623 buftype == SA_BONUS) 00624 *will_spill = B_TRUE; 00625 } 00626 00627 hdrsize = P2ROUNDUP(hdrsize, 8); 00628 return (hdrsize); 00629 } 00630 00631 #define BUF_SPACE_NEEDED(total, header) (total + header) 00632 00639 static int 00640 sa_build_layouts(sa_handle_t *hdl, sa_bulk_attr_t *attr_desc, int attr_count, 00641 dmu_tx_t *tx) 00642 { 00643 sa_os_t *sa = hdl->sa_os->os_sa; 00644 uint64_t hash; 00645 sa_buf_type_t buftype; 00646 sa_hdr_phys_t *sahdr; 00647 void *data_start; 00648 int buf_space; 00649 sa_attr_type_t *attrs, *attrs_start; 00650 int i, lot_count; 00651 int hdrsize, spillhdrsize; 00652 int used; 00653 dmu_object_type_t bonustype; 00654 sa_lot_t *lot; 00655 int len_idx; 00656 int spill_used; 00657 boolean_t spilling; 00658 00659 dmu_buf_will_dirty(hdl->sa_bonus, tx); 00660 bonustype = SA_BONUSTYPE_FROM_DB(hdl->sa_bonus); 00661 00662 /* first determine bonus header size and sum of all attributes */ 00663 hdrsize = sa_find_sizes(sa, attr_desc, attr_count, hdl->sa_bonus, 00664 SA_BONUS, &i, &used, &spilling); 00665 00666 if (used > SPA_MAXBLOCKSIZE) 00667 return (EFBIG); 00668 00669 VERIFY(0 == dmu_set_bonus(hdl->sa_bonus, spilling ? 00670 MIN(DN_MAX_BONUSLEN - sizeof (blkptr_t), used + hdrsize) : 00671 used + hdrsize, tx)); 00672 00673 ASSERT((bonustype == DMU_OT_ZNODE && spilling == 0) || 00674 bonustype == DMU_OT_SA); 00675 00676 /* setup and size spill buffer when needed */ 00677 if (spilling) { 00678 boolean_t dummy; 00679 00680 if (hdl->sa_spill == NULL) { 00681 VERIFY(dmu_spill_hold_by_bonus(hdl->sa_bonus, NULL, 00682 &hdl->sa_spill) == 0); 00683 } 00684 dmu_buf_will_dirty(hdl->sa_spill, tx); 00685 00686 spillhdrsize = sa_find_sizes(sa, &attr_desc[i], 00687 attr_count - i, hdl->sa_spill, SA_SPILL, &i, 00688 &spill_used, &dummy); 00689 00690 if (spill_used > SPA_MAXBLOCKSIZE) 00691 return (EFBIG); 00692 00693 buf_space = hdl->sa_spill->db_size - spillhdrsize; 00694 if (BUF_SPACE_NEEDED(spill_used, spillhdrsize) > 00695 hdl->sa_spill->db_size) 00696 VERIFY(0 == sa_resize_spill(hdl, 00697 BUF_SPACE_NEEDED(spill_used, spillhdrsize), tx)); 00698 } 00699 00700 /* setup starting pointers to lay down data */ 00701 data_start = (void *)((uintptr_t)hdl->sa_bonus->db_data + hdrsize); 00702 sahdr = (sa_hdr_phys_t *)hdl->sa_bonus->db_data; 00703 buftype = SA_BONUS; 00704 00705 if (spilling) 00706 buf_space = (sa->sa_force_spill) ? 00707 0 : SA_BLKPTR_SPACE - hdrsize; 00708 else 00709 buf_space = hdl->sa_bonus->db_size - hdrsize; 00710 00711 attrs_start = attrs = kmem_alloc(sizeof (sa_attr_type_t) * attr_count, 00712 KM_SLEEP); 00713 lot_count = 0; 00714 00715 for (i = 0, len_idx = 0, hash = -1ULL; i != attr_count; i++) { 00716 uint16_t length; 00717 00718 attrs[i] = attr_desc[i].sa_attr; 00719 length = SA_REGISTERED_LEN(sa, attrs[i]); 00720 if (length == 0) 00721 length = attr_desc[i].sa_length; 00722 else 00723 VERIFY(length == attr_desc[i].sa_length); 00724 00725 if (buf_space < length) { /* switch to spill buffer */ 00726 VERIFY(bonustype == DMU_OT_SA); 00727 if (buftype == SA_BONUS && !sa->sa_force_spill) { 00728 sa_find_layout(hdl->sa_os, hash, attrs_start, 00729 lot_count, tx, &lot); 00730 SA_SET_HDR(sahdr, lot->lot_num, hdrsize); 00731 } 00732 00733 buftype = SA_SPILL; 00734 hash = -1ULL; 00735 len_idx = 0; 00736 00737 sahdr = (sa_hdr_phys_t *)hdl->sa_spill->db_data; 00738 sahdr->sa_magic = SA_MAGIC; 00739 data_start = (void *)((uintptr_t)sahdr + 00740 spillhdrsize); 00741 attrs_start = &attrs[i]; 00742 buf_space = hdl->sa_spill->db_size - spillhdrsize; 00743 lot_count = 0; 00744 } 00745 hash ^= SA_ATTR_HASH(attrs[i]); 00746 attr_desc[i].sa_addr = data_start; 00747 attr_desc[i].sa_size = length; 00748 SA_COPY_DATA(attr_desc[i].sa_data_func, attr_desc[i].sa_data, 00749 data_start, length); 00750 if (sa->sa_attr_table[attrs[i]].sa_length == 0) { 00751 sahdr->sa_lengths[len_idx++] = length; 00752 } 00753 VERIFY((uintptr_t)data_start % 8 == 0); 00754 data_start = (void *)P2ROUNDUP(((uintptr_t)data_start + 00755 length), 8); 00756 buf_space -= P2ROUNDUP(length, 8); 00757 lot_count++; 00758 } 00759 00760 sa_find_layout(hdl->sa_os, hash, attrs_start, lot_count, tx, &lot); 00761 00762 /* 00763 * Verify that old znodes always have layout number 0. 00764 * Must be DMU_OT_SA for arbitrary layouts 00765 */ 00766 VERIFY((bonustype == DMU_OT_ZNODE && lot->lot_num == 0) || 00767 (bonustype == DMU_OT_SA && lot->lot_num > 1)); 00768 00769 if (bonustype == DMU_OT_SA) { 00770 SA_SET_HDR(sahdr, lot->lot_num, 00771 buftype == SA_BONUS ? hdrsize : spillhdrsize); 00772 } 00773 00774 kmem_free(attrs, sizeof (sa_attr_type_t) * attr_count); 00775 if (hdl->sa_bonus_tab) { 00776 sa_idx_tab_rele(hdl->sa_os, hdl->sa_bonus_tab); 00777 hdl->sa_bonus_tab = NULL; 00778 } 00779 if (!sa->sa_force_spill) 00780 VERIFY(0 == sa_build_index(hdl, SA_BONUS)); 00781 if (hdl->sa_spill) { 00782 sa_idx_tab_rele(hdl->sa_os, hdl->sa_spill_tab); 00783 if (!spilling) { 00784 /* 00785 * remove spill block that is no longer needed. 00786 */ 00787 dmu_buf_rele(hdl->sa_spill, NULL); 00788 hdl->sa_spill = NULL; 00789 hdl->sa_spill_tab = NULL; 00790 VERIFY(0 == dmu_rm_spill(hdl->sa_os, 00791 sa_handle_object(hdl), tx)); 00792 } else { 00793 VERIFY(0 == sa_build_index(hdl, SA_SPILL)); 00794 } 00795 } 00796 00797 return (0); 00798 } 00799 00800 static void 00801 sa_free_attr_table(sa_os_t *sa) 00802 { 00803 int i; 00804 00805 if (sa->sa_attr_table == NULL) 00806 return; 00807 00808 for (i = 0; i != sa->sa_num_attrs; i++) { 00809 if (sa->sa_attr_table[i].sa_name) 00810 kmem_free(sa->sa_attr_table[i].sa_name, 00811 strlen(sa->sa_attr_table[i].sa_name) + 1); 00812 } 00813 00814 kmem_free(sa->sa_attr_table, 00815 sizeof (sa_attr_table_t) * sa->sa_num_attrs); 00816 00817 sa->sa_attr_table = NULL; 00818 } 00819 00820 static int 00821 sa_attr_table_setup(objset_t *os, sa_attr_reg_t *reg_attrs, int count) 00822 { 00823 sa_os_t *sa = os->os_sa; 00824 uint64_t sa_attr_count = 0; 00825 uint64_t sa_reg_count; 00826 int error = 0; 00827 uint64_t attr_value; 00828 sa_attr_table_t *tb; 00829 zap_cursor_t zc; 00830 zap_attribute_t za; 00831 int registered_count = 0; 00832 int i; 00833 dmu_objset_type_t ostype = dmu_objset_type(os); 00834 00835 sa->sa_user_table = 00836 kmem_zalloc(count * sizeof (sa_attr_type_t), KM_SLEEP); 00837 sa->sa_user_table_sz = count * sizeof (sa_attr_type_t); 00838 00839 if (sa->sa_reg_attr_obj != 0) { 00840 error = zap_count(os, sa->sa_reg_attr_obj, 00841 &sa_attr_count); 00842 00843 /* 00844 * Make sure we retrieved a count and that it isn't zero 00845 */ 00846 if (error || (error == 0 && sa_attr_count == 0)) { 00847 if (error == 0) 00848 error = EINVAL; 00849 goto bail; 00850 } 00851 sa_reg_count = sa_attr_count; 00852 } 00853 00854 if (ostype == DMU_OST_ZFS && sa_attr_count == 0) 00855 sa_attr_count += sa_legacy_attr_count; 00856 00857 /* Allocate attribute numbers for attributes that aren't registered */ 00858 for (i = 0; i != count; i++) { 00859 boolean_t found = B_FALSE; 00860 int j; 00861 00862 if (ostype == DMU_OST_ZFS) { 00863 for (j = 0; j != sa_legacy_attr_count; j++) { 00864 if (strcmp(reg_attrs[i].sa_name, 00865 sa_legacy_attrs[j].sa_name) == 0) { 00866 sa->sa_user_table[i] = 00867 sa_legacy_attrs[j].sa_attr; 00868 found = B_TRUE; 00869 } 00870 } 00871 } 00872 if (found) 00873 continue; 00874 00875 if (sa->sa_reg_attr_obj) 00876 error = zap_lookup(os, sa->sa_reg_attr_obj, 00877 reg_attrs[i].sa_name, 8, 1, &attr_value); 00878 else 00879 error = ENOENT; 00880 switch (error) { 00881 case ENOENT: 00882 sa->sa_user_table[i] = (sa_attr_type_t)sa_attr_count; 00883 sa_attr_count++; 00884 break; 00885 case 0: 00886 sa->sa_user_table[i] = ATTR_NUM(attr_value); 00887 break; 00888 default: 00889 goto bail; 00890 } 00891 } 00892 00893 sa->sa_num_attrs = sa_attr_count; 00894 tb = sa->sa_attr_table = 00895 kmem_zalloc(sizeof (sa_attr_table_t) * sa_attr_count, KM_SLEEP); 00896 00897 /* 00898 * Attribute table is constructed from requested attribute list, 00899 * previously foreign registered attributes, and also the legacy 00900 * ZPL set of attributes. 00901 */ 00902 00903 if (sa->sa_reg_attr_obj) { 00904 for (zap_cursor_init(&zc, os, sa->sa_reg_attr_obj); 00905 (error = zap_cursor_retrieve(&zc, &za)) == 0; 00906 zap_cursor_advance(&zc)) { 00907 uint64_t value; 00908 value = za.za_first_integer; 00909 00910 registered_count++; 00911 tb[ATTR_NUM(value)].sa_attr = ATTR_NUM(value); 00912 tb[ATTR_NUM(value)].sa_length = ATTR_LENGTH(value); 00913 tb[ATTR_NUM(value)].sa_byteswap = ATTR_BSWAP(value); 00914 tb[ATTR_NUM(value)].sa_registered = B_TRUE; 00915 00916 if (tb[ATTR_NUM(value)].sa_name) { 00917 continue; 00918 } 00919 tb[ATTR_NUM(value)].sa_name = 00920 kmem_zalloc(strlen(za.za_name) +1, KM_SLEEP); 00921 (void) strlcpy(tb[ATTR_NUM(value)].sa_name, za.za_name, 00922 strlen(za.za_name) +1); 00923 } 00924 zap_cursor_fini(&zc); 00925 /* 00926 * Make sure we processed the correct number of registered 00927 * attributes 00928 */ 00929 if (registered_count != sa_reg_count) { 00930 ASSERT(error != 0); 00931 goto bail; 00932 } 00933 00934 } 00935 00936 if (ostype == DMU_OST_ZFS) { 00937 for (i = 0; i != sa_legacy_attr_count; i++) { 00938 if (tb[i].sa_name) 00939 continue; 00940 tb[i].sa_attr = sa_legacy_attrs[i].sa_attr; 00941 tb[i].sa_length = sa_legacy_attrs[i].sa_length; 00942 tb[i].sa_byteswap = sa_legacy_attrs[i].sa_byteswap; 00943 tb[i].sa_registered = B_FALSE; 00944 tb[i].sa_name = 00945 kmem_zalloc(strlen(sa_legacy_attrs[i].sa_name) +1, 00946 KM_SLEEP); 00947 (void) strlcpy(tb[i].sa_name, 00948 sa_legacy_attrs[i].sa_name, 00949 strlen(sa_legacy_attrs[i].sa_name) + 1); 00950 } 00951 } 00952 00953 for (i = 0; i != count; i++) { 00954 sa_attr_type_t attr_id; 00955 00956 attr_id = sa->sa_user_table[i]; 00957 if (tb[attr_id].sa_name) 00958 continue; 00959 00960 tb[attr_id].sa_length = reg_attrs[i].sa_length; 00961 tb[attr_id].sa_byteswap = reg_attrs[i].sa_byteswap; 00962 tb[attr_id].sa_attr = attr_id; 00963 tb[attr_id].sa_name = 00964 kmem_zalloc(strlen(reg_attrs[i].sa_name) + 1, KM_SLEEP); 00965 (void) strlcpy(tb[attr_id].sa_name, reg_attrs[i].sa_name, 00966 strlen(reg_attrs[i].sa_name) + 1); 00967 } 00968 00969 sa->sa_need_attr_registration = 00970 (sa_attr_count != registered_count); 00971 00972 return (0); 00973 bail: 00974 kmem_free(sa->sa_user_table, count * sizeof (sa_attr_type_t)); 00975 sa->sa_user_table = NULL; 00976 sa_free_attr_table(sa); 00977 return ((error != 0) ? error : EINVAL); 00978 } 00979 00980 int 00981 sa_setup(objset_t *os, uint64_t sa_obj, sa_attr_reg_t *reg_attrs, int count, 00982 sa_attr_type_t **user_table) 00983 { 00984 zap_cursor_t zc; 00985 zap_attribute_t za; 00986 sa_os_t *sa; 00987 dmu_objset_type_t ostype = dmu_objset_type(os); 00988 sa_attr_type_t *tb; 00989 int error; 00990 00991 mutex_enter(&os->os_lock); 00992 if (os->os_sa) { 00993 mutex_enter(&os->os_sa->sa_lock); 00994 mutex_exit(&os->os_lock); 00995 tb = os->os_sa->sa_user_table; 00996 mutex_exit(&os->os_sa->sa_lock); 00997 *user_table = tb; 00998 return (0); 00999 } 01000 01001 sa = kmem_zalloc(sizeof (sa_os_t), KM_SLEEP); 01002 mutex_init(&sa->sa_lock, NULL, MUTEX_DEFAULT, NULL); 01003 sa->sa_master_obj = sa_obj; 01004 01005 os->os_sa = sa; 01006 mutex_enter(&sa->sa_lock); 01007 mutex_exit(&os->os_lock); 01008 avl_create(&sa->sa_layout_num_tree, layout_num_compare, 01009 sizeof (sa_lot_t), offsetof(sa_lot_t, lot_num_node)); 01010 avl_create(&sa->sa_layout_hash_tree, layout_hash_compare, 01011 sizeof (sa_lot_t), offsetof(sa_lot_t, lot_hash_node)); 01012 01013 if (sa_obj) { 01014 error = zap_lookup(os, sa_obj, SA_LAYOUTS, 01015 8, 1, &sa->sa_layout_attr_obj); 01016 if (error != 0 && error != ENOENT) 01017 goto fail; 01018 error = zap_lookup(os, sa_obj, SA_REGISTRY, 01019 8, 1, &sa->sa_reg_attr_obj); 01020 if (error != 0 && error != ENOENT) 01021 goto fail; 01022 } 01023 01024 if ((error = sa_attr_table_setup(os, reg_attrs, count)) != 0) 01025 goto fail; 01026 01027 if (sa->sa_layout_attr_obj != 0) { 01028 uint64_t layout_count; 01029 01030 error = zap_count(os, sa->sa_layout_attr_obj, 01031 &layout_count); 01032 01033 /* 01034 * Layout number count should be > 0 01035 */ 01036 if (error || (error == 0 && layout_count == 0)) { 01037 if (error == 0) 01038 error = EINVAL; 01039 goto fail; 01040 } 01041 01042 for (zap_cursor_init(&zc, os, sa->sa_layout_attr_obj); 01043 (error = zap_cursor_retrieve(&zc, &za)) == 0; 01044 zap_cursor_advance(&zc)) { 01045 sa_attr_type_t *lot_attrs; 01046 uint64_t lot_num; 01047 01048 lot_attrs = kmem_zalloc(sizeof (sa_attr_type_t) * 01049 za.za_num_integers, KM_SLEEP); 01050 01051 if ((error = (zap_lookup(os, sa->sa_layout_attr_obj, 01052 za.za_name, 2, za.za_num_integers, 01053 lot_attrs))) != 0) { 01054 kmem_free(lot_attrs, sizeof (sa_attr_type_t) * 01055 za.za_num_integers); 01056 break; 01057 } 01058 VERIFY(ddi_strtoull(za.za_name, NULL, 10, 01059 (unsigned long long *)&lot_num) == 0); 01060 01061 (void) sa_add_layout_entry(os, lot_attrs, 01062 za.za_num_integers, lot_num, 01063 sa_layout_info_hash(lot_attrs, 01064 za.za_num_integers), B_FALSE, NULL); 01065 kmem_free(lot_attrs, sizeof (sa_attr_type_t) * 01066 za.za_num_integers); 01067 } 01068 zap_cursor_fini(&zc); 01069 01070 /* 01071 * Make sure layout count matches number of entries added 01072 * to AVL tree 01073 */ 01074 if (avl_numnodes(&sa->sa_layout_num_tree) != layout_count) { 01075 ASSERT(error != 0); 01076 goto fail; 01077 } 01078 } 01079 01080 /* Add special layout number for old ZNODES */ 01081 if (ostype == DMU_OST_ZFS) { 01082 (void) sa_add_layout_entry(os, sa_legacy_zpl_layout, 01083 sa_legacy_attr_count, 0, 01084 sa_layout_info_hash(sa_legacy_zpl_layout, 01085 sa_legacy_attr_count), B_FALSE, NULL); 01086 01087 (void) sa_add_layout_entry(os, sa_dummy_zpl_layout, 0, 1, 01088 0, B_FALSE, NULL); 01089 } 01090 *user_table = os->os_sa->sa_user_table; 01091 mutex_exit(&sa->sa_lock); 01092 return (0); 01093 fail: 01094 os->os_sa = NULL; 01095 sa_free_attr_table(sa); 01096 if (sa->sa_user_table) 01097 kmem_free(sa->sa_user_table, sa->sa_user_table_sz); 01098 mutex_exit(&sa->sa_lock); 01099 kmem_free(sa, sizeof (sa_os_t)); 01100 return ((error == ECKSUM) ? EIO : error); 01101 } 01102 01103 void 01104 sa_tear_down(objset_t *os) 01105 { 01106 sa_os_t *sa = os->os_sa; 01107 sa_lot_t *layout; 01108 void *cookie; 01109 01110 kmem_free(sa->sa_user_table, sa->sa_user_table_sz); 01111 01112 /* Free up attr table */ 01113 01114 sa_free_attr_table(sa); 01115 01116 cookie = NULL; 01117 while (layout = avl_destroy_nodes(&sa->sa_layout_hash_tree, &cookie)) { 01118 sa_idx_tab_t *tab; 01119 while (tab = list_head(&layout->lot_idx_tab)) { 01120 ASSERT(refcount_count(&tab->sa_refcount)); 01121 sa_idx_tab_rele(os, tab); 01122 } 01123 } 01124 01125 cookie = NULL; 01126 while (layout = avl_destroy_nodes(&sa->sa_layout_num_tree, &cookie)) { 01127 kmem_free(layout->lot_attrs, 01128 sizeof (sa_attr_type_t) * layout->lot_attr_count); 01129 kmem_free(layout, sizeof (sa_lot_t)); 01130 } 01131 01132 avl_destroy(&sa->sa_layout_hash_tree); 01133 avl_destroy(&sa->sa_layout_num_tree); 01134 01135 kmem_free(sa, sizeof (sa_os_t)); 01136 os->os_sa = NULL; 01137 } 01138 01139 void 01140 sa_build_idx_tab(void *hdr, void *attr_addr, sa_attr_type_t attr, 01141 uint16_t length, int length_idx, boolean_t var_length, void *userp) 01142 { 01143 sa_idx_tab_t *idx_tab = userp; 01144 01145 if (var_length) { 01146 ASSERT(idx_tab->sa_variable_lengths); 01147 idx_tab->sa_variable_lengths[length_idx] = length; 01148 } 01149 TOC_ATTR_ENCODE(idx_tab->sa_idx_tab[attr], length_idx, 01150 (uint32_t)((uintptr_t)attr_addr - (uintptr_t)hdr)); 01151 } 01152 01153 static void 01154 sa_attr_iter(objset_t *os, sa_hdr_phys_t *hdr, dmu_object_type_t type, 01155 sa_iterfunc_t func, sa_lot_t *tab, void *userp) 01156 { 01157 void *data_start; 01158 sa_lot_t *tb = tab; 01159 sa_lot_t search; 01160 avl_index_t loc; 01161 sa_os_t *sa = os->os_sa; 01162 int i; 01163 uint16_t *length_start = NULL; 01164 uint8_t length_idx = 0; 01165 01166 if (tab == NULL) { 01167 search.lot_num = SA_LAYOUT_NUM(hdr, type); 01168 tb = avl_find(&sa->sa_layout_num_tree, &search, &loc); 01169 ASSERT(tb); 01170 } 01171 01172 if (IS_SA_BONUSTYPE(type)) { 01173 data_start = (void *)P2ROUNDUP(((uintptr_t)hdr + 01174 offsetof(sa_hdr_phys_t, sa_lengths) + 01175 (sizeof (uint16_t) * tb->lot_var_sizes)), 8); 01176 length_start = hdr->sa_lengths; 01177 } else { 01178 data_start = hdr; 01179 } 01180 01181 for (i = 0; i != tb->lot_attr_count; i++) { 01182 int attr_length, reg_length; 01183 uint8_t idx_len; 01184 01185 reg_length = sa->sa_attr_table[tb->lot_attrs[i]].sa_length; 01186 if (reg_length) { 01187 attr_length = reg_length; 01188 idx_len = 0; 01189 } else { 01190 attr_length = length_start[length_idx]; 01191 idx_len = length_idx++; 01192 } 01193 01194 func(hdr, data_start, tb->lot_attrs[i], attr_length, 01195 idx_len, reg_length == 0 ? B_TRUE : B_FALSE, userp); 01196 01197 data_start = (void *)P2ROUNDUP(((uintptr_t)data_start + 01198 attr_length), 8); 01199 } 01200 } 01201 01202 /*ARGSUSED*/ 01203 void 01204 sa_byteswap_cb(void *hdr, void *attr_addr, sa_attr_type_t attr, 01205 uint16_t length, int length_idx, boolean_t variable_length, void *userp) 01206 { 01207 sa_handle_t *hdl = userp; 01208 sa_os_t *sa = hdl->sa_os->os_sa; 01209 01210 sa_bswap_table[sa->sa_attr_table[attr].sa_byteswap](attr_addr, length); 01211 } 01212 01213 void 01214 sa_byteswap(sa_handle_t *hdl, sa_buf_type_t buftype) 01215 { 01216 sa_hdr_phys_t *sa_hdr_phys = SA_GET_HDR(hdl, buftype); 01217 dmu_buf_impl_t *db; 01218 sa_os_t *sa = hdl->sa_os->os_sa; 01219 int num_lengths = 1; 01220 int i; 01221 01222 ASSERT(MUTEX_HELD(&sa->sa_lock)); 01223 if (sa_hdr_phys->sa_magic == SA_MAGIC) 01224 return; 01225 01226 db = SA_GET_DB(hdl, buftype); 01227 01228 if (buftype == SA_SPILL) { 01229 arc_release(db->db_buf, NULL); 01230 arc_buf_thaw(db->db_buf); 01231 } 01232 01233 sa_hdr_phys->sa_magic = BSWAP_32(sa_hdr_phys->sa_magic); 01234 sa_hdr_phys->sa_layout_info = BSWAP_16(sa_hdr_phys->sa_layout_info); 01235 01236 /* 01237 * Determine number of variable lenghts in header 01238 * The standard 8 byte header has one for free and a 01239 * 16 byte header would have 4 + 1; 01240 */ 01241 if (SA_HDR_SIZE(sa_hdr_phys) > 8) 01242 num_lengths += (SA_HDR_SIZE(sa_hdr_phys) - 8) >> 1; 01243 for (i = 0; i != num_lengths; i++) 01244 sa_hdr_phys->sa_lengths[i] = 01245 BSWAP_16(sa_hdr_phys->sa_lengths[i]); 01246 01247 sa_attr_iter(hdl->sa_os, sa_hdr_phys, DMU_OT_SA, 01248 sa_byteswap_cb, NULL, hdl); 01249 01250 if (buftype == SA_SPILL) 01251 arc_buf_freeze(((dmu_buf_impl_t *)hdl->sa_spill)->db_buf); 01252 } 01253 01254 static int 01255 sa_build_index(sa_handle_t *hdl, sa_buf_type_t buftype) 01256 { 01257 sa_hdr_phys_t *sa_hdr_phys; 01258 dmu_buf_impl_t *db = SA_GET_DB(hdl, buftype); 01259 dmu_object_type_t bonustype = SA_BONUSTYPE_FROM_DB(db); 01260 sa_os_t *sa = hdl->sa_os->os_sa; 01261 sa_idx_tab_t *idx_tab; 01262 01263 sa_hdr_phys = SA_GET_HDR(hdl, buftype); 01264 01265 mutex_enter(&sa->sa_lock); 01266 01267 /* Do we need to byteswap? */ 01268 01269 /* only check if not old znode */ 01270 if (IS_SA_BONUSTYPE(bonustype) && sa_hdr_phys->sa_magic != SA_MAGIC && 01271 sa_hdr_phys->sa_magic != 0) { 01272 VERIFY(BSWAP_32(sa_hdr_phys->sa_magic) == SA_MAGIC); 01273 sa_byteswap(hdl, buftype); 01274 } 01275 01276 idx_tab = sa_find_idx_tab(hdl->sa_os, bonustype, sa_hdr_phys); 01277 01278 if (buftype == SA_BONUS) 01279 hdl->sa_bonus_tab = idx_tab; 01280 else 01281 hdl->sa_spill_tab = idx_tab; 01282 01283 mutex_exit(&sa->sa_lock); 01284 return (0); 01285 } 01286 01287 /*ARGSUSED*/ 01288 void 01289 sa_evict(dmu_buf_t *db, void *sap) 01290 { 01291 panic("evicting sa dbuf %p\n", (void *)db); 01292 } 01293 01294 static void 01295 sa_idx_tab_rele(objset_t *os, void *arg) 01296 { 01297 sa_os_t *sa = os->os_sa; 01298 sa_idx_tab_t *idx_tab = arg; 01299 01300 if (idx_tab == NULL) 01301 return; 01302 01303 mutex_enter(&sa->sa_lock); 01304 if (refcount_remove(&idx_tab->sa_refcount, NULL) == 0) { 01305 list_remove(&idx_tab->sa_layout->lot_idx_tab, idx_tab); 01306 if (idx_tab->sa_variable_lengths) 01307 kmem_free(idx_tab->sa_variable_lengths, 01308 sizeof (uint16_t) * 01309 idx_tab->sa_layout->lot_var_sizes); 01310 refcount_destroy(&idx_tab->sa_refcount); 01311 kmem_free(idx_tab->sa_idx_tab, 01312 sizeof (uint32_t) * sa->sa_num_attrs); 01313 kmem_free(idx_tab, sizeof (sa_idx_tab_t)); 01314 } 01315 mutex_exit(&sa->sa_lock); 01316 } 01317 01318 static void 01319 sa_idx_tab_hold(objset_t *os, sa_idx_tab_t *idx_tab) 01320 { 01321 sa_os_t *sa = os->os_sa; 01322 01323 ASSERT(MUTEX_HELD(&sa->sa_lock)); 01324 (void) refcount_add(&idx_tab->sa_refcount, NULL); 01325 } 01326 01327 void 01328 sa_handle_destroy(sa_handle_t *hdl) 01329 { 01330 mutex_enter(&hdl->sa_lock); 01331 (void) dmu_buf_update_user((dmu_buf_t *)hdl->sa_bonus, hdl, 01332 NULL, NULL, NULL); 01333 01334 if (hdl->sa_bonus_tab) { 01335 sa_idx_tab_rele(hdl->sa_os, hdl->sa_bonus_tab); 01336 hdl->sa_bonus_tab = NULL; 01337 } 01338 if (hdl->sa_spill_tab) { 01339 sa_idx_tab_rele(hdl->sa_os, hdl->sa_spill_tab); 01340 hdl->sa_spill_tab = NULL; 01341 } 01342 01343 dmu_buf_rele(hdl->sa_bonus, NULL); 01344 01345 if (hdl->sa_spill) 01346 dmu_buf_rele((dmu_buf_t *)hdl->sa_spill, NULL); 01347 mutex_exit(&hdl->sa_lock); 01348 01349 kmem_cache_free(sa_cache, hdl); 01350 } 01351 01352 int 01353 sa_handle_get_from_db(objset_t *os, dmu_buf_t *db, void *userp, 01354 sa_handle_type_t hdl_type, sa_handle_t **handlepp) 01355 { 01356 int error = 0; 01357 dmu_object_info_t doi; 01358 sa_handle_t *handle; 01359 01360 #ifdef ZFS_DEBUG 01361 dmu_object_info_from_db(db, &doi); 01362 ASSERT(doi.doi_bonus_type == DMU_OT_SA || 01363 doi.doi_bonus_type == DMU_OT_ZNODE); 01364 #endif 01365 /* find handle, if it exists */ 01366 /* if one doesn't exist then create a new one, and initialize it */ 01367 01368 handle = (hdl_type == SA_HDL_SHARED) ? dmu_buf_get_user(db) : NULL; 01369 if (handle == NULL) { 01370 sa_handle_t *newhandle; 01371 handle = kmem_cache_alloc(sa_cache, KM_SLEEP); 01372 handle->sa_userp = userp; 01373 handle->sa_bonus = db; 01374 handle->sa_os = os; 01375 handle->sa_spill = NULL; 01376 01377 error = sa_build_index(handle, SA_BONUS); 01378 newhandle = (hdl_type == SA_HDL_SHARED) ? 01379 dmu_buf_set_user_ie(db, handle, 01380 NULL, sa_evict) : NULL; 01381 01382 if (newhandle != NULL) { 01383 kmem_cache_free(sa_cache, handle); 01384 handle = newhandle; 01385 } 01386 } 01387 *handlepp = handle; 01388 01389 return (error); 01390 } 01391 01392 int 01393 sa_handle_get(objset_t *objset, uint64_t objid, void *userp, 01394 sa_handle_type_t hdl_type, sa_handle_t **handlepp) 01395 { 01396 dmu_buf_t *db; 01397 int error; 01398 01399 if (error = dmu_bonus_hold(objset, objid, NULL, &db)) 01400 return (error); 01401 01402 return (sa_handle_get_from_db(objset, db, userp, hdl_type, 01403 handlepp)); 01404 } 01405 01406 int 01407 sa_buf_hold(objset_t *objset, uint64_t obj_num, void *tag, dmu_buf_t **db) 01408 { 01409 return (dmu_bonus_hold(objset, obj_num, tag, db)); 01410 } 01411 01412 void 01413 sa_buf_rele(dmu_buf_t *db, void *tag) 01414 { 01415 dmu_buf_rele(db, tag); 01416 } 01417 01418 int 01419 sa_lookup_impl(sa_handle_t *hdl, sa_bulk_attr_t *bulk, int count) 01420 { 01421 ASSERT(hdl); 01422 ASSERT(MUTEX_HELD(&hdl->sa_lock)); 01423 return (sa_attr_op(hdl, bulk, count, SA_LOOKUP, NULL)); 01424 } 01425 01426 int 01427 sa_lookup(sa_handle_t *hdl, sa_attr_type_t attr, void *buf, uint32_t buflen) 01428 { 01429 int error; 01430 sa_bulk_attr_t bulk; 01431 01432 bulk.sa_attr = attr; 01433 bulk.sa_data = buf; 01434 bulk.sa_length = buflen; 01435 bulk.sa_data_func = NULL; 01436 01437 ASSERT(hdl); 01438 mutex_enter(&hdl->sa_lock); 01439 error = sa_lookup_impl(hdl, &bulk, 1); 01440 mutex_exit(&hdl->sa_lock); 01441 return (error); 01442 } 01443 01444 #ifdef _KERNEL 01445 int 01446 sa_lookup_uio(sa_handle_t *hdl, sa_attr_type_t attr, uio_t *uio) 01447 { 01448 int error; 01449 sa_bulk_attr_t bulk; 01450 01451 bulk.sa_data = NULL; 01452 bulk.sa_attr = attr; 01453 bulk.sa_data_func = NULL; 01454 01455 ASSERT(hdl); 01456 01457 mutex_enter(&hdl->sa_lock); 01458 if ((error = sa_attr_op(hdl, &bulk, 1, SA_LOOKUP, NULL)) == 0) { 01459 error = uiomove((void *)bulk.sa_addr, MIN(bulk.sa_size, 01460 uio->uio_resid), UIO_READ, uio); 01461 } 01462 mutex_exit(&hdl->sa_lock); 01463 return (error); 01464 01465 } 01466 #endif 01467 01468 void * 01469 sa_find_idx_tab(objset_t *os, dmu_object_type_t bonustype, void *data) 01470 { 01471 sa_idx_tab_t *idx_tab; 01472 sa_hdr_phys_t *hdr = (sa_hdr_phys_t *)data; 01473 sa_os_t *sa = os->os_sa; 01474 sa_lot_t *tb, search; 01475 avl_index_t loc; 01476 01477 /* 01478 * Deterimine layout number. If SA node and header == 0 then 01479 * force the index table to the dummy "1" empty layout. 01480 * 01481 * The layout number would only be zero for a newly created file 01482 * that has not added any attributes yet, or with crypto enabled which 01483 * doesn't write any attributes to the bonus buffer. 01484 */ 01485 01486 search.lot_num = SA_LAYOUT_NUM(hdr, bonustype); 01487 01488 tb = avl_find(&sa->sa_layout_num_tree, &search, &loc); 01489 01490 /* Verify header size is consistent with layout information */ 01491 ASSERT(tb); 01492 ASSERT(IS_SA_BONUSTYPE(bonustype) && 01493 SA_HDR_SIZE_MATCH_LAYOUT(hdr, tb) || !IS_SA_BONUSTYPE(bonustype) || 01494 (IS_SA_BONUSTYPE(bonustype) && hdr->sa_layout_info == 0)); 01495 01496 /* 01497 * See if any of the already existing TOC entries can be reused? 01498 */ 01499 01500 for (idx_tab = list_head(&tb->lot_idx_tab); idx_tab; 01501 idx_tab = list_next(&tb->lot_idx_tab, idx_tab)) { 01502 boolean_t valid_idx = B_TRUE; 01503 int i; 01504 01505 if (tb->lot_var_sizes != 0 && 01506 idx_tab->sa_variable_lengths != NULL) { 01507 for (i = 0; i != tb->lot_var_sizes; i++) { 01508 if (hdr->sa_lengths[i] != 01509 idx_tab->sa_variable_lengths[i]) { 01510 valid_idx = B_FALSE; 01511 break; 01512 } 01513 } 01514 } 01515 if (valid_idx) { 01516 sa_idx_tab_hold(os, idx_tab); 01517 return (idx_tab); 01518 } 01519 } 01520 01521 /* No such luck, create a new entry */ 01522 idx_tab = kmem_zalloc(sizeof (sa_idx_tab_t), KM_SLEEP); 01523 idx_tab->sa_idx_tab = 01524 kmem_zalloc(sizeof (uint32_t) * sa->sa_num_attrs, KM_SLEEP); 01525 idx_tab->sa_layout = tb; 01526 refcount_create(&idx_tab->sa_refcount); 01527 if (tb->lot_var_sizes) 01528 idx_tab->sa_variable_lengths = kmem_alloc(sizeof (uint16_t) * 01529 tb->lot_var_sizes, KM_SLEEP); 01530 01531 sa_attr_iter(os, hdr, bonustype, sa_build_idx_tab, 01532 tb, idx_tab); 01533 sa_idx_tab_hold(os, idx_tab); /* one hold for consumer */ 01534 sa_idx_tab_hold(os, idx_tab); /* one for layout */ 01535 list_insert_tail(&tb->lot_idx_tab, idx_tab); 01536 return (idx_tab); 01537 } 01538 01539 void 01540 sa_default_locator(void **dataptr, uint32_t *len, uint32_t total_len, 01541 boolean_t start, void *userdata) 01542 { 01543 ASSERT(start); 01544 01545 *dataptr = userdata; 01546 *len = total_len; 01547 } 01548 01549 static void 01550 sa_attr_register_sync(sa_handle_t *hdl, dmu_tx_t *tx) 01551 { 01552 uint64_t attr_value = 0; 01553 sa_os_t *sa = hdl->sa_os->os_sa; 01554 sa_attr_table_t *tb = sa->sa_attr_table; 01555 int i; 01556 01557 mutex_enter(&sa->sa_lock); 01558 01559 if (!sa->sa_need_attr_registration || sa->sa_master_obj == 0) { 01560 mutex_exit(&sa->sa_lock); 01561 return; 01562 } 01563 01564 if (sa->sa_reg_attr_obj == 0) { 01565 sa->sa_reg_attr_obj = zap_create_link(hdl->sa_os, 01566 DMU_OT_SA_ATTR_REGISTRATION, 01567 sa->sa_master_obj, SA_REGISTRY, tx); 01568 } 01569 for (i = 0; i != sa->sa_num_attrs; i++) { 01570 if (sa->sa_attr_table[i].sa_registered) 01571 continue; 01572 ATTR_ENCODE(attr_value, tb[i].sa_attr, tb[i].sa_length, 01573 tb[i].sa_byteswap); 01574 VERIFY(0 == zap_update(hdl->sa_os, sa->sa_reg_attr_obj, 01575 tb[i].sa_name, 8, 1, &attr_value, tx)); 01576 tb[i].sa_registered = B_TRUE; 01577 } 01578 sa->sa_need_attr_registration = B_FALSE; 01579 mutex_exit(&sa->sa_lock); 01580 } 01581 01591 int 01592 sa_replace_all_by_template_locked(sa_handle_t *hdl, sa_bulk_attr_t *attr_desc, 01593 int attr_count, dmu_tx_t *tx) 01594 { 01595 sa_os_t *sa = hdl->sa_os->os_sa; 01596 01597 if (sa->sa_need_attr_registration) 01598 sa_attr_register_sync(hdl, tx); 01599 return (sa_build_layouts(hdl, attr_desc, attr_count, tx)); 01600 } 01601 01602 int 01603 sa_replace_all_by_template(sa_handle_t *hdl, sa_bulk_attr_t *attr_desc, 01604 int attr_count, dmu_tx_t *tx) 01605 { 01606 int error; 01607 01608 mutex_enter(&hdl->sa_lock); 01609 error = sa_replace_all_by_template_locked(hdl, attr_desc, 01610 attr_count, tx); 01611 mutex_exit(&hdl->sa_lock); 01612 return (error); 01613 } 01614 01622 static int 01623 sa_modify_attrs(sa_handle_t *hdl, sa_attr_type_t newattr, 01624 sa_data_op_t action, sa_data_locator_t *locator, void *datastart, 01625 uint16_t buflen, dmu_tx_t *tx) 01626 { 01627 sa_os_t *sa = hdl->sa_os->os_sa; 01628 dmu_buf_impl_t *db = (dmu_buf_impl_t *)hdl->sa_bonus; 01629 dnode_t *dn; 01630 sa_bulk_attr_t *attr_desc; 01631 void *old_data[2]; 01632 int bonus_attr_count = 0; 01633 int bonus_data_size, spill_data_size; 01634 int spill_attr_count = 0; 01635 int error; 01636 uint16_t length; 01637 int i, j, k, length_idx; 01638 sa_hdr_phys_t *hdr; 01639 sa_idx_tab_t *idx_tab; 01640 int attr_count; 01641 int count; 01642 01643 ASSERT(MUTEX_HELD(&hdl->sa_lock)); 01644 01645 /* First make of copy of the old data */ 01646 01647 DB_DNODE_ENTER(db); 01648 dn = DB_DNODE(db); 01649 if (dn->dn_bonuslen != 0) { 01650 bonus_data_size = hdl->sa_bonus->db_size; 01651 old_data[0] = kmem_alloc(bonus_data_size, KM_SLEEP); 01652 bcopy(hdl->sa_bonus->db_data, old_data[0], 01653 hdl->sa_bonus->db_size); 01654 bonus_attr_count = hdl->sa_bonus_tab->sa_layout->lot_attr_count; 01655 } else { 01656 old_data[0] = NULL; 01657 } 01658 DB_DNODE_EXIT(db); 01659 01660 /* Bring spill buffer online if it isn't currently */ 01661 01662 if ((error = sa_get_spill(hdl)) == 0) { 01663 spill_data_size = hdl->sa_spill->db_size; 01664 old_data[1] = kmem_alloc(spill_data_size, KM_SLEEP); 01665 bcopy(hdl->sa_spill->db_data, old_data[1], 01666 hdl->sa_spill->db_size); 01667 spill_attr_count = 01668 hdl->sa_spill_tab->sa_layout->lot_attr_count; 01669 } else if (error && error != ENOENT) { 01670 if (old_data[0]) 01671 kmem_free(old_data[0], bonus_data_size); 01672 return (error); 01673 } else { 01674 old_data[1] = NULL; 01675 } 01676 01677 /* build descriptor of all attributes */ 01678 01679 attr_count = bonus_attr_count + spill_attr_count; 01680 if (action == SA_ADD) 01681 attr_count++; 01682 else if (action == SA_REMOVE) 01683 attr_count--; 01684 01685 attr_desc = kmem_zalloc(sizeof (sa_bulk_attr_t) * attr_count, KM_SLEEP); 01686 01687 /* 01688 * loop through bonus and spill buffer if it exists, and 01689 * build up new attr_descriptor to reset the attributes 01690 */ 01691 k = j = 0; 01692 count = bonus_attr_count; 01693 hdr = SA_GET_HDR(hdl, SA_BONUS); 01694 idx_tab = SA_IDX_TAB_GET(hdl, SA_BONUS); 01695 for (; k != 2; k++) { 01696 /* iterate over each attribute in layout */ 01697 for (i = 0, length_idx = 0; i != count; i++) { 01698 sa_attr_type_t attr; 01699 01700 attr = idx_tab->sa_layout->lot_attrs[i]; 01701 if (attr == newattr) { 01702 /* duplicate attributes are not allowed */ 01703 ASSERT(action == SA_REPLACE || 01704 action == SA_REMOVE); 01705 /* must be variable-sized to be replaced here */ 01706 if (action == SA_REPLACE) { 01707 ASSERT(SA_REGISTERED_LEN(sa, attr) == 0); 01708 SA_ADD_BULK_ATTR(attr_desc, j, attr, 01709 locator, datastart, buflen); 01710 } 01711 } else { 01712 length = SA_REGISTERED_LEN(sa, attr); 01713 if (length == 0) { 01714 length = hdr->sa_lengths[length_idx]; 01715 } 01716 01717 SA_ADD_BULK_ATTR(attr_desc, j, attr, 01718 NULL, (void *) 01719 (TOC_OFF(idx_tab->sa_idx_tab[attr]) + 01720 (uintptr_t)old_data[k]), length); 01721 } 01722 if (SA_REGISTERED_LEN(sa, attr) == 0) 01723 length_idx++; 01724 } 01725 if (k == 0 && hdl->sa_spill) { 01726 hdr = SA_GET_HDR(hdl, SA_SPILL); 01727 idx_tab = SA_IDX_TAB_GET(hdl, SA_SPILL); 01728 count = spill_attr_count; 01729 } else { 01730 break; 01731 } 01732 } 01733 if (action == SA_ADD) { 01734 length = SA_REGISTERED_LEN(sa, newattr); 01735 if (length == 0) { 01736 length = buflen; 01737 } 01738 SA_ADD_BULK_ATTR(attr_desc, j, newattr, locator, 01739 datastart, buflen); 01740 } 01741 ASSERT3U(j, ==, attr_count); 01742 01743 error = sa_build_layouts(hdl, attr_desc, attr_count, tx); 01744 01745 if (old_data[0]) 01746 kmem_free(old_data[0], bonus_data_size); 01747 if (old_data[1]) 01748 kmem_free(old_data[1], spill_data_size); 01749 kmem_free(attr_desc, sizeof (sa_bulk_attr_t) * attr_count); 01750 01751 return (error); 01752 } 01753 01754 static int 01755 sa_bulk_update_impl(sa_handle_t *hdl, sa_bulk_attr_t *bulk, int count, 01756 dmu_tx_t *tx) 01757 { 01758 int error; 01759 sa_os_t *sa = hdl->sa_os->os_sa; 01760 dmu_object_type_t bonustype; 01761 01762 bonustype = SA_BONUSTYPE_FROM_DB(SA_GET_DB(hdl, SA_BONUS)); 01763 01764 ASSERT(hdl); 01765 ASSERT(MUTEX_HELD(&hdl->sa_lock)); 01766 01767 /* sync out registration table if necessary */ 01768 if (sa->sa_need_attr_registration) 01769 sa_attr_register_sync(hdl, tx); 01770 01771 error = sa_attr_op(hdl, bulk, count, SA_UPDATE, tx); 01772 if (error == 0 && !IS_SA_BONUSTYPE(bonustype) && sa->sa_update_cb) 01773 sa->sa_update_cb(hdl, tx); 01774 01775 return (error); 01776 } 01777 01781 int 01782 sa_update(sa_handle_t *hdl, sa_attr_type_t type, 01783 void *buf, uint32_t buflen, dmu_tx_t *tx) 01784 { 01785 int error; 01786 sa_bulk_attr_t bulk; 01787 01788 bulk.sa_attr = type; 01789 bulk.sa_data_func = NULL; 01790 bulk.sa_length = buflen; 01791 bulk.sa_data = buf; 01792 01793 mutex_enter(&hdl->sa_lock); 01794 error = sa_bulk_update_impl(hdl, &bulk, 1, tx); 01795 mutex_exit(&hdl->sa_lock); 01796 return (error); 01797 } 01798 01799 int 01800 sa_update_from_cb(sa_handle_t *hdl, sa_attr_type_t attr, 01801 uint32_t buflen, sa_data_locator_t *locator, void *userdata, dmu_tx_t *tx) 01802 { 01803 int error; 01804 sa_bulk_attr_t bulk; 01805 01806 bulk.sa_attr = attr; 01807 bulk.sa_data = userdata; 01808 bulk.sa_data_func = locator; 01809 bulk.sa_length = buflen; 01810 01811 mutex_enter(&hdl->sa_lock); 01812 error = sa_bulk_update_impl(hdl, &bulk, 1, tx); 01813 mutex_exit(&hdl->sa_lock); 01814 return (error); 01815 } 01816 01820 int 01821 sa_size(sa_handle_t *hdl, sa_attr_type_t attr, int *size) 01822 { 01823 sa_bulk_attr_t bulk; 01824 int error; 01825 01826 bulk.sa_data = NULL; 01827 bulk.sa_attr = attr; 01828 bulk.sa_data_func = NULL; 01829 01830 ASSERT(hdl); 01831 mutex_enter(&hdl->sa_lock); 01832 if ((error = sa_attr_op(hdl, &bulk, 1, SA_LOOKUP, NULL)) != 0) { 01833 mutex_exit(&hdl->sa_lock); 01834 return (error); 01835 } 01836 *size = bulk.sa_size; 01837 01838 mutex_exit(&hdl->sa_lock); 01839 return (0); 01840 } 01841 01842 int 01843 sa_bulk_lookup_locked(sa_handle_t *hdl, sa_bulk_attr_t *attrs, int count) 01844 { 01845 ASSERT(hdl); 01846 ASSERT(MUTEX_HELD(&hdl->sa_lock)); 01847 return (sa_lookup_impl(hdl, attrs, count)); 01848 } 01849 01850 int 01851 sa_bulk_lookup(sa_handle_t *hdl, sa_bulk_attr_t *attrs, int count) 01852 { 01853 int error; 01854 01855 ASSERT(hdl); 01856 mutex_enter(&hdl->sa_lock); 01857 error = sa_bulk_lookup_locked(hdl, attrs, count); 01858 mutex_exit(&hdl->sa_lock); 01859 return (error); 01860 } 01861 01862 int 01863 sa_bulk_update(sa_handle_t *hdl, sa_bulk_attr_t *attrs, int count, dmu_tx_t *tx) 01864 { 01865 int error; 01866 01867 ASSERT(hdl); 01868 mutex_enter(&hdl->sa_lock); 01869 error = sa_bulk_update_impl(hdl, attrs, count, tx); 01870 mutex_exit(&hdl->sa_lock); 01871 return (error); 01872 } 01873 01874 int 01875 sa_remove(sa_handle_t *hdl, sa_attr_type_t attr, dmu_tx_t *tx) 01876 { 01877 int error; 01878 01879 mutex_enter(&hdl->sa_lock); 01880 error = sa_modify_attrs(hdl, attr, SA_REMOVE, NULL, 01881 NULL, 0, tx); 01882 mutex_exit(&hdl->sa_lock); 01883 return (error); 01884 } 01885 01886 void 01887 sa_object_info(sa_handle_t *hdl, dmu_object_info_t *doi) 01888 { 01889 dmu_object_info_from_db((dmu_buf_t *)hdl->sa_bonus, doi); 01890 } 01891 01892 void 01893 sa_object_size(sa_handle_t *hdl, uint32_t *blksize, u_longlong_t *nblocks) 01894 { 01895 dmu_object_size_from_db((dmu_buf_t *)hdl->sa_bonus, 01896 blksize, nblocks); 01897 } 01898 01899 void 01900 sa_update_user(sa_handle_t *newhdl, sa_handle_t *oldhdl) 01901 { 01902 (void) dmu_buf_update_user((dmu_buf_t *)newhdl->sa_bonus, 01903 oldhdl, newhdl, NULL, sa_evict); 01904 oldhdl->sa_bonus = NULL; 01905 } 01906 01907 void 01908 sa_set_userp(sa_handle_t *hdl, void *ptr) 01909 { 01910 hdl->sa_userp = ptr; 01911 } 01912 01913 dmu_buf_t * 01914 sa_get_db(sa_handle_t *hdl) 01915 { 01916 return ((dmu_buf_t *)hdl->sa_bonus); 01917 } 01918 01919 void * 01920 sa_get_userdata(sa_handle_t *hdl) 01921 { 01922 return (hdl->sa_userp); 01923 } 01924 01925 void 01926 sa_register_update_callback_locked(objset_t *os, sa_update_cb_t *func) 01927 { 01928 ASSERT(MUTEX_HELD(&os->os_sa->sa_lock)); 01929 os->os_sa->sa_update_cb = func; 01930 } 01931 01932 void 01933 sa_register_update_callback(objset_t *os, sa_update_cb_t *func) 01934 { 01935 01936 mutex_enter(&os->os_sa->sa_lock); 01937 sa_register_update_callback_locked(os, func); 01938 mutex_exit(&os->os_sa->sa_lock); 01939 } 01940 01941 uint64_t 01942 sa_handle_object(sa_handle_t *hdl) 01943 { 01944 return (hdl->sa_bonus->db_object); 01945 } 01946 01947 boolean_t 01948 sa_enabled(objset_t *os) 01949 { 01950 return (os->os_sa == NULL); 01951 } 01952 01953 int 01954 sa_set_sa_object(objset_t *os, uint64_t sa_object) 01955 { 01956 sa_os_t *sa = os->os_sa; 01957 01958 if (sa->sa_master_obj) 01959 return (1); 01960 01961 sa->sa_master_obj = sa_object; 01962 01963 return (0); 01964 } 01965 01966 int 01967 sa_hdrsize(void *arg) 01968 { 01969 sa_hdr_phys_t *hdr = arg; 01970 01971 return (SA_HDR_SIZE(hdr)); 01972 } 01973 01974 void 01975 sa_handle_lock(sa_handle_t *hdl) 01976 { 01977 ASSERT(hdl); 01978 mutex_enter(&hdl->sa_lock); 01979 } 01980 01981 void 01982 sa_handle_unlock(sa_handle_t *hdl) 01983 { 01984 ASSERT(hdl); 01985 mutex_exit(&hdl->sa_lock); 01986 }