FreeBSD ZFS
The Zettabyte File System

sa.c

Go to the documentation of this file.
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 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines