static int sa_legacy_attr_count = 16;
static kmem_cache_t *sa_cache = NULL;
+static kmem_cache_t *spill_cache = NULL;
/*ARGSUSED*/
static int
sa_cache = kmem_cache_create("sa_cache",
sizeof (sa_handle_t), 0, sa_cache_constructor,
sa_cache_destructor, NULL, NULL, NULL, 0);
+ spill_cache = kmem_cache_create("spill_cache",
+ SPA_MAXBLOCKSIZE, 0, NULL, NULL, NULL, NULL, NULL, 0);
}
void
{
if (sa_cache)
kmem_cache_destroy(sa_cache);
+
+ if (spill_cache)
+ kmem_cache_destroy(spill_cache);
+}
+
+void *
+sa_spill_alloc(int flags)
+{
+ return kmem_cache_alloc(spill_cache, flags);
+}
+
+void
+sa_spill_free(void *obj)
+{
+ kmem_cache_free(spill_cache, obj);
}
static int
}
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);
sa_bulk_attr_t *attr_desc;
void *old_data[2];
int bonus_attr_count = 0;
- int bonus_data_size = 0, spill_data_size = 0;
+ int bonus_data_size = 0;
int spill_attr_count = 0;
int error;
uint16_t length;
/* Bring spill buffer online if it isn't currently */
if ((error = sa_get_spill(hdl)) == 0) {
- spill_data_size = hdl->sa_spill->db_size;
- old_data[1] = kmem_alloc(spill_data_size, KM_SLEEP);
+ ASSERT3U(hdl->sa_spill->db_size, <=, SPA_MAXBLOCKSIZE);
+ old_data[1] = sa_spill_alloc(KM_SLEEP);
bcopy(hdl->sa_spill->db_data, old_data[1],
hdl->sa_spill->db_size);
spill_attr_count =
if (old_data[0])
kmem_free(old_data[0], bonus_data_size);
if (old_data[1])
- kmem_free(old_data[1], spill_data_size);
+ sa_spill_free(old_data[1]);
kmem_free(attr_desc, sizeof (sa_bulk_attr_t) * attr_count);
return (error);
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);
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);
}
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);
EXPORT_SYMBOL(sa_enabled);
EXPORT_SYMBOL(sa_cache_init);
EXPORT_SYMBOL(sa_cache_fini);
+EXPORT_SYMBOL(sa_spill_alloc);
+EXPORT_SYMBOL(sa_spill_free);
EXPORT_SYMBOL(sa_set_sa_object);
EXPORT_SYMBOL(sa_hdrsize);
EXPORT_SYMBOL(sa_handle_lock);