]> git.proxmox.com Git - mirror_zfs-debian.git/commitdiff
Illumos #1862 incremental zfs receive fails for sparse file > 8PB
authorArne Jansen <sensille@gmx.net>
Mon, 14 Jan 2013 18:26:31 +0000 (10:26 -0800)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Mon, 14 Jan 2013 18:34:41 +0000 (10:34 -0800)
1862 incremental zfs receive fails for sparse file > 8PB

Reviewed by: Matt Ahrens <matthew.ahrens@delphix.com>
Reviewed by: Simon Klinkert <klinkert@webgods.de>
Approved by: Eric Schrock <eric.schrock@delphix.com>

References:
  illumos/illumos-gate@31495a1e56860f4575614774a592fe33fc9c71f2
  illumos changeset: 13789:f0c17d471b7a
  https://www.illumos.org/issues/1862

Ported-by: Brian Behlendorf <behlendorf1@llnl.gov>
module/zfs/dmu_tx.c

index 47ec4c1091e8c467373fb837f06de978fbd10442..044349c342d7305cf6a620b359762412d8146541 100644 (file)
@@ -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;