diff options
author | Arne Jansen <[email protected]> | 2013-01-14 10:26:31 -0800 |
---|---|---|
committer | Brian Behlendorf <[email protected]> | 2013-01-14 10:34:41 -0800 |
commit | ff80d9b142826c15fa84e3c4b9ef1795fd6e9485 (patch) | |
tree | 76a58643ff9c8d238879e976efb76e0f93499754 /module/zfs/dmu_tx.c | |
parent | a94addd9749e8272664a2476460e75829626a465 (diff) |
Illumos #1862 incremental zfs receive fails for sparse file > 8PB
1862 incremental zfs receive fails for sparse file > 8PB
Reviewed by: Matt Ahrens <[email protected]>
Reviewed by: Simon Klinkert <[email protected]>
Approved by: Eric Schrock <[email protected]>
References:
illumos/illumos-gate@31495a1e56860f4575614774a592fe33fc9c71f2
illumos changeset: 13789:f0c17d471b7a
https://www.illumos.org/issues/1862
Ported-by: Brian Behlendorf <[email protected]>
Diffstat (limited to 'module/zfs/dmu_tx.c')
-rw-r--r-- | module/zfs/dmu_tx.c | 42 |
1 files changed, 27 insertions, 15 deletions
diff --git a/module/zfs/dmu_tx.c b/module/zfs/dmu_tx.c index 47ec4c109..044349c34 100644 --- a/module/zfs/dmu_tx.c +++ b/module/zfs/dmu_tx.c @@ -446,6 +446,7 @@ dmu_tx_count_free(dmu_tx_hold_t *txh, uint64_t off, uint64_t len) dsl_dataset_t *ds = dn->dn_objset->os_dsl_dataset; spa_t *spa = txh->txh_tx->tx_pool->dp_spa; int epbs; + uint64_t l0span = 0, nl1blks = 0; if (dn->dn_nlevels == 0) return; @@ -478,6 +479,7 @@ dmu_tx_count_free(dmu_tx_hold_t *txh, uint64_t off, uint64_t len) nblks = dn->dn_maxblkid - blkid; } + l0span = nblks; /* save for later use to calc level > 1 overhead */ if (dn->dn_nlevels == 1) { int i; for (i = 0; i < nblks; i++) { @@ -490,24 +492,10 @@ dmu_tx_count_free(dmu_tx_hold_t *txh, uint64_t off, uint64_t len) } unref += BP_GET_ASIZE(bp); } + nl1blks = 1; nblks = 0; } - /* - * Add in memory requirements of higher-level indirects. - * This assumes a worst-possible scenario for dn_nlevels. - */ - { - uint64_t blkcnt = 1 + ((nblks >> epbs) >> epbs); - int level = (dn->dn_nlevels > 1) ? 2 : 1; - - while (level++ < DN_MAX_LEVELS) { - txh->txh_memory_tohold += blkcnt << dn->dn_indblkshift; - blkcnt = 1 + (blkcnt >> epbs); - } - ASSERT(blkcnt <= dn->dn_nblkptr); - } - lastblk = blkid + nblks - 1; while (nblks) { dmu_buf_impl_t *dbuf; @@ -578,11 +566,35 @@ dmu_tx_count_free(dmu_tx_hold_t *txh, uint64_t off, uint64_t len) } dbuf_rele(dbuf, FTAG); + ++nl1blks; blkid += tochk; nblks -= tochk; } rw_exit(&dn->dn_struct_rwlock); + /* + * Add in memory requirements of higher-level indirects. + * This assumes a worst-possible scenario for dn_nlevels and a + * worst-possible distribution of l1-blocks over the region to free. + */ + { + uint64_t blkcnt = 1 + ((l0span >> epbs) >> epbs); + int level = 2; + /* + * Here we don't use DN_MAX_LEVEL, but calculate it with the + * given datablkshift and indblkshift. This makes the + * difference between 19 and 8 on large files. + */ + int maxlevel = 2 + (DN_MAX_OFFSET_SHIFT - dn->dn_datablkshift) / + (dn->dn_indblkshift - SPA_BLKPTRSHIFT); + + while (level++ < maxlevel) { + txh->txh_memory_tohold += MIN(blkcnt, (nl1blks >> epbs)) + << dn->dn_indblkshift; + blkcnt = 1 + (blkcnt >> epbs); + } + } + /* account for new level 1 indirect blocks that might show up */ if (skipped > 0) { txh->txh_fudge += skipped << dn->dn_indblkshift; |