mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2024-12-26 11:19:32 +03:00
Drop spill buffer reference
When calling sa_update() and friends it is possible that a spill buffer will be needed to accomidate the update. When this happens a hold is taken on the new dbuf and that hold must be released before calling dmu_tx_commit(). Failing to release the hold will cause a copy of the dbuf to be made in dbuf_sync_leaf(). This is done to ensure further updates to the dbuf never sneak in to the syncing txg. This could be left to the sa_update() caller. But then the caller would need to be aware of this internal SA implementation detail. It is therefore preferable to handle this all internally in the SA implementation. Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov> Closes #503 Closes #513
This commit is contained in:
parent
f828e63a0d
commit
a47587389e
@ -1773,12 +1773,14 @@ sa_bulk_update_impl(sa_handle_t *hdl, sa_bulk_attr_t *bulk, int count,
|
|||||||
int error;
|
int error;
|
||||||
sa_os_t *sa = hdl->sa_os->os_sa;
|
sa_os_t *sa = hdl->sa_os->os_sa;
|
||||||
dmu_object_type_t bonustype;
|
dmu_object_type_t bonustype;
|
||||||
|
dmu_buf_t *saved_spill;
|
||||||
bonustype = SA_BONUSTYPE_FROM_DB(SA_GET_DB(hdl, SA_BONUS));
|
|
||||||
|
|
||||||
ASSERT(hdl);
|
ASSERT(hdl);
|
||||||
ASSERT(MUTEX_HELD(&hdl->sa_lock));
|
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 */
|
/* sync out registration table if necessary */
|
||||||
if (sa->sa_need_attr_registration)
|
if (sa->sa_need_attr_registration)
|
||||||
sa_attr_register_sync(hdl, tx);
|
sa_attr_register_sync(hdl, tx);
|
||||||
@ -1787,6 +1789,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)
|
if (error == 0 && !IS_SA_BONUSTYPE(bonustype) && sa->sa_update_cb)
|
||||||
sa->sa_update_cb(hdl, tx);
|
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);
|
return (error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user