aboutsummaryrefslogtreecommitdiff
path: root/cddl/contrib/opensolaris/cmd
diff options
context:
space:
mode:
Diffstat (limited to 'cddl/contrib/opensolaris/cmd')
-rw-r--r--cddl/contrib/opensolaris/cmd/zdb/zdb.c137
-rw-r--r--cddl/contrib/opensolaris/cmd/zfs/zfs.819
-rw-r--r--cddl/contrib/opensolaris/cmd/zpool/zpool-features.719
-rw-r--r--cddl/contrib/opensolaris/cmd/zpool/zpool.8191
-rw-r--r--cddl/contrib/opensolaris/cmd/zpool/zpool_main.c556
-rw-r--r--cddl/contrib/opensolaris/cmd/zpool/zpool_vdev.c173
-rw-r--r--cddl/contrib/opensolaris/cmd/ztest/ztest.c191
7 files changed, 1039 insertions, 247 deletions
diff --git a/cddl/contrib/opensolaris/cmd/zdb/zdb.c b/cddl/contrib/opensolaris/cmd/zdb/zdb.c
index a775595bda60..e3ee43a8661c 100644
--- a/cddl/contrib/opensolaris/cmd/zdb/zdb.c
+++ b/cddl/contrib/opensolaris/cmd/zdb/zdb.c
@@ -21,7 +21,7 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2011, 2017 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2018 by Delphix. All rights reserved.
* Copyright (c) 2014 Integros [integros.com]
* Copyright 2017 Nexenta Systems, Inc.
* Copyright (c) 2017, 2018 Lawrence Livermore National Security, LLC.
@@ -931,13 +931,23 @@ dump_metaslab(metaslab_t *msp)
static void
print_vdev_metaslab_header(vdev_t *vd)
{
- (void) printf("\tvdev %10llu\n\t%-10s%5llu %-19s %-15s %-10s\n",
- (u_longlong_t)vd->vdev_id,
+ vdev_alloc_bias_t alloc_bias = vd->vdev_alloc_bias;
+ const char *bias_str;
+
+ bias_str = (alloc_bias == VDEV_BIAS_LOG || vd->vdev_islog) ?
+ VDEV_ALLOC_BIAS_LOG :
+ (alloc_bias == VDEV_BIAS_SPECIAL) ? VDEV_ALLOC_BIAS_SPECIAL :
+ (alloc_bias == VDEV_BIAS_DEDUP) ? VDEV_ALLOC_BIAS_DEDUP :
+ vd->vdev_islog ? "log" : "";
+
+ (void) printf("\tvdev %10llu %s\n"
+ "\t%-10s%5llu %-19s %-15s %-12s\n",
+ (u_longlong_t)vd->vdev_id, bias_str,
"metaslabs", (u_longlong_t)vd->vdev_ms_count,
"offset", "spacemap", "free");
- (void) printf("\t%15s %19s %15s %10s\n",
+ (void) printf("\t%15s %19s %15s %12s\n",
"---------------", "-------------------",
- "---------------", "-------------");
+ "---------------", "------------");
}
static void
@@ -953,7 +963,7 @@ dump_metaslab_groups(spa_t *spa)
vdev_t *tvd = rvd->vdev_child[c];
metaslab_group_t *mg = tvd->vdev_mg;
- if (mg->mg_class != mc)
+ if (mg == NULL || mg->mg_class != mc)
continue;
metaslab_group_histogram_verify(mg);
@@ -2807,6 +2817,7 @@ typedef struct zdb_blkstats {
uint64_t zb_count;
uint64_t zb_gangs;
uint64_t zb_ditto_samevdev;
+ uint64_t zb_ditto_same_ms;
uint64_t zb_psize_histogram[PSIZE_HISTO_SIZE];
} zdb_blkstats_t;
@@ -2846,6 +2857,16 @@ typedef struct zdb_cb {
uint32_t **zcb_vd_obsolete_counts;
} zdb_cb_t;
+/* test if two DVA offsets from same vdev are within the same metaslab */
+static boolean_t
+same_metaslab(spa_t *spa, uint64_t vdev, uint64_t off1, uint64_t off2)
+{
+ vdev_t *vd = vdev_lookup_top(spa, vdev);
+ uint64_t ms_shift = vd->vdev_ms_shift;
+
+ return ((off1 >> ms_shift) == (off2 >> ms_shift));
+}
+
static void
zdb_count_block(zdb_cb_t *zcb, zilog_t *zilog, const blkptr_t *bp,
dmu_object_type_t type)
@@ -2857,6 +2878,8 @@ zdb_count_block(zdb_cb_t *zcb, zilog_t *zilog, const blkptr_t *bp,
if (zilog && zil_bp_tree_add(zilog, bp) != 0)
return;
+ spa_config_enter(zcb->zcb_spa, SCL_CONFIG, FTAG, RW_READER);
+
for (int i = 0; i < 4; i++) {
int l = (i < 2) ? BP_GET_LEVEL(bp) : ZB_TOTAL;
int t = (i & 1) ? type : ZDB_OT_TOTAL;
@@ -2882,8 +2905,15 @@ zdb_count_block(zdb_cb_t *zcb, zilog_t *zilog, const blkptr_t *bp,
switch (BP_GET_NDVAS(bp)) {
case 2:
if (DVA_GET_VDEV(&bp->blk_dva[0]) ==
- DVA_GET_VDEV(&bp->blk_dva[1]))
+ DVA_GET_VDEV(&bp->blk_dva[1])) {
zb->zb_ditto_samevdev++;
+
+ if (same_metaslab(zcb->zcb_spa,
+ DVA_GET_VDEV(&bp->blk_dva[0]),
+ DVA_GET_OFFSET(&bp->blk_dva[0]),
+ DVA_GET_OFFSET(&bp->blk_dva[1])))
+ zb->zb_ditto_same_ms++;
+ }
break;
case 3:
equal = (DVA_GET_VDEV(&bp->blk_dva[0]) ==
@@ -2892,13 +2922,37 @@ zdb_count_block(zdb_cb_t *zcb, zilog_t *zilog, const blkptr_t *bp,
DVA_GET_VDEV(&bp->blk_dva[2])) +
(DVA_GET_VDEV(&bp->blk_dva[1]) ==
DVA_GET_VDEV(&bp->blk_dva[2]));
- if (equal != 0)
+ if (equal != 0) {
zb->zb_ditto_samevdev++;
+
+ if (DVA_GET_VDEV(&bp->blk_dva[0]) ==
+ DVA_GET_VDEV(&bp->blk_dva[1]) &&
+ same_metaslab(zcb->zcb_spa,
+ DVA_GET_VDEV(&bp->blk_dva[0]),
+ DVA_GET_OFFSET(&bp->blk_dva[0]),
+ DVA_GET_OFFSET(&bp->blk_dva[1])))
+ zb->zb_ditto_same_ms++;
+ else if (DVA_GET_VDEV(&bp->blk_dva[0]) ==
+ DVA_GET_VDEV(&bp->blk_dva[2]) &&
+ same_metaslab(zcb->zcb_spa,
+ DVA_GET_VDEV(&bp->blk_dva[0]),
+ DVA_GET_OFFSET(&bp->blk_dva[0]),
+ DVA_GET_OFFSET(&bp->blk_dva[2])))
+ zb->zb_ditto_same_ms++;
+ else if (DVA_GET_VDEV(&bp->blk_dva[1]) ==
+ DVA_GET_VDEV(&bp->blk_dva[2]) &&
+ same_metaslab(zcb->zcb_spa,
+ DVA_GET_VDEV(&bp->blk_dva[1]),
+ DVA_GET_OFFSET(&bp->blk_dva[1]),
+ DVA_GET_OFFSET(&bp->blk_dva[2])))
+ zb->zb_ditto_same_ms++;
+ }
break;
}
-
}
+ spa_config_exit(zcb->zcb_spa, SCL_CONFIG, FTAG);
+
if (BP_IS_EMBEDDED(bp)) {
zcb->zcb_embedded_blocks[BPE_GET_ETYPE(bp)]++;
zcb->zcb_embedded_histogram[BPE_GET_ETYPE(bp)]
@@ -3709,6 +3763,7 @@ dump_block_stats(spa_t *spa)
uint64_t norm_alloc, norm_space, total_alloc, total_found;
int flags = TRAVERSE_PRE | TRAVERSE_PREFETCH_METADATA | TRAVERSE_HARD;
boolean_t leaks = B_FALSE;
+ int err;
bzero(&zcb, sizeof (zcb));
(void) printf("\nTraversing all blocks %s%s%s%s%s...\n\n",
@@ -3751,8 +3806,10 @@ dump_block_stats(spa_t *spa)
flags |= TRAVERSE_PREFETCH_DATA;
zcb.zcb_totalasize = metaslab_class_get_alloc(spa_normal_class(spa));
+ zcb.zcb_totalasize += metaslab_class_get_alloc(spa_special_class(spa));
+ zcb.zcb_totalasize += metaslab_class_get_alloc(spa_dedup_class(spa));
zcb.zcb_start = zcb.zcb_lastprint = gethrtime();
- zcb.zcb_haderrors |= traverse_pool(spa, 0, flags, zdb_blkptr_cb, &zcb);
+ err = traverse_pool(spa, 0, flags, zdb_blkptr_cb, &zcb);
/*
* If we've traversed the data blocks then we need to wait for those
@@ -3768,6 +3825,12 @@ dump_block_stats(spa_t *spa)
}
}
+ /*
+ * Done after zio_wait() since zcb_haderrors is modified in
+ * zdb_blkptr_done()
+ */
+ zcb.zcb_haderrors |= err;
+
if (zcb.zcb_haderrors) {
(void) printf("\nError counts:\n\n");
(void) printf("\t%5s %s\n", "errno", "count");
@@ -3789,7 +3852,10 @@ dump_block_stats(spa_t *spa)
norm_alloc = metaslab_class_get_alloc(spa_normal_class(spa));
norm_space = metaslab_class_get_space(spa_normal_class(spa));
- total_alloc = norm_alloc + metaslab_class_get_alloc(spa_log_class(spa));
+ total_alloc = norm_alloc +
+ metaslab_class_get_alloc(spa_log_class(spa)) +
+ metaslab_class_get_alloc(spa_special_class(spa)) +
+ metaslab_class_get_alloc(spa_dedup_class(spa));
total_found = tzb->zb_asize - zcb.zcb_dedup_asize +
zcb.zcb_removing_size + zcb.zcb_checkpoint_size;
@@ -3811,31 +3877,50 @@ dump_block_stats(spa_t *spa)
return (2);
(void) printf("\n");
- (void) printf("\tbp count: %10llu\n",
+ (void) printf("\t%-16s %14llu\n", "bp count:",
(u_longlong_t)tzb->zb_count);
- (void) printf("\tganged count: %10llu\n",
+ (void) printf("\t%-16s %14llu\n", "ganged count:",
(longlong_t)tzb->zb_gangs);
- (void) printf("\tbp logical: %10llu avg: %6llu\n",
+ (void) printf("\t%-16s %14llu avg: %6llu\n", "bp logical:",
(u_longlong_t)tzb->zb_lsize,
(u_longlong_t)(tzb->zb_lsize / tzb->zb_count));
- (void) printf("\tbp physical: %10llu avg:"
- " %6llu compression: %6.2f\n",
- (u_longlong_t)tzb->zb_psize,
+ (void) printf("\t%-16s %14llu avg: %6llu compression: %6.2f\n",
+ "bp physical:", (u_longlong_t)tzb->zb_psize,
(u_longlong_t)(tzb->zb_psize / tzb->zb_count),
(double)tzb->zb_lsize / tzb->zb_psize);
- (void) printf("\tbp allocated: %10llu avg:"
- " %6llu compression: %6.2f\n",
- (u_longlong_t)tzb->zb_asize,
+ (void) printf("\t%-16s %14llu avg: %6llu compression: %6.2f\n",
+ "bp allocated:", (u_longlong_t)tzb->zb_asize,
(u_longlong_t)(tzb->zb_asize / tzb->zb_count),
(double)tzb->zb_lsize / tzb->zb_asize);
- (void) printf("\tbp deduped: %10llu ref>1:"
- " %6llu deduplication: %6.2f\n",
- (u_longlong_t)zcb.zcb_dedup_asize,
+ (void) printf("\t%-16s %14llu ref>1: %6llu deduplication: %6.2f\n",
+ "bp deduped:", (u_longlong_t)zcb.zcb_dedup_asize,
(u_longlong_t)zcb.zcb_dedup_blocks,
(double)zcb.zcb_dedup_asize / tzb->zb_asize + 1.0);
- (void) printf("\tSPA allocated: %10llu used: %5.2f%%\n",
+ (void) printf("\t%-16s %14llu used: %5.2f%%\n", "Normal class:",
(u_longlong_t)norm_alloc, 100.0 * norm_alloc / norm_space);
+ if (spa_special_class(spa)->mc_rotor != NULL) {
+ uint64_t alloc = metaslab_class_get_alloc(
+ spa_special_class(spa));
+ uint64_t space = metaslab_class_get_space(
+ spa_special_class(spa));
+
+ (void) printf("\t%-16s %14llu used: %5.2f%%\n",
+ "Special class", (u_longlong_t)alloc,
+ 100.0 * alloc / space);
+ }
+
+ if (spa_dedup_class(spa)->mc_rotor != NULL) {
+ uint64_t alloc = metaslab_class_get_alloc(
+ spa_dedup_class(spa));
+ uint64_t space = metaslab_class_get_space(
+ spa_dedup_class(spa));
+
+ (void) printf("\t%-16s %14llu used: %5.2f%%\n",
+ "Dedup class", (u_longlong_t)alloc,
+ 100.0 * alloc / space);
+ }
+
for (bp_embedded_type_t i = 0; i < NUM_BP_EMBEDDED_TYPES; i++) {
if (zcb.zcb_embedded_blocks[i] == 0)
continue;
@@ -3857,6 +3942,10 @@ dump_block_stats(spa_t *spa)
(void) printf("\tDittoed blocks on same vdev: %llu\n",
(longlong_t)tzb->zb_ditto_samevdev);
}
+ if (tzb->zb_ditto_same_ms != 0) {
+ (void) printf("\tDittoed blocks in same metaslab: %llu\n",
+ (longlong_t)tzb->zb_ditto_same_ms);
+ }
for (uint64_t v = 0; v < spa->spa_root_vdev->vdev_children; v++) {
vdev_t *vd = spa->spa_root_vdev->vdev_child[v];
diff --git a/cddl/contrib/opensolaris/cmd/zfs/zfs.8 b/cddl/contrib/opensolaris/cmd/zfs/zfs.8
index ef256a1c47e4..e060db67867c 100644
--- a/cddl/contrib/opensolaris/cmd/zfs/zfs.8
+++ b/cddl/contrib/opensolaris/cmd/zfs/zfs.8
@@ -1134,8 +1134,23 @@ This feature must be enabled to be used
.Po see
.Xr zpool-features 7
.Pc .
+.It Sy special_small_blocks Ns = Ns Ar size
+This value represents the threshold block size for including small file
+blocks into the special allocation class.
+Blocks smaller than or equal to this value will be assigned to the special
+allocation class while greater blocks will be assigned to the regular class.
+Valid values are zero or a power of two from 512B up to 128K.
+The default size is 0 which means no small file blocks will be allocated in
+the special class.
+.Pp
+Before setting this property, a special class vdev must be added to the
+pool.
+See
+.Xr zpool 8
+for more details on the special allocation class.
.It Sy mountpoint Ns = Ns Ar path | Cm none | legacy
-Controls the mount point used for this file system. See the
+Controls the mount point used for this file system.
+See the
.Qq Sx Mount Points
section for more information on how this property is used.
.Pp
@@ -3023,7 +3038,7 @@ property of the filesystem or volume which is received into.
To use this flag, the storage pool must have the
.Sy extensible_dataset
feature enabled. See
-.Xr zpool-features 5
+.Xr zpool-features 7
for details on ZFS feature flags.
.El
.It Xo
diff --git a/cddl/contrib/opensolaris/cmd/zpool/zpool-features.7 b/cddl/contrib/opensolaris/cmd/zpool/zpool-features.7
index 168d30f8a210..b40bf9b5b1c7 100644
--- a/cddl/contrib/opensolaris/cmd/zpool/zpool-features.7
+++ b/cddl/contrib/opensolaris/cmd/zpool/zpool-features.7
@@ -632,6 +632,25 @@ and will return to being
once all filesystems that have ever had their checksum set to
.Sy skein
are destroyed.
+.It Sy allocation_classes
+.Bl -column "READ\-ONLY COMPATIBLE" "com.intel:allocation_classes"
+.It GUID Ta com.intel:allocation_classes
+.It READ\-ONLY COMPATIBLE Ta yes
+.It DEPENDENCIES Ta none
+.El
+.Pp
+This feature enables support for separate allocation classes.
+.Pp
+This feature becomes
+.Sy active
+when a dedicated allocation class vdev
+(dedup or special) is created with
+.Dq zpool create
+or
+.Dq zpool add .
+With device removal, it can be returned to the
+.Sy enabled
+state if all the top-level vdevs from an allocation class are removed.
.El
.Sh SEE ALSO
.Xr zpool 8
diff --git a/cddl/contrib/opensolaris/cmd/zpool/zpool.8 b/cddl/contrib/opensolaris/cmd/zpool/zpool.8
index 6aa4e5a5f4b9..11d275d386f9 100644
--- a/cddl/contrib/opensolaris/cmd/zpool/zpool.8
+++ b/cddl/contrib/opensolaris/cmd/zpool/zpool.8
@@ -24,6 +24,8 @@
.\" Copyright (c) 2012, 2017 by Delphix. All Rights Reserved.
.\" Copyright 2017 Nexenta Systems, Inc.
.\" Copyright (c) 2017 Datto Inc.
+.\" Copyright (c) 2017 George Melikov. All Rights Reserved.
+.\" Copyright 2019 Joyent, Inc.
.\"
.\" $FreeBSD$
.\"
@@ -38,7 +40,7 @@
.Op Fl \&?
.Nm
.Cm add
-.Op Fl fn
+.Op Fl fgLnP
.Ar pool vdev ...
.Nm
.Cm attach
@@ -127,17 +129,19 @@
.Op Ar device Ns ...
.Nm
.Cm iostat
-.Op Fl T Cm d Ns | Ns Cm u
.Op Fl v
+.Op Fl T Cm d Ns | Ns Cm u
+.Op Fl gLP
.Op Ar pool
.Ar ...
+.Op Ar inverval Op Ar count
.Nm
.Cm labelclear
.Op Fl f
.Ar device
.Nm
.Cm list
-.Op Fl Hpv
+.Op Fl HgLpPv
.Op Fl o Ar property Ns Op , Ns Ar ...
.Op Fl T Cm d Ns | Ns Cm u
.Op Ar pool
@@ -179,7 +183,7 @@
.Ar property Ns = Ns Ar value pool
.Nm
.Cm split
-.Op Fl n
+.Op Fl gLnP
.Op Fl R Ar altroot
.Op Fl o Ar mntopts
.Op Fl o Ar property Ns = Ns Ar value
@@ -187,7 +191,7 @@
.Op Ar device ...
.Nm
.Cm status
-.Op Fl Dvx
+.Op Fl DgLPvx
.Op Fl T Cm d Ns | Ns Cm u
.Op Ar pool
.Ar ...
@@ -320,11 +324,27 @@ types are not supported for the intent log. For more information,
see the
.Qq Sx Intent Log
section.
+.It Sy dedup
+A device dedicated solely for allocating dedup data.
+The redundancy of this device should match the redundancy of the other normal
+devices in the pool.
+If more than one dedup device is specified, then allocations are load-balanced
+between devices.
+.It Sy special
+A device dedicated solely for allocating various kinds of internal metadata,
+and optionally small file data.
+The redundancy of this device should match the redundancy of the other normal
+devices in the pool.
+If more than one special device is specified, then allocations are
+load-balanced between devices.
+.Pp
+For more information on special allocations, see the
+.Sx Special Allocation Class
+section.
.It Sy cache
-A device used to cache storage pool data. A cache device cannot be configured
-as a mirror or
-.No raidz
-group. For more information, see the
+A device used to cache storage pool data.
+A cache device cannot be configured as a mirror or raidz group.
+For more information, see the
.Qq Sx Cache Devices
section.
.El
@@ -602,6 +622,31 @@ zfs properties) may be unenforceable while a checkpoint exists, because the
checkpoint is allowed to consume the dataset's reservation.
Finally, data that is part of the checkpoint but has been freed in the
current state of the pool won't be scanned during a scrub.
+.Ss Special Allocation Class
+The allocations in the special class are dedicated to specific block types.
+By default this includes all metadata, the indirect blocks of user data, and
+any dedup data.
+The class can also be provisioned to accept a limited percentage of small file
+data blocks.
+.Pp
+A pool must always have at least one general (non-specified) vdev before
+other devices can be assigned to the special class.
+If the special class becomes full, then allocations intended for it will spill
+back into the normal class.
+.Pp
+Dedup data can be excluded from the special class by setting the
+.Sy vfs.zfs.ddt_data_is_special
+sysctl to false (0).
+.Pp
+Inclusion of small file blocks in the special class is opt-in.
+Each dataset can control the size of small file blocks allowed in the special
+class by setting the
+.Sy special_small_blocks
+dataset property.
+It defaults to zero so you must opt-in by setting it to a non-zero value.
+See
+.Xr zfs 1M
+for more info on setting this property.
.Ss Properties
Each pool has several properties associated with it. Some properties are
read-only statistics while others are configurable and change the behavior of
@@ -872,7 +917,7 @@ Displays a help message.
.It Xo
.Nm
.Cm add
-.Op Fl fn
+.Op Fl fgLnP
.Ar pool vdev ...
.Xc
.Pp
@@ -891,11 +936,30 @@ Forces use of
.Ar vdev ,
even if they appear in use or specify a conflicting replication level.
Not all devices can be overridden in this manner.
+.It Fl g
+Display
+.Ar vdev ,
+GUIDs instead of the normal device names.
+These GUIDs can be used in place of
+device names for the zpool detach/offline/remove/replace commands.
+.It Fl L
+Display real paths for
+.Ar vdev Ns s
+resolving all symbolic links.
+This can be used to look up the current block
+device name regardless of the /dev/disk/ path used to open it.
.It Fl n
Displays the configuration that would be used without actually adding the
.Ar vdev Ns s.
-The actual pool creation can still fail due to insufficient privileges or device
-sharing.
+The actual pool creation can still fail due to insufficient privileges or
+device sharing.
+.It Fl P
+Display real paths for
+.Ar vdev Ns s
+instead of only the last component of the path.
+This can be used in conjunction with the
+.Fl L
+flag.
.El
.It Xo
.Nm
@@ -1512,7 +1576,7 @@ with no flags on the relevant target devices.
.Nm
.Cm iostat
.Op Fl T Cm d Ns | Ns Cm u
-.Op Fl v
+.Op Fl gLPv
.Op Ar pool
.Ar ...
.Op Ar interval Op Ar count
@@ -1544,10 +1608,25 @@ Use modifier
.Cm u
for unixtime
.Pq equals Qq Ic date +%s .
+.It Fl g
+Display vdev GUIDs instead of the normal device names.
+These GUIDs can be used in place of device names for the zpool
+detach/offline/remove/replace commands.
+.It Fl L
+Display real paths for vdevs resolving all symbolic links.
+This can be used to look up the current block device name regardless of the
+.Pa /dev/disk/
+path used to open it.
+.It Fl P
+Display full paths for vdevs instead of only the last component of
+the path.
+This can be used in conjunction with the
+.Fl L
+flag.
.It Fl v
-Verbose statistics. Reports usage statistics for individual
-.No vdev Ns s
-within the pool, in addition to the pool-wide statistics.
+Verbose statistics.
+Reports usage statistics for individual vdevs within the
+pool, in addition to the pool-wide statistics.
.El
.It Xo
.Nm
@@ -1570,7 +1649,7 @@ Treat exported or foreign devices as inactive.
.It Xo
.Nm
.Cm list
-.Op Fl Hpv
+.Op Fl HgLpPv
.Op Fl o Ar property Ns Op , Ns Ar ...
.Op Fl T Cm d Ns | Ns Cm u
.Op Ar pool
@@ -1603,11 +1682,27 @@ Use modifier
.Cm u
for unixtime
.Pq equals Qq Ic date +%s .
+.It Fl g
+Display vdev GUIDs instead of the normal device names.
+These GUIDs can be used in place of device names for the zpool
+detach/offline/remove/replace commands.
.It Fl H
Scripted mode. Do not display headers, and separate fields by a single tab
instead of arbitrary space.
+.It Fl L
+Display real paths for vdevs resolving all symbolic links.
+This can be used to look up the current block device name regardless of the
+/dev/disk/ path used to open it.
.It Fl p
-Display numbers in parsable (exact) values.
+Display numbers in parsable
+.Pq exact
+values.
+.It Fl P
+Display full paths for vdevs instead of only the last component of
+the path.
+This can be used in conjunction with the
+.Fl L
+flag.
.It Fl v
Verbose statistics. Reports usage statistics for individual
.Em vdevs
@@ -1702,7 +1797,7 @@ the background.
The removal progress can be monitored with
.Nm zpool Cm status.
This feature must be enabled to be used, see
-.Xr zpool-features 5
+.Xr zpool-features 7
.Pp
A mirrored top-level device (log or data) can be removed by specifying the
top-level mirror for the same.
@@ -1844,7 +1939,7 @@ values.
.It Xo
.Nm
.Cm split
-.Op Fl n
+.Op Fl gLnP
.Op Fl R Ar altroot
.Op Fl o Ar mntopts
.Op Fl o Ar property Ns = Ns Ar value
@@ -1884,6 +1979,15 @@ parameter for the new pool's alternate root. See the
description in the
.Qq Sx Properties
section, above.
+.It Fl g
+Display vdev GUIDs instead of the normal device names.
+These GUIDs can be used in place of device names for the zpool
+detach/offline/remove/replace commands.
+.It Fl L
+Display real paths for vdevs resolving all symbolic links.
+This can be used to look up the current block device name regardless of the
+.Pa /dev/disk/
+path used to open it.
.It Fl n
Displays the configuration that would be created without actually splitting the
pool. The actual pool split could still fail due to insufficient privileges or
@@ -1900,11 +2004,17 @@ option.
Sets the specified property on the new pool. See the
.Qq Sx Properties
section, above, for more information on the available pool properties.
+.It Fl P
+Display full paths for vdevs instead of only the last component of
+the path.
+This can be used in conjunction with the
+.Fl L
+flag.
.El
.It Xo
.Nm
.Cm status
-.Op Fl Dvx
+.Op Fl DgLPvx
.Op Fl T Cm d Ns | Ns Cm u
.Op Ar pool
.Ar ...
@@ -1939,6 +2049,21 @@ Display a histogram of deduplication statistics, showing the allocated
and referenced
.Pq logically referenced in the pool
block counts and sizes by reference count.
+.It Fl g
+Display vdev GUIDs instead of the normal device names.
+These GUIDs can be used in place of device names for the zpool
+detach/offline/remove/replace commands.
+.It Fl L
+Display real paths for vdevs resolving all symbolic links.
+This can be used to look up the current block device name regardless of the
+.Pa /dev/disk/
+path used to open it.
+.It Fl P
+Display full paths for vdevs instead of only the last component of
+the path.
+This can be used in conjunction with the
+.Fl L
+flag.
.It Fl T Cm d Ns | Ns Cm u
Print a timestamp.
.Pp
@@ -2030,6 +2155,30 @@ An error occurred.
.It 2
Invalid command line options were specified.
.El
+.Sh ENVIRONMENT VARIABLES
+.Bl -tag -width "ZPOOL_VDEV_NAME_FOLLOW_LINKS"
+.It Ev ZPOOL_VDEV_NAME_GUID
+Cause
+.Nm zpool
+subcommands to output vdev guids by default.
+This behavior is identical to the
+.Nm zpool status -g
+command line option.
+.It Ev ZPOOL_VDEV_NAME_FOLLOW_LINKS
+Cause
+.Nm zpool
+subcommands to follow links for vdev names by default.
+This behavior is identical to the
+.Nm zpool status -L
+command line option.
+.It Ev ZPOOL_VDEV_NAME_PATH
+Cause
+.Nm zpool
+subcommands to output full vdev path names by default.
+This behavior is identical to the
+.Nm zpool status -P
+command line option.
+.El
.Sh EXAMPLES
.Bl -tag -width 0n
.It Sy Example 1 No Creating a RAID-Z Storage Pool
diff --git a/cddl/contrib/opensolaris/cmd/zpool/zpool_main.c b/cddl/contrib/opensolaris/cmd/zpool/zpool_main.c
index d07d18247e96..d4e0a73ade67 100644
--- a/cddl/contrib/opensolaris/cmd/zpool/zpool_main.c
+++ b/cddl/contrib/opensolaris/cmd/zpool/zpool_main.c
@@ -28,6 +28,7 @@
* Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>.
* Copyright 2016 Nexenta Systems, Inc.
* Copyright (c) 2017 Datto Inc.
+ * Copyright (c) 2017, Intel Corporation.
*/
#include <solaris.h>
@@ -209,6 +210,8 @@ static zpool_command_t command_table[] = {
#define NCOMMAND (sizeof (command_table) / sizeof (command_table[0]))
+#define VDEV_ALLOC_CLASS_LOGS "logs"
+
static zpool_command_t *current_command;
static char history_str[HIS_MAX_RECORD_LEN];
static boolean_t log_history = B_TRUE;
@@ -219,7 +222,7 @@ get_usage(zpool_help_t idx)
{
switch (idx) {
case HELP_ADD:
- return (gettext("\tadd [-fn] <pool> <vdev> ...\n"));
+ return (gettext("\tadd [-fgLnP] <pool> <vdev> ...\n"));
case HELP_ATTACH:
return (gettext("\tattach [-f] <pool> <device> "
"<new-device>\n"));
@@ -251,12 +254,12 @@ get_usage(zpool_help_t idx)
"[-R root] [-F [-n]] [-t]\n"
"\t [--rewind-to-checkpoint] <pool | id> [newpool]\n"));
case HELP_IOSTAT:
- return (gettext("\tiostat [-v] [-T d|u] [pool] ... [interval "
- "[count]]\n"));
+ return (gettext("\tiostat [-gLPv] [-T d|u] [pool] ... "
+ "[interval [count]]\n"));
case HELP_LABELCLEAR:
return (gettext("\tlabelclear [-f] <vdev>\n"));
case HELP_LIST:
- return (gettext("\tlist [-Hpv] [-o property[,...]] "
+ return (gettext("\tlist [-gHLpPv] [-o property[,...]] "
"[-T d|u] [pool] ... [interval [count]]\n"));
case HELP_OFFLINE:
return (gettext("\toffline [-t] <pool> <device> ...\n"));
@@ -274,8 +277,8 @@ get_usage(zpool_help_t idx)
case HELP_SCRUB:
return (gettext("\tscrub [-s | -p] <pool> ...\n"));
case HELP_STATUS:
- return (gettext("\tstatus [-vx] [-T d|u] [pool] ... [interval "
- "[count]]\n"));
+ return (gettext("\tstatus [-DgLPvx] [-T d|u] [pool] ... "
+ "[interval [count]]\n"));
case HELP_UPGRADE:
return (gettext("\tupgrade [-v]\n"
"\tupgrade [-V version] <-a | pool ...>\n"));
@@ -285,7 +288,7 @@ get_usage(zpool_help_t idx)
case HELP_SET:
return (gettext("\tset <property=value> <pool> \n"));
case HELP_SPLIT:
- return (gettext("\tsplit [-n] [-R altroot] [-o mntopts]\n"
+ return (gettext("\tsplit [-gLnP] [-R altroot] [-o mntopts]\n"
"\t [-o property=value] <pool> <newpool> "
"[<device> ...]\n"));
case HELP_REGUID:
@@ -307,7 +310,7 @@ print_prop_cb(int prop, void *cb)
{
FILE *fp = cb;
- (void) fprintf(fp, "\t%-15s ", zpool_prop_to_name(prop));
+ (void) fprintf(fp, "\t%-19s ", zpool_prop_to_name(prop));
if (zpool_prop_readonly(prop))
(void) fprintf(fp, " NO ");
@@ -359,14 +362,14 @@ usage(boolean_t requested)
(void) fprintf(fp,
gettext("\nthe following properties are supported:\n"));
- (void) fprintf(fp, "\n\t%-15s %s %s\n\n",
+ (void) fprintf(fp, "\n\t%-19s %s %s\n\n",
"PROPERTY", "EDIT", "VALUES");
/* Iterate over all properties */
(void) zprop_iter(print_prop_cb, fp, B_FALSE, B_TRUE,
ZFS_TYPE_POOL);
- (void) fprintf(fp, "\t%-15s ", "feature@...");
+ (void) fprintf(fp, "\t%-19s ", "feature@...");
(void) fprintf(fp, "YES disabled | enabled | active\n");
(void) fprintf(fp, gettext("\nThe feature@ properties must be "
@@ -384,32 +387,45 @@ usage(boolean_t requested)
exit(requested ? 0 : 2);
}
-void
+/*
+ * print a pool vdev config for dry runs
+ */
+static void
print_vdev_tree(zpool_handle_t *zhp, const char *name, nvlist_t *nv, int indent,
- boolean_t print_logs)
+ const char *match, int name_flags)
{
nvlist_t **child;
uint_t c, children;
char *vname;
-
- if (name != NULL)
- (void) printf("\t%*s%s\n", indent, "", name);
+ boolean_t printed = B_FALSE;
if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
- &child, &children) != 0)
+ &child, &children) != 0) {
+ if (name != NULL)
+ (void) printf("\t%*s%s\n", indent, "", name);
return;
+ }
for (c = 0; c < children; c++) {
uint64_t is_log = B_FALSE;
+ char *class = "";
(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
&is_log);
- if ((is_log && !print_logs) || (!is_log && print_logs))
+ if (is_log)
+ class = VDEV_ALLOC_BIAS_LOG;
+ (void) nvlist_lookup_string(child[c],
+ ZPOOL_CONFIG_ALLOCATION_BIAS, &class);
+ if (strcmp(match, class) != 0)
continue;
- vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE);
- print_vdev_tree(zhp, vname, child[c], indent + 2,
- B_FALSE);
+ if (!printed && name != NULL) {
+ (void) printf("\t%*s%s\n", indent, "", name);
+ printed = B_TRUE;
+ }
+ vname = zpool_vdev_name(g_zfs, zhp, child[c], name_flags);
+ print_vdev_tree(zhp, vname, child[c], indent + 2, "",
+ name_flags);
free(vname);
}
}
@@ -517,11 +533,14 @@ add_prop_list_default(const char *propname, char *propval, nvlist_t **props,
}
/*
- * zpool add [-fn] <pool> <vdev> ...
+ * zpool add [-fgLnP] [-o property=value] <pool> <vdev> ...
*
* -f Force addition of devices, even if they appear in use
+ * -g Display guid for individual vdev name.
+ * -L Follow links when resolving vdev path name.
* -n Do not add the devices, but display the resulting layout if
* they were to be added.
+ * -P Display full path for vdev name.
*
* Adds the given vdevs to 'pool'. As with create, the bulk of this work is
* handled by get_vdev_spec(), which constructs the nvlist needed to pass to
@@ -532,6 +551,7 @@ zpool_do_add(int argc, char **argv)
{
boolean_t force = B_FALSE;
boolean_t dryrun = B_FALSE;
+ int name_flags = 0;
int c;
nvlist_t *nvroot;
char *poolname;
@@ -542,14 +562,23 @@ zpool_do_add(int argc, char **argv)
nvlist_t *config;
/* check options */
- while ((c = getopt(argc, argv, "fn")) != -1) {
+ while ((c = getopt(argc, argv, "fgLnP")) != -1) {
switch (c) {
case 'f':
force = B_TRUE;
break;
+ case 'g':
+ name_flags |= VDEV_NAME_GUID;
+ break;
+ case 'L':
+ name_flags |= VDEV_NAME_FOLLOW_LINKS;
+ break;
case 'n':
dryrun = B_TRUE;
break;
+ case 'P':
+ name_flags |= VDEV_NAME_PATH;
+ break;
case '?':
(void) fprintf(stderr, gettext("invalid option '%c'\n"),
optopt);
@@ -609,16 +638,25 @@ zpool_do_add(int argc, char **argv)
"configuration:\n"), zpool_get_name(zhp));
/* print original main pool and new tree */
- print_vdev_tree(zhp, poolname, poolnvroot, 0, B_FALSE);
- print_vdev_tree(zhp, NULL, nvroot, 0, B_FALSE);
-
- /* Do the same for the logs */
- if (num_logs(poolnvroot) > 0) {
- print_vdev_tree(zhp, "logs", poolnvroot, 0, B_TRUE);
- print_vdev_tree(zhp, NULL, nvroot, 0, B_TRUE);
- } else if (num_logs(nvroot) > 0) {
- print_vdev_tree(zhp, "logs", nvroot, 0, B_TRUE);
- }
+ print_vdev_tree(zhp, poolname, poolnvroot, 0, "",
+ name_flags | VDEV_NAME_TYPE_ID);
+ print_vdev_tree(zhp, NULL, nvroot, 0, "", name_flags);
+
+ /* print other classes: 'dedup', 'special', and 'log' */
+ print_vdev_tree(zhp, "dedup", poolnvroot, 0,
+ VDEV_ALLOC_BIAS_DEDUP, name_flags);
+ print_vdev_tree(zhp, NULL, nvroot, 0, VDEV_ALLOC_BIAS_DEDUP,
+ name_flags);
+
+ print_vdev_tree(zhp, "special", poolnvroot, 0,
+ VDEV_ALLOC_BIAS_SPECIAL, name_flags);
+ print_vdev_tree(zhp, NULL, nvroot, 0, VDEV_ALLOC_BIAS_SPECIAL,
+ name_flags);
+
+ print_vdev_tree(zhp, "logs", poolnvroot, 0, VDEV_ALLOC_BIAS_LOG,
+ name_flags);
+ print_vdev_tree(zhp, NULL, nvroot, 0, VDEV_ALLOC_BIAS_LOG,
+ name_flags);
ret = 0;
} else {
@@ -1217,9 +1255,13 @@ zpool_do_create(int argc, char **argv)
(void) printf(gettext("would create '%s' with the "
"following layout:\n\n"), poolname);
- print_vdev_tree(NULL, poolname, nvroot, 0, B_FALSE);
- if (num_logs(nvroot) > 0)
- print_vdev_tree(NULL, "logs", nvroot, 0, B_TRUE);
+ print_vdev_tree(NULL, poolname, nvroot, 0, "", 0);
+ print_vdev_tree(NULL, "dedup", nvroot, 0,
+ VDEV_ALLOC_BIAS_DEDUP, 0);
+ print_vdev_tree(NULL, "special", nvroot, 0,
+ VDEV_ALLOC_BIAS_SPECIAL, 0);
+ print_vdev_tree(NULL, "logs", nvroot, 0,
+ VDEV_ALLOC_BIAS_LOG, 0);
ret = 0;
} else {
@@ -1426,13 +1468,15 @@ zpool_do_export(int argc, char **argv)
* name column.
*/
static int
-max_width(zpool_handle_t *zhp, nvlist_t *nv, int depth, int max)
+max_width(zpool_handle_t *zhp, nvlist_t *nv, int depth, int max,
+ int name_flags)
{
- char *name = zpool_vdev_name(g_zfs, zhp, nv, B_TRUE);
+ char *name;
nvlist_t **child;
uint_t c, children;
int ret;
+ name = zpool_vdev_name(g_zfs, zhp, nv, name_flags | VDEV_NAME_TYPE_ID);
if (strlen(name) + depth > max)
max = strlen(name) + depth;
@@ -1442,7 +1486,7 @@ max_width(zpool_handle_t *zhp, nvlist_t *nv, int depth, int max)
&child, &children) == 0) {
for (c = 0; c < children; c++)
if ((ret = max_width(zhp, child[c], depth + 2,
- max)) > max)
+ max, name_flags)) > max)
max = ret;
}
@@ -1450,7 +1494,7 @@ max_width(zpool_handle_t *zhp, nvlist_t *nv, int depth, int max)
&child, &children) == 0) {
for (c = 0; c < children; c++)
if ((ret = max_width(zhp, child[c], depth + 2,
- max)) > max)
+ max, name_flags)) > max)
max = ret;
}
@@ -1458,11 +1502,10 @@ max_width(zpool_handle_t *zhp, nvlist_t *nv, int depth, int max)
&child, &children) == 0) {
for (c = 0; c < children; c++)
if ((ret = max_width(zhp, child[c], depth + 2,
- max)) > max)
+ max, name_flags)) > max)
max = ret;
}
-
return (max);
}
@@ -1511,12 +1554,24 @@ find_spare(zpool_handle_t *zhp, void *data)
return (0);
}
+typedef struct status_cbdata {
+ int cb_count;
+ int cb_name_flags;
+ int cb_namewidth;
+ boolean_t cb_allpools;
+ boolean_t cb_verbose;
+ boolean_t cb_explain;
+ boolean_t cb_first;
+ boolean_t cb_dedup_stats;
+ boolean_t cb_print_status;
+} status_cbdata_t;
+
/*
* Print out configuration state as requested by status_callback.
*/
-void
-print_status_config(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
- int namewidth, int depth, boolean_t isspare)
+static void
+print_status_config(zpool_handle_t *zhp, status_cbdata_t *cb, const char *name,
+ nvlist_t *nv, int depth, boolean_t isspare)
{
nvlist_t **child;
uint_t c, vsc, children;
@@ -1526,7 +1581,7 @@ print_status_config(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
char *vname;
uint64_t notpresent;
uint64_t ashift;
- spare_cbdata_t cb;
+ spare_cbdata_t spare_cb;
const char *state;
char *type;
@@ -1554,7 +1609,7 @@ print_status_config(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
state = "AVAIL";
}
- (void) printf("\t%*s%-*s %-8s", depth, "", namewidth - depth,
+ (void) printf("\t%*s%-*s %-8s", depth, "", cb->cb_namewidth - depth,
name, state);
if (!isspare) {
@@ -1600,17 +1655,17 @@ print_status_config(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
case VDEV_AUX_SPARED:
verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID,
- &cb.cb_guid) == 0);
- if (zpool_iter(g_zfs, find_spare, &cb) == 1) {
- if (strcmp(zpool_get_name(cb.cb_zhp),
+ &spare_cb.cb_guid) == 0);
+ if (zpool_iter(g_zfs, find_spare, &spare_cb) == 1) {
+ if (strcmp(zpool_get_name(spare_cb.cb_zhp),
zpool_get_name(zhp)) == 0)
(void) printf(gettext("currently in "
"use"));
else
(void) printf(gettext("in use by "
"pool '%s'"),
- zpool_get_name(cb.cb_zhp));
- zpool_close(cb.cb_zhp);
+ zpool_get_name(spare_cb.cb_zhp));
+ zpool_close(spare_cb.cb_zhp);
} else {
(void) printf(gettext("currently in use"));
}
@@ -1715,20 +1770,25 @@ print_status_config(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
&ishole);
if (islog || ishole)
continue;
- vname = zpool_vdev_name(g_zfs, zhp, child[c], B_TRUE);
- print_status_config(zhp, vname, child[c],
- namewidth, depth + 2, isspare);
+ /* Only print normal classes here */
+ if (nvlist_exists(child[c], ZPOOL_CONFIG_ALLOCATION_BIAS))
+ continue;
+
+ vname = zpool_vdev_name(g_zfs, zhp, child[c],
+ cb->cb_name_flags | VDEV_NAME_TYPE_ID);
+ print_status_config(zhp, cb, vname, child[c], depth + 2,
+ isspare);
free(vname);
}
}
-
/*
* Print the configuration of an exported pool. Iterate over all vdevs in the
* pool, printing out the name and status for each one.
*/
-void
-print_import_config(const char *name, nvlist_t *nv, int namewidth, int depth)
+static void
+print_import_config(status_cbdata_t *cb, const char *name, nvlist_t *nv,
+ int depth)
{
nvlist_t **child;
uint_t c, children;
@@ -1743,7 +1803,7 @@ print_import_config(const char *name, nvlist_t *nv, int namewidth, int depth)
verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS,
(uint64_t **)&vs, &c) == 0);
- (void) printf("\t%*s%-*s", depth, "", namewidth - depth, name);
+ (void) printf("\t%*s%-*s", depth, "", cb->cb_namewidth - depth, name);
(void) printf(" %s", zpool_state_to_name(vs->vs_state, vs->vs_aux));
if (vs->vs_aux != 0) {
@@ -1800,9 +1860,12 @@ print_import_config(const char *name, nvlist_t *nv, int namewidth, int depth)
&is_log);
if (is_log)
continue;
+ if (nvlist_exists(child[c], ZPOOL_CONFIG_ALLOCATION_BIAS))
+ continue;
- vname = zpool_vdev_name(g_zfs, NULL, child[c], B_TRUE);
- print_import_config(vname, child[c], namewidth, depth + 2);
+ vname = zpool_vdev_name(g_zfs, NULL, child[c],
+ cb->cb_name_flags | VDEV_NAME_TYPE_ID);
+ print_import_config(cb, vname, child[c], depth + 2);
free(vname);
}
@@ -1810,7 +1873,8 @@ print_import_config(const char *name, nvlist_t *nv, int namewidth, int depth)
&child, &children) == 0) {
(void) printf(gettext("\tcache\n"));
for (c = 0; c < children; c++) {
- vname = zpool_vdev_name(g_zfs, NULL, child[c], B_FALSE);
+ vname = zpool_vdev_name(g_zfs, NULL, child[c],
+ cb->cb_name_flags);
(void) printf("\t %s\n", vname);
free(vname);
}
@@ -1820,7 +1884,8 @@ print_import_config(const char *name, nvlist_t *nv, int namewidth, int depth)
&child, &children) == 0) {
(void) printf(gettext("\tspares\n"));
for (c = 0; c < children; c++) {
- vname = zpool_vdev_name(g_zfs, NULL, child[c], B_FALSE);
+ vname = zpool_vdev_name(g_zfs, NULL, child[c],
+ cb->cb_name_flags);
(void) printf("\t %s\n", vname);
free(vname);
}
@@ -1828,39 +1893,62 @@ print_import_config(const char *name, nvlist_t *nv, int namewidth, int depth)
}
/*
- * Print log vdevs.
- * Logs are recorded as top level vdevs in the main pool child array
- * but with "is_log" set to 1. We use either print_status_config() or
- * print_import_config() to print the top level logs then any log
- * children (eg mirrored slogs) are printed recursively - which
- * works because only the top level vdev is marked "is_log"
+ * Print specialized class vdevs.
+ *
+ * These are recorded as top level vdevs in the main pool child array
+ * but with "is_log" set to 1 or an "alloc_bias" string. We use either
+ * print_status_config() or print_import_config() to print the top level
+ * class vdevs then any of their children (eg mirrored slogs) are printed
+ * recursively - which works because only the top level vdev is marked.
*/
static void
-print_logs(zpool_handle_t *zhp, nvlist_t *nv, int namewidth, boolean_t verbose)
+print_class_vdevs(zpool_handle_t *zhp, status_cbdata_t *cb, nvlist_t *nv,
+ const char *class)
{
uint_t c, children;
nvlist_t **child;
+ boolean_t printed = B_FALSE;
+
+ assert(zhp != NULL || !cb->cb_verbose);
if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, &child,
&children) != 0)
return;
- (void) printf(gettext("\tlogs\n"));
-
for (c = 0; c < children; c++) {
uint64_t is_log = B_FALSE;
- char *name;
+ char *bias = NULL;
+ char *type = NULL;
(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
&is_log);
- if (!is_log)
+
+ if (is_log) {
+ bias = VDEV_ALLOC_CLASS_LOGS;
+ } else {
+ (void) nvlist_lookup_string(child[c],
+ ZPOOL_CONFIG_ALLOCATION_BIAS, &bias);
+ (void) nvlist_lookup_string(child[c],
+ ZPOOL_CONFIG_TYPE, &type);
+ }
+
+ if (bias == NULL || strcmp(bias, class) != 0)
continue;
- name = zpool_vdev_name(g_zfs, zhp, child[c], B_TRUE);
- if (verbose)
- print_status_config(zhp, name, child[c], namewidth,
- 2, B_FALSE);
+ if (!is_log && strcmp(type, VDEV_TYPE_INDIRECT) == 0)
+ continue;
+
+ if (!printed) {
+ (void) printf("\t%s\t\n", gettext(class));
+ printed = B_TRUE;
+ }
+
+ char *name = zpool_vdev_name(g_zfs, zhp, child[c],
+ cb->cb_name_flags | VDEV_NAME_TYPE_ID);
+ if (cb->cb_print_status)
+ print_status_config(zhp, cb, name, child[c], 2,
+ B_FALSE);
else
- print_import_config(name, child[c], namewidth, 2);
+ print_import_config(cb, name, child[c], 2);
free(name);
}
}
@@ -1882,8 +1970,8 @@ show_import(nvlist_t *config)
int reason;
const char *health;
uint_t vsc;
- int namewidth;
char *comment;
+ status_cbdata_t cb = { 0 };
verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
&name) == 0);
@@ -2115,13 +2203,15 @@ show_import(nvlist_t *config)
(void) printf(gettext(" config:\n\n"));
- namewidth = max_width(NULL, nvroot, 0, 0);
- if (namewidth < 10)
- namewidth = 10;
+ cb.cb_namewidth = max_width(NULL, nvroot, 0, 0, 0);
+ if (cb.cb_namewidth < 10)
+ cb.cb_namewidth = 10;
- print_import_config(name, nvroot, namewidth, 0);
- if (num_logs(nvroot) > 0)
- print_logs(NULL, nvroot, namewidth, B_FALSE);
+ print_import_config(&cb, name, nvroot, 0);
+
+ print_class_vdevs(NULL, &cb, nvroot, VDEV_ALLOC_BIAS_DEDUP);
+ print_class_vdevs(NULL, &cb, nvroot, VDEV_ALLOC_BIAS_SPECIAL);
+ print_class_vdevs(NULL, &cb, nvroot, VDEV_ALLOC_CLASS_LOGS);
if (reason == ZPOOL_STATUS_BAD_GUID_SUM) {
(void) printf(gettext("\n\tAdditional devices are known to "
@@ -2783,8 +2873,10 @@ zpool_do_sync(int argc, char **argv)
typedef struct iostat_cbdata {
boolean_t cb_verbose;
+ int cb_name_flags;
int cb_namewidth;
int cb_iteration;
+ boolean_t cb_scripted;
zpool_list_t *cb_list;
} iostat_cbdata_t;
@@ -2820,12 +2912,20 @@ print_one_stat(uint64_t value)
(void) printf(" %5s", buf);
}
+static const char *class_name[] = {
+ VDEV_ALLOC_BIAS_DEDUP,
+ VDEV_ALLOC_BIAS_SPECIAL,
+ VDEV_ALLOC_CLASS_LOGS
+};
+
/*
* Print out all the statistics for the given vdev. This can either be the
* toplevel configuration, or called recursively. If 'name' is NULL, then this
* is a verbose output, and we don't want to display the toplevel pool stats.
+ *
+ * Returns the number of stat lines printed.
*/
-void
+static unsigned int
print_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv,
nvlist_t *newnv, iostat_cbdata_t *cb, int depth)
{
@@ -2833,12 +2933,13 @@ print_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv,
uint_t c, children;
vdev_stat_t *oldvs, *newvs;
vdev_stat_t zerovs = { 0 };
+ char *vname;
+ int ret = 0;
uint64_t tdelta;
double scale;
- char *vname;
if (strcmp(name, VDEV_TYPE_INDIRECT) == 0)
- return;
+ return (ret);
if (oldnv != NULL) {
verify(nvlist_lookup_uint64_array(oldnv,
@@ -2886,16 +2987,19 @@ print_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv,
(void) printf("\n");
if (!cb->cb_verbose)
- return;
+ return (ret);
if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_CHILDREN,
&newchild, &children) != 0)
- return;
+ return (ret);
if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_CHILDREN,
&oldchild, &c) != 0)
- return;
+ return (ret);
+ /*
+ * print normal top-level devices
+ */
for (c = 0; c < children; c++) {
uint64_t ishole = B_FALSE, islog = B_FALSE;
@@ -2908,33 +3012,45 @@ print_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv,
if (ishole || islog)
continue;
- vname = zpool_vdev_name(g_zfs, zhp, newchild[c], B_FALSE);
+ if (nvlist_exists(newchild[c], ZPOOL_CONFIG_ALLOCATION_BIAS))
+ continue;
+
+ vname = zpool_vdev_name(g_zfs, zhp, newchild[c],
+ cb->cb_name_flags);
print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL,
newchild[c], cb, depth + 2);
free(vname);
}
/*
- * Log device section
+ * print all other top-level devices
*/
-
- if (num_logs(newnv) > 0) {
- (void) printf("%-*s - - - - - "
- "-\n", cb->cb_namewidth, "logs");
-
+ for (uint_t n = 0; n < 3; n++) {
for (c = 0; c < children; c++) {
uint64_t islog = B_FALSE;
+ char *bias = NULL;
+ char *type = NULL;
+
(void) nvlist_lookup_uint64(newchild[c],
ZPOOL_CONFIG_IS_LOG, &islog);
-
if (islog) {
- vname = zpool_vdev_name(g_zfs, zhp, newchild[c],
- B_FALSE);
- print_vdev_stats(zhp, vname, oldnv ?
- oldchild[c] : NULL, newchild[c],
- cb, depth + 2);
- free(vname);
+ bias = VDEV_ALLOC_CLASS_LOGS;
+ } else {
+ (void) nvlist_lookup_string(newchild[c],
+ ZPOOL_CONFIG_ALLOCATION_BIAS, &bias);
+ (void) nvlist_lookup_string(newchild[c],
+ ZPOOL_CONFIG_TYPE, &type);
}
+ if (bias == NULL || strcmp(bias, class_name[n]) != 0)
+ continue;
+ if (!islog && strcmp(type, VDEV_TYPE_INDIRECT) == 0)
+ continue;
+
+ vname = zpool_vdev_name(g_zfs, zhp, newchild[c],
+ cb->cb_name_flags);
+ ret += print_vdev_stats(zhp, vname, oldnv ?
+ oldchild[c] : NULL, newchild[c], cb, depth + 2);
+ free(vname);
}
}
@@ -2944,23 +3060,25 @@ print_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv,
*/
if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_L2CACHE,
&newchild, &children) != 0)
- return;
+ return (ret);
if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_L2CACHE,
&oldchild, &c) != 0)
- return;
+ return (ret);
if (children > 0) {
(void) printf("%-*s - - - - - "
"-\n", cb->cb_namewidth, "cache");
for (c = 0; c < children; c++) {
vname = zpool_vdev_name(g_zfs, zhp, newchild[c],
- B_FALSE);
+ cb->cb_name_flags);
print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL,
newchild[c], cb, depth + 2);
free(vname);
}
}
+
+ return (ret);
}
static int
@@ -3029,7 +3147,7 @@ get_namewidth(zpool_handle_t *zhp, void *data)
cb->cb_namewidth = strlen(zpool_get_name(zhp));
else
cb->cb_namewidth = max_width(zhp, nvroot, 0,
- cb->cb_namewidth);
+ cb->cb_namewidth, cb->cb_name_flags);
}
/*
@@ -3127,8 +3245,11 @@ get_timestamp_arg(char c)
}
/*
- * zpool iostat [-v] [-T d|u] [pool] ... [interval [count]]
+ * zpool iostat [-gLPv] [-T d|u] [pool] ... [interval [count]]
*
+ * -g Display guid for individual vdev name.
+ * -L Follow links when resolving vdev path name.
+ * -P Display full path for vdev name.
* -v Display statistics for individual vdevs
* -T Display a timestamp in date(1) or Unix format
*
@@ -3147,11 +3268,23 @@ zpool_do_iostat(int argc, char **argv)
unsigned long interval = 0, count = 0;
zpool_list_t *list;
boolean_t verbose = B_FALSE;
- iostat_cbdata_t cb;
+ boolean_t guid = B_FALSE;
+ boolean_t follow_links = B_FALSE;
+ boolean_t full_name = B_FALSE;
+ iostat_cbdata_t cb = { 0 };
/* check options */
- while ((c = getopt(argc, argv, "T:v")) != -1) {
+ while ((c = getopt(argc, argv, "gLPT:v")) != -1) {
switch (c) {
+ case 'g':
+ guid = B_TRUE;
+ break;
+ case 'L':
+ follow_links = B_TRUE;
+ break;
+ case 'P':
+ full_name = B_TRUE;
+ break;
case 'T':
get_timestamp_arg(*optarg);
break;
@@ -3193,6 +3326,12 @@ zpool_do_iostat(int argc, char **argv)
*/
cb.cb_list = list;
cb.cb_verbose = verbose;
+ if (guid)
+ cb.cb_name_flags |= VDEV_NAME_GUID;
+ if (follow_links)
+ cb.cb_name_flags |= VDEV_NAME_FOLLOW_LINKS;
+ if (full_name)
+ cb.cb_name_flags |= VDEV_NAME_PATH;
cb.cb_iteration = 0;
cb.cb_namewidth = 0;
@@ -3259,12 +3398,14 @@ zpool_do_iostat(int argc, char **argv)
typedef struct list_cbdata {
boolean_t cb_verbose;
+ int cb_name_flags;
int cb_namewidth;
boolean_t cb_scripted;
zprop_list_t *cb_proplist;
boolean_t cb_literal;
} list_cbdata_t;
+
/*
* Given a list of columns to display, output appropriate headers for each one.
*/
@@ -3320,7 +3461,7 @@ print_header(list_cbdata_t *cb)
/*
* Given a pool and a list of properties, print out all the properties according
- * to the described layout.
+ * to the described layout. Used by zpool_do_list().
*/
static void
print_pool(zpool_handle_t *zhp, list_cbdata_t *cb)
@@ -3412,7 +3553,9 @@ print_one_column(zpool_prop_t prop, uint64_t value, boolean_t scripted,
}
break;
case ZPOOL_PROP_CAPACITY:
- (void) snprintf(propval, sizeof (propval), "%llu%%", value);
+ (void) snprintf(propval, sizeof (propval),
+ value < 1000 ? "%1.2f%%" : value < 10000 ?
+ "%2.1f%%" : "%3.0f%%", value / 100.0);
break;
default:
zfs_nicenum(value, propval, sizeof (propval));
@@ -3427,6 +3570,9 @@ print_one_column(zpool_prop_t prop, uint64_t value, boolean_t scripted,
(void) printf(" %*s", width, propval);
}
+/*
+ * print static default line per vdev
+ */
void
print_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
list_cbdata_t *cb, int depth)
@@ -3437,7 +3583,6 @@ print_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
char *vname;
boolean_t scripted = cb->cb_scripted;
uint64_t islog = B_FALSE;
- boolean_t haslog = B_FALSE;
char *dashes = "%-*s - - - - - -\n";
verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS,
@@ -3478,7 +3623,7 @@ print_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
vs->vs_fragmentation, scripted,
(vs->vs_fragmentation != ZFS_FRAG_INVALID && toplevel));
cap = (vs->vs_space == 0) ? 0 :
- (vs->vs_alloc * 100 / vs->vs_space);
+ (vs->vs_alloc * 10000 / vs->vs_space);
print_one_column(ZPOOL_PROP_CAPACITY, cap, scripted, toplevel);
(void) printf("\n");
}
@@ -3487,6 +3632,7 @@ print_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
&child, &children) != 0)
return;
+ /* list the normal vdevs first */
for (c = 0; c < children; c++) {
uint64_t ishole = B_FALSE;
@@ -3495,24 +3641,48 @@ print_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
continue;
if (nvlist_lookup_uint64(child[c],
- ZPOOL_CONFIG_IS_LOG, &islog) == 0 && islog) {
- haslog = B_TRUE;
+ ZPOOL_CONFIG_IS_LOG, &islog) == 0 && islog)
continue;
- }
- vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE);
+ if (nvlist_exists(child[c], ZPOOL_CONFIG_ALLOCATION_BIAS))
+ continue;
+
+ vname = zpool_vdev_name(g_zfs, zhp, child[c],
+ cb->cb_name_flags);
print_list_stats(zhp, vname, child[c], cb, depth + 2);
free(vname);
}
- if (haslog == B_TRUE) {
- /* LINTED E_SEC_PRINTF_VAR_FMT */
- (void) printf(dashes, cb->cb_namewidth, "log");
+ /* list the classes: 'logs', 'dedup', and 'special' */
+ for (uint_t n = 0; n < 3; n++) {
+ boolean_t printed = B_FALSE;
+
for (c = 0; c < children; c++) {
+ char *bias = NULL;
+ char *type = NULL;
+
if (nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
- &islog) != 0 || !islog)
+ &islog) == 0 && islog) {
+ bias = VDEV_ALLOC_CLASS_LOGS;
+ } else {
+ (void) nvlist_lookup_string(child[c],
+ ZPOOL_CONFIG_ALLOCATION_BIAS, &bias);
+ (void) nvlist_lookup_string(child[c],
+ ZPOOL_CONFIG_TYPE, &type);
+ }
+ if (bias == NULL || strcmp(bias, class_name[n]) != 0)
+ continue;
+ if (!islog && strcmp(type, VDEV_TYPE_INDIRECT) == 0)
continue;
- vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE);
+
+ if (!printed) {
+ /* LINTED E_SEC_PRINTF_VAR_FMT */
+ (void) printf(dashes, cb->cb_namewidth,
+ class_name[n]);
+ printed = B_TRUE;
+ }
+ vname = zpool_vdev_name(g_zfs, zhp, child[c],
+ cb->cb_name_flags);
print_list_stats(zhp, vname, child[c], cb, depth + 2);
free(vname);
}
@@ -3523,7 +3693,8 @@ print_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
/* LINTED E_SEC_PRINTF_VAR_FMT */
(void) printf(dashes, cb->cb_namewidth, "cache");
for (c = 0; c < children; c++) {
- vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE);
+ vname = zpool_vdev_name(g_zfs, zhp, child[c],
+ cb->cb_name_flags);
print_list_stats(zhp, vname, child[c], cb, depth + 2);
free(vname);
}
@@ -3534,14 +3705,14 @@ print_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
/* LINTED E_SEC_PRINTF_VAR_FMT */
(void) printf(dashes, cb->cb_namewidth, "spare");
for (c = 0; c < children; c++) {
- vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE);
+ vname = zpool_vdev_name(g_zfs, zhp, child[c],
+ cb->cb_name_flags);
print_list_stats(zhp, vname, child[c], cb, depth + 2);
free(vname);
}
}
}
-
/*
* Generic callback function to list a pool.
*/
@@ -3554,26 +3725,37 @@ list_callback(zpool_handle_t *zhp, void *data)
config = zpool_get_config(zhp, NULL);
+ if (cbp->cb_verbose) {
+ config = zpool_get_config(zhp, NULL);
+
+ verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
+ &nvroot) == 0);
+ }
+
+ if (cbp->cb_verbose)
+ cbp->cb_namewidth = max_width(zhp, nvroot, 0, 0,
+ cbp->cb_name_flags);
+
print_pool(zhp, cbp);
- if (!cbp->cb_verbose)
- return (0);
- verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
- &nvroot) == 0);
- print_list_stats(zhp, NULL, nvroot, cbp, 0);
+ if (cbp->cb_verbose)
+ print_list_stats(zhp, NULL, nvroot, cbp, 0);
return (0);
}
/*
- * zpool list [-Hp] [-o prop[,prop]*] [-T d|u] [pool] ... [interval [count]]
+ * zpool list [-gHLP] [-o prop[,prop]*] [-T d|u] [pool] ... [interval [count]]
*
+ * -g Display guid for individual vdev name.
* -H Scripted mode. Don't display headers, and separate properties
* by a single tab.
+ * -L Follow links when resolving vdev path name.
* -o List of properties to display. Defaults to
* "name,size,allocated,free,expandsize,fragmentation,capacity,"
* "dedupratio,health,altroot"
* -p Diplay values in parsable (exact) format.
+ * -P Display full path for vdev name.
* -T Display a timestamp in date(1) or Unix format
*
* List all pools in the system, whether or not they're healthy. Output space
@@ -3594,14 +3776,23 @@ zpool_do_list(int argc, char **argv)
boolean_t first = B_TRUE;
/* check options */
- while ((c = getopt(argc, argv, ":Ho:pT:v")) != -1) {
+ while ((c = getopt(argc, argv, ":gHLo:pPT:v")) != -1) {
switch (c) {
+ case 'g':
+ cb.cb_name_flags |= VDEV_NAME_GUID;
+ break;
case 'H':
cb.cb_scripted = B_TRUE;
break;
+ case 'L':
+ cb.cb_name_flags |= VDEV_NAME_FOLLOW_LINKS;
+ break;
case 'o':
props = optarg;
break;
+ case 'P':
+ cb.cb_name_flags |= VDEV_NAME_PATH;
+ break;
case 'p':
cb.cb_literal = B_TRUE;
break;
@@ -3610,6 +3801,7 @@ zpool_do_list(int argc, char **argv)
break;
case 'v':
cb.cb_verbose = B_TRUE;
+ cb.cb_namewidth = 8; /* 8 until precalc is avail */
break;
case ':':
(void) fprintf(stderr, gettext("missing argument for "
@@ -3855,13 +4047,16 @@ zpool_do_detach(int argc, char **argv)
}
/*
- * zpool split [-n] [-o prop=val] ...
+ * zpool split [-gLnP] [-o prop=val] ...
* [-o mntopt] ...
* [-R altroot] <pool> <newpool> [<device> ...]
*
+ * -g Display guid for individual vdev name.
+ * -L Follow links when resolving vdev path name.
* -n Do not split the pool, but display the resulting layout if
* it were to be split.
* -o Set property=value, or set mount options.
+ * -P Display full path for vdev name.
* -R Mount the split-off pool under an alternate root.
*
* Splits the named pool and gives it the new pool name. Devices to be split
@@ -3885,10 +4080,17 @@ zpool_do_split(int argc, char **argv)
flags.dryrun = B_FALSE;
flags.import = B_FALSE;
+ flags.name_flags = 0;
/* check options */
- while ((c = getopt(argc, argv, ":R:no:")) != -1) {
+ while ((c = getopt(argc, argv, ":gLR:no:P")) != -1) {
switch (c) {
+ case 'g':
+ flags.name_flags |= VDEV_NAME_GUID;
+ break;
+ case 'L':
+ flags.name_flags |= VDEV_NAME_FOLLOW_LINKS;
+ break;
case 'R':
flags.import = B_TRUE;
if (add_prop_list(
@@ -3914,6 +4116,9 @@ zpool_do_split(int argc, char **argv)
mntopts = optarg;
}
break;
+ case 'P':
+ flags.name_flags |= VDEV_NAME_PATH;
+ break;
case ':':
(void) fprintf(stderr, gettext("missing argument for "
"'%c' option\n"), optopt);
@@ -3961,7 +4166,8 @@ zpool_do_split(int argc, char **argv)
if (flags.dryrun) {
(void) printf(gettext("would create '%s' with the "
"following layout:\n\n"), newpool);
- print_vdev_tree(NULL, newpool, config, 0, B_FALSE);
+ print_vdev_tree(NULL, newpool, config, 0, "",
+ flags.name_flags);
}
nvlist_free(config);
}
@@ -4526,15 +4732,6 @@ zpool_do_initialize(int argc, char **argv)
return (err);
}
-typedef struct status_cbdata {
- int cb_count;
- boolean_t cb_allpools;
- boolean_t cb_verbose;
- boolean_t cb_explain;
- boolean_t cb_first;
- boolean_t cb_dedup_stats;
-} status_cbdata_t;
-
/*
* Print out detailed scrub status.
*/
@@ -4895,8 +5092,8 @@ print_error_log(zpool_handle_t *zhp)
}
static void
-print_spares(zpool_handle_t *zhp, nvlist_t **spares, uint_t nspares,
- int namewidth)
+print_spares(zpool_handle_t *zhp, status_cbdata_t *cb, nvlist_t **spares,
+ uint_t nspares)
{
uint_t i;
char *name;
@@ -4907,16 +5104,16 @@ print_spares(zpool_handle_t *zhp, nvlist_t **spares, uint_t nspares,
(void) printf(gettext("\tspares\n"));
for (i = 0; i < nspares; i++) {
- name = zpool_vdev_name(g_zfs, zhp, spares[i], B_FALSE);
- print_status_config(zhp, name, spares[i],
- namewidth, 2, B_TRUE);
+ name = zpool_vdev_name(g_zfs, zhp, spares[i],
+ cb->cb_name_flags);
+ print_status_config(zhp, cb, name, spares[i], 2, B_TRUE);
free(name);
}
}
static void
-print_l2cache(zpool_handle_t *zhp, nvlist_t **l2cache, uint_t nl2cache,
- int namewidth)
+print_l2cache(zpool_handle_t *zhp, status_cbdata_t *cb, nvlist_t **l2cache,
+ uint_t nl2cache)
{
uint_t i;
char *name;
@@ -4927,9 +5124,9 @@ print_l2cache(zpool_handle_t *zhp, nvlist_t **l2cache, uint_t nl2cache,
(void) printf(gettext("\tcache\n"));
for (i = 0; i < nl2cache; i++) {
- name = zpool_vdev_name(g_zfs, zhp, l2cache[i], B_FALSE);
- print_status_config(zhp, name, l2cache[i],
- namewidth, 2, B_FALSE);
+ name = zpool_vdev_name(g_zfs, zhp, l2cache[i],
+ cb->cb_name_flags);
+ print_status_config(zhp, cb, name, l2cache[i], 2, B_FALSE);
free(name);
}
}
@@ -5245,7 +5442,6 @@ status_callback(zpool_handle_t *zhp, void *data)
msgid);
if (config != NULL) {
- int namewidth;
uint64_t nerr;
nvlist_t **spares, **l2cache;
uint_t nspares, nl2cache;
@@ -5265,25 +5461,30 @@ status_callback(zpool_handle_t *zhp, void *data)
print_removal_status(zhp, prs);
print_checkpoint_status(pcs);
- namewidth = max_width(zhp, nvroot, 0, 0);
- if (namewidth < 10)
- namewidth = 10;
+ cbp->cb_namewidth = max_width(zhp, nvroot, 0, 0,
+ cbp->cb_name_flags);
+ if (cbp->cb_namewidth < 10)
+ cbp->cb_namewidth = 10;
(void) printf(gettext("config:\n\n"));
- (void) printf(gettext("\t%-*s %-8s %5s %5s %5s\n"), namewidth,
- "NAME", "STATE", "READ", "WRITE", "CKSUM");
- print_status_config(zhp, zpool_get_name(zhp), nvroot,
- namewidth, 0, B_FALSE);
+ (void) printf(gettext("\t%-*s %-8s %5s %5s %5s\n"),
+ cbp->cb_namewidth, "NAME", "STATE", "READ", "WRITE",
+ "CKSUM");
+
+ print_status_config(zhp, cbp, zpool_get_name(zhp), nvroot, 0,
+ B_FALSE);
+
+ print_class_vdevs(zhp, cbp, nvroot, VDEV_ALLOC_BIAS_DEDUP);
+ print_class_vdevs(zhp, cbp, nvroot, VDEV_ALLOC_BIAS_SPECIAL);
+ print_class_vdevs(zhp, cbp, nvroot, VDEV_ALLOC_CLASS_LOGS);
- if (num_logs(nvroot) > 0)
- print_logs(zhp, nvroot, namewidth, B_TRUE);
if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE,
&l2cache, &nl2cache) == 0)
- print_l2cache(zhp, l2cache, nl2cache, namewidth);
+ print_l2cache(zhp, cbp, l2cache, nl2cache);
if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES,
&spares, &nspares) == 0)
- print_spares(zhp, spares, nspares, namewidth);
+ print_spares(zhp, cbp, spares, nspares);
if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRCOUNT,
&nerr) == 0) {
@@ -5331,8 +5532,11 @@ status_callback(zpool_handle_t *zhp, void *data)
}
/*
- * zpool status [-vx] [-T d|u] [pool] ... [interval [count]]
+ * zpool status [-gLPvx] [-T d|u] [pool] ... [interval [count]]
*
+ * -g Display guid for individual vdev name.
+ * -L Follow links when resolving vdev path name.
+ * -P Display full path for vdev name.
* -v Display complete error logs
* -x Display only pools with potential problems
* -D Display dedup status (undocumented)
@@ -5349,8 +5553,17 @@ zpool_do_status(int argc, char **argv)
status_cbdata_t cb = { 0 };
/* check options */
- while ((c = getopt(argc, argv, "vxDT:")) != -1) {
+ while ((c = getopt(argc, argv, "gLPvxDT:")) != -1) {
switch (c) {
+ case 'g':
+ cb.cb_name_flags |= VDEV_NAME_GUID;
+ break;
+ case 'L':
+ cb.cb_name_flags |= VDEV_NAME_FOLLOW_LINKS;
+ break;
+ case 'P':
+ cb.cb_name_flags |= VDEV_NAME_PATH;
+ break;
case 'v':
cb.cb_verbose = B_TRUE;
break;
@@ -5379,6 +5592,7 @@ zpool_do_status(int argc, char **argv)
cb.cb_allpools = B_TRUE;
cb.cb_first = B_TRUE;
+ cb.cb_print_status = B_TRUE;
for (;;) {
if (timestamp_fmt != NODATE)
diff --git a/cddl/contrib/opensolaris/cmd/zpool/zpool_vdev.c b/cddl/contrib/opensolaris/cmd/zpool/zpool_vdev.c
index f72e3f7fc97c..43d66d2263e0 100644
--- a/cddl/contrib/opensolaris/cmd/zpool/zpool_vdev.c
+++ b/cddl/contrib/opensolaris/cmd/zpool/zpool_vdev.c
@@ -21,7 +21,8 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2013, 2015 by Delphix. All rights reserved.
+ * Copyright (c) 2013, 2018 by Delphix. All rights reserved.
+ * Copyright (c) 2016, 2017 Intel Corporation.
* Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>.
*/
@@ -508,6 +509,9 @@ make_leaf_vdev(const char *arg, uint64_t is_log)
verify(nvlist_add_string(vdev, ZPOOL_CONFIG_PATH, path) == 0);
verify(nvlist_add_string(vdev, ZPOOL_CONFIG_TYPE, type) == 0);
verify(nvlist_add_uint64(vdev, ZPOOL_CONFIG_IS_LOG, is_log) == 0);
+ if (is_log)
+ verify(nvlist_add_string(vdev, ZPOOL_CONFIG_ALLOCATION_BIAS,
+ VDEV_ALLOC_BIAS_LOG) == 0);
if (strcmp(type, VDEV_TYPE_DISK) == 0)
verify(nvlist_add_uint64(vdev, ZPOOL_CONFIG_WHOLE_DISK,
(uint64_t)wholedisk) == 0);
@@ -564,6 +568,9 @@ make_leaf_vdev(const char *arg, uint64_t is_log)
*
* Otherwise, make sure that the current spec (if there is one) and the new
* spec have consistent replication levels.
+ *
+ * If there is no current spec (create), make sure new spec has at least
+ * one general purpose vdev.
*/
typedef struct replication_level {
char *zprl_type;
@@ -573,6 +580,19 @@ typedef struct replication_level {
#define ZPOOL_FUZZ (16 * 1024 * 1024)
+static boolean_t
+is_raidz_mirror(replication_level_t *a, replication_level_t *b,
+ replication_level_t **raidz, replication_level_t **mirror)
+{
+ if (strcmp(a->zprl_type, "raidz") == 0 &&
+ strcmp(b->zprl_type, "mirror") == 0) {
+ *raidz = a;
+ *mirror = b;
+ return (B_TRUE);
+ }
+ return (B_FALSE);
+}
+
/*
* Given a list of toplevel vdevs, return the current replication level. If
* the config is inconsistent, then NULL is returned. If 'fatal' is set, then
@@ -590,6 +610,7 @@ get_replication(nvlist_t *nvroot, boolean_t fatal)
replication_level_t lastrep = {0};
replication_level_t rep;
replication_level_t *ret;
+ replication_level_t *raidz, *mirror;
boolean_t dontreport;
ret = safe_malloc(sizeof (replication_level_t));
@@ -787,11 +808,39 @@ get_replication(nvlist_t *nvroot, boolean_t fatal)
/*
* At this point, we have the replication of the last toplevel
- * vdev in 'rep'. Compare it to 'lastrep' to see if its
+ * vdev in 'rep'. Compare it to 'lastrep' to see if it is
* different.
*/
if (lastrep.zprl_type != NULL) {
- if (strcmp(lastrep.zprl_type, rep.zprl_type) != 0) {
+ if (is_raidz_mirror(&lastrep, &rep, &raidz, &mirror) ||
+ is_raidz_mirror(&rep, &lastrep, &raidz, &mirror)) {
+ /*
+ * Accepted raidz and mirror when they can
+ * handle the same number of disk failures.
+ */
+ if (raidz->zprl_parity !=
+ mirror->zprl_children - 1) {
+ if (ret != NULL)
+ free(ret);
+ ret = NULL;
+ if (fatal)
+ vdev_error(gettext(
+ "mismatched replication "
+ "level: "
+ "%s and %s vdevs with "
+ "different redundancy, "
+ "%llu vs. %llu (%llu-way) "
+ "are present\n"),
+ raidz->zprl_type,
+ mirror->zprl_type,
+ raidz->zprl_parity,
+ mirror->zprl_children - 1,
+ mirror->zprl_children);
+ else
+ return (NULL);
+ }
+ } else if (strcmp(lastrep.zprl_type, rep.zprl_type) !=
+ 0) {
if (ret != NULL)
free(ret);
ret = NULL;
@@ -854,6 +903,7 @@ check_replication(nvlist_t *config, nvlist_t *newroot)
nvlist_t **child;
uint_t children;
replication_level_t *current = NULL, *new;
+ replication_level_t *raidz, *mirror;
int ret;
/*
@@ -901,7 +951,21 @@ check_replication(nvlist_t *config, nvlist_t *newroot)
*/
ret = 0;
if (current != NULL) {
- if (strcmp(current->zprl_type, new->zprl_type) != 0) {
+ if (is_raidz_mirror(current, new, &raidz, &mirror) ||
+ is_raidz_mirror(new, current, &raidz, &mirror)) {
+ if (raidz->zprl_parity != mirror->zprl_children - 1) {
+ vdev_error(gettext(
+ "mismatched replication level: pool and "
+ "new vdev with different redundancy, %s "
+ "and %s vdevs, %llu vs. %llu (%llu-way)\n"),
+ raidz->zprl_type,
+ mirror->zprl_type,
+ raidz->zprl_parity,
+ mirror->zprl_children - 1,
+ mirror->zprl_children);
+ ret = -1;
+ }
+ } else if (strcmp(current->zprl_type, new->zprl_type) != 0) {
vdev_error(gettext(
"mismatched replication level: pool uses %s "
"and new vdev is %s\n"),
@@ -1237,6 +1301,13 @@ is_grouping(const char *type, int *mindev, int *maxdev)
return (VDEV_TYPE_LOG);
}
+ if (strcmp(type, VDEV_ALLOC_BIAS_SPECIAL) == 0 ||
+ strcmp(type, VDEV_ALLOC_BIAS_DEDUP) == 0) {
+ if (mindev != NULL)
+ *mindev = 1;
+ return (type);
+ }
+
if (strcmp(type, "cache") == 0) {
if (mindev != NULL)
*mindev = 1;
@@ -1258,7 +1329,7 @@ construct_spec(int argc, char **argv)
nvlist_t *nvroot, *nv, **top, **spares, **l2cache;
int t, toplevels, mindev, maxdev, nspares, nlogs, nl2cache;
const char *type;
- uint64_t is_log;
+ uint64_t is_log, is_special, is_dedup;
boolean_t seen_logs;
top = NULL;
@@ -1268,7 +1339,7 @@ construct_spec(int argc, char **argv)
nspares = 0;
nlogs = 0;
nl2cache = 0;
- is_log = B_FALSE;
+ is_log = is_special = is_dedup = B_FALSE;
seen_logs = B_FALSE;
while (argc > 0) {
@@ -1290,7 +1361,7 @@ construct_spec(int argc, char **argv)
"specified only once\n"));
return (NULL);
}
- is_log = B_FALSE;
+ is_log = is_special = is_dedup = B_FALSE;
}
if (strcmp(type, VDEV_TYPE_LOG) == 0) {
@@ -1303,6 +1374,8 @@ construct_spec(int argc, char **argv)
}
seen_logs = B_TRUE;
is_log = B_TRUE;
+ is_special = B_FALSE;
+ is_dedup = B_FALSE;
argc--;
argv++;
/*
@@ -1312,6 +1385,24 @@ construct_spec(int argc, char **argv)
continue;
}
+ if (strcmp(type, VDEV_ALLOC_BIAS_SPECIAL) == 0) {
+ is_special = B_TRUE;
+ is_log = B_FALSE;
+ is_dedup = B_FALSE;
+ argc--;
+ argv++;
+ continue;
+ }
+
+ if (strcmp(type, VDEV_ALLOC_BIAS_DEDUP) == 0) {
+ is_dedup = B_TRUE;
+ is_log = B_FALSE;
+ is_special = B_FALSE;
+ argc--;
+ argv++;
+ continue;
+ }
+
if (strcmp(type, VDEV_TYPE_L2CACHE) == 0) {
if (l2cache != NULL) {
(void) fprintf(stderr,
@@ -1320,15 +1411,16 @@ construct_spec(int argc, char **argv)
"specified only once\n"));
return (NULL);
}
- is_log = B_FALSE;
+ is_log = is_special = is_dedup = B_FALSE;
}
- if (is_log) {
+ if (is_log || is_special || is_dedup) {
if (strcmp(type, VDEV_TYPE_MIRROR) != 0) {
(void) fprintf(stderr,
gettext("invalid vdev "
- "specification: unsupported 'log' "
- "device: %s\n"), type);
+ "specification: unsupported '%s' "
+ "device: %s\n"), is_log ? "log" :
+ "special", type);
return (NULL);
}
nlogs++;
@@ -1374,12 +1466,27 @@ construct_spec(int argc, char **argv)
nl2cache = children;
continue;
} else {
+ /* create a top-level vdev with children */
verify(nvlist_alloc(&nv, NV_UNIQUE_NAME,
0) == 0);
verify(nvlist_add_string(nv, ZPOOL_CONFIG_TYPE,
type) == 0);
verify(nvlist_add_uint64(nv,
ZPOOL_CONFIG_IS_LOG, is_log) == 0);
+ if (is_log)
+ verify(nvlist_add_string(nv,
+ ZPOOL_CONFIG_ALLOCATION_BIAS,
+ VDEV_ALLOC_BIAS_LOG) == 0);
+ if (is_special) {
+ verify(nvlist_add_string(nv,
+ ZPOOL_CONFIG_ALLOCATION_BIAS,
+ VDEV_ALLOC_BIAS_SPECIAL) == 0);
+ }
+ if (is_dedup) {
+ verify(nvlist_add_string(nv,
+ ZPOOL_CONFIG_ALLOCATION_BIAS,
+ VDEV_ALLOC_BIAS_DEDUP) == 0);
+ }
if (strcmp(type, VDEV_TYPE_RAIDZ) == 0) {
verify(nvlist_add_uint64(nv,
ZPOOL_CONFIG_NPARITY,
@@ -1402,6 +1509,16 @@ construct_spec(int argc, char **argv)
return (NULL);
if (is_log)
nlogs++;
+ if (is_special) {
+ verify(nvlist_add_string(nv,
+ ZPOOL_CONFIG_ALLOCATION_BIAS,
+ VDEV_ALLOC_BIAS_SPECIAL) == 0);
+ }
+ if (is_dedup) {
+ verify(nvlist_add_string(nv,
+ ZPOOL_CONFIG_ALLOCATION_BIAS,
+ VDEV_ALLOC_BIAS_DEDUP) == 0);
+ }
argc--;
argv++;
}
@@ -1513,6 +1630,30 @@ split_mirror_vdev(zpool_handle_t *zhp, char *newname, nvlist_t *props,
return (newroot);
}
+static int
+num_normal_vdevs(nvlist_t *nvroot)
+{
+ nvlist_t **top;
+ uint_t t, toplevels, normal = 0;
+
+ verify(nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN,
+ &top, &toplevels) == 0);
+
+ for (t = 0; t < toplevels; t++) {
+ uint64_t log = B_FALSE;
+
+ (void) nvlist_lookup_uint64(top[t], ZPOOL_CONFIG_IS_LOG, &log);
+ if (log)
+ continue;
+ if (nvlist_exists(top[t], ZPOOL_CONFIG_ALLOCATION_BIAS))
+ continue;
+
+ normal++;
+ }
+
+ return (normal);
+}
+
/*
* Get and validate the contents of the given vdev specification. This ensures
* that the nvlist returned is well-formed, that all the devices exist, and that
@@ -1566,6 +1707,16 @@ make_root_vdev(zpool_handle_t *zhp, int force, int check_rep,
#ifdef illumos
/*
+ * On pool create the new vdev spec must have one normal vdev.
+ */
+ if (poolconfig == NULL && num_normal_vdevs(newroot) == 0) {
+ vdev_error(gettext("at least one general top-level vdev must "
+ "be specified\n"));
+ nvlist_free(newroot);
+ return (NULL);
+ }
+
+ /*
* Run through the vdev specification and label any whole disks found.
*/
if (!dryrun && make_disks(zhp, newroot, boot_type, boot_size) != 0) {
diff --git a/cddl/contrib/opensolaris/cmd/ztest/ztest.c b/cddl/contrib/opensolaris/cmd/ztest/ztest.c
index 130f590595cc..be2f2cdd029f 100644
--- a/cddl/contrib/opensolaris/cmd/ztest/ztest.c
+++ b/cddl/contrib/opensolaris/cmd/ztest/ztest.c
@@ -20,12 +20,13 @@
*/
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2011, 2017 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2018 by Delphix. All rights reserved.
* Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2012 Martin Matuska <mm@FreeBSD.org>. All rights reserved.
* Copyright (c) 2013 Steven Hartland. All rights reserved.
* Copyright (c) 2014 Integros [integros.com]
* Copyright 2017 Joyent, Inc.
+ * Copyright (c) 2017, Intel Corporation.
* Copyright 2017 RackTop Systems.
*/
@@ -146,6 +147,12 @@ typedef struct ztest_shared_hdr {
static ztest_shared_hdr_t *ztest_shared_hdr;
+enum ztest_class_state {
+ ZTEST_VDEV_CLASS_OFF,
+ ZTEST_VDEV_CLASS_ON,
+ ZTEST_VDEV_CLASS_RND
+};
+
typedef struct ztest_shared_opts {
char zo_pool[ZFS_MAX_DATASET_NAME_LEN];
char zo_dir[ZFS_MAX_DATASET_NAME_LEN];
@@ -168,6 +175,7 @@ typedef struct ztest_shared_opts {
uint64_t zo_maxloops;
uint64_t zo_metaslab_force_ganging;
int zo_mmp_test;
+ int zo_special_vdevs;
} ztest_shared_opts_t;
static const ztest_shared_opts_t ztest_opts_defaults = {
@@ -190,7 +198,8 @@ static const ztest_shared_opts_t ztest_opts_defaults = {
.zo_init = 1,
.zo_time = 300, /* 5 minutes */
.zo_maxloops = 50, /* max loops during spa_freeze() */
- .zo_metaslab_force_ganging = 32 << 10
+ .zo_metaslab_force_ganging = 32 << 10,
+ .zo_special_vdevs = ZTEST_VDEV_CLASS_RND,
};
extern uint64_t metaslab_force_ganging;
@@ -352,6 +361,7 @@ ztest_func_t ztest_dsl_dataset_promote_busy;
ztest_func_t ztest_vdev_attach_detach;
ztest_func_t ztest_vdev_LUN_growth;
ztest_func_t ztest_vdev_add_remove;
+ztest_func_t ztest_vdev_class_add;
ztest_func_t ztest_vdev_aux_add_remove;
ztest_func_t ztest_split_pool;
ztest_func_t ztest_reguid;
@@ -401,6 +411,8 @@ ztest_info_t ztest_info[] = {
{ ztest_vdev_LUN_growth, 1, &zopt_rarely },
{ ztest_vdev_add_remove, 1,
&ztest_opts.zo_vdevtime },
+ { ztest_vdev_class_add, 1,
+ &ztest_opts.zo_vdevtime },
{ ztest_vdev_aux_add_remove, 1,
&ztest_opts.zo_vdevtime },
{ ztest_device_removal, 1, &zopt_sometimes },
@@ -613,6 +625,7 @@ usage(boolean_t requested)
"\t[-F freezeloops (default: %llu)] max loops in spa_freeze()\n"
"\t[-P passtime (default: %llu sec)] time per pass\n"
"\t[-B alt_ztest (default: <none>)] alternate ztest path\n"
+ "\t[-C vdev class state (default: random)] special=on|off|random\n"
"\t[-o variable=value] ... set global variable to an unsigned\n"
"\t 32-bit integer value\n"
"\t[-h] (print help)\n"
@@ -637,6 +650,46 @@ usage(boolean_t requested)
exit(requested ? 0 : 1);
}
+
+static void
+ztest_parse_name_value(const char *input, ztest_shared_opts_t *zo)
+{
+ char name[32];
+ char *value;
+ int state = ZTEST_VDEV_CLASS_RND;
+
+ (void) strlcpy(name, input, sizeof (name));
+
+ value = strchr(name, '=');
+ if (value == NULL) {
+ (void) fprintf(stderr, "missing value in property=value "
+ "'-C' argument (%s)\n", input);
+ usage(B_FALSE);
+ }
+ *(value) = '\0';
+ value++;
+
+ if (strcmp(value, "on") == 0) {
+ state = ZTEST_VDEV_CLASS_ON;
+ } else if (strcmp(value, "off") == 0) {
+ state = ZTEST_VDEV_CLASS_OFF;
+ } else if (strcmp(value, "random") == 0) {
+ state = ZTEST_VDEV_CLASS_RND;
+ } else {
+ (void) fprintf(stderr, "invalid property value '%s'\n", value);
+ usage(B_FALSE);
+ }
+
+ if (strcmp(name, "special") == 0) {
+ zo->zo_special_vdevs = state;
+ } else {
+ (void) fprintf(stderr, "invalid property name '%s'\n", name);
+ usage(B_FALSE);
+ }
+ if (zo->zo_verbose >= 3)
+ (void) printf("%s vdev state is '%s'\n", name, value);
+}
+
static void
process_options(int argc, char **argv)
{
@@ -650,7 +703,7 @@ process_options(int argc, char **argv)
bcopy(&ztest_opts_defaults, zo, sizeof (*zo));
while ((opt = getopt(argc, argv,
- "v:s:a:m:r:R:d:t:g:i:k:p:f:MVET:P:hF:B:o:")) != EOF) {
+ "v:s:a:m:r:R:d:t:g:i:k:p:f:MVET:P:hF:B:C:o:")) != EOF) {
value = 0;
switch (opt) {
case 'v':
@@ -740,6 +793,9 @@ process_options(int argc, char **argv)
case 'B':
(void) strlcpy(altdir, optarg, sizeof (altdir));
break;
+ case 'C':
+ ztest_parse_name_value(optarg, zo);
+ break;
case 'o':
if (set_global_var(optarg) != 0)
usage(B_FALSE);
@@ -962,13 +1018,16 @@ make_vdev_mirror(char *path, char *aux, char *pool, size_t size,
static nvlist_t *
make_vdev_root(char *path, char *aux, char *pool, size_t size, uint64_t ashift,
- int log, int r, int m, int t)
+ const char *class, int r, int m, int t)
{
nvlist_t *root, **child;
int c;
+ boolean_t log;
ASSERT(t > 0);
+ log = (class != NULL && strcmp(class, "log") == 0);
+
child = umem_alloc(t * sizeof (nvlist_t *), UMEM_NOFAIL);
for (c = 0; c < t; c++) {
@@ -976,6 +1035,12 @@ make_vdev_root(char *path, char *aux, char *pool, size_t size, uint64_t ashift,
r, m);
VERIFY(nvlist_add_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
log) == 0);
+
+ if (class != NULL && class[0] != '\0') {
+ ASSERT(m > 1 || log); /* expecting a mirror */
+ VERIFY(nvlist_add_string(child[c],
+ ZPOOL_CONFIG_ALLOCATION_BIAS, class) == 0);
+ }
}
VERIFY(nvlist_alloc(&root, NV_UNIQUE_NAME, 0) == 0);
@@ -1016,6 +1081,9 @@ static int
ztest_random_blocksize(void)
{
uint64_t block_shift;
+
+ ASSERT(ztest_spa->spa_max_ashift != 0);
+
/*
* Choose a block size >= the ashift.
* If the SPA supports new MAXBLOCKSIZE, test up to 1MB blocks.
@@ -2495,7 +2563,7 @@ ztest_spa_create_destroy(ztest_ds_t *zd, uint64_t id)
/*
* Attempt to create using a bad file.
*/
- nvroot = make_vdev_root("/dev/bogus", NULL, NULL, 0, 0, 0, 0, 0, 1);
+ nvroot = make_vdev_root("/dev/bogus", NULL, NULL, 0, 0, NULL, 0, 0, 1);
VERIFY3U(ENOENT, ==,
spa_create("ztest_bad_file", nvroot, NULL, NULL));
nvlist_free(nvroot);
@@ -2503,7 +2571,7 @@ ztest_spa_create_destroy(ztest_ds_t *zd, uint64_t id)
/*
* Attempt to create using a bad mirror.
*/
- nvroot = make_vdev_root("/dev/bogus", NULL, NULL, 0, 0, 0, 0, 2, 1);
+ nvroot = make_vdev_root("/dev/bogus", NULL, NULL, 0, 0, NULL, 0, 2, 1);
VERIFY3U(ENOENT, ==,
spa_create("ztest_bad_mirror", nvroot, NULL, NULL));
nvlist_free(nvroot);
@@ -2513,7 +2581,7 @@ ztest_spa_create_destroy(ztest_ds_t *zd, uint64_t id)
* what's in the nvroot; we should fail with EEXIST.
*/
rw_enter(&ztest_name_lock, RW_READER);
- nvroot = make_vdev_root("/dev/bogus", NULL, NULL, 0, 0, 0, 0, 0, 1);
+ nvroot = make_vdev_root("/dev/bogus", NULL, NULL, 0, 0, NULL, 0, 0, 1);
VERIFY3U(EEXIST, ==, spa_create(zo->zo_pool, nvroot, NULL, NULL));
nvlist_free(nvroot);
VERIFY3U(0, ==, spa_open(zo->zo_pool, &spa, FTAG));
@@ -2595,7 +2663,7 @@ ztest_spa_upgrade(ztest_ds_t *zd, uint64_t id)
(void) spa_destroy(name);
nvroot = make_vdev_root(NULL, NULL, name, ztest_opts.zo_vdev_size, 0,
- 0, ztest_opts.zo_raidz, ztest_opts.zo_mirrors, 1);
+ NULL, ztest_opts.zo_raidz, ztest_opts.zo_mirrors, 1);
/*
* If we're configuring a RAIDZ device then make sure that the
@@ -2768,10 +2836,16 @@ ztest_vdev_add_remove(ztest_ds_t *zd, uint64_t id)
* If we have slogs then remove them 1/4 of the time.
*/
if (spa_has_slogs(spa) && ztest_random(4) == 0) {
+ metaslab_group_t *mg;
+
/*
- * Grab the guid from the head of the log class rotor.
+ * find the first real slog in log allocation class
*/
- guid = spa_log_class(spa)->mc_rotor->mg_vd->vdev_guid;
+ mg = spa_log_class(spa)->mc_rotor;
+ while (!mg->mg_vd->vdev_islog)
+ mg = mg->mg_next;
+
+ guid = mg->mg_vd->vdev_guid;
spa_config_exit(spa, SCL_VDEV, FTAG);
@@ -2800,12 +2874,11 @@ ztest_vdev_add_remove(ztest_ds_t *zd, uint64_t id)
spa_config_exit(spa, SCL_VDEV, FTAG);
/*
- * Make 1/4 of the devices be log devices.
+ * Make 1/4 of the devices be log devices
*/
nvroot = make_vdev_root(NULL, NULL, NULL,
- ztest_opts.zo_vdev_size, 0,
- ztest_random(4) == 0, ztest_opts.zo_raidz,
- zs->zs_mirrors, 1);
+ ztest_opts.zo_vdev_size, 0, (ztest_random(4) == 0) ?
+ "log" : NULL, ztest_opts.zo_raidz, zs->zs_mirrors, 1);
error = spa_vdev_add(spa, nvroot);
nvlist_free(nvroot);
@@ -2824,6 +2897,83 @@ ztest_vdev_add_remove(ztest_ds_t *zd, uint64_t id)
mutex_exit(&ztest_vdev_lock);
}
+/* ARGSUSED */
+void
+ztest_vdev_class_add(ztest_ds_t *zd, uint64_t id)
+{
+ ztest_shared_t *zs = ztest_shared;
+ spa_t *spa = ztest_spa;
+ uint64_t leaves;
+ nvlist_t *nvroot;
+ const char *class = (ztest_random(2) == 0) ?
+ VDEV_ALLOC_BIAS_SPECIAL : VDEV_ALLOC_BIAS_DEDUP;
+ int error;
+
+ /*
+ * By default add a special vdev 50% of the time
+ */
+ if ((ztest_opts.zo_special_vdevs == ZTEST_VDEV_CLASS_OFF) ||
+ (ztest_opts.zo_special_vdevs == ZTEST_VDEV_CLASS_RND &&
+ ztest_random(2) == 0)) {
+ return;
+ }
+
+ mutex_enter(&ztest_vdev_lock);
+
+ /* Only test with mirrors */
+ if (zs->zs_mirrors < 2) {
+ mutex_exit(&ztest_vdev_lock);
+ return;
+ }
+
+ /* requires feature@allocation_classes */
+ if (!spa_feature_is_enabled(spa, SPA_FEATURE_ALLOCATION_CLASSES)) {
+ mutex_exit(&ztest_vdev_lock);
+ return;
+ }
+
+ leaves = MAX(zs->zs_mirrors + zs->zs_splits, 1) * ztest_opts.zo_raidz;
+
+ spa_config_enter(spa, SCL_VDEV, FTAG, RW_READER);
+ ztest_shared->zs_vdev_next_leaf = find_vdev_hole(spa) * leaves;
+ spa_config_exit(spa, SCL_VDEV, FTAG);
+
+ nvroot = make_vdev_root(NULL, NULL, NULL, ztest_opts.zo_vdev_size, 0,
+ class, ztest_opts.zo_raidz, zs->zs_mirrors, 1);
+
+ error = spa_vdev_add(spa, nvroot);
+ nvlist_free(nvroot);
+
+ if (error == ENOSPC)
+ ztest_record_enospc("spa_vdev_add");
+ else if (error != 0)
+ fatal(0, "spa_vdev_add() = %d", error);
+
+ /*
+ * 50% of the time allow small blocks in the special class
+ */
+ if (error == 0 &&
+ spa_special_class(spa)->mc_groups == 1 && ztest_random(2) == 0) {
+ if (ztest_opts.zo_verbose >= 3)
+ (void) printf("Enabling special VDEV small blocks\n");
+ (void) ztest_dsl_prop_set_uint64(zd->zd_name,
+ ZFS_PROP_SPECIAL_SMALL_BLOCKS, 32768, B_FALSE);
+ }
+
+ mutex_exit(&ztest_vdev_lock);
+
+ if (ztest_opts.zo_verbose >= 3) {
+ metaslab_class_t *mc;
+
+ if (strcmp(class, VDEV_ALLOC_BIAS_SPECIAL) == 0)
+ mc = spa_special_class(spa);
+ else
+ mc = spa_dedup_class(spa);
+ (void) printf("Added a %s mirrored vdev (of %d)\n",
+ class, (int)mc->mc_groups);
+ }
+}
+
/*
* Verify that adding/removing aux devices (l2arc, hot spare) works as expected.
*/
@@ -2888,7 +3038,7 @@ ztest_vdev_aux_add_remove(ztest_ds_t *zd, uint64_t id)
* Add a new device.
*/
nvlist_t *nvroot = make_vdev_root(NULL, aux, NULL,
- (ztest_opts.zo_vdev_size * 5) / 4, 0, 0, 0, 0, 1);
+ (ztest_opts.zo_vdev_size * 5) / 4, 0, NULL, 0, 0, 1);
error = spa_vdev_add(spa, nvroot);
switch (error) {
@@ -3085,11 +3235,15 @@ ztest_vdev_attach_detach(ztest_ds_t *zd, uint64_t id)
* Locate this vdev.
*/
oldvd = rvd->vdev_child[top];
+
+ /* pick a child from the mirror */
if (zs->zs_mirrors >= 1) {
ASSERT(oldvd->vdev_ops == &vdev_mirror_ops);
ASSERT(oldvd->vdev_children >= zs->zs_mirrors);
oldvd = oldvd->vdev_child[leaf / ztest_opts.zo_raidz];
}
+
+ /* pick a child out of the raidz group */
if (ztest_opts.zo_raidz > 1) {
ASSERT(oldvd->vdev_ops == &vdev_raidz_ops);
ASSERT(oldvd->vdev_children == ztest_opts.zo_raidz);
@@ -3192,7 +3346,7 @@ ztest_vdev_attach_detach(ztest_ds_t *zd, uint64_t id)
* Build the nvlist describing newpath.
*/
root = make_vdev_root(newpath, NULL, NULL, newvd == NULL ? newsize : 0,
- ashift, 0, 0, 0, 1);
+ ashift, NULL, 0, 0, 1);
error = spa_vdev_attach(spa, oldguid, root, replacing);
@@ -3453,7 +3607,7 @@ ztest_vdev_LUN_growth(ztest_ds_t *zd, uint64_t id)
return;
}
ASSERT(psize > 0);
- newsize = psize + psize / 8;
+ newsize = psize + MAX(psize / 8, SPA_MAXBLOCKSIZE);
ASSERT3U(newsize, >, psize);
if (ztest_opts.zo_verbose >= 6) {
@@ -6470,6 +6624,7 @@ make_random_props()
nvlist_t *props;
VERIFY(nvlist_alloc(&props, NV_UNIQUE_NAME, 0) == 0);
+
if (ztest_random(2) == 0)
return (props);
VERIFY(nvlist_add_uint64(props, "autoreplace", 1) == 0);
@@ -6551,7 +6706,7 @@ ztest_init(ztest_shared_t *zs)
zs->zs_splits = 0;
zs->zs_mirrors = ztest_opts.zo_mirrors;
nvroot = make_vdev_root(NULL, NULL, NULL, ztest_opts.zo_vdev_size, 0,
- 0, ztest_opts.zo_raidz, zs->zs_mirrors, 1);
+ NULL, ztest_opts.zo_raidz, zs->zs_mirrors, 1);
props = make_random_props();
for (int i = 0; i < SPA_FEATURES; i++) {
char buf[1024];