MFV r302651: 7054 dmu_tx_hold_t should use refcount_t to track space
illumos/illumos-gate@0c779ad424 https://github.com/illumos/illumos-gate/commit/0c779ad424a92a84d1e07d47cab7f8009 189202b https://www.illumos.org/issues/7054 upstream: ee0003de7d3e598499be7ac3fe6b61efcc47cb7f DLPX-40399 dmu_tx_hold_t should use refcount_t to track space Reviewed by: George Wilson <george.wilson@delphix.com> Reviewed by: Paul Dagnelie <pcd@delphix.com> Reviewed by: Igor Kozhukhov <ikozhukhov@gmail.com> Approved by: Dan McDonald <danmcd@omniti.com> Author: Matthew Ahrens <mahrens@delphix.com>
This commit is contained in:
commit
a95a9fe945
@ -129,6 +129,12 @@ dmu_tx_hold_object_impl(dmu_tx_t *tx, objset_t *os, uint64_t object,
|
|||||||
txh = kmem_zalloc(sizeof (dmu_tx_hold_t), KM_SLEEP);
|
txh = kmem_zalloc(sizeof (dmu_tx_hold_t), KM_SLEEP);
|
||||||
txh->txh_tx = tx;
|
txh->txh_tx = tx;
|
||||||
txh->txh_dnode = dn;
|
txh->txh_dnode = dn;
|
||||||
|
refcount_create(&txh->txh_space_towrite);
|
||||||
|
refcount_create(&txh->txh_space_tofree);
|
||||||
|
refcount_create(&txh->txh_space_tooverwrite);
|
||||||
|
refcount_create(&txh->txh_space_tounref);
|
||||||
|
refcount_create(&txh->txh_memory_tohold);
|
||||||
|
refcount_create(&txh->txh_fudge);
|
||||||
#ifdef ZFS_DEBUG
|
#ifdef ZFS_DEBUG
|
||||||
txh->txh_type = type;
|
txh->txh_type = type;
|
||||||
txh->txh_arg1 = arg1;
|
txh->txh_arg1 = arg1;
|
||||||
@ -201,12 +207,18 @@ dmu_tx_count_twig(dmu_tx_hold_t *txh, dnode_t *dn, dmu_buf_impl_t *db,
|
|||||||
freeable = (bp && (freeable ||
|
freeable = (bp && (freeable ||
|
||||||
dsl_dataset_block_freeable(ds, bp, bp->blk_birth)));
|
dsl_dataset_block_freeable(ds, bp, bp->blk_birth)));
|
||||||
|
|
||||||
if (freeable)
|
if (freeable) {
|
||||||
txh->txh_space_tooverwrite += space;
|
(void) refcount_add_many(&txh->txh_space_tooverwrite,
|
||||||
else
|
space, FTAG);
|
||||||
txh->txh_space_towrite += space;
|
} else {
|
||||||
if (bp)
|
(void) refcount_add_many(&txh->txh_space_towrite,
|
||||||
txh->txh_space_tounref += bp_get_dsize(os->os_spa, bp);
|
space, FTAG);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bp) {
|
||||||
|
(void) refcount_add_many(&txh->txh_space_tounref,
|
||||||
|
bp_get_dsize(os->os_spa, bp), FTAG);
|
||||||
|
}
|
||||||
|
|
||||||
dmu_tx_count_twig(txh, dn, parent, level + 1,
|
dmu_tx_count_twig(txh, dn, parent, level + 1,
|
||||||
blkid >> epbs, freeable, history);
|
blkid >> epbs, freeable, history);
|
||||||
@ -336,8 +348,11 @@ dmu_tx_count_write(dmu_tx_hold_t *txh, uint64_t off, uint64_t len)
|
|||||||
bits = 64 - min_bs;
|
bits = 64 - min_bs;
|
||||||
epbs = min_ibs - SPA_BLKPTRSHIFT;
|
epbs = min_ibs - SPA_BLKPTRSHIFT;
|
||||||
for (bits -= epbs * (nlvls - 1);
|
for (bits -= epbs * (nlvls - 1);
|
||||||
bits >= 0; bits -= epbs)
|
bits >= 0; bits -= epbs) {
|
||||||
txh->txh_fudge += 1ULL << max_ibs;
|
(void) refcount_add_many(
|
||||||
|
&txh->txh_fudge,
|
||||||
|
1ULL << max_ibs, FTAG);
|
||||||
|
}
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
off += delta;
|
off += delta;
|
||||||
@ -353,7 +368,8 @@ dmu_tx_count_write(dmu_tx_hold_t *txh, uint64_t off, uint64_t len)
|
|||||||
*/
|
*/
|
||||||
start = P2ALIGN(off, 1ULL << max_bs);
|
start = P2ALIGN(off, 1ULL << max_bs);
|
||||||
end = P2ROUNDUP(off + len, 1ULL << max_bs) - 1;
|
end = P2ROUNDUP(off + len, 1ULL << max_bs) - 1;
|
||||||
txh->txh_space_towrite += end - start + 1;
|
(void) refcount_add_many(&txh->txh_space_towrite,
|
||||||
|
end - start + 1, FTAG);
|
||||||
|
|
||||||
start >>= min_bs;
|
start >>= min_bs;
|
||||||
end >>= min_bs;
|
end >>= min_bs;
|
||||||
@ -368,18 +384,21 @@ dmu_tx_count_write(dmu_tx_hold_t *txh, uint64_t off, uint64_t len)
|
|||||||
start >>= epbs;
|
start >>= epbs;
|
||||||
end >>= epbs;
|
end >>= epbs;
|
||||||
ASSERT3U(end, >=, start);
|
ASSERT3U(end, >=, start);
|
||||||
txh->txh_space_towrite += (end - start + 1) << max_ibs;
|
(void) refcount_add_many(&txh->txh_space_towrite,
|
||||||
|
(end - start + 1) << max_ibs, FTAG);
|
||||||
if (start != 0) {
|
if (start != 0) {
|
||||||
/*
|
/*
|
||||||
* We also need a new blkid=0 indirect block
|
* We also need a new blkid=0 indirect block
|
||||||
* to reference any existing file data.
|
* to reference any existing file data.
|
||||||
*/
|
*/
|
||||||
txh->txh_space_towrite += 1ULL << max_ibs;
|
(void) refcount_add_many(&txh->txh_space_towrite,
|
||||||
|
1ULL << max_ibs, FTAG);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
if (txh->txh_space_towrite + txh->txh_space_tooverwrite >
|
if (refcount_count(&txh->txh_space_towrite) +
|
||||||
|
refcount_count(&txh->txh_space_tooverwrite) >
|
||||||
2 * DMU_MAX_ACCESS)
|
2 * DMU_MAX_ACCESS)
|
||||||
err = SET_ERROR(EFBIG);
|
err = SET_ERROR(EFBIG);
|
||||||
|
|
||||||
@ -398,12 +417,15 @@ dmu_tx_count_dnode(dmu_tx_hold_t *txh)
|
|||||||
if (dn && dn->dn_dbuf->db_blkptr &&
|
if (dn && dn->dn_dbuf->db_blkptr &&
|
||||||
dsl_dataset_block_freeable(dn->dn_objset->os_dsl_dataset,
|
dsl_dataset_block_freeable(dn->dn_objset->os_dsl_dataset,
|
||||||
dn->dn_dbuf->db_blkptr, dn->dn_dbuf->db_blkptr->blk_birth)) {
|
dn->dn_dbuf->db_blkptr, dn->dn_dbuf->db_blkptr->blk_birth)) {
|
||||||
txh->txh_space_tooverwrite += space;
|
(void) refcount_add_many(&txh->txh_space_tooverwrite,
|
||||||
txh->txh_space_tounref += space;
|
space, FTAG);
|
||||||
|
(void) refcount_add_many(&txh->txh_space_tounref, space, FTAG);
|
||||||
} else {
|
} else {
|
||||||
txh->txh_space_towrite += space;
|
(void) refcount_add_many(&txh->txh_space_towrite, space, FTAG);
|
||||||
if (dn && dn->dn_dbuf->db_blkptr)
|
if (dn && dn->dn_dbuf->db_blkptr) {
|
||||||
txh->txh_space_tounref += space;
|
(void) refcount_add_many(&txh->txh_space_tounref,
|
||||||
|
space, FTAG);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -525,7 +547,8 @@ dmu_tx_count_free(dmu_tx_hold_t *txh, uint64_t off, uint64_t len)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
txh->txh_memory_tohold += dbuf->db.db_size;
|
(void) refcount_add_many(&txh->txh_memory_tohold,
|
||||||
|
dbuf->db.db_size, FTAG);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We don't check memory_tohold against DMU_MAX_ACCESS because
|
* We don't check memory_tohold against DMU_MAX_ACCESS because
|
||||||
@ -578,20 +601,23 @@ dmu_tx_count_free(dmu_tx_hold_t *txh, uint64_t off, uint64_t len)
|
|||||||
(dn->dn_indblkshift - SPA_BLKPTRSHIFT);
|
(dn->dn_indblkshift - SPA_BLKPTRSHIFT);
|
||||||
|
|
||||||
while (level++ < maxlevel) {
|
while (level++ < maxlevel) {
|
||||||
txh->txh_memory_tohold += MAX(MIN(blkcnt, nl1blks), 1)
|
(void) refcount_add_many(&txh->txh_memory_tohold,
|
||||||
<< dn->dn_indblkshift;
|
MAX(MIN(blkcnt, nl1blks), 1) << dn->dn_indblkshift,
|
||||||
|
FTAG);
|
||||||
blkcnt = 1 + (blkcnt >> epbs);
|
blkcnt = 1 + (blkcnt >> epbs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* account for new level 1 indirect blocks that might show up */
|
/* account for new level 1 indirect blocks that might show up */
|
||||||
if (skipped > 0) {
|
if (skipped > 0) {
|
||||||
txh->txh_fudge += skipped << dn->dn_indblkshift;
|
(void) refcount_add_many(&txh->txh_fudge,
|
||||||
|
skipped << dn->dn_indblkshift, FTAG);
|
||||||
skipped = MIN(skipped, DMU_MAX_DELETEBLKCNT >> epbs);
|
skipped = MIN(skipped, DMU_MAX_DELETEBLKCNT >> epbs);
|
||||||
txh->txh_memory_tohold += skipped << dn->dn_indblkshift;
|
(void) refcount_add_many(&txh->txh_memory_tohold,
|
||||||
|
skipped << dn->dn_indblkshift, FTAG);
|
||||||
}
|
}
|
||||||
txh->txh_space_tofree += space;
|
(void) refcount_add_many(&txh->txh_space_tofree, space, FTAG);
|
||||||
txh->txh_space_tounref += unref;
|
(void) refcount_add_many(&txh->txh_space_tounref, unref, FTAG);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -617,7 +643,10 @@ dmu_tx_mark_netfree(dmu_tx_t *tx)
|
|||||||
* cause overflows when doing math with these values (e.g. in
|
* cause overflows when doing math with these values (e.g. in
|
||||||
* dmu_tx_try_assign()).
|
* dmu_tx_try_assign()).
|
||||||
*/
|
*/
|
||||||
txh->txh_space_tofree = txh->txh_space_tounref = 1024 * 1024 * 1024;
|
(void) refcount_add_many(&txh->txh_space_tofree,
|
||||||
|
1024 * 1024 * 1024, FTAG);
|
||||||
|
(void) refcount_add_many(&txh->txh_space_tounref,
|
||||||
|
1024 * 1024 * 1024, FTAG);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -717,9 +746,7 @@ dmu_tx_hold_zap(dmu_tx_t *tx, uint64_t object, int add, const char *name)
|
|||||||
{
|
{
|
||||||
dmu_tx_hold_t *txh;
|
dmu_tx_hold_t *txh;
|
||||||
dnode_t *dn;
|
dnode_t *dn;
|
||||||
dsl_dataset_phys_t *ds_phys;
|
int err;
|
||||||
uint64_t nblocks;
|
|
||||||
int epbs, err;
|
|
||||||
|
|
||||||
ASSERT(tx->tx_txg == 0);
|
ASSERT(tx->tx_txg == 0);
|
||||||
|
|
||||||
@ -762,12 +789,17 @@ dmu_tx_hold_zap(dmu_tx_t *tx, uint64_t object, int add, const char *name)
|
|||||||
*/
|
*/
|
||||||
bp = &dn->dn_phys->dn_blkptr[0];
|
bp = &dn->dn_phys->dn_blkptr[0];
|
||||||
if (dsl_dataset_block_freeable(dn->dn_objset->os_dsl_dataset,
|
if (dsl_dataset_block_freeable(dn->dn_objset->os_dsl_dataset,
|
||||||
bp, bp->blk_birth))
|
bp, bp->blk_birth)) {
|
||||||
txh->txh_space_tooverwrite += MZAP_MAX_BLKSZ;
|
(void) refcount_add_many(&txh->txh_space_tooverwrite,
|
||||||
else
|
MZAP_MAX_BLKSZ, FTAG);
|
||||||
txh->txh_space_towrite += MZAP_MAX_BLKSZ;
|
} else {
|
||||||
if (!BP_IS_HOLE(bp))
|
(void) refcount_add_many(&txh->txh_space_towrite,
|
||||||
txh->txh_space_tounref += MZAP_MAX_BLKSZ;
|
MZAP_MAX_BLKSZ, FTAG);
|
||||||
|
}
|
||||||
|
if (!BP_IS_HOLE(bp)) {
|
||||||
|
(void) refcount_add_many(&txh->txh_space_tounref,
|
||||||
|
MZAP_MAX_BLKSZ, FTAG);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -789,15 +821,29 @@ dmu_tx_hold_zap(dmu_tx_t *tx, uint64_t object, int add, const char *name)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* If the modified blocks are scattered to the four winds,
|
* If the modified blocks are scattered to the four winds,
|
||||||
* we'll have to modify an indirect twig for each.
|
* we'll have to modify an indirect twig for each. We can make
|
||||||
|
* modifications at up to 3 locations:
|
||||||
|
* - header block at the beginning of the object
|
||||||
|
* - target leaf block
|
||||||
|
* - end of the object, where we might need to write:
|
||||||
|
* - a new leaf block if the target block needs to be split
|
||||||
|
* - the new pointer table, if it is growing
|
||||||
|
* - the new cookie table, if it is growing
|
||||||
*/
|
*/
|
||||||
epbs = dn->dn_indblkshift - SPA_BLKPTRSHIFT;
|
int epbs = dn->dn_indblkshift - SPA_BLKPTRSHIFT;
|
||||||
ds_phys = dsl_dataset_phys(dn->dn_objset->os_dsl_dataset);
|
dsl_dataset_phys_t *ds_phys =
|
||||||
for (nblocks = dn->dn_maxblkid >> epbs; nblocks != 0; nblocks >>= epbs)
|
dsl_dataset_phys(dn->dn_objset->os_dsl_dataset);
|
||||||
if (ds_phys->ds_prev_snap_obj)
|
for (int lvl = 1; lvl < dn->dn_nlevels; lvl++) {
|
||||||
txh->txh_space_towrite += 3 << dn->dn_indblkshift;
|
uint64_t num_indirects = 1 + (dn->dn_maxblkid >> (epbs * lvl));
|
||||||
else
|
uint64_t spc = MIN(3, num_indirects) << dn->dn_indblkshift;
|
||||||
txh->txh_space_tooverwrite += 3 << dn->dn_indblkshift;
|
if (ds_phys->ds_prev_snap_obj != 0) {
|
||||||
|
(void) refcount_add_many(&txh->txh_space_towrite,
|
||||||
|
spc, FTAG);
|
||||||
|
} else {
|
||||||
|
(void) refcount_add_many(&txh->txh_space_tooverwrite,
|
||||||
|
spc, FTAG);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -822,7 +868,7 @@ dmu_tx_hold_space(dmu_tx_t *tx, uint64_t space)
|
|||||||
txh = dmu_tx_hold_object_impl(tx, tx->tx_objset,
|
txh = dmu_tx_hold_object_impl(tx, tx->tx_objset,
|
||||||
DMU_NEW_OBJECT, THT_SPACE, space, 0);
|
DMU_NEW_OBJECT, THT_SPACE, space, 0);
|
||||||
|
|
||||||
txh->txh_space_towrite += space;
|
(void) refcount_add_many(&txh->txh_space_towrite, space, FTAG);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@ -1175,12 +1221,12 @@ dmu_tx_try_assign(dmu_tx_t *tx, txg_how_t txg_how)
|
|||||||
(void) refcount_add(&dn->dn_tx_holds, tx);
|
(void) refcount_add(&dn->dn_tx_holds, tx);
|
||||||
mutex_exit(&dn->dn_mtx);
|
mutex_exit(&dn->dn_mtx);
|
||||||
}
|
}
|
||||||
towrite += txh->txh_space_towrite;
|
towrite += refcount_count(&txh->txh_space_towrite);
|
||||||
tofree += txh->txh_space_tofree;
|
tofree += refcount_count(&txh->txh_space_tofree);
|
||||||
tooverwrite += txh->txh_space_tooverwrite;
|
tooverwrite += refcount_count(&txh->txh_space_tooverwrite);
|
||||||
tounref += txh->txh_space_tounref;
|
tounref += refcount_count(&txh->txh_space_tounref);
|
||||||
tohold += txh->txh_memory_tohold;
|
tohold += refcount_count(&txh->txh_memory_tohold);
|
||||||
fudge += txh->txh_fudge;
|
fudge += refcount_count(&txh->txh_fudge);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1383,24 +1429,59 @@ dmu_tx_willuse_space(dmu_tx_t *tx, int64_t delta)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
static void
|
||||||
dmu_tx_commit(dmu_tx_t *tx)
|
dmu_tx_destroy(dmu_tx_t *tx)
|
||||||
{
|
{
|
||||||
dmu_tx_hold_t *txh;
|
dmu_tx_hold_t *txh;
|
||||||
|
|
||||||
|
while ((txh = list_head(&tx->tx_holds)) != NULL) {
|
||||||
|
dnode_t *dn = txh->txh_dnode;
|
||||||
|
|
||||||
|
list_remove(&tx->tx_holds, txh);
|
||||||
|
refcount_destroy_many(&txh->txh_space_towrite,
|
||||||
|
refcount_count(&txh->txh_space_towrite));
|
||||||
|
refcount_destroy_many(&txh->txh_space_tofree,
|
||||||
|
refcount_count(&txh->txh_space_tofree));
|
||||||
|
refcount_destroy_many(&txh->txh_space_tooverwrite,
|
||||||
|
refcount_count(&txh->txh_space_tooverwrite));
|
||||||
|
refcount_destroy_many(&txh->txh_space_tounref,
|
||||||
|
refcount_count(&txh->txh_space_tounref));
|
||||||
|
refcount_destroy_many(&txh->txh_memory_tohold,
|
||||||
|
refcount_count(&txh->txh_memory_tohold));
|
||||||
|
refcount_destroy_many(&txh->txh_fudge,
|
||||||
|
refcount_count(&txh->txh_fudge));
|
||||||
|
kmem_free(txh, sizeof (dmu_tx_hold_t));
|
||||||
|
if (dn != NULL)
|
||||||
|
dnode_rele(dn, tx);
|
||||||
|
}
|
||||||
|
|
||||||
|
list_destroy(&tx->tx_callbacks);
|
||||||
|
list_destroy(&tx->tx_holds);
|
||||||
|
#ifdef ZFS_DEBUG
|
||||||
|
refcount_destroy_many(&tx->tx_space_written,
|
||||||
|
refcount_count(&tx->tx_space_written));
|
||||||
|
refcount_destroy_many(&tx->tx_space_freed,
|
||||||
|
refcount_count(&tx->tx_space_freed));
|
||||||
|
#endif
|
||||||
|
kmem_free(tx, sizeof (dmu_tx_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
dmu_tx_commit(dmu_tx_t *tx)
|
||||||
|
{
|
||||||
ASSERT(tx->tx_txg != 0);
|
ASSERT(tx->tx_txg != 0);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Go through the transaction's hold list and remove holds on
|
* Go through the transaction's hold list and remove holds on
|
||||||
* associated dnodes, notifying waiters if no holds remain.
|
* associated dnodes, notifying waiters if no holds remain.
|
||||||
*/
|
*/
|
||||||
while (txh = list_head(&tx->tx_holds)) {
|
for (dmu_tx_hold_t *txh = list_head(&tx->tx_holds); txh != NULL;
|
||||||
|
txh = list_next(&tx->tx_holds, txh)) {
|
||||||
dnode_t *dn = txh->txh_dnode;
|
dnode_t *dn = txh->txh_dnode;
|
||||||
|
|
||||||
list_remove(&tx->tx_holds, txh);
|
|
||||||
kmem_free(txh, sizeof (dmu_tx_hold_t));
|
|
||||||
if (dn == NULL)
|
if (dn == NULL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
mutex_enter(&dn->dn_mtx);
|
mutex_enter(&dn->dn_mtx);
|
||||||
ASSERT3U(dn->dn_assigned_txg, ==, tx->tx_txg);
|
ASSERT3U(dn->dn_assigned_txg, ==, tx->tx_txg);
|
||||||
|
|
||||||
@ -1409,7 +1490,6 @@ dmu_tx_commit(dmu_tx_t *tx)
|
|||||||
cv_broadcast(&dn->dn_notxholds);
|
cv_broadcast(&dn->dn_notxholds);
|
||||||
}
|
}
|
||||||
mutex_exit(&dn->dn_mtx);
|
mutex_exit(&dn->dn_mtx);
|
||||||
dnode_rele(dn, tx);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tx->tx_tempreserve_cookie)
|
if (tx->tx_tempreserve_cookie)
|
||||||
@ -1421,51 +1501,26 @@ dmu_tx_commit(dmu_tx_t *tx)
|
|||||||
if (tx->tx_anyobj == FALSE)
|
if (tx->tx_anyobj == FALSE)
|
||||||
txg_rele_to_sync(&tx->tx_txgh);
|
txg_rele_to_sync(&tx->tx_txgh);
|
||||||
|
|
||||||
list_destroy(&tx->tx_callbacks);
|
|
||||||
list_destroy(&tx->tx_holds);
|
|
||||||
#ifdef ZFS_DEBUG
|
#ifdef ZFS_DEBUG
|
||||||
dprintf("towrite=%llu written=%llu tofree=%llu freed=%llu\n",
|
dprintf("towrite=%llu written=%llu tofree=%llu freed=%llu\n",
|
||||||
tx->tx_space_towrite, refcount_count(&tx->tx_space_written),
|
tx->tx_space_towrite, refcount_count(&tx->tx_space_written),
|
||||||
tx->tx_space_tofree, refcount_count(&tx->tx_space_freed));
|
tx->tx_space_tofree, refcount_count(&tx->tx_space_freed));
|
||||||
refcount_destroy_many(&tx->tx_space_written,
|
|
||||||
refcount_count(&tx->tx_space_written));
|
|
||||||
refcount_destroy_many(&tx->tx_space_freed,
|
|
||||||
refcount_count(&tx->tx_space_freed));
|
|
||||||
#endif
|
#endif
|
||||||
kmem_free(tx, sizeof (dmu_tx_t));
|
dmu_tx_destroy(tx);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
dmu_tx_abort(dmu_tx_t *tx)
|
dmu_tx_abort(dmu_tx_t *tx)
|
||||||
{
|
{
|
||||||
dmu_tx_hold_t *txh;
|
|
||||||
|
|
||||||
ASSERT(tx->tx_txg == 0);
|
ASSERT(tx->tx_txg == 0);
|
||||||
|
|
||||||
while (txh = list_head(&tx->tx_holds)) {
|
|
||||||
dnode_t *dn = txh->txh_dnode;
|
|
||||||
|
|
||||||
list_remove(&tx->tx_holds, txh);
|
|
||||||
kmem_free(txh, sizeof (dmu_tx_hold_t));
|
|
||||||
if (dn != NULL)
|
|
||||||
dnode_rele(dn, tx);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Call any registered callbacks with an error code.
|
* Call any registered callbacks with an error code.
|
||||||
*/
|
*/
|
||||||
if (!list_is_empty(&tx->tx_callbacks))
|
if (!list_is_empty(&tx->tx_callbacks))
|
||||||
dmu_tx_do_callbacks(&tx->tx_callbacks, ECANCELED);
|
dmu_tx_do_callbacks(&tx->tx_callbacks, ECANCELED);
|
||||||
|
|
||||||
list_destroy(&tx->tx_callbacks);
|
dmu_tx_destroy(tx);
|
||||||
list_destroy(&tx->tx_holds);
|
|
||||||
#ifdef ZFS_DEBUG
|
|
||||||
refcount_destroy_many(&tx->tx_space_written,
|
|
||||||
refcount_count(&tx->tx_space_written));
|
|
||||||
refcount_destroy_many(&tx->tx_space_freed,
|
|
||||||
refcount_count(&tx->tx_space_freed));
|
|
||||||
#endif
|
|
||||||
kmem_free(tx, sizeof (dmu_tx_t));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t
|
uint64_t
|
||||||
@ -1504,7 +1559,7 @@ dmu_tx_do_callbacks(list_t *cb_list, int error)
|
|||||||
{
|
{
|
||||||
dmu_tx_callback_t *dcb;
|
dmu_tx_callback_t *dcb;
|
||||||
|
|
||||||
while (dcb = list_head(cb_list)) {
|
while ((dcb = list_head(cb_list)) != NULL) {
|
||||||
list_remove(cb_list, dcb);
|
list_remove(cb_list, dcb);
|
||||||
dcb->dcb_func(dcb->dcb_data, error);
|
dcb->dcb_func(dcb->dcb_data, error);
|
||||||
kmem_free(dcb, sizeof (dmu_tx_callback_t));
|
kmem_free(dcb, sizeof (dmu_tx_callback_t));
|
||||||
@ -1562,18 +1617,24 @@ dmu_tx_hold_spill(dmu_tx_t *tx, uint64_t object)
|
|||||||
|
|
||||||
/* If blkptr doesn't exist then add space to towrite */
|
/* If blkptr doesn't exist then add space to towrite */
|
||||||
if (!(dn->dn_phys->dn_flags & DNODE_FLAG_SPILL_BLKPTR)) {
|
if (!(dn->dn_phys->dn_flags & DNODE_FLAG_SPILL_BLKPTR)) {
|
||||||
txh->txh_space_towrite += SPA_OLD_MAXBLOCKSIZE;
|
(void) refcount_add_many(&txh->txh_space_towrite,
|
||||||
|
SPA_OLD_MAXBLOCKSIZE, FTAG);
|
||||||
} else {
|
} else {
|
||||||
blkptr_t *bp;
|
blkptr_t *bp;
|
||||||
|
|
||||||
bp = &dn->dn_phys->dn_spill;
|
bp = &dn->dn_phys->dn_spill;
|
||||||
if (dsl_dataset_block_freeable(dn->dn_objset->os_dsl_dataset,
|
if (dsl_dataset_block_freeable(dn->dn_objset->os_dsl_dataset,
|
||||||
bp, bp->blk_birth))
|
bp, bp->blk_birth)) {
|
||||||
txh->txh_space_tooverwrite += SPA_OLD_MAXBLOCKSIZE;
|
(void) refcount_add_many(&txh->txh_space_tooverwrite,
|
||||||
else
|
SPA_OLD_MAXBLOCKSIZE, FTAG);
|
||||||
txh->txh_space_towrite += SPA_OLD_MAXBLOCKSIZE;
|
} else {
|
||||||
if (!BP_IS_HOLE(bp))
|
(void) refcount_add_many(&txh->txh_space_towrite,
|
||||||
txh->txh_space_tounref += SPA_OLD_MAXBLOCKSIZE;
|
SPA_OLD_MAXBLOCKSIZE, FTAG);
|
||||||
|
}
|
||||||
|
if (!BP_IS_HOLE(bp)) {
|
||||||
|
(void) refcount_add_many(&txh->txh_space_tounref,
|
||||||
|
SPA_OLD_MAXBLOCKSIZE, FTAG);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
* Use is subject to license terms.
|
* Use is subject to license terms.
|
||||||
*/
|
*/
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2013 by Delphix. All rights reserved.
|
* Copyright (c) 2012, 2015 by Delphix. All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _SYS_DMU_TX_H
|
#ifndef _SYS_DMU_TX_H
|
||||||
@ -101,12 +101,12 @@ typedef struct dmu_tx_hold {
|
|||||||
dmu_tx_t *txh_tx;
|
dmu_tx_t *txh_tx;
|
||||||
list_node_t txh_node;
|
list_node_t txh_node;
|
||||||
struct dnode *txh_dnode;
|
struct dnode *txh_dnode;
|
||||||
uint64_t txh_space_towrite;
|
refcount_t txh_space_towrite;
|
||||||
uint64_t txh_space_tofree;
|
refcount_t txh_space_tofree;
|
||||||
uint64_t txh_space_tooverwrite;
|
refcount_t txh_space_tooverwrite;
|
||||||
uint64_t txh_space_tounref;
|
refcount_t txh_space_tounref;
|
||||||
uint64_t txh_memory_tohold;
|
refcount_t txh_memory_tohold;
|
||||||
uint64_t txh_fudge;
|
refcount_t txh_fudge;
|
||||||
#ifdef ZFS_DEBUG
|
#ifdef ZFS_DEBUG
|
||||||
enum dmu_tx_hold_type txh_type;
|
enum dmu_tx_hold_type txh_type;
|
||||||
uint64_t txh_arg1;
|
uint64_t txh_arg1;
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
*/
|
*/
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||||
* Copyright (c) 2012 by Delphix. All rights reserved.
|
* Copyright (c) 2012, 2015 by Delphix. All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _SYS_ZAP_H
|
#ifndef _SYS_ZAP_H
|
||||||
@ -80,6 +80,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/dmu.h>
|
#include <sys/dmu.h>
|
||||||
|
#include <sys/refcount.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@ -217,7 +218,7 @@ int zap_prefetch_uint64(objset_t *os, uint64_t zapobj, const uint64_t *key,
|
|||||||
int key_numints);
|
int key_numints);
|
||||||
|
|
||||||
int zap_count_write(objset_t *os, uint64_t zapobj, const char *name,
|
int zap_count_write(objset_t *os, uint64_t zapobj, const char *name,
|
||||||
int add, uint64_t *towrite, uint64_t *tooverwrite);
|
int add, refcount_t *towrite, refcount_t *tooverwrite);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create an attribute with the given name and value.
|
* Create an attribute with the given name and value.
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
*/
|
*/
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* Copyright (c) 2013, 2015 by Delphix. All rights reserved.
|
||||||
* Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
|
* Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
|
||||||
* Copyright (c) 2014 Integros [integros.com]
|
* Copyright (c) 2014 Integros [integros.com]
|
||||||
*/
|
*/
|
||||||
@ -213,8 +214,8 @@ int fzap_lookup(zap_name_t *zn,
|
|||||||
uint64_t integer_size, uint64_t num_integers, void *buf,
|
uint64_t integer_size, uint64_t num_integers, void *buf,
|
||||||
char *realname, int rn_len, boolean_t *normalization_conflictp);
|
char *realname, int rn_len, boolean_t *normalization_conflictp);
|
||||||
void fzap_prefetch(zap_name_t *zn);
|
void fzap_prefetch(zap_name_t *zn);
|
||||||
int fzap_count_write(zap_name_t *zn, int add, uint64_t *towrite,
|
int fzap_count_write(zap_name_t *zn, int add, refcount_t *towrite,
|
||||||
uint64_t *tooverwrite);
|
refcount_t *tooverwrite);
|
||||||
int fzap_add(zap_name_t *zn, uint64_t integer_size, uint64_t num_integers,
|
int fzap_add(zap_name_t *zn, uint64_t integer_size, uint64_t num_integers,
|
||||||
const void *val, dmu_tx_t *tx);
|
const void *val, dmu_tx_t *tx);
|
||||||
int fzap_update(zap_name_t *zn,
|
int fzap_update(zap_name_t *zn,
|
||||||
|
@ -1342,8 +1342,8 @@ fzap_get_stats(zap_t *zap, zap_stats_t *zs)
|
|||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
fzap_count_write(zap_name_t *zn, int add, uint64_t *towrite,
|
fzap_count_write(zap_name_t *zn, int add, refcount_t *towrite,
|
||||||
uint64_t *tooverwrite)
|
refcount_t *tooverwrite)
|
||||||
{
|
{
|
||||||
zap_t *zap = zn->zn_zap;
|
zap_t *zap = zn->zn_zap;
|
||||||
zap_leaf_t *l;
|
zap_leaf_t *l;
|
||||||
@ -1353,9 +1353,11 @@ fzap_count_write(zap_name_t *zn, int add, uint64_t *towrite,
|
|||||||
* Account for the header block of the fatzap.
|
* Account for the header block of the fatzap.
|
||||||
*/
|
*/
|
||||||
if (!add && dmu_buf_freeable(zap->zap_dbuf)) {
|
if (!add && dmu_buf_freeable(zap->zap_dbuf)) {
|
||||||
*tooverwrite += zap->zap_dbuf->db_size;
|
(void) refcount_add_many(tooverwrite,
|
||||||
|
zap->zap_dbuf->db_size, FTAG);
|
||||||
} else {
|
} else {
|
||||||
*towrite += zap->zap_dbuf->db_size;
|
(void) refcount_add_many(towrite,
|
||||||
|
zap->zap_dbuf->db_size, FTAG);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1367,10 +1369,13 @@ fzap_count_write(zap_name_t *zn, int add, uint64_t *towrite,
|
|||||||
* could extend the table.
|
* could extend the table.
|
||||||
*/
|
*/
|
||||||
if (add) {
|
if (add) {
|
||||||
if (zap_f_phys(zap)->zap_ptrtbl.zt_blk == 0)
|
if (zap_f_phys(zap)->zap_ptrtbl.zt_blk == 0) {
|
||||||
*towrite += zap->zap_dbuf->db_size;
|
(void) refcount_add_many(towrite,
|
||||||
else
|
zap->zap_dbuf->db_size, FTAG);
|
||||||
*towrite += (zap->zap_dbuf->db_size * 3);
|
} else {
|
||||||
|
(void) refcount_add_many(towrite,
|
||||||
|
zap->zap_dbuf->db_size * 3, FTAG);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1383,13 +1388,14 @@ fzap_count_write(zap_name_t *zn, int add, uint64_t *towrite,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!add && dmu_buf_freeable(l->l_dbuf)) {
|
if (!add && dmu_buf_freeable(l->l_dbuf)) {
|
||||||
*tooverwrite += l->l_dbuf->db_size;
|
(void) refcount_add_many(tooverwrite, l->l_dbuf->db_size, FTAG);
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
* If this an add operation, the leaf block could split.
|
* If this an add operation, the leaf block could split.
|
||||||
* Hence, we need to account for an additional leaf block.
|
* Hence, we need to account for an additional leaf block.
|
||||||
*/
|
*/
|
||||||
*towrite += (add ? 2 : 1) * l->l_dbuf->db_size;
|
(void) refcount_add_many(towrite,
|
||||||
|
(add ? 2 : 1) * l->l_dbuf->db_size, FTAG);
|
||||||
}
|
}
|
||||||
|
|
||||||
zap_put_leaf(l);
|
zap_put_leaf(l);
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
*/
|
*/
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||||
* Copyright (c) 2011, 2014 by Delphix. All rights reserved.
|
* Copyright (c) 2011, 2015 by Delphix. All rights reserved.
|
||||||
* Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
|
* Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
|
||||||
* Copyright (c) 2014 Integros [integros.com]
|
* Copyright (c) 2014 Integros [integros.com]
|
||||||
*/
|
*/
|
||||||
@ -1414,7 +1414,7 @@ zap_get_stats(objset_t *os, uint64_t zapobj, zap_stats_t *zs)
|
|||||||
|
|
||||||
int
|
int
|
||||||
zap_count_write(objset_t *os, uint64_t zapobj, const char *name, int add,
|
zap_count_write(objset_t *os, uint64_t zapobj, const char *name, int add,
|
||||||
uint64_t *towrite, uint64_t *tooverwrite)
|
refcount_t *towrite, refcount_t *tooverwrite)
|
||||||
{
|
{
|
||||||
zap_t *zap;
|
zap_t *zap;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
@ -1424,14 +1424,15 @@ zap_count_write(objset_t *os, uint64_t zapobj, const char *name, int add,
|
|||||||
* be affected in this operation. So, account for the worst case :
|
* be affected in this operation. So, account for the worst case :
|
||||||
* - 3 blocks overwritten: target leaf, ptrtbl block, header block
|
* - 3 blocks overwritten: target leaf, ptrtbl block, header block
|
||||||
* - 4 new blocks written if adding:
|
* - 4 new blocks written if adding:
|
||||||
* - 2 blocks for possibly split leaves,
|
* - 2 blocks for possibly split leaves,
|
||||||
* - 2 grown ptrtbl blocks
|
* - 2 grown ptrtbl blocks
|
||||||
*
|
*
|
||||||
* This also accomodates the case where an add operation to a fairly
|
* This also accomodates the case where an add operation to a fairly
|
||||||
* large microzap results in a promotion to fatzap.
|
* large microzap results in a promotion to fatzap.
|
||||||
*/
|
*/
|
||||||
if (name == NULL) {
|
if (name == NULL) {
|
||||||
*towrite += (3 + (add ? 4 : 0)) * SPA_OLD_MAXBLOCKSIZE;
|
(void) refcount_add_many(towrite,
|
||||||
|
(3 + (add ? 4 : 0)) * SPA_OLD_MAXBLOCKSIZE, FTAG);
|
||||||
return (err);
|
return (err);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1455,7 +1456,8 @@ zap_count_write(objset_t *os, uint64_t zapobj, const char *name, int add,
|
|||||||
/*
|
/*
|
||||||
* We treat this case as similar to (name == NULL)
|
* We treat this case as similar to (name == NULL)
|
||||||
*/
|
*/
|
||||||
*towrite += (3 + (add ? 4 : 0)) * SPA_OLD_MAXBLOCKSIZE;
|
(void) refcount_add_many(towrite,
|
||||||
|
(3 + (add ? 4 : 0)) * SPA_OLD_MAXBLOCKSIZE, FTAG);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
@ -1473,13 +1475,17 @@ zap_count_write(objset_t *os, uint64_t zapobj, const char *name, int add,
|
|||||||
* 4 new blocks written : 2 new split leaf, 2 grown
|
* 4 new blocks written : 2 new split leaf, 2 grown
|
||||||
* ptrtbl blocks
|
* ptrtbl blocks
|
||||||
*/
|
*/
|
||||||
if (dmu_buf_freeable(zap->zap_dbuf))
|
if (dmu_buf_freeable(zap->zap_dbuf)) {
|
||||||
*tooverwrite += MZAP_MAX_BLKSZ;
|
(void) refcount_add_many(tooverwrite,
|
||||||
else
|
MZAP_MAX_BLKSZ, FTAG);
|
||||||
*towrite += MZAP_MAX_BLKSZ;
|
} else {
|
||||||
|
(void) refcount_add_many(towrite,
|
||||||
|
MZAP_MAX_BLKSZ, FTAG);
|
||||||
|
}
|
||||||
|
|
||||||
if (add) {
|
if (add) {
|
||||||
*towrite += 4 * MZAP_MAX_BLKSZ;
|
(void) refcount_add_many(towrite,
|
||||||
|
4 * MZAP_MAX_BLKSZ, FTAG);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user