Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 11 Jun 2012 11:35:22 +0000 (UTC)
From:      Martin Matuska <mm@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r236884 - in head: . cddl/contrib/opensolaris/cmd/zdb cddl/contrib/opensolaris/cmd/zhack cddl/contrib/opensolaris/cmd/zpool cddl/contrib/opensolaris/cmd/ztest cddl/contrib/opensolaris/l...
Message-ID:  <201206111135.q5BBZMva081982@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: mm
Date: Mon Jun 11 11:35:22 2012
New Revision: 236884
URL: http://svn.freebsd.org/changeset/base/236884

Log:
  Introduce "feature flags" for ZFS pools (bump SPA version to 5000).
  Add first feature "com.delphix:async_destroy" (asynchronous destroy
  of ZFS datasets).
  Implement features support in ZFS boot code.
  
  Illumos revisions merged:
  13700:2889e2596bd6
  13701:1949b688d5fb
  2619 asynchronous destruction of ZFS file systems
  2747 SPA versioning with zfs feature flags
  
  References:
  https://www.illumos.org/issues/2619
  https://www.illumos.org/issues/2747
  
  Obtained from:	illumos (issue #2619, #2747)
  MFC after:	1 month

Added:
  head/cddl/contrib/opensolaris/cmd/zhack/
  head/cddl/contrib/opensolaris/cmd/zhack/zhack.c   (contents, props changed)
  head/cddl/contrib/opensolaris/cmd/zpool/zpool-features.5   (contents, props changed)
  head/cddl/usr.sbin/zhack/
  head/cddl/usr.sbin/zhack/Makefile   (contents, props changed)
  head/sys/cddl/contrib/opensolaris/common/nvpair/fnvpair.c   (contents, props changed)
  head/sys/cddl/contrib/opensolaris/common/zfs/zfeature_common.c   (contents, props changed)
  head/sys/cddl/contrib/opensolaris/common/zfs/zfeature_common.h   (contents, props changed)
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/bptree.c   (contents, props changed)
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/bptree.h   (contents, props changed)
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zfeature.h   (contents, props changed)
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfeature.c   (contents, props changed)
Modified:
  head/UPDATING
  head/cddl/contrib/opensolaris/cmd/zdb/zdb.c
  head/cddl/contrib/opensolaris/cmd/zpool/zpool.8
  head/cddl/contrib/opensolaris/cmd/zpool/zpool_main.c
  head/cddl/contrib/opensolaris/cmd/ztest/ztest.c
  head/cddl/contrib/opensolaris/lib/libnvpair/libnvpair.c
  head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h
  head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_config.c
  head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_pool.c
  head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_status.c
  head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_util.c
  head/cddl/contrib/opensolaris/lib/libzpool/common/kernel.c
  head/cddl/lib/libnvpair/Makefile
  head/cddl/lib/libzfs/Makefile
  head/cddl/sbin/zpool/Makefile
  head/cddl/usr.bin/ztest/Makefile
  head/cddl/usr.sbin/Makefile
  head/sys/boot/zfs/zfsimpl.c
  head/sys/cddl/boot/zfs/zfsimpl.h
  head/sys/cddl/contrib/opensolaris/common/zfs/zpool_prop.c
  head/sys/cddl/contrib/opensolaris/uts/common/Makefile.files
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/arc.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_send.c
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_traverse.c
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_tx.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_deleg.c
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_pool.c
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_scan.c
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sa.c
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa.c
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa_config.c
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa_misc.c
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dmu.h
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dmu_traverse.h
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dsl_dataset.h
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dsl_pool.h
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dsl_scan.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/vdev_impl.h
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zap.h
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zio.h
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev.c
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_label.c
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zap.c
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zap_micro.c
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zio.c
  head/sys/cddl/contrib/opensolaris/uts/common/sys/fs/zfs.h
  head/sys/cddl/contrib/opensolaris/uts/common/sys/nvpair.h
  head/sys/modules/zfs/Makefile

Modified: head/UPDATING
==============================================================================
--- head/UPDATING	Mon Jun 11 08:52:21 2012	(r236883)
+++ head/UPDATING	Mon Jun 11 11:35:22 2012	(r236884)
@@ -24,6 +24,17 @@ NOTE TO PEOPLE WHO THINK THAT FreeBSD 10
 	disable the most expensive debugging functionality run
 	"ln -s 'abort:false,junk:false' /etc/malloc.conf".)
 
+20120611:
+	A new version of ZFS (pool version 5000) has been merged to -HEAD.
+	Starting with this version the old system of ZFS pool versioning
+	is superseded by "feature flags". This concept enables forward
+	compatibility against certain future changes in functionality of ZFS
+	pools. The first read-only compatible "feature flag" for ZFS pools
+	is named "com.delphix:async_destroy". For more information
+	read the new zpool-features(5) manual page.
+	Please refer to the "ZFS notes" section of this file for information
+	on upgrading boot ZFS pools.
+
 20120417:
 	The malloc(3) implementation embedded in libc now uses sources imported
 	as contrib/jemalloc.  The most disruptive API change is to

Modified: head/cddl/contrib/opensolaris/cmd/zdb/zdb.c
==============================================================================
--- head/cddl/contrib/opensolaris/cmd/zdb/zdb.c	Mon Jun 11 08:52:21 2012	(r236883)
+++ head/cddl/contrib/opensolaris/cmd/zdb/zdb.c	Mon Jun 11 11:35:22 2012	(r236884)
@@ -18,8 +18,10 @@
  *
  * CDDL HEADER END
  */
+
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012 by Delphix. All rights reserved.
  */
 
 #include <stdio.h>
@@ -54,6 +56,7 @@
 #include <sys/zfs_fuid.h>
 #include <sys/arc.h>
 #include <sys/ddt.h>
+#include <sys/zfeature.h>
 #undef ZFS_MAXNAMELEN
 #undef verify
 #include <libzfs.h>
@@ -63,7 +66,8 @@
 #define	ZDB_CHECKSUM_NAME(idx) ((idx) < ZIO_CHECKSUM_FUNCTIONS ? \
     zio_checksum_table[(idx)].ci_name : "UNKNOWN")
 #define	ZDB_OT_NAME(idx) ((idx) < DMU_OT_NUMTYPES ? \
-    dmu_ot[(idx)].ot_name : "UNKNOWN")
+    dmu_ot[(idx)].ot_name : DMU_OT_IS_VALID(idx) ? \
+    dmu_ot_byteswap[DMU_OT_BYTESWAP(idx)].ob_name : "UNKNOWN")
 #define	ZDB_OT_TYPE(idx) ((idx) < DMU_OT_NUMTYPES ? (idx) : DMU_OT_NUMTYPES)
 
 #ifndef lint
@@ -1088,7 +1092,7 @@ dump_dsl_dataset(objset_t *os, uint64_t 
 
 	ASSERT(size == sizeof (*ds));
 	crtime = ds->ds_creation_time;
-	zdb_nicenum(ds->ds_used_bytes, used);
+	zdb_nicenum(ds->ds_referenced_bytes, used);
 	zdb_nicenum(ds->ds_compressed_bytes, compressed);
 	zdb_nicenum(ds->ds_uncompressed_bytes, uncompressed);
 	zdb_nicenum(ds->ds_unique_bytes, unique);
@@ -1132,6 +1136,44 @@ dump_dsl_dataset(objset_t *os, uint64_t 
 
 /* ARGSUSED */
 static int
+dump_bptree_cb(void *arg, const blkptr_t *bp, dmu_tx_t *tx)
+{
+	char blkbuf[BP_SPRINTF_LEN];
+
+	if (bp->blk_birth != 0) {
+		sprintf_blkptr(blkbuf, bp);
+		(void) printf("\t%s\n", blkbuf);
+	}
+	return (0);
+}
+
+static void
+dump_bptree(objset_t *os, uint64_t obj, char *name)
+{
+	char bytes[32];
+	bptree_phys_t *bt;
+	dmu_buf_t *db;
+
+	if (dump_opt['d'] < 3)
+		return;
+
+	VERIFY3U(0, ==, dmu_bonus_hold(os, obj, FTAG, &db));
+	bt = db->db_data;
+	zdb_nicenum(bt->bt_bytes, bytes);
+	(void) printf("\n    %s: %llu datasets, %s\n",
+	    name, (unsigned long long)(bt->bt_end - bt->bt_begin), bytes);
+	dmu_buf_rele(db, FTAG);
+
+	if (dump_opt['d'] < 5)
+		return;
+
+	(void) printf("\n");
+
+	(void) bptree_iterate(os, obj, B_FALSE, dump_bptree_cb, NULL, NULL);
+}
+
+/* ARGSUSED */
+static int
 dump_bpobj_cb(void *arg, const blkptr_t *bp, dmu_tx_t *tx)
 {
 	char blkbuf[BP_SPRINTF_LEN];
@@ -1883,11 +1925,13 @@ typedef struct zdb_blkstats {
  */
 #define	ZDB_OT_DEFERRED	(DMU_OT_NUMTYPES + 0)
 #define	ZDB_OT_DITTO	(DMU_OT_NUMTYPES + 1)
-#define	ZDB_OT_TOTAL	(DMU_OT_NUMTYPES + 2)
+#define	ZDB_OT_OTHER	(DMU_OT_NUMTYPES + 2)
+#define	ZDB_OT_TOTAL	(DMU_OT_NUMTYPES + 3)
 
 static char *zdb_ot_extname[] = {
 	"deferred free",
 	"dedup ditto",
+	"other",
 	"Total",
 };
 
@@ -1968,9 +2012,10 @@ zdb_blkptr_cb(spa_t *spa, zilog_t *zilog
 
 	type = BP_GET_TYPE(bp);
 
-	zdb_count_block(zcb, zilog, bp, type);
+	zdb_count_block(zcb, zilog, bp,
+	    (type & DMU_OT_NEWTYPE) ? ZDB_OT_OTHER : type);
 
-	is_metadata = (BP_GET_LEVEL(bp) != 0 || dmu_ot[type].ot_metadata);
+	is_metadata = (BP_GET_LEVEL(bp) != 0 || DMU_OT_IS_METADATA(type));
 
 	if (dump_opt['c'] > 1 || (dump_opt['c'] && is_metadata)) {
 		int ioerr;
@@ -2197,6 +2242,12 @@ dump_block_stats(spa_t *spa)
 		(void) bpobj_iterate_nofree(&spa->spa_dsl_pool->dp_free_bpobj,
 		    count_block_cb, &zcb, NULL);
 	}
+	if (spa_feature_is_active(spa,
+	    &spa_feature_table[SPA_FEATURE_ASYNC_DESTROY])) {
+		VERIFY3U(0, ==, bptree_iterate(spa->spa_meta_objset,
+		    spa->spa_dsl_pool->dp_bptree_obj, B_FALSE, count_block_cb,
+		    &zcb, NULL));
+	}
 
 	if (dump_opt['c'] > 1)
 		flags |= TRAVERSE_PREFETCH_DATA;
@@ -2373,7 +2424,7 @@ zdb_ddt_add_cb(spa_t *spa, zilog_t *zilo
 	}
 
 	if (BP_IS_HOLE(bp) || BP_GET_CHECKSUM(bp) == ZIO_CHECKSUM_OFF ||
-	    BP_GET_LEVEL(bp) > 0 || dmu_ot[BP_GET_TYPE(bp)].ot_metadata)
+	    BP_GET_LEVEL(bp) > 0 || DMU_OT_IS_METADATA(BP_GET_TYPE(bp)))
 		return (0);
 
 	ddt_key_fill(&zdde_search.zdde_key, bp);
@@ -2478,7 +2529,14 @@ dump_zpool(spa_t *spa)
 			dump_bpobj(&spa->spa_deferred_bpobj, "Deferred frees");
 			if (spa_version(spa) >= SPA_VERSION_DEADLISTS) {
 				dump_bpobj(&spa->spa_dsl_pool->dp_free_bpobj,
-				    "Pool frees");
+				    "Pool snapshot frees");
+			}
+
+			if (spa_feature_is_active(spa,
+			    &spa_feature_table[SPA_FEATURE_ASYNC_DESTROY])) {
+				dump_bptree(spa->spa_meta_objset,
+				    spa->spa_dsl_pool->dp_bptree_obj,
+				    "Pool dataset frees");
 			}
 			dump_dtl(spa->spa_root_vdev, 0);
 		}

Added: head/cddl/contrib/opensolaris/cmd/zhack/zhack.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/cddl/contrib/opensolaris/cmd/zhack/zhack.c	Mon Jun 11 11:35:22 2012	(r236884)
@@ -0,0 +1,533 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ */
+
+/*
+ * zhack is a debugging tool that can write changes to ZFS pool using libzpool
+ * for testing purposes. Altering pools with zhack is unsupported and may
+ * result in corrupted pools.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <sys/zfs_context.h>
+#include <sys/spa.h>
+#include <sys/spa_impl.h>
+#include <sys/dmu.h>
+#include <sys/zap.h>
+#include <sys/zfs_znode.h>
+#include <sys/dsl_synctask.h>
+#include <sys/vdev.h>
+#include <sys/fs/zfs.h>
+#include <sys/dmu_objset.h>
+#include <sys/dsl_pool.h>
+#include <sys/zio_checksum.h>
+#include <sys/zio_compress.h>
+#include <sys/zfeature.h>
+#undef ZFS_MAXNAMELEN
+#undef verify
+#include <libzfs.h>
+
+extern boolean_t zfeature_checks_disable;
+
+const char cmdname[] = "zhack";
+libzfs_handle_t *g_zfs;
+static importargs_t g_importargs;
+static char *g_pool;
+static boolean_t g_readonly;
+
+static void
+usage(void)
+{
+	(void) fprintf(stderr,
+	    "Usage: %s [-c cachefile] [-d dir] <subcommand> <args> ...\n"
+	    "where <subcommand> <args> is one of the following:\n"
+	    "\n", cmdname);
+
+	(void) fprintf(stderr,
+	    "    feature stat <pool>\n"
+	    "        print information about enabled features\n"
+	    "    feature enable [-d desc] <pool> <feature>\n"
+	    "        add a new enabled feature to the pool\n"
+	    "        -d <desc> sets the feature's description\n"
+	    "    feature ref [-md] <pool> <feature>\n"
+	    "        change the refcount on the given feature\n"
+	    "        -d decrease instead of increase the refcount\n"
+	    "        -m add the feature to the label if increasing refcount\n"
+	    "\n"
+	    "    <feature> : should be a feature guid\n");
+	exit(1);
+}
+
+
+static void
+fatal(const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	(void) fprintf(stderr, "%s: ", cmdname);
+	(void) vfprintf(stderr, fmt, ap);
+	va_end(ap);
+	(void) fprintf(stderr, "\n");
+
+	exit(1);
+}
+
+/* ARGSUSED */
+static int
+space_delta_cb(dmu_object_type_t bonustype, void *data,
+    uint64_t *userp, uint64_t *groupp)
+{
+	/*
+	 * Is it a valid type of object to track?
+	 */
+	if (bonustype != DMU_OT_ZNODE && bonustype != DMU_OT_SA)
+		return (ENOENT);
+	(void) fprintf(stderr, "modifying object that needs user accounting");
+	abort();
+	/* NOTREACHED */
+}
+
+/*
+ * Target is the dataset whose pool we want to open.
+ */
+static void
+import_pool(const char *target, boolean_t readonly)
+{
+	nvlist_t *config;
+	nvlist_t *pools;
+	int error;
+	char *sepp;
+	spa_t *spa;
+	nvpair_t *elem;
+	nvlist_t *props;
+	const char *name;
+
+	kernel_init(readonly ? FREAD : (FREAD | FWRITE));
+	g_zfs = libzfs_init();
+	ASSERT(g_zfs != NULL);
+
+	dmu_objset_register_type(DMU_OST_ZFS, space_delta_cb);
+
+	g_readonly = readonly;
+
+	/*
+	 * If we only want readonly access, it's OK if we find
+	 * a potentially-active (ie, imported into the kernel) pool from the
+	 * default cachefile.
+	 */
+	if (readonly && spa_open(target, &spa, FTAG) == 0) {
+		spa_close(spa, FTAG);
+		return;
+	}
+
+	g_importargs.unique = B_TRUE;
+	g_importargs.can_be_active = readonly;
+	g_pool = strdup(target);
+	if ((sepp = strpbrk(g_pool, "/@")) != NULL)
+		*sepp = '\0';
+	g_importargs.poolname = g_pool;
+	pools = zpool_search_import(g_zfs, &g_importargs);
+
+	if (pools == NULL || nvlist_next_nvpair(pools, NULL) == NULL) {
+		if (!g_importargs.can_be_active) {
+			g_importargs.can_be_active = B_TRUE;
+			if (zpool_search_import(g_zfs, &g_importargs) != NULL ||
+			    spa_open(target, &spa, FTAG) == 0) {
+				fatal("cannot import '%s': pool is active; run "
+				    "\"zpool export %s\" first\n",
+				    g_pool, g_pool);
+			}
+		}
+
+		fatal("cannot import '%s': no such pool available\n", g_pool);
+	}
+
+	elem = nvlist_next_nvpair(pools, NULL);
+	name = nvpair_name(elem);
+	verify(nvpair_value_nvlist(elem, &config) == 0);
+
+	props = NULL;
+	if (readonly) {
+		verify(nvlist_alloc(&props, NV_UNIQUE_NAME, 0) == 0);
+		verify(nvlist_add_uint64(props,
+		    zpool_prop_to_name(ZPOOL_PROP_READONLY), 1) == 0);
+	}
+
+	zfeature_checks_disable = B_TRUE;
+	error = spa_import(name, config, props, ZFS_IMPORT_NORMAL);
+	zfeature_checks_disable = B_FALSE;
+	if (error == EEXIST)
+		error = 0;
+
+	if (error)
+		fatal("can't import '%s': %s", name, strerror(error));
+}
+
+static void
+zhack_spa_open(const char *target, boolean_t readonly, void *tag, spa_t **spa)
+{
+	int err;
+
+	import_pool(target, readonly);
+
+	zfeature_checks_disable = B_TRUE;
+	err = spa_open(target, spa, tag);
+	zfeature_checks_disable = B_FALSE;
+
+	if (err != 0)
+		fatal("cannot open '%s': %s", target, strerror(err));
+	if (spa_version(*spa) < SPA_VERSION_FEATURES) {
+		fatal("'%s' has version %d, features not enabled", target,
+		    (int)spa_version(*spa));
+	}
+}
+
+static void
+dump_obj(objset_t *os, uint64_t obj, const char *name)
+{
+	zap_cursor_t zc;
+	zap_attribute_t za;
+
+	(void) printf("%s_obj:\n", name);
+
+	for (zap_cursor_init(&zc, os, obj);
+	    zap_cursor_retrieve(&zc, &za) == 0;
+	    zap_cursor_advance(&zc)) {
+		if (za.za_integer_length == 8) {
+			ASSERT(za.za_num_integers == 1);
+			(void) printf("\t%s = %llu\n",
+			    za.za_name, (u_longlong_t)za.za_first_integer);
+		} else {
+			ASSERT(za.za_integer_length == 1);
+			char val[1024];
+			VERIFY(zap_lookup(os, obj, za.za_name,
+			    1, sizeof (val), val) == 0);
+			(void) printf("\t%s = %s\n", za.za_name, val);
+		}
+	}
+	zap_cursor_fini(&zc);
+}
+
+static void
+dump_mos(spa_t *spa)
+{
+	nvlist_t *nv = spa->spa_label_features;
+
+	(void) printf("label config:\n");
+	for (nvpair_t *pair = nvlist_next_nvpair(nv, NULL);
+	    pair != NULL;
+	    pair = nvlist_next_nvpair(nv, pair)) {
+		(void) printf("\t%s\n", nvpair_name(pair));
+	}
+}
+
+static void
+zhack_do_feature_stat(int argc, char **argv)
+{
+	spa_t *spa;
+	objset_t *os;
+	char *target;
+
+	argc--;
+	argv++;
+
+	if (argc < 1) {
+		(void) fprintf(stderr, "error: missing pool name\n");
+		usage();
+	}
+	target = argv[0];
+
+	zhack_spa_open(target, B_TRUE, FTAG, &spa);
+	os = spa->spa_meta_objset;
+
+	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");
+	dump_mos(spa);
+
+	spa_close(spa, FTAG);
+}
+
+static void
+feature_enable_sync(void *arg1, void *arg2, dmu_tx_t *tx)
+{
+	spa_t *spa = arg1;
+	zfeature_info_t *feature = arg2;
+
+	spa_feature_enable(spa, feature, tx);
+}
+
+static void
+zhack_do_feature_enable(int argc, char **argv)
+{
+	char c;
+	char *desc, *target;
+	spa_t *spa;
+	objset_t *mos;
+	zfeature_info_t feature;
+	zfeature_info_t *nodeps[] = { NULL };
+
+	/*
+	 * Features are not added to the pool's label until their refcounts
+	 * are incremented, so fi_mos can just be left as false for now.
+	 */
+	desc = NULL;
+	feature.fi_uname = "zhack";
+	feature.fi_mos = B_FALSE;
+	feature.fi_can_readonly = B_FALSE;
+	feature.fi_depends = nodeps;
+
+	optind = 1;
+	while ((c = getopt(argc, argv, "rmd:")) != -1) {
+		switch (c) {
+		case 'r':
+			feature.fi_can_readonly = B_TRUE;
+			break;
+		case 'd':
+			desc = strdup(optarg);
+			break;
+		default:
+			usage();
+			break;
+		}
+	}
+
+	if (desc == NULL)
+		desc = strdup("zhack injected");
+	feature.fi_desc = desc;
+
+	argc -= optind;
+	argv += optind;
+
+	if (argc < 2) {
+		(void) fprintf(stderr, "error: missing feature or pool name\n");
+		usage();
+	}
+	target = argv[0];
+	feature.fi_guid = argv[1];
+
+	if (!zfeature_is_valid_guid(feature.fi_guid))
+		fatal("invalid feature guid: %s", feature.fi_guid);
+
+	zhack_spa_open(target, B_FALSE, FTAG, &spa);
+	mos = spa->spa_meta_objset;
+
+	if (0 == zfeature_lookup_guid(feature.fi_guid, NULL))
+		fatal("'%s' is a real feature, will not enable");
+	if (0 == zap_contains(mos, spa->spa_feat_desc_obj, feature.fi_guid))
+		fatal("feature already enabled: %s", feature.fi_guid);
+
+	VERIFY3U(0, ==, dsl_sync_task_do(spa->spa_dsl_pool, NULL,
+	    feature_enable_sync, spa, &feature, 5));
+
+	spa_close(spa, FTAG);
+
+	free(desc);
+}
+
+static void
+feature_incr_sync(void *arg1, void *arg2, dmu_tx_t *tx)
+{
+	spa_t *spa = arg1;
+	zfeature_info_t *feature = arg2;
+
+	spa_feature_incr(spa, feature, tx);
+}
+
+static void
+feature_decr_sync(void *arg1, void *arg2, dmu_tx_t *tx)
+{
+	spa_t *spa = arg1;
+	zfeature_info_t *feature = arg2;
+
+	spa_feature_decr(spa, feature, tx);
+}
+
+static void
+zhack_do_feature_ref(int argc, char **argv)
+{
+	char c;
+	char *target;
+	boolean_t decr = B_FALSE;
+	spa_t *spa;
+	objset_t *mos;
+	zfeature_info_t feature;
+	zfeature_info_t *nodeps[] = { NULL };
+
+	/*
+	 * fi_desc does not matter here because it was written to disk
+	 * when the feature was enabled, but we need to properly set the
+	 * feature for read or write based on the information we read off
+	 * disk later.
+	 */
+	feature.fi_uname = "zhack";
+	feature.fi_mos = B_FALSE;
+	feature.fi_desc = NULL;
+	feature.fi_depends = nodeps;
+
+	optind = 1;
+	while ((c = getopt(argc, argv, "md")) != -1) {
+		switch (c) {
+		case 'm':
+			feature.fi_mos = B_TRUE;
+			break;
+		case 'd':
+			decr = B_TRUE;
+			break;
+		default:
+			usage();
+			break;
+		}
+	}
+	argc -= optind;
+	argv += optind;
+
+	if (argc < 2) {
+		(void) fprintf(stderr, "error: missing feature or pool name\n");
+		usage();
+	}
+	target = argv[0];
+	feature.fi_guid = argv[1];
+
+	if (!zfeature_is_valid_guid(feature.fi_guid))
+		fatal("invalid feature guid: %s", feature.fi_guid);
+
+	zhack_spa_open(target, B_FALSE, FTAG, &spa);
+	mos = spa->spa_meta_objset;
+
+	if (0 == zfeature_lookup_guid(feature.fi_guid, NULL))
+		fatal("'%s' is a real feature, will not change refcount");
+
+	if (0 == zap_contains(mos, spa->spa_feat_for_read_obj,
+	    feature.fi_guid)) {
+		feature.fi_can_readonly = B_FALSE;
+	} else if (0 == zap_contains(mos, spa->spa_feat_for_write_obj,
+	    feature.fi_guid)) {
+		feature.fi_can_readonly = B_TRUE;
+	} else {
+		fatal("feature is not enabled: %s", feature.fi_guid);
+	}
+
+	if (decr && !spa_feature_is_active(spa, &feature))
+		fatal("feature refcount already 0: %s", feature.fi_guid);
+
+	VERIFY3U(0, ==, dsl_sync_task_do(spa->spa_dsl_pool, NULL,
+	    decr ? feature_decr_sync : feature_incr_sync, spa, &feature, 5));
+
+	spa_close(spa, FTAG);
+}
+
+static int
+zhack_do_feature(int argc, char **argv)
+{
+	char *subcommand;
+
+	argc--;
+	argv++;
+	if (argc == 0) {
+		(void) fprintf(stderr,
+		    "error: no feature operation specified\n");
+		usage();
+	}
+
+	subcommand = argv[0];
+	if (strcmp(subcommand, "stat") == 0) {
+		zhack_do_feature_stat(argc, argv);
+	} else if (strcmp(subcommand, "enable") == 0) {
+		zhack_do_feature_enable(argc, argv);
+	} else if (strcmp(subcommand, "ref") == 0) {
+		zhack_do_feature_ref(argc, argv);
+	} else {
+		(void) fprintf(stderr, "error: unknown subcommand: %s\n",
+		    subcommand);
+		usage();
+	}
+
+	return (0);
+}
+
+#define	MAX_NUM_PATHS 1024
+
+int
+main(int argc, char **argv)
+{
+	extern void zfs_prop_init(void);
+
+	char *path[MAX_NUM_PATHS];
+	const char *subcommand;
+	int rv = 0;
+	char c;
+
+	g_importargs.path = path;
+
+	dprintf_setup(&argc, argv);
+	zfs_prop_init();
+
+	while ((c = getopt(argc, argv, "c:d:")) != -1) {
+		switch (c) {
+		case 'c':
+			g_importargs.cachefile = optarg;
+			break;
+		case 'd':
+			assert(g_importargs.paths < MAX_NUM_PATHS);
+			g_importargs.path[g_importargs.paths++] = optarg;
+			break;
+		default:
+			usage();
+			break;
+		}
+	}
+
+	argc -= optind;
+	argv += optind;
+	optind = 1;
+
+	if (argc == 0) {
+		(void) fprintf(stderr, "error: no command specified\n");
+		usage();
+	}
+
+	subcommand = argv[0];
+
+	if (strcmp(subcommand, "feature") == 0) {
+		rv = zhack_do_feature(argc, argv);
+	} else {
+		(void) fprintf(stderr, "error: unknown subcommand: %s\n",
+		    subcommand);
+		usage();
+	}
+
+	if (!g_readonly && spa_export(g_pool, NULL, B_TRUE, B_TRUE) != 0) {
+		fatal("pool export failed; "
+		    "changes may not be committed to disk\n");
+	}
+
+	libzfs_fini(g_zfs);
+	kernel_fini();
+
+	return (rv);
+}

Added: head/cddl/contrib/opensolaris/cmd/zpool/zpool-features.5
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/cddl/contrib/opensolaris/cmd/zpool/zpool-features.5	Mon Jun 11 11:35:22 2012	(r236884)
@@ -0,0 +1,174 @@
+'\" te
+.\" Copyright (c) 2012, Martin Matuska <mm@FreeBSD.org>.
+.\" All Rights Reserved.
+.\"
+.\" The contents of this file are subject to the terms of the
+.\" Common Development and Distribution License (the "License").
+.\" You may not use this file except in compliance with the License.
+.\"
+.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+.\" or http://www.opensolaris.org/os/licensing.
+.\" See the License for the specific language governing permissions
+.\" and limitations under the License.
+.\"
+.\" When distributing Covered Code, include this CDDL HEADER in each
+.\" file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+.\" If applicable, add the following below this CDDL HEADER, with the
+.\" fields enclosed by brackets "[]" replaced with your own identifying
+.\" information: Portions Copyright [yyyy] [name of copyright owner]
+.\"
+.\" Copyright (c) 2012 by Delphix. All rights reserved.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd May 28, 2012
+.Dt ZPOOL-FEATURES 8
+.Os
+.Sh NAME
+.Nm zpool-features
+.Nd ZFS pool feature descriptions
+.Sh DESCRIPTION
+ZFS pool on\-disk format versions are specified via "features" which replace
+the old on\-disk format numbers (the last supported on\-disk format number is
+28).
+To enable a feature on a pool use the
+.Xr zpool 8
+command to set the
+.Sy feature@feature_name
+property to
+.Ar enabled .
+.Pp
+The pool format does not affect file system version compatibility or the ability
+to send file systems between pools.
+.Pp
+Since most features can be enabled independently of each other the on\-disk
+format of the pool is specified by the set of all features marked as
+.Sy active
+on the pool. If the pool was created by another software version this set may
+include unsupported features.
+.Ss Identifying features
+Every feature has a guid of the form
+.Sy com.example:feature_name .
+The reverse DNS name ensures that the feature's guid is unique across all ZFS
+implementations. When unsupported features are encountered on a pool they will
+be identified by their guids.
+Refer to the documentation for the ZFS implementation that created the pool
+for information about those features.
+.Pp
+Each supported feature also has a short name.
+By convention a feature's short name is the portion of its guid which follows
+the ':' (e.g.
+.Sy com.example:feature_name
+would have the short name
+.Sy feature_name ),
+however a feature's short name may differ across ZFS implementations if
+following the convention would result in name conflicts.
+.Ss Feature states
+Features can be in one of three states:
+.Bl -tag
+.It Sy active
+This feature's on\-disk format changes are in effect on the pool.
+Support for this feature is required to import the pool in read\-write mode.
+If this feature is not read-only compatible, support is also required to
+import the pool in read\-only mode (see "Read\-only compatibility").
+.It Sy enabled
+An administrator has marked this feature as enabled on the pool, but the
+feature's on\-disk format changes have not been made yet.
+The pool can still be imported by software that does not support this feature,
+but changes may be made to the on\-disk format at any time which will move
+the feature to the
+.Sy active
+state.
+Some features may support returning to the
+.Sy enabled
+state after becoming
+.Sy active .
+See feature\-specific documentation for details.
+.It Sy disabled
+This feature's on\-disk format changes have not been made and will not be made
+unless an administrator moves the feature to the
+.Sy enabled
+state.
+Features cannot be disabled once they have been enabled.
+.El
+The state of supported features is exposed through pool properties of the form
+.Sy feature@short_name .
+.Ss Read\-only compatibility
+Some features may make on\-disk format changes that do not interfere with other
+software's ability to read from the pool.
+These features are referred to as "read\-only compatible".
+If all unsupported features on a pool are read\-only compatible, the pool can
+be imported in read\-only mode by setting the
+.Sy readonly
+property during import (see
+.Xr zpool 8
+for details on importing pools).
+.Ss Unsupported features
+For each unsupported feature enabled on an imported pool a pool property
+named
+.Sy unsupported@feature_guid
+will indicate why the import was allowed despite the unsupported feature.
+Possible values for this property are:
+.Bl -tag
+.It Sy inactive
+The feature is in the
+.Sy enabled
+state and therefore the pool's on\-disk format is still compatible with
+software that does not support this feature.
+.It Sy readonly
+The feature is read\-only compatible and the pool has been imported in
+read\-only mode.
+.El
+.Ss Feature dependencies
+Some features depend on other features being enabled in order to function
+properly.
+Enabling a feature will automatically enable any features it depends on.
+.Sh FEATURES
+The following features are supported on this system:
+.Bl -tag
+.It Sy async_destroy
+.Bl -column "READ\-ONLY COMPATIBLE" "com.delphix:async_destroy"
+.It GUID Ta com.delphix:async_destroy
+.It READ\-ONLY COMPATIBLE Ta yes
+.It DEPENDENCIES Ta none
+.El
+.Pp
+Destroying a file system requires traversing all of its data in order to
+return its used space to the pool.
+Without
+.Sy async_destroy
+the file system is not fully removed until all space has been reclaimed.
+If the destroy operation is interrupted by a reboot or power outage the next
+attempt to open the pool will need to complete the destroy operation
+synchronously.
+.Pp
+When
+.Sy async_destroy
+is enabled the file system's data will be reclaimed by a background process,
+allowing the destroy operation to complete without traversing the entire file
+system.
+The background process is able to resume interrupted destroys after the pool
+has been opened, eliminating the need to finish interrupted destroys as part
+of the open operation.
+The amount of space remaining to be reclaimed by the background process is
+available through the
+.Sy freeing
+property.
+.Sh SEE ALSO
+.Xr zpool 8
+.Sh AUTHORS
+This manual page is a
+.Xr mdoc 7
+reimplementation of the
+.Tn illumos
+manual page
+.Em zpool-features(5) ,
+modified and customized for
+.Fx
+and licensed under the Common Development and Distribution License
+.Pq Tn CDDL .
+.Pp
+The
+.Xr mdoc 7
+implementation of this manual page was initially written by
+.An Martin Matuska Aq mm@FreeBSD.org .

Modified: head/cddl/contrib/opensolaris/cmd/zpool/zpool.8
==============================================================================
--- head/cddl/contrib/opensolaris/cmd/zpool/zpool.8	Mon Jun 11 08:52:21 2012	(r236883)
+++ head/cddl/contrib/opensolaris/cmd/zpool/zpool.8	Mon Jun 11 11:35:22 2012	(r236884)
@@ -1,5 +1,5 @@
 '\" te
-.\" Copyright (c) 2011, Martin Matuska <mm@FreeBSD.org>.
+.\" Copyright (c) 2012, Martin Matuska <mm@FreeBSD.org>.
 .\" All Rights Reserved.
 .\"
 .\" The contents of this file are subject to the terms of the
@@ -20,6 +20,7 @@
 .\" Copyright (c) 2010, Sun Microsystems, Inc. All Rights Reserved.
 .\" Copyright 2011, Nexenta Systems, Inc. All Rights Reserved.
 .\" Copyright (c) 2011, Justin T. Gibbs <gibbs@FreeBSD.org>
+.\" Copyright (c) 2012 by Delphix. All Rights Reserved.
 .\"
 .\" $FreeBSD$
 .\"
@@ -47,7 +48,7 @@
 .Op Ar device
 .Nm
 .Cm create
-.Op Fl fn
+.Op Fl fnd
 .Op Fl o Ar property Ns = Ns Ar value
 .Ar ...
 .Op Fl O Ar file-system-property Ns = Ns Ar value
@@ -537,6 +538,16 @@ value of 1.76 indicates that 1.76 units 
 for a description of the deduplication feature.
 .It Sy free
 Number of blocks within the pool that are not allocated.
+.It Sy freeing
+After a file system or snapshot is destroyed, the space it was using is
+returned to the pool asynchronously.
+.Sy freeing
+is the amount of space remaining to be reclaimed.
+Over time
+.Sy freeing
+will decrease while
+.Sy free
+increases.
 .It Sy expandsize
 This property has currently no value on FreeBSD.
 .It Sy guid
@@ -552,11 +563,16 @@ or
 .Qq Sy UNAVAIL .
 .It Sy size
 Total size of the storage pool.
+.It Sy unsupported@ Ns Ar feature_guid
+Information about unsupported features that are enabled on the pool.
+See
+.Xr zpool-features 5
+for details.
 .It Sy used
 Amount of storage space used within the pool.
 .El
 .Pp
-These space usage properties report actual physical space available to the
+The space usage properties report actual physical space available to the
 storage pool. The physical space can be different from the total amount of
 space that any contained datasets can actually use. The amount of space used in
 a
@@ -653,6 +669,11 @@ Setting it to the special value
 creates a temporary pool that is never cached, and the special value
 .Cm ''
 (empty string) uses the default location.
+.It Sy comment Ns = Ns Ar text
+A text string consisting of printable ASCII characters that will be stored
+such that it is available even if the pool becomes faulted.
+An administrator can provide additional information about a pool using this
+property.
 .It Sy dedupditto Ns = Ns Ar number
 Threshold for the number of block ditto copies. If the reference count for a
 deduplicated block increases above this number, a new ditto copy of this block
@@ -686,6 +707,17 @@ requests that have yet to be committed t
 .It Sy panic
 Prints out a message to the console and generates a system crash dump.
 .El
+.It Sy feature@ Ns Ar feature_name Ns = Ns Sy enabled
+The value of this property is the current state of
+.Ar feature_name .
+The only valid value when setting this property is
+.Sy enabled
+which moves
+.Ar feature_name
+to the enabled state.
+See
+.Xr zpool-features 5
+for details on feature states.
 .It Sy listsnaps Ns = Ns Cm on No | Cm off
 Controls whether information about snapshots associated with this pool is
 output when
@@ -699,9 +731,9 @@ The current on-disk version of the pool.
 decreased. The preferred method of updating pools is with the
 .Qq Nm Cm upgrade
 command, though this property can be used when a specific version is needed
-for backwards compatibility. This property can be any number between 1 and the
-current version reported by
-.Qo Ic zpool upgrade -v Qc .
+for backwards compatibility. 
+Once feature flags is enabled on a pool this property will no longer have a
+value.
 .El
 .Sh SUBCOMMANDS
 All subcommands that modify state are logged persistently to the pool in their
@@ -810,7 +842,7 @@ do not actually discard any transactions
 .It Xo
 .Nm
 .Cm create
-.Op Fl fn
+.Op Fl fnd
 .Op Fl o Ar property Ns = Ns Ar value
 .Ar ...
 .Op Fl O Ar file-system-property Ns = Ns Ar value
@@ -859,6 +891,10 @@ The mount point must not exist or must b
 root dataset cannot be mounted. This can be overridden with the
 .Fl m

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201206111135.q5BBZMva081982>