Add -p switch to "zpool get"
[zfs.git] / module / zfs / sa.c
index bcef7d1..581cf4b 100644 (file)
  *
  * CDDL HEADER END
  */
+
 /*
  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012 by Delphix. All rights reserved.
  */
 
 #include <sys/zfs_context.h>
@@ -134,7 +136,7 @@ static int sa_modify_attrs(sa_handle_t *hdl, sa_attr_type_t newattr,
     sa_data_op_t action, sa_data_locator_t *locator, void *datastart,
     uint16_t buflen, dmu_tx_t *tx);
 
-arc_byteswap_func_t *sa_bswap_table[] = {
+arc_byteswap_func_t sa_bswap_table[] = {
        byteswap_uint64_array,
        byteswap_uint32_array,
        byteswap_uint16_array,
@@ -433,10 +435,10 @@ sa_add_layout_entry(objset_t *os, sa_attr_type_t *attrs, int attr_count,
        avl_index_t loc;
 
        ASSERT(MUTEX_HELD(&sa->sa_lock));
-       tb = kmem_zalloc(sizeof (sa_lot_t), KM_SLEEP);
+       tb = kmem_zalloc(sizeof (sa_lot_t), KM_PUSHPAGE);
        tb->lot_attr_count = attr_count;
        tb->lot_attrs = kmem_alloc(sizeof (sa_attr_type_t) * attr_count,
-           KM_SLEEP);
+           KM_PUSHPAGE);
        bcopy(attrs, tb->lot_attrs, sizeof (sa_attr_type_t) * attr_count);
        tb->lot_num = lot_num;
        tb->lot_hash = hash;
@@ -446,10 +448,9 @@ sa_add_layout_entry(objset_t *os, sa_attr_type_t *attrs, int attr_count,
                char attr_name[8];
 
                if (sa->sa_layout_attr_obj == 0) {
-                       sa->sa_layout_attr_obj = zap_create(os,
-                           DMU_OT_SA_ATTR_LAYOUTS, DMU_OT_NONE, 0, tx);
-                       VERIFY(zap_add(os, sa->sa_master_obj, SA_LAYOUTS, 8, 1,
-                           &sa->sa_layout_attr_obj, tx) == 0);
+                       sa->sa_layout_attr_obj = zap_create_link(os,
+                           DMU_OT_SA_ATTR_LAYOUTS,
+                           sa->sa_master_obj, SA_LAYOUTS, tx);
                }
 
                (void) snprintf(attr_name, sizeof (attr_name),
@@ -571,6 +572,7 @@ sa_find_sizes(sa_os_t *sa, sa_bulk_attr_t *attr_desc, int attr_count,
 {
        int var_size = 0;
        int i;
+       int j = -1;
        int full_space;
        int hdrsize;
        boolean_t done = B_FALSE;
@@ -592,10 +594,12 @@ sa_find_sizes(sa_os_t *sa, sa_bulk_attr_t *attr_desc, int attr_count,
            sizeof (sa_hdr_phys_t);
 
        full_space = (buftype == SA_BONUS) ? DN_MAX_BONUSLEN : db->db_size;
+       ASSERT(IS_P2ALIGNED(full_space, 8));
 
        for (i = 0; i != attr_count; i++) {
                boolean_t is_var_sz;
 
+               *total = P2ROUNDUP(*total, 8);
                *total += attr_desc[i].sa_length;
                if (done)
                        goto next;
@@ -608,7 +612,14 @@ sa_find_sizes(sa_os_t *sa, sa_bulk_attr_t *attr_desc, int attr_count,
                if (is_var_sz && var_size > 1) {
                        if (P2ROUNDUP(hdrsize + sizeof (uint16_t), 8) +
                            *total < full_space) {
+                               /*
+                                * Account for header space used by array of
+                                * optional sizes of variable-length attributes.
+                                * Record the index in case this increase needs
+                                * to be reversed due to spill-over.
+                                */
                                hdrsize += sizeof (uint16_t);
+                               j = i;
                        } else {
                                done = B_TRUE;
                                *index = i;
@@ -637,6 +648,14 @@ next:
                        *will_spill = B_TRUE;
        }
 
+       /*
+        * j holds the index of the last variable-sized attribute for
+        * which hdrsize was increased.  Reverse the increase if that
+        * attribute will be relocated to the spill block.
+        */
+       if (*will_spill && j == *index)
+               hdrsize -= sizeof (uint16_t);
+
        hdrsize = P2ROUNDUP(hdrsize, 8);
        return (hdrsize);
 }
@@ -721,18 +740,21 @@ sa_build_layouts(sa_handle_t *hdl, sa_bulk_attr_t *attr_desc, int attr_count,
                buf_space = hdl->sa_bonus->db_size - hdrsize;
 
        attrs_start = attrs = kmem_alloc(sizeof (sa_attr_type_t) * attr_count,
-           KM_SLEEP);
+           KM_PUSHPAGE);
        lot_count = 0;
 
        for (i = 0, len_idx = 0, hash = -1ULL; i != attr_count; i++) {
                uint16_t length;
 
+               ASSERT(IS_P2ALIGNED(data_start, 8));
+               ASSERT(IS_P2ALIGNED(buf_space, 8));
                attrs[i] = attr_desc[i].sa_attr;
                length = SA_REGISTERED_LEN(sa, attrs[i]);
                if (length == 0)
                        length = attr_desc[i].sa_length;
 
                if (buf_space < length) {  /* switch to spill buffer */
+                       VERIFY(spilling);
                        VERIFY(bonustype == DMU_OT_SA);
                        if (buftype == SA_BONUS && !sa->sa_force_spill) {
                                sa_find_layout(hdl->sa_os, hash, attrs_start,
@@ -842,7 +864,7 @@ sa_attr_table_setup(objset_t *os, sa_attr_reg_t *reg_attrs, int count)
        dmu_objset_type_t ostype = dmu_objset_type(os);
 
        sa->sa_user_table =
-           kmem_zalloc(count * sizeof (sa_attr_type_t), KM_SLEEP);
+           kmem_zalloc(count * sizeof (sa_attr_type_t), KM_PUSHPAGE);
        sa->sa_user_table_sz = count * sizeof (sa_attr_type_t);
 
        if (sa->sa_reg_attr_obj != 0) {
@@ -901,7 +923,7 @@ sa_attr_table_setup(objset_t *os, sa_attr_reg_t *reg_attrs, int count)
 
        sa->sa_num_attrs = sa_attr_count;
        tb = sa->sa_attr_table =
-           kmem_zalloc(sizeof (sa_attr_table_t) * sa_attr_count, KM_SLEEP);
+           kmem_zalloc(sizeof (sa_attr_table_t) * sa_attr_count, KM_PUSHPAGE);
 
        /*
         * Attribute table is constructed from requested attribute list,
@@ -926,7 +948,7 @@ sa_attr_table_setup(objset_t *os, sa_attr_reg_t *reg_attrs, int count)
                                continue;
                        }
                        tb[ATTR_NUM(value)].sa_name =
-                           kmem_zalloc(strlen(za.za_name) +1, KM_SLEEP);
+                           kmem_zalloc(strlen(za.za_name) +1, KM_PUSHPAGE);
                        (void) strlcpy(tb[ATTR_NUM(value)].sa_name, za.za_name,
                            strlen(za.za_name) +1);
                }
@@ -952,7 +974,7 @@ sa_attr_table_setup(objset_t *os, sa_attr_reg_t *reg_attrs, int count)
                        tb[i].sa_registered = B_FALSE;
                        tb[i].sa_name =
                            kmem_zalloc(strlen(sa_legacy_attrs[i].sa_name) +1,
-                           KM_SLEEP);
+                           KM_PUSHPAGE);
                        (void) strlcpy(tb[i].sa_name,
                            sa_legacy_attrs[i].sa_name,
                            strlen(sa_legacy_attrs[i].sa_name) + 1);
@@ -970,7 +992,7 @@ sa_attr_table_setup(objset_t *os, sa_attr_reg_t *reg_attrs, int count)
                tb[attr_id].sa_byteswap = reg_attrs[i].sa_byteswap;
                tb[attr_id].sa_attr = attr_id;
                tb[attr_id].sa_name =
-                   kmem_zalloc(strlen(reg_attrs[i].sa_name) + 1, KM_SLEEP);
+                   kmem_zalloc(strlen(reg_attrs[i].sa_name) + 1, KM_PUSHPAGE);
                (void) strlcpy(tb[attr_id].sa_name, reg_attrs[i].sa_name,
                    strlen(reg_attrs[i].sa_name) + 1);
        }
@@ -1007,7 +1029,7 @@ sa_setup(objset_t *os, uint64_t sa_obj, sa_attr_reg_t *reg_attrs, int count,
                return (0);
        }
 
-       sa = kmem_zalloc(sizeof (sa_os_t), KM_SLEEP);
+       sa = kmem_zalloc(sizeof (sa_os_t), KM_PUSHPAGE);
        mutex_init(&sa->sa_lock, NULL, MUTEX_DEFAULT, NULL);
        sa->sa_master_obj = sa_obj;
 
@@ -1055,7 +1077,7 @@ sa_setup(objset_t *os, uint64_t sa_obj, sa_attr_reg_t *reg_attrs, int count,
                        uint64_t lot_num;
 
                        lot_attrs = kmem_zalloc(sizeof (sa_attr_type_t) *
-                           za.za_num_integers, KM_SLEEP);
+                           za.za_num_integers, KM_PUSHPAGE);
 
                        if ((error = (zap_lookup(os, sa->sa_layout_attr_obj,
                            za.za_name, 2, za.za_num_integers,
@@ -1334,6 +1356,19 @@ sa_idx_tab_hold(objset_t *os, sa_idx_tab_t *idx_tab)
 }
 
 void
+sa_spill_rele(sa_handle_t *hdl)
+{
+       mutex_enter(&hdl->sa_lock);
+       if (hdl->sa_spill) {
+               sa_idx_tab_rele(hdl->sa_os, hdl->sa_spill_tab);
+               dmu_buf_rele(hdl->sa_spill, NULL);
+               hdl->sa_spill = NULL;
+               hdl->sa_spill_tab = NULL;
+       }
+       mutex_exit(&hdl->sa_lock);
+}
+
+void
 sa_handle_destroy(sa_handle_t *hdl)
 {
        mutex_enter(&hdl->sa_lock);
@@ -1527,14 +1562,14 @@ sa_find_idx_tab(objset_t *os, dmu_object_type_t bonustype, void *data)
        }
 
        /* No such luck, create a new entry */
-       idx_tab = kmem_zalloc(sizeof (sa_idx_tab_t), KM_SLEEP);
+       idx_tab = kmem_zalloc(sizeof (sa_idx_tab_t), KM_PUSHPAGE);
        idx_tab->sa_idx_tab =
-           kmem_zalloc(sizeof (uint32_t) * sa->sa_num_attrs, KM_SLEEP);
+           kmem_zalloc(sizeof (uint32_t) * sa->sa_num_attrs, KM_PUSHPAGE);
        idx_tab->sa_layout = tb;
        refcount_create(&idx_tab->sa_refcount);
        if (tb->lot_var_sizes)
                idx_tab->sa_variable_lengths = kmem_alloc(sizeof (uint16_t) *
-                   tb->lot_var_sizes, KM_SLEEP);
+                   tb->lot_var_sizes, KM_PUSHPAGE);
 
        sa_attr_iter(os, hdr, bonustype, sa_build_idx_tab,
            tb, idx_tab);
@@ -1570,10 +1605,9 @@ sa_attr_register_sync(sa_handle_t *hdl, dmu_tx_t *tx)
        }
 
        if (sa->sa_reg_attr_obj == 0) {
-               sa->sa_reg_attr_obj = zap_create(hdl->sa_os,
-                   DMU_OT_SA_ATTR_REGISTRATION, DMU_OT_NONE, 0, tx);
-               VERIFY(zap_add(hdl->sa_os, sa->sa_master_obj,
-                   SA_REGISTRY, 8, 1, &sa->sa_reg_attr_obj, tx) == 0);
+               sa->sa_reg_attr_obj = zap_create_link(hdl->sa_os,
+                   DMU_OT_SA_ATTR_REGISTRATION,
+                   sa->sa_master_obj, SA_REGISTRY, tx);
        }
        for (i = 0; i != sa->sa_num_attrs; i++) {
                if (sa->sa_attr_table[i].sa_registered)
@@ -1760,12 +1794,14 @@ sa_bulk_update_impl(sa_handle_t *hdl, sa_bulk_attr_t *bulk, int count,
        int error;
        sa_os_t *sa = hdl->sa_os->os_sa;
        dmu_object_type_t bonustype;
-
-       bonustype = SA_BONUSTYPE_FROM_DB(SA_GET_DB(hdl, SA_BONUS));
+       dmu_buf_t *saved_spill;
 
        ASSERT(hdl);
        ASSERT(MUTEX_HELD(&hdl->sa_lock));
 
+       bonustype = SA_BONUSTYPE_FROM_DB(SA_GET_DB(hdl, SA_BONUS));
+       saved_spill = hdl->sa_spill;
+
        /* sync out registration table if necessary */
        if (sa->sa_need_attr_registration)
                sa_attr_register_sync(hdl, tx);
@@ -1774,6 +1810,24 @@ sa_bulk_update_impl(sa_handle_t *hdl, sa_bulk_attr_t *bulk, int count,
        if (error == 0 && !IS_SA_BONUSTYPE(bonustype) && sa->sa_update_cb)
                sa->sa_update_cb(hdl, tx);
 
+       /*
+        * If saved_spill is NULL and current sa_spill is not NULL that
+        * means we increased the refcount of the spill buffer through
+        * sa_get_spill() or dmu_spill_hold_by_dnode().  Therefore we
+        * must release the hold before calling dmu_tx_commit() to avoid
+        * making a copy of this buffer in dbuf_sync_leaf() due to the
+        * reference count now being greater than 1.
+        */
+       if (!saved_spill && hdl->sa_spill) {
+               if (hdl->sa_spill_tab) {
+                       sa_idx_tab_rele(hdl->sa_os, hdl->sa_spill_tab);
+                       hdl->sa_spill_tab = NULL;
+               }
+
+               dmu_buf_rele((dmu_buf_t *)hdl->sa_spill, NULL);
+               hdl->sa_spill = NULL;
+       }
+
        return (error);
 }
 
@@ -1994,6 +2048,7 @@ EXPORT_SYMBOL(sa_handle_get_from_db);
 EXPORT_SYMBOL(sa_handle_destroy);
 EXPORT_SYMBOL(sa_buf_hold);
 EXPORT_SYMBOL(sa_buf_rele);
+EXPORT_SYMBOL(sa_spill_rele);
 EXPORT_SYMBOL(sa_lookup);
 EXPORT_SYMBOL(sa_update);
 EXPORT_SYMBOL(sa_remove);