Author: delphij
Date: Wed Jan  1 00:45:28 2014
New Revision: 260150
URL: http://svnweb.freebsd.org/changeset/base/260150

Log:
  MFV r259170:
  
  4370 avoid transmitting holes during zfs send
  
  4371 DMU code clean up
  
  illumos/illumos-gate@43466aae47bfcd2ad9bf501faec8e75c08095e4f
  
  NOTE: Make sure the boot code is updated if a zpool upgrade is
  done on boot zpool.
  
  MFC after:    2 weeks

Modified:
  head/cddl/contrib/opensolaris/cmd/zdb/zdb.c
  head/cddl/contrib/opensolaris/cmd/zdb/zdb_il.c
  head/cddl/contrib/opensolaris/cmd/zhack/zhack.c
  head/cddl/contrib/opensolaris/cmd/zpool/zpool-features.7
  head/lib/libprocstat/zfs/Makefile
  head/sys/boot/zfs/zfsimpl.c
  head/sys/cddl/boot/zfs/zfsimpl.h
  head/sys/cddl/contrib/opensolaris/common/zfs/zfeature_common.c
  head/sys/cddl/contrib/opensolaris/common/zfs/zfeature_common.h
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/arc.c
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/bptree.c
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dbuf.c
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/ddt.c
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu.c
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_diff.c
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_send.c
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_traverse.c
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dnode.c
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dnode_sync.c
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dataset.c
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_destroy.c
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_scan.c
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa.c
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa_misc.c
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dbuf.h
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dmu.h
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/spa.h
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/spa_impl.h
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/vdev.h
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zfeature.h
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_cache.c
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_disk.c
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfeature.c
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zil.c
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zio.c
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c
Directory Properties:
  head/cddl/contrib/opensolaris/   (props changed)
  head/sys/cddl/contrib/opensolaris/   (props changed)

Modified: head/cddl/contrib/opensolaris/cmd/zdb/zdb.c
==============================================================================
--- head/cddl/contrib/opensolaris/cmd/zdb/zdb.c Wed Jan  1 00:38:22 2014        
(r260149)
+++ head/cddl/contrib/opensolaris/cmd/zdb/zdb.c Wed Jan  1 00:45:28 2014        
(r260150)
@@ -764,7 +764,7 @@ dump_dde(const ddt_t *ddt, const ddt_ent
                if (ddp->ddp_phys_birth == 0)
                        continue;
                ddt_bp_create(ddt->ddt_checksum, ddk, ddp, &blk);
-               sprintf_blkptr(blkbuf, &blk);
+               snprintf_blkptr(blkbuf, sizeof (blkbuf), &blk);
                (void) printf("index %llx refcnt %llu %s %s\n",
                    (u_longlong_t)index, (u_longlong_t)ddp->ddp_refcnt,
                    types[p], blkbuf);
@@ -1024,31 +1024,39 @@ blkid2offset(const dnode_phys_t *dnp, co
 }
 
 static void
-sprintf_blkptr_compact(char *blkbuf, const blkptr_t *bp)
+snprintf_blkptr_compact(char *blkbuf, size_t buflen, const blkptr_t *bp)
 {
        const dva_t *dva = bp->blk_dva;
        int ndvas = dump_opt['d'] > 5 ? BP_GET_NDVAS(bp) : 1;
 
        if (dump_opt['b'] >= 6) {
-               sprintf_blkptr(blkbuf, bp);
+               snprintf_blkptr(blkbuf, buflen, bp);
                return;
        }
 
        blkbuf[0] = '\0';
 
        for (int i = 0; i < ndvas; i++)
-               (void) sprintf(blkbuf + strlen(blkbuf), "%llu:%llx:%llx ",
+               (void) snprintf(blkbuf + strlen(blkbuf),
+                   buflen - strlen(blkbuf), "%llu:%llx:%llx ",
                    (u_longlong_t)DVA_GET_VDEV(&dva[i]),
                    (u_longlong_t)DVA_GET_OFFSET(&dva[i]),
                    (u_longlong_t)DVA_GET_ASIZE(&dva[i]));
 
-       (void) sprintf(blkbuf + strlen(blkbuf),
-           "%llxL/%llxP F=%llu B=%llu/%llu",
-           (u_longlong_t)BP_GET_LSIZE(bp),
-           (u_longlong_t)BP_GET_PSIZE(bp),
-           (u_longlong_t)bp->blk_fill,
-           (u_longlong_t)bp->blk_birth,
-           (u_longlong_t)BP_PHYSICAL_BIRTH(bp));
+       if (BP_IS_HOLE(bp)) {
+               (void) snprintf(blkbuf + strlen(blkbuf),
+                   buflen - strlen(blkbuf), "B=%llu",
+                   (u_longlong_t)bp->blk_birth);
+       } else {
+               (void) snprintf(blkbuf + strlen(blkbuf),
+                   buflen - strlen(blkbuf),
+                   "%llxL/%llxP F=%llu B=%llu/%llu",
+                   (u_longlong_t)BP_GET_LSIZE(bp),
+                   (u_longlong_t)BP_GET_PSIZE(bp),
+                   (u_longlong_t)bp->blk_fill,
+                   (u_longlong_t)bp->blk_birth,
+                   (u_longlong_t)BP_PHYSICAL_BIRTH(bp));
+       }
 }
 
 static void
@@ -1073,7 +1081,7 @@ print_indirect(blkptr_t *bp, const zbook
                }
        }
 
-       sprintf_blkptr_compact(blkbuf, bp);
+       snprintf_blkptr_compact(blkbuf, sizeof (blkbuf), bp);
        (void) printf("%s\n", blkbuf);
 }
 
@@ -1088,7 +1096,7 @@ visit_indirect(spa_t *spa, const dnode_p
 
        print_indirect(bp, zb, dnp);
 
-       if (BP_GET_LEVEL(bp) > 0) {
+       if (BP_GET_LEVEL(bp) > 0 && !BP_IS_HOLE(bp)) {
                uint32_t flags = ARC_WAIT;
                int i;
                blkptr_t *cbp;
@@ -1213,7 +1221,7 @@ dump_dsl_dataset(objset_t *os, uint64_t 
        zdb_nicenum(ds->ds_compressed_bytes, compressed);
        zdb_nicenum(ds->ds_uncompressed_bytes, uncompressed);
        zdb_nicenum(ds->ds_unique_bytes, unique);
-       sprintf_blkptr(blkbuf, &ds->ds_bp);
+       snprintf_blkptr(blkbuf, sizeof (blkbuf), &ds->ds_bp);
 
        (void) printf("\t\tdir_obj = %llu\n",
            (u_longlong_t)ds->ds_dir_obj);
@@ -1258,7 +1266,7 @@ dump_bptree_cb(void *arg, const blkptr_t
        char blkbuf[BP_SPRINTF_LEN];
 
        if (bp->blk_birth != 0) {
-               sprintf_blkptr(blkbuf, bp);
+               snprintf_blkptr(blkbuf, sizeof (blkbuf), bp);
                (void) printf("\t%s\n", blkbuf);
        }
        return (0);
@@ -1296,7 +1304,7 @@ dump_bpobj_cb(void *arg, const blkptr_t 
        char blkbuf[BP_SPRINTF_LEN];
 
        ASSERT(bp->blk_birth != 0);
-       sprintf_blkptr_compact(blkbuf, bp);
+       snprintf_blkptr_compact(blkbuf, sizeof (blkbuf), bp);
        (void) printf("\t%s\n", blkbuf);
        return (0);
 }
@@ -1795,8 +1803,9 @@ dump_dir(objset_t *os)
        zdb_nicenum(refdbytes, numbuf);
 
        if (verbosity >= 4) {
-               (void) sprintf(blkbuf, ", rootbp ");
-               (void) sprintf_blkptr(blkbuf + strlen(blkbuf), os->os_rootbp);
+               (void) snprintf(blkbuf, sizeof (blkbuf), ", rootbp ");
+               (void) snprintf_blkptr(blkbuf + strlen(blkbuf),
+                   sizeof (blkbuf) - strlen(blkbuf), os->os_rootbp);
        } else {
                blkbuf[0] = '\0';
        }
@@ -1826,7 +1835,7 @@ dump_dir(objset_t *os)
        if (verbosity < 2)
                return;
 
-       if (os->os_rootbp->blk_birth == 0)
+       if (BP_IS_HOLE(os->os_rootbp))
                return;
 
        dump_object(os, 0, verbosity, &print_header);
@@ -1867,7 +1876,7 @@ dump_uberblock(uberblock_t *ub, const ch
            (u_longlong_t)ub->ub_timestamp, asctime(localtime(&timestamp)));
        if (dump_opt['u'] >= 3) {
                char blkbuf[BP_SPRINTF_LEN];
-               sprintf_blkptr(blkbuf, &ub->ub_rootbp);
+               snprintf_blkptr(blkbuf, sizeof (blkbuf), &ub->ub_rootbp);
                (void) printf("\trootbp = %s\n", blkbuf);
        }
        (void) printf(footer ? footer : "");
@@ -2181,7 +2190,7 @@ zdb_blkptr_done(zio_t *zio)
                zcb->zcb_errors[ioerr]++;
 
                if (dump_opt['b'] >= 2)
-                       sprintf_blkptr(blkbuf, bp);
+                       snprintf_blkptr(blkbuf, sizeof (blkbuf), bp);
                else
                        blkbuf[0] = '\0';
 
@@ -2204,11 +2213,22 @@ zdb_blkptr_cb(spa_t *spa, zilog_t *zilog
     const zbookmark_t *zb, const dnode_phys_t *dnp, void *arg)
 {
        zdb_cb_t *zcb = arg;
-       char blkbuf[BP_SPRINTF_LEN];
        dmu_object_type_t type;
        boolean_t is_metadata;
 
-       if (bp == NULL)
+       if (dump_opt['b'] >= 5 && bp->blk_birth > 0) {
+               char blkbuf[BP_SPRINTF_LEN];
+               snprintf_blkptr(blkbuf, sizeof (blkbuf), bp);
+               (void) printf("objset %llu object %llu "
+                   "level %lld offset 0x%llx %s\n",
+                   (u_longlong_t)zb->zb_objset,
+                   (u_longlong_t)zb->zb_object,
+                   (longlong_t)zb->zb_level,
+                   (u_longlong_t)blkid2offset(dnp, bp, zb),
+                   blkbuf);
+       }
+
+       if (BP_IS_HOLE(bp))
                return (0);
 
        type = BP_GET_TYPE(bp);
@@ -2239,17 +2259,6 @@ zdb_blkptr_cb(spa_t *spa, zilog_t *zilog
 
        zcb->zcb_readfails = 0;
 
-       if (dump_opt['b'] >= 5) {
-               sprintf_blkptr(blkbuf, bp);
-               (void) printf("objset %llu object %llu "
-                   "level %lld offset 0x%llx %s\n",
-                   (u_longlong_t)zb->zb_objset,
-                   (u_longlong_t)zb->zb_object,
-                   (longlong_t)zb->zb_level,
-                   (u_longlong_t)blkid2offset(dnp, bp, zb),
-                   blkbuf);
-       }
-
        if (dump_opt['b'] < 5 && isatty(STDERR_FILENO) &&
            gethrtime() > zcb->zcb_lastprint + NANOSEC) {
                uint64_t now = gethrtime();
@@ -2406,7 +2415,7 @@ count_block_cb(void *arg, const blkptr_t
 
        if (dump_opt['b'] >= 5) {
                char blkbuf[BP_SPRINTF_LEN];
-               sprintf_blkptr(blkbuf, bp);
+               snprintf_blkptr(blkbuf, sizeof (blkbuf), bp);
                (void) printf("[%s] %s\n",
                    "deferred free", blkbuf);
        }
@@ -2640,7 +2649,7 @@ zdb_ddt_add_cb(spa_t *spa, zilog_t *zilo
        avl_index_t where;
        zdb_ddt_entry_t *zdde, zdde_search;
 
-       if (bp == NULL)
+       if (BP_IS_HOLE(bp))
                return (0);
 
        if (dump_opt['S'] > 1 && zb->zb_level == ZB_ROOT_LEVEL) {
@@ -2807,7 +2816,7 @@ zdb_print_blkptr(blkptr_t *bp, int flags
        if (flags & ZDB_FLAG_BSWAP)
                byteswap_uint64_array((void *)bp, sizeof (blkptr_t));
 
-       sprintf_blkptr(blkbuf, bp);
+       snprintf_blkptr(blkbuf, sizeof (blkbuf), bp);
        (void) printf("%s\n", blkbuf);
 }
 

Modified: head/cddl/contrib/opensolaris/cmd/zdb/zdb_il.c
==============================================================================
--- head/cddl/contrib/opensolaris/cmd/zdb/zdb_il.c      Wed Jan  1 00:38:22 
2014        (r260149)
+++ head/cddl/contrib/opensolaris/cmd/zdb/zdb_il.c      Wed Jan  1 00:45:28 
2014        (r260150)
@@ -24,6 +24,10 @@
  */
 
 /*
+ * Copyright (c) 2013 by Delphix. All rights reserved.
+ */
+
+/*
  * Print intent log header and statistics.
  */
 
@@ -47,7 +51,7 @@ print_log_bp(const blkptr_t *bp, const c
 {
        char blkbuf[BP_SPRINTF_LEN];
 
-       sprintf_blkptr(blkbuf, bp);
+       snprintf_blkptr(blkbuf, sizeof (blkbuf), bp);
        (void) printf("%s%s\n", prefix, blkbuf);
 }
 
@@ -132,6 +136,7 @@ zil_prt_rec_write(zilog_t *zilog, int tx
 
        if (lr->lr_common.lrc_reclen == sizeof (lr_write_t)) {
                (void) printf("%shas blkptr, %s\n", prefix,
+                   !BP_IS_HOLE(bp) &&
                    bp->blk_birth >= spa_first_txg(zilog->zl_spa) ?
                    "will claim" : "won't claim");
                print_log_bp(bp, prefix);
@@ -139,8 +144,6 @@ zil_prt_rec_write(zilog_t *zilog, int tx
                if (BP_IS_HOLE(bp)) {
                        (void) printf("\t\t\tLSIZE 0x%llx\n",
                            (u_longlong_t)BP_GET_LSIZE(bp));
-               }
-               if (bp->blk_birth == 0) {
                        bzero(buf, sizeof (buf));
                        (void) printf("%s<hole>\n", prefix);
                        return;
@@ -313,7 +316,8 @@ print_log_block(zilog_t *zilog, blkptr_t
 
        if (verbose >= 5) {
                (void) strcpy(blkbuf, ", ");
-               sprintf_blkptr(blkbuf + strlen(blkbuf), bp);
+               snprintf_blkptr(blkbuf + strlen(blkbuf),
+                   sizeof (blkbuf) - strlen(blkbuf), bp);
        } else {
                blkbuf[0] = '\0';
        }
@@ -361,7 +365,7 @@ dump_intent_log(zilog_t *zilog)
        int verbose = MAX(dump_opt['d'], dump_opt['i']);
        int i;
 
-       if (zh->zh_log.blk_birth == 0 || verbose < 1)
+       if (BP_IS_HOLE(&zh->zh_log) || verbose < 1)
                return;
 
        (void) printf("\n    ZIL header: claim_txg %llu, "

Modified: head/cddl/contrib/opensolaris/cmd/zhack/zhack.c
==============================================================================
--- head/cddl/contrib/opensolaris/cmd/zhack/zhack.c     Wed Jan  1 00:38:22 
2014        (r260149)
+++ head/cddl/contrib/opensolaris/cmd/zhack/zhack.c     Wed Jan  1 00:45:28 
2014        (r260150)
@@ -277,6 +277,9 @@ zhack_do_feature_stat(int argc, char **a
        dump_obj(os, spa->spa_feat_for_read_obj, "for_read");
        dump_obj(os, spa->spa_feat_for_write_obj, "for_write");
        dump_obj(os, spa->spa_feat_desc_obj, "descriptions");
+       if (spa_feature_is_active(spa, SPA_FEATURE_ENABLED_TXG)) {
+               dump_obj(os, spa->spa_feat_enabled_txg_obj, "enabled_txg");
+       }
        dump_mos(spa);
 
        spa_close(spa, FTAG);
@@ -313,7 +316,9 @@ zhack_do_feature_enable(int argc, char *
        feature.fi_uname = "zhack";
        feature.fi_mos = B_FALSE;
        feature.fi_can_readonly = B_FALSE;
+       feature.fi_activate_on_enable = B_FALSE;
        feature.fi_depends = nodeps;
+       feature.fi_feature = SPA_FEATURE_NONE;
 
        optind = 1;
        while ((c = getopt(argc, argv, "rmd:")) != -1) {
@@ -371,7 +376,7 @@ feature_incr_sync(void *arg, dmu_tx_t *t
        zfeature_info_t *feature = arg;
        uint64_t refcount;
 
-       VERIFY0(feature_get_refcount(spa, feature, &refcount));
+       VERIFY0(feature_get_refcount_from_disk(spa, feature, &refcount));
        feature_sync(spa, feature, refcount + 1, tx);
        spa_history_log_internal(spa, "zhack feature incr", tx,
            "name=%s", feature->fi_guid);
@@ -384,7 +389,7 @@ feature_decr_sync(void *arg, dmu_tx_t *t
        zfeature_info_t *feature = arg;
        uint64_t refcount;
 
-       VERIFY0(feature_get_refcount(spa, feature, &refcount));
+       VERIFY0(feature_get_refcount_from_disk(spa, feature, &refcount));
        feature_sync(spa, feature, refcount - 1, tx);
        spa_history_log_internal(spa, "zhack feature decr", tx,
            "name=%s", feature->fi_guid);
@@ -411,6 +416,7 @@ zhack_do_feature_ref(int argc, char **ar
        feature.fi_mos = B_FALSE;
        feature.fi_desc = NULL;
        feature.fi_depends = nodeps;
+       feature.fi_feature = SPA_FEATURE_NONE;
 
        optind = 1;
        while ((c = getopt(argc, argv, "md")) != -1) {
@@ -459,8 +465,8 @@ zhack_do_feature_ref(int argc, char **ar
 
        if (decr) {
                uint64_t count;
-               if (feature_get_refcount(spa, &feature, &count) == 0 &&
-                   count != 0) {
+               if (feature_get_refcount_from_disk(spa, &feature,
+                   &count) == 0 && count != 0) {
                        fatal(spa, FTAG, "feature refcount already 0: %s",
                            feature.fi_guid);
                }

Modified: head/cddl/contrib/opensolaris/cmd/zpool/zpool-features.7
==============================================================================
--- head/cddl/contrib/opensolaris/cmd/zpool/zpool-features.7    Wed Jan  1 
00:38:22 2014        (r260149)
+++ head/cddl/contrib/opensolaris/cmd/zpool/zpool-features.7    Wed Jan  1 
00:45:28 2014        (r260150)
@@ -23,7 +23,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd October 08, 2013
+.Dd December 31, 2013
 .Dt ZPOOL-FEATURES 7
 .Os
 .Sh NAME
@@ -286,6 +286,76 @@ and will be returned to the
 .Sy enabled
 state when all datasets that use
 this feature are destroyed.
+.It Sy enabled_txg
+.Bl -column "READ\-ONLY COMPATIBLE" "com.delphix:enabled_txg"
+.It GUID Ta com.delphix:enabled_txg
+.It READ\-ONLY COMPATIBLE Ta yes
+.It DEPENDENCIES Ta none
+.El
+.Pp
+Once this feature is enabled ZFS records the transaction group number
+in which new features are enabled. This has no user-visible impact,
+but other features may depend on this feature.
+.Pp
+This feature becomes
+.Sy active
+as soon as it is enabled and will
+never return to being
+.Sy enabled .
+.It Sy hole_birth
+.Bl -column "READ\-ONLY COMPATIBLE" "com.delphix:hole_birth"
+.It GUID Ta com.delphix:hole_birth
+.It READ\-ONLY COMPATIBLE Ta no
+.It DEPENDENCIES Ta enabled_txg
+.El
+.Pp
+This feature improves performance of incremental sends
+.Pq Dq zfs send -i
+and receives for objects with many holes.
+The most common case of
+hole-filled objects is zvols.
+.Pp
+An incremental send stream from snapshot
+.Sy A
+to snapshot
+.Sy B
+contains information about every block that changed between
+.Sy A
+and
+.Sy B .
+Blocks which did not change between those snapshots can be
+identified and omitted from the stream using a piece of metadata called
+the 'block birth time', but birth times are not recorded for holes
+.Pq blocks filled only with zeroes .
+Since holes created after
+.Sy A
+cannot be
+distinguished from holes created before
+.Sy A ,
+information about every
+hole in the entire filesystem or zvol is included in the send stream.
+.Pp
+For workloads where holes are rare this is not a problem.
+However, when
+incrementally replicating filesystems or zvols with many holes
+.Pq for example a zvol formatted with another filesystem
+a lot of time will
+be spent sending and receiving unnecessary information about holes that
+already exist on the receiving side.
+.Pp
+Once the
+.Sy hole_birth
+feature has been enabled the block birth times
+of all new holes will be recorded.
+Incremental sends between snapshots
+created after this feature is enabled will use this new metadata to avoid
+sending information about holes that already exist on the receiving side.
+.Pp
+This feature becomes
+.Sy active
+as soon as it is enabled and will
+never return to being
+.Sy enabled .
 .El
 .Sh SEE ALSO
 .Xr zpool 8

Modified: head/lib/libprocstat/zfs/Makefile
==============================================================================
--- head/lib/libprocstat/zfs/Makefile   Wed Jan  1 00:38:22 2014        
(r260149)
+++ head/lib/libprocstat/zfs/Makefile   Wed Jan  1 00:45:28 2014        
(r260150)
@@ -10,6 +10,7 @@ CFLAGS+= -I${.CURDIR}/../../../sys/cddl/
 CFLAGS+= -I${.CURDIR}/../../../cddl/compat/opensolaris/include
 CFLAGS+= -I${.CURDIR}/../../../cddl/compat/opensolaris/lib/libumem
 CFLAGS+= -I${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libzpool/common
+CFLAGS+= -I${.CURDIR}/../../../sys/cddl/contrib/opensolaris/common/zfs
 CFLAGS+= -I${.CURDIR}/../../../sys/cddl/contrib/opensolaris/uts/common/fs/zfs
 CFLAGS+= -I${.CURDIR}/../../../sys/cddl/contrib/opensolaris/uts/common
 CFLAGS+= -I${.CURDIR}/../../../sys/cddl/contrib/opensolaris/uts/common/sys

Modified: head/sys/boot/zfs/zfsimpl.c
==============================================================================
--- head/sys/boot/zfs/zfsimpl.c Wed Jan  1 00:38:22 2014        (r260149)
+++ head/sys/boot/zfs/zfsimpl.c Wed Jan  1 00:45:28 2014        (r260150)
@@ -53,6 +53,9 @@ static vdev_list_t zfs_vdevs;
  * List of ZFS features supported for read
  */
 static const char *features_for_read[] = {
+       "org.illumos:lz4_compress",
+       "com.delphix:hole_birth",
+       "com.delphix:extensible_dataset",
        NULL
 };
 

Modified: head/sys/cddl/boot/zfs/zfsimpl.h
==============================================================================
--- head/sys/cddl/boot/zfs/zfsimpl.h    Wed Jan  1 00:38:22 2014        
(r260149)
+++ head/sys/cddl/boot/zfs/zfsimpl.h    Wed Jan  1 00:45:28 2014        
(r260150)
@@ -222,9 +222,10 @@ typedef struct blkptr {
  * Macros to get and set fields in a bp or DVA.
  */
 #define        DVA_GET_ASIZE(dva)      \
-       BF64_GET_SB((dva)->dva_word[0], 0, 24, SPA_MINBLOCKSHIFT, 0)
+       BF64_GET_SB((dva)->dva_word[0], 0, SPA_ASIZEBITS, SPA_MINBLOCKSHIFT, 0)
 #define        DVA_SET_ASIZE(dva, x)   \
-       BF64_SET_SB((dva)->dva_word[0], 0, 24, SPA_MINBLOCKSHIFT, 0, x)
+       BF64_SET_SB((dva)->dva_word[0], 0, SPA_ASIZEBITS, \
+       SPA_MINBLOCKSHIFT, 0, x)
 
 #define        DVA_GET_GRID(dva)       BF64_GET((dva)->dva_word[0], 24, 8)
 #define        DVA_SET_GRID(dva, x)    BF64_SET((dva)->dva_word[0], 24, 8, x)
@@ -242,14 +243,14 @@ typedef struct blkptr {
 
 #define        BP_GET_LSIZE(bp)        \
        (BP_IS_HOLE(bp) ? 0 : \
-       BF64_GET_SB((bp)->blk_prop, 0, 16, SPA_MINBLOCKSHIFT, 1))
+       BF64_GET_SB((bp)->blk_prop, 0, SPA_LSIZEBITS, SPA_MINBLOCKSHIFT, 1))
 #define        BP_SET_LSIZE(bp, x)     \
-       BF64_SET_SB((bp)->blk_prop, 0, 16, SPA_MINBLOCKSHIFT, 1, x)
+       BF64_SET_SB((bp)->blk_prop, 0, SPA_LSIZEBITS, SPA_MINBLOCKSHIFT, 1, x)
 
 #define        BP_GET_PSIZE(bp)        \
-       BF64_GET_SB((bp)->blk_prop, 16, 16, SPA_MINBLOCKSHIFT, 1)
+       BF64_GET_SB((bp)->blk_prop, 16, SPA_LSIZEBITS, SPA_MINBLOCKSHIFT, 1)
 #define        BP_SET_PSIZE(bp, x)     \
-       BF64_SET_SB((bp)->blk_prop, 16, 16, SPA_MINBLOCKSHIFT, 1, x)
+       BF64_SET_SB((bp)->blk_prop, 16, SPA_LSIZEBITS, SPA_MINBLOCKSHIFT, 1, x)
 
 #define        BP_GET_COMPRESS(bp)     BF64_GET((bp)->blk_prop, 32, 8)
 #define        BP_SET_COMPRESS(bp, x)  BF64_SET((bp)->blk_prop, 32, 8, x)
@@ -266,7 +267,7 @@ typedef struct blkptr {
 #define        BP_GET_DEDUP(bp)        BF64_GET((bp)->blk_prop, 62, 1)
 #define        BP_SET_DEDUP(bp, x)     BF64_SET((bp)->blk_prop, 62, 1, x)
 
-#define        BP_GET_BYTEORDER(bp)    (0 - BF64_GET((bp)->blk_prop, 63, 1))
+#define        BP_GET_BYTEORDER(bp)    BF64_GET((bp)->blk_prop, 63, 1)
 #define        BP_SET_BYTEORDER(bp, x) BF64_SET((bp)->blk_prop, 63, 1, x)
 
 #define        BP_PHYSICAL_BIRTH(bp)           \
@@ -285,11 +286,6 @@ typedef struct blkptr {
        !!DVA_GET_ASIZE(&(bp)->blk_dva[1]) + \
        !!DVA_GET_ASIZE(&(bp)->blk_dva[2]))
 
-#define        BP_COUNT_GANG(bp)       \
-       (DVA_GET_GANG(&(bp)->blk_dva[0]) + \
-       DVA_GET_GANG(&(bp)->blk_dva[1]) + \
-       DVA_GET_GANG(&(bp)->blk_dva[2]))
-
 #define        DVA_EQUAL(dva1, dva2)   \
        ((dva1)->dva_word[1] == (dva2)->dva_word[1] && \
        (dva1)->dva_word[0] == (dva2)->dva_word[0])
@@ -313,7 +309,9 @@ typedef struct blkptr {
 
 #define        BP_IDENTITY(bp)         (&(bp)->blk_dva[0])
 #define        BP_IS_GANG(bp)          DVA_GET_GANG(BP_IDENTITY(bp))
-#define        BP_IS_HOLE(bp)          ((bp)->blk_birth == 0)
+#define        DVA_IS_EMPTY(dva)       ((dva)->dva_word[0] == 0ULL &&  \
+       (dva)->dva_word[1] == 0ULL)
+#define        BP_IS_HOLE(bp)          DVA_IS_EMPTY(BP_IDENTITY(bp))
 #define        BP_IS_OLDER(bp, txg)    (!BP_IS_HOLE(bp) && (bp)->blk_birth < 
(txg))
 
 #define        BP_ZERO(bp)                             \

Modified: head/sys/cddl/contrib/opensolaris/common/zfs/zfeature_common.c
==============================================================================
--- head/sys/cddl/contrib/opensolaris/common/zfs/zfeature_common.c      Wed Jan 
 1 00:38:22 2014        (r260149)
+++ head/sys/cddl/contrib/opensolaris/common/zfs/zfeature_common.c      Wed Jan 
 1 00:45:28 2014        (r260150)
@@ -114,10 +114,21 @@ zfeature_lookup_name(const char *name, s
        return (ENOENT);
 }
 
+boolean_t
+zfeature_depends_on(spa_feature_t fid, spa_feature_t check) {
+       zfeature_info_t *feature = &spa_feature_table[fid];
+
+       for (int i = 0; feature->fi_depends[i] != SPA_FEATURE_NONE; i++) {
+               if (feature->fi_depends[i] == check)
+                       return (B_TRUE);
+       }
+       return (B_FALSE);
+}
+
 static void
 zfeature_register(spa_feature_t fid, const char *guid, const char *name,
     const char *desc, boolean_t readonly, boolean_t mos,
-    const spa_feature_t *deps)
+    boolean_t activate_on_enable, const spa_feature_t *deps)
 {
        zfeature_info_t *feature = &spa_feature_table[fid];
        static spa_feature_t nodeps[] = { SPA_FEATURE_NONE };
@@ -137,6 +148,7 @@ zfeature_register(spa_feature_t fid, con
        feature->fi_desc = desc;
        feature->fi_can_readonly = readonly;
        feature->fi_mos = mos;
+       feature->fi_activate_on_enable = activate_on_enable;
        feature->fi_depends = deps;
 }
 
@@ -145,21 +157,43 @@ zpool_feature_init(void)
 {
        zfeature_register(SPA_FEATURE_ASYNC_DESTROY,
            "com.delphix:async_destroy", "async_destroy",
-           "Destroy filesystems asynchronously.", B_TRUE, B_FALSE, NULL);
+           "Destroy filesystems asynchronously.", B_TRUE, B_FALSE,
+           B_FALSE, NULL);
+
        zfeature_register(SPA_FEATURE_EMPTY_BPOBJ,
            "com.delphix:empty_bpobj", "empty_bpobj",
-           "Snapshots use less space.", B_TRUE, B_FALSE, NULL);
+           "Snapshots use less space.", B_TRUE, B_FALSE,
+           B_FALSE, NULL);
+
        zfeature_register(SPA_FEATURE_LZ4_COMPRESS,
            "org.illumos:lz4_compress", "lz4_compress",
-           "LZ4 compression algorithm support.", B_FALSE, B_FALSE, NULL);
+           "LZ4 compression algorithm support.", B_FALSE, B_FALSE,
+           B_FALSE, NULL);
+
        zfeature_register(SPA_FEATURE_MULTI_VDEV_CRASH_DUMP,
            "com.joyent:multi_vdev_crash_dump", "multi_vdev_crash_dump",
-           "Crash dumps to multiple vdev pools.", B_FALSE, B_FALSE, NULL);
+           "Crash dumps to multiple vdev pools.", B_FALSE, B_FALSE,
+           B_FALSE, NULL);
+
        zfeature_register(SPA_FEATURE_SPACEMAP_HISTOGRAM,
            "com.delphix:spacemap_histogram", "spacemap_histogram",
-           "Spacemaps maintain space histograms.", B_TRUE, B_FALSE, NULL);
+           "Spacemaps maintain space histograms.", B_TRUE, B_FALSE,
+           B_FALSE, NULL);
+
+       zfeature_register(SPA_FEATURE_ENABLED_TXG,
+           "com.delphix:enabled_txg", "enabled_txg",
+           "Record txg at which a feature is enabled", B_TRUE, B_FALSE,
+           B_FALSE, NULL);
+
+       static spa_feature_t hole_birth_deps[] = { SPA_FEATURE_ENABLED_TXG,
+           SPA_FEATURE_NONE };
+       zfeature_register(SPA_FEATURE_HOLE_BIRTH,
+           "com.delphix:hole_birth", "hole_birth",
+           "Retain hole birth txg for more precise zfs send",
+           B_FALSE, B_TRUE, B_TRUE, hole_birth_deps);
+
        zfeature_register(SPA_FEATURE_EXTENSIBLE_DATASET,
            "com.delphix:extensible_dataset", "extensible_dataset",
            "Enhanced dataset functionality, used by other features.",
-           B_FALSE, B_FALSE, NULL);
+           B_FALSE, B_FALSE, B_FALSE, NULL);
 }

Modified: head/sys/cddl/contrib/opensolaris/common/zfs/zfeature_common.h
==============================================================================
--- head/sys/cddl/contrib/opensolaris/common/zfs/zfeature_common.h      Wed Jan 
 1 00:38:22 2014        (r260149)
+++ head/sys/cddl/contrib/opensolaris/common/zfs/zfeature_common.h      Wed Jan 
 1 00:45:28 2014        (r260150)
@@ -44,10 +44,14 @@ typedef enum spa_feature {
        SPA_FEATURE_LZ4_COMPRESS,
        SPA_FEATURE_MULTI_VDEV_CRASH_DUMP,
        SPA_FEATURE_SPACEMAP_HISTOGRAM,
+       SPA_FEATURE_ENABLED_TXG,
+       SPA_FEATURE_HOLE_BIRTH,
        SPA_FEATURE_EXTENSIBLE_DATASET,
        SPA_FEATURES
 } spa_feature_t;
 
+#define        SPA_FEATURE_DISABLED    (-1ULL)
+
 typedef struct zfeature_info {
        spa_feature_t fi_feature;
        const char *fi_uname;   /* User-facing feature name */
@@ -55,6 +59,8 @@ typedef struct zfeature_info {
        const char *fi_desc;    /* Feature description */
        boolean_t fi_can_readonly; /* Can open pool readonly w/o support? */
        boolean_t fi_mos;       /* Is the feature necessary to read the MOS? */
+       /* Activate this feature at the same time it is enabled */
+       boolean_t fi_activate_on_enable;
        /* array of dependencies, terminated by SPA_FEATURE_NONE */
        const spa_feature_t *fi_depends;
 } zfeature_info_t;
@@ -69,6 +75,7 @@ extern boolean_t zfeature_is_valid_guid(
 
 extern boolean_t zfeature_is_supported(const char *);
 extern int zfeature_lookup_name(const char *name, spa_feature_t *res);
+extern boolean_t zfeature_depends_on(spa_feature_t fid, spa_feature_t check);
 
 extern void zpool_feature_init(void);
 

Modified: head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/arc.c
==============================================================================
--- head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/arc.c   Wed Jan  1 
00:38:22 2014        (r260149)
+++ head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/arc.c   Wed Jan  1 
00:45:28 2014        (r260150)
@@ -845,7 +845,7 @@ buf_hash(uint64_t spa, const dva_t *dva,
 #define        BUF_EMPTY(buf)                                          \
        ((buf)->b_dva.dva_word[0] == 0 &&                       \
        (buf)->b_dva.dva_word[1] == 0 &&                        \
-       (buf)->b_birth == 0)
+       (buf)->b_cksum0 == 0)
 
 #define        BUF_EQUAL(spa, dva, birth, buf)                         \
        ((buf)->b_dva.dva_word[0] == (dva)->dva_word[0]) &&     \
@@ -3767,9 +3767,13 @@ arc_write_done(zio_t *zio)
        ASSERT(hdr->b_acb == NULL);
 
        if (zio->io_error == 0) {
-               hdr->b_dva = *BP_IDENTITY(zio->io_bp);
-               hdr->b_birth = BP_PHYSICAL_BIRTH(zio->io_bp);
-               hdr->b_cksum0 = zio->io_bp->blk_cksum.zc_word[0];
+               if (BP_IS_HOLE(zio->io_bp)) {
+                       buf_discard_identity(hdr);
+               } else {
+                       hdr->b_dva = *BP_IDENTITY(zio->io_bp);
+                       hdr->b_birth = BP_PHYSICAL_BIRTH(zio->io_bp);
+                       hdr->b_cksum0 = zio->io_bp->blk_cksum.zc_word[0];
+               }
        } else {
                ASSERT(BUF_EMPTY(hdr));
        }

Modified: head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/bptree.c
==============================================================================
--- head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/bptree.c        Wed Jan 
 1 00:38:22 2014        (r260149)
+++ head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/bptree.c        Wed Jan 
 1 00:45:28 2014        (r260150)
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright (c) 2012 by Delphix. All rights reserved.
+ * Copyright (c) 2013 by Delphix. All rights reserved.
  */
 
 #include <sys/arc.h>
@@ -141,7 +141,7 @@ bptree_visit_cb(spa_t *spa, zilog_t *zil
        int err;
        struct bptree_args *ba = arg;
 
-       if (bp == NULL)
+       if (BP_IS_HOLE(bp))
                return (0);
 
        err = ba->ba_func(ba->ba_arg, bp, ba->ba_tx);

Modified: head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dbuf.c
==============================================================================
--- head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dbuf.c  Wed Jan  1 
00:38:22 2014        (r260149)
+++ head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dbuf.c  Wed Jan  1 
00:45:28 2014        (r260150)
@@ -455,10 +455,9 @@ dbuf_loan_arcbuf(dmu_buf_impl_t *db)
        mutex_enter(&db->db_mtx);
        if (arc_released(db->db_buf) || refcount_count(&db->db_holds) > 1) {
                int blksz = db->db.db_size;
-               spa_t *spa;
+               spa_t *spa = db->db_objset->os_spa;
 
                mutex_exit(&db->db_mtx);
-               DB_GET_SPA(&spa, db);
                abuf = arc_loan_buf(spa, blksz);
                bcopy(db->db.db_data, abuf->b_data, blksz);
        } else {
@@ -519,7 +518,6 @@ static void
 dbuf_read_impl(dmu_buf_impl_t *db, zio_t *zio, uint32_t *flags)
 {
        dnode_t *dn;
-       spa_t *spa;
        zbookmark_t zb;
        uint32_t aflags = ARC_NOWAIT;
 
@@ -559,9 +557,9 @@ dbuf_read_impl(dmu_buf_impl_t *db, zio_t
            BP_IS_HOLE(db->db_blkptr)))) {
                arc_buf_contents_t type = DBUF_GET_BUFC_TYPE(db);
 
-               dbuf_set_data(db, arc_buf_alloc(dn->dn_objset->os_spa,
-                   db->db.db_size, db, type));
                DB_DNODE_EXIT(db);
+               dbuf_set_data(db, arc_buf_alloc(db->db_objset->os_spa,
+                   db->db.db_size, db, type));
                bzero(db->db.db_data, db->db.db_size);
                db->db_state = DB_CACHED;
                *flags |= DB_RF_CACHED;
@@ -569,7 +567,6 @@ dbuf_read_impl(dmu_buf_impl_t *db, zio_t
                return;
        }
 
-       spa = dn->dn_objset->os_spa;
        DB_DNODE_EXIT(db);
 
        db->db_state = DB_READ;
@@ -586,7 +583,7 @@ dbuf_read_impl(dmu_buf_impl_t *db, zio_t
 
        dbuf_add_ref(db, NULL);
 
-       (void) arc_read(zio, spa, db->db_blkptr,
+       (void) arc_read(zio, db->db_objset->os_spa, db->db_blkptr,
            dbuf_read_done, db, ZIO_PRIORITY_SYNC_READ,
            (*flags & DB_RF_CANFAIL) ? ZIO_FLAG_CANFAIL : ZIO_FLAG_MUSTSUCCEED,
            &aflags, &zb);
@@ -598,8 +595,8 @@ int
 dbuf_read(dmu_buf_impl_t *db, zio_t *zio, uint32_t flags)
 {
        int err = 0;
-       int havepzio = (zio != NULL);
-       int prefetch;
+       boolean_t havepzio = (zio != NULL);
+       boolean_t prefetch;
        dnode_t *dn;
 
        /*
@@ -694,11 +691,10 @@ dbuf_noread(dmu_buf_impl_t *db)
                cv_wait(&db->db_changed, &db->db_mtx);
        if (db->db_state == DB_UNCACHED) {
                arc_buf_contents_t type = DBUF_GET_BUFC_TYPE(db);
-               spa_t *spa;
+               spa_t *spa = db->db_objset->os_spa;
 
                ASSERT(db->db_buf == NULL);
                ASSERT(db->db.db_data == NULL);
-               DB_GET_SPA(&spa, db);
                dbuf_set_data(db, arc_buf_alloc(spa, db->db.db_size, db, type));
                db->db_state = DB_FILL;
        } else if (db->db_state == DB_NOFILL) {
@@ -753,9 +749,8 @@ dbuf_fix_old_data(dmu_buf_impl_t *db, ui
        } else if (refcount_count(&db->db_holds) > db->db_dirtycnt) {
                int size = db->db.db_size;
                arc_buf_contents_t type = DBUF_GET_BUFC_TYPE(db);
-               spa_t *spa;
+               spa_t *spa = db->db_objset->os_spa;
 
-               DB_GET_SPA(&spa, db);
                dr->dt.dl.dr_data = arc_buf_alloc(spa, size, db, type);
                bcopy(db->db.db_data, dr->dt.dl.dr_data->b_data, size);
        } else {
@@ -781,12 +776,9 @@ dbuf_unoverride(dbuf_dirty_record_t *dr)
        ASSERT(db->db_data_pending != dr);
 
        /* free this block */
-       if (!BP_IS_HOLE(bp) && !dr->dt.dl.dr_nopwrite) {
-               spa_t *spa;
+       if (!BP_IS_HOLE(bp) && !dr->dt.dl.dr_nopwrite)
+               zio_free(db->db_objset->os_spa, txg, bp);
 
-               DB_GET_SPA(&spa, db);
-               zio_free(spa, txg, bp);
-       }
        dr->dt.dl.dr_override_state = DR_NOT_OVERRIDDEN;
        dr->dt.dl.dr_nopwrite = B_FALSE;
 
@@ -804,9 +796,7 @@ dbuf_unoverride(dbuf_dirty_record_t *dr)
 /*
  * Evict (if its unreferenced) or clear (if its referenced) any level-0
  * data blocks in the free range, so that any future readers will find
- * empty blocks.  Also, if we happen across any level-1 dbufs in the
- * range that have not already been marked dirty, mark them dirty so
- * they stay in memory.
+ * empty blocks.
  *
  * This is a no-op if the dataset is in the middle of an incremental
  * receive; see comment below for details.
@@ -816,14 +806,9 @@ dbuf_free_range(dnode_t *dn, uint64_t st
 {
        dmu_buf_impl_t *db, *db_next;
        uint64_t txg = tx->tx_txg;
-       int epbs = dn->dn_indblkshift - SPA_BLKPTRSHIFT;
-       uint64_t first_l1 = start >> epbs;
-       uint64_t last_l1 = end >> epbs;
 
-       if (end > dn->dn_maxblkid && (end != DMU_SPILL_BLKID)) {
+       if (end > dn->dn_maxblkid && (end != DMU_SPILL_BLKID))
                end = dn->dn_maxblkid;
-               last_l1 = end >> epbs;
-       }
        dprintf_dnode(dn, "start=%llu end=%llu\n", start, end);
 
        mutex_enter(&dn->dn_dbufs_mtx);
@@ -846,23 +831,8 @@ dbuf_free_range(dnode_t *dn, uint64_t st
                db_next = list_next(&dn->dn_dbufs, db);
                ASSERT(db->db_blkid != DMU_BONUS_BLKID);
 
-               if (db->db_level == 1 &&
-                   db->db_blkid >= first_l1 && db->db_blkid <= last_l1) {
-                       mutex_enter(&db->db_mtx);
-                       if (db->db_last_dirty &&
-                           db->db_last_dirty->dr_txg < txg) {
-                               dbuf_add_ref(db, FTAG);
-                               mutex_exit(&db->db_mtx);
-                               dbuf_will_dirty(db, tx);
-                               dbuf_rele(db, FTAG);
-                       } else {
-                               mutex_exit(&db->db_mtx);
-                       }
-               }
-
                if (db->db_level != 0)
                        continue;
-               dprintf_dbuf(db, "found buf %s\n", "");
                if (db->db_blkid < start || db->db_blkid > end)
                        continue;
 
@@ -939,24 +909,29 @@ dbuf_block_freeable(dmu_buf_impl_t *db)
         * We don't need any locking to protect db_blkptr:
         * If it's syncing, then db_last_dirty will be set
         * so we'll ignore db_blkptr.
+        *
+        * This logic ensures that only block births for
+        * filled blocks are considered.
         */
        ASSERT(MUTEX_HELD(&db->db_mtx));
-       if (db->db_last_dirty)
+       if (db->db_last_dirty && (db->db_blkptr == NULL ||
+           !BP_IS_HOLE(db->db_blkptr))) {
                birth_txg = db->db_last_dirty->dr_txg;
-       else if (db->db_blkptr)
+       } else if (db->db_blkptr != NULL && !BP_IS_HOLE(db->db_blkptr)) {
                birth_txg = db->db_blkptr->blk_birth;
+       }
 
        /*
-        * If we don't exist or are in a snapshot, we can't be freed.
+        * If this block don't exist or is in a snapshot, it can't be freed.
         * Don't pass the bp to dsl_dataset_block_freeable() since we
         * are holding the db_mtx lock and might deadlock if we are
         * prefetching a dedup-ed block.
         */
-       if (birth_txg)
+       if (birth_txg != 0)
                return (ds == NULL ||
                    dsl_dataset_block_freeable(ds, NULL, birth_txg));
        else
-               return (FALSE);
+               return (B_FALSE);
 }
 
 void
@@ -976,7 +951,7 @@ dbuf_new_size(dmu_buf_impl_t *db, int si
        ASSERT(RW_WRITE_HELD(&dn->dn_struct_rwlock));
 
        /*
-        * This call to dbuf_will_dirty() with the dn_struct_rwlock held
+        * This call to dmu_buf_will_dirty() with the dn_struct_rwlock held
         * is OK, because there can be no other references to the db
         * when we are changing its size, so no concurrent DB_FILL can
         * be happening.
@@ -985,7 +960,7 @@ dbuf_new_size(dmu_buf_impl_t *db, int si
         * XXX we should be doing a dbuf_read, checking the return
         * value and returning that up to our callers
         */
-       dbuf_will_dirty(db, tx);
+       dmu_buf_will_dirty(&db->db, tx);
 
        /* create the data buffer for the new block */
        buf = arc_buf_alloc(dn->dn_objset->os_spa, size, db, type);
@@ -1015,9 +990,8 @@ dbuf_new_size(dmu_buf_impl_t *db, int si
 void
 dbuf_release_bp(dmu_buf_impl_t *db)
 {
-       objset_t *os;
+       objset_t *os = db->db_objset;
 
-       DB_GET_OBJSET(&os, db);
        ASSERT(dsl_pool_sync_context(dmu_objset_pool(os)));
        ASSERT(arc_released(os->os_phys_buf) ||
            list_link_active(&os->os_dsl_dataset->ds_synced_link));
@@ -1391,10 +1365,10 @@ dbuf_undirty(dmu_buf_impl_t *db, dmu_tx_
        return (B_FALSE);
 }
 
-#pragma weak dmu_buf_will_dirty = dbuf_will_dirty
 void
-dbuf_will_dirty(dmu_buf_impl_t *db, dmu_tx_t *tx)
+dmu_buf_will_dirty(dmu_buf_t *db_fake, dmu_tx_t *tx)
 {
+       dmu_buf_impl_t *db = (dmu_buf_impl_t *)db_fake;
        int rf = DB_RF_MUST_SUCCEED | DB_RF_NOPREFETCH;
 
        ASSERT(tx->tx_txg != 0);
@@ -1517,7 +1491,7 @@ dbuf_assign_arcbuf(dmu_buf_impl_t *db, a
        db->db_state = DB_FILL;
        mutex_exit(&db->db_mtx);
        (void) dbuf_dirty(db, tx);
-       dbuf_fill_done(db, tx);
+       dmu_buf_fill_done(&db->db, tx);
 }
 
 /*
@@ -2022,7 +1996,6 @@ dbuf_add_ref(dmu_buf_impl_t *db, void *t
  * Without that, the dbuf_rele() could lead to a dnode_rele() followed by the
  * dnode's parent dbuf evicting its dnode handles.
  */
-#pragma weak dmu_buf_rele = dbuf_rele
 void
 dbuf_rele(dmu_buf_impl_t *db, void *tag)
 {
@@ -2030,6 +2003,12 @@ dbuf_rele(dmu_buf_impl_t *db, void *tag)
        dbuf_rele_and_unlock(db, tag);
 }
 
+void
+dmu_buf_rele(dmu_buf_t *db, void *tag)
+{
+       dbuf_rele((dmu_buf_impl_t *)db, tag);
+}
+
 /*
  * dbuf_rele() for an already-locked dbuf.  This is necessary to allow
  * db_dirtycnt and db_holds to be updated atomically.
@@ -2480,18 +2459,14 @@ dbuf_write_ready(zio_t *zio, arc_buf_t *
        dnode_diduse_space(dn, delta - zio->io_prev_space_delta);
        zio->io_prev_space_delta = delta;
 
-       if (BP_IS_HOLE(bp)) {
-               ASSERT(bp->blk_fill == 0);
-               DB_DNODE_EXIT(db);
-               return;
+       if (bp->blk_birth != 0) {
+               ASSERT((db->db_blkid != DMU_SPILL_BLKID &&
+                   BP_GET_TYPE(bp) == dn->dn_type) ||
+                   (db->db_blkid == DMU_SPILL_BLKID &&
+                   BP_GET_TYPE(bp) == dn->dn_bonustype));
+               ASSERT(BP_GET_LEVEL(bp) == db->db_level);
        }
 
-       ASSERT((db->db_blkid != DMU_SPILL_BLKID &&
-           BP_GET_TYPE(bp) == dn->dn_type) ||
-           (db->db_blkid == DMU_SPILL_BLKID &&
-           BP_GET_TYPE(bp) == dn->dn_bonustype));
-       ASSERT(BP_GET_LEVEL(bp) == db->db_level);
-
        mutex_enter(&db->db_mtx);
 
 #ifdef ZFS_DEBUG
@@ -2517,7 +2492,11 @@ dbuf_write_ready(zio_t *zio, arc_buf_t *
                                        fill++;
                        }
                } else {
-                       fill = 1;
+                       if (BP_IS_HOLE(bp)) {
+                               fill = 0;
+                       } else {
+                               fill = 1;
+                       }
                }
        } else {
                blkptr_t *ibp = db->db.db_data;
@@ -2572,9 +2551,10 @@ static void
 dbuf_write_done(zio_t *zio, arc_buf_t *buf, void *vdb)
 {
        dmu_buf_impl_t *db = vdb;
-       blkptr_t *bp = zio->io_bp;
        blkptr_t *bp_orig = &zio->io_bp_orig;
-       uint64_t txg = zio->io_txg;
+       blkptr_t *bp = db->db_blkptr;
+       objset_t *os = db->db_objset;
+       dmu_tx_t *tx = os->os_synctx;
        dbuf_dirty_record_t **drp, *dr;
 
        ASSERT0(zio->io_error);
@@ -2587,14 +2567,7 @@ dbuf_write_done(zio_t *zio, arc_buf_t *b
        if (zio->io_flags & (ZIO_FLAG_IO_REWRITE | ZIO_FLAG_NOPWRITE)) {
                ASSERT(BP_EQUAL(bp, bp_orig));
        } else {
-               objset_t *os;
-               dsl_dataset_t *ds;
-               dmu_tx_t *tx;
-
-               DB_GET_OBJSET(&os, db);
-               ds = os->os_dsl_dataset;
-               tx = os->os_synctx;
-
+               dsl_dataset_t *ds = os->os_dsl_dataset;
                (void) dsl_dataset_block_kill(ds, bp_orig, tx, B_TRUE);
                dsl_dataset_block_born(ds, bp, tx);
        }
@@ -2607,7 +2580,6 @@ dbuf_write_done(zio_t *zio, arc_buf_t *b

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to