Add zpool properties for allocation class space

The existing zpool properties accounting pool space (size, allocated,
fragmentation, expandsize, free, capacity) are based on the normal
metaslab class or are cumulative properties of several classes combined.

Add properties reporting the space accounting metrics for each metaslab
class individually.

Also introduce pool-wide AVAIL, USABLE, and USED properties reporting
values corresponding to FREE, SIZE, and ALLOC deflated for raidz.

Update ZTS to recognize the new properties and validate reported values.

While in zpool_get_parsable.cfg, add "fragmentation" to the list of
parsable properties.

Sponsored-by: Klara, Inc.
Reviewed-by: Alexander Motin <alexander.motin@TrueNAS.com>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Reviewed-by: Ameer Hamza <ahamza@ixsystems.com>
Signed-off-by: Ryan Moeller <ryan.moeller@klarasystems.com>
Cloes #18238
This commit is contained in:
Ryan Moeller 2026-02-18 11:54:13 -05:00 committed by Brian Behlendorf
parent 6ba3f915d0
commit ac0fd40c8c
14 changed files with 1047 additions and 36 deletions

View File

@ -6960,7 +6960,19 @@ collect_vdev_prop(zpool_prop_t prop, uint64_t value, const char *str,
switch (prop) {
case ZPOOL_PROP_SIZE:
case ZPOOL_PROP_NORMAL_SIZE:
case ZPOOL_PROP_SPECIAL_SIZE:
case ZPOOL_PROP_DEDUP_SIZE:
case ZPOOL_PROP_LOG_SIZE:
case ZPOOL_PROP_ELOG_SIZE:
case ZPOOL_PROP_SELOG_SIZE:
case ZPOOL_PROP_EXPANDSZ:
case ZPOOL_PROP_NORMAL_EXPANDSZ:
case ZPOOL_PROP_SPECIAL_EXPANDSZ:
case ZPOOL_PROP_DEDUP_EXPANDSZ:
case ZPOOL_PROP_LOG_EXPANDSZ:
case ZPOOL_PROP_ELOG_EXPANDSZ:
case ZPOOL_PROP_SELOG_EXPANDSZ:
case ZPOOL_PROP_CHECKPOINT:
case ZPOOL_PROP_DEDUPRATIO:
case ZPOOL_PROP_DEDUPCACHED:
@ -6971,6 +6983,12 @@ collect_vdev_prop(zpool_prop_t prop, uint64_t value, const char *str,
format);
break;
case ZPOOL_PROP_FRAGMENTATION:
case ZPOOL_PROP_NORMAL_FRAGMENTATION:
case ZPOOL_PROP_SPECIAL_FRAGMENTATION:
case ZPOOL_PROP_DEDUP_FRAGMENTATION:
case ZPOOL_PROP_LOG_FRAGMENTATION:
case ZPOOL_PROP_ELOG_FRAGMENTATION:
case ZPOOL_PROP_SELOG_FRAGMENTATION:
if (value == ZFS_FRAG_INVALID) {
(void) strlcpy(propval, "-", sizeof (propval));
} else if (format == ZFS_NICENUM_RAW) {
@ -6982,6 +7000,12 @@ collect_vdev_prop(zpool_prop_t prop, uint64_t value, const char *str,
}
break;
case ZPOOL_PROP_CAPACITY:
case ZPOOL_PROP_NORMAL_CAPACITY:
case ZPOOL_PROP_SPECIAL_CAPACITY:
case ZPOOL_PROP_DEDUP_CAPACITY:
case ZPOOL_PROP_LOG_CAPACITY:
case ZPOOL_PROP_ELOG_CAPACITY:
case ZPOOL_PROP_SELOG_CAPACITY:
/* capacity value is in parts-per-10,000 (aka permyriad) */
if (format == ZFS_NICENUM_RAW)
(void) snprintf(propval, sizeof (propval), "%llu",

View File

@ -275,9 +275,90 @@ typedef enum {
ZPOOL_PROP_LAST_SCRUBBED_TXG,
ZPOOL_PROP_DEDUPUSED,
ZPOOL_PROP_DEDUPSAVED,
ZPOOL_PROP_AVAILABLE,
ZPOOL_PROP_USABLE,
ZPOOL_PROP_USED,
ZPOOL_PROP_NORMAL_SIZE,
ZPOOL_PROP_NORMAL_CAPACITY,
ZPOOL_PROP_NORMAL_FREE,
ZPOOL_PROP_NORMAL_ALLOCATED,
ZPOOL_PROP_NORMAL_AVAILABLE,
ZPOOL_PROP_NORMAL_USABLE,
ZPOOL_PROP_NORMAL_USED,
ZPOOL_PROP_NORMAL_EXPANDSZ,
ZPOOL_PROP_NORMAL_FRAGMENTATION,
ZPOOL_PROP_SPECIAL_SIZE,
ZPOOL_PROP_SPECIAL_CAPACITY,
ZPOOL_PROP_SPECIAL_FREE,
ZPOOL_PROP_SPECIAL_ALLOCATED,
ZPOOL_PROP_SPECIAL_AVAILABLE,
ZPOOL_PROP_SPECIAL_USABLE,
ZPOOL_PROP_SPECIAL_USED,
ZPOOL_PROP_SPECIAL_EXPANDSZ,
ZPOOL_PROP_SPECIAL_FRAGMENTATION,
ZPOOL_PROP_DEDUP_SIZE,
ZPOOL_PROP_DEDUP_CAPACITY,
ZPOOL_PROP_DEDUP_FREE,
ZPOOL_PROP_DEDUP_ALLOCATED,
ZPOOL_PROP_DEDUP_AVAILABLE,
ZPOOL_PROP_DEDUP_USABLE,
ZPOOL_PROP_DEDUP_USED,
ZPOOL_PROP_DEDUP_EXPANDSZ,
ZPOOL_PROP_DEDUP_FRAGMENTATION,
ZPOOL_PROP_LOG_SIZE,
ZPOOL_PROP_LOG_CAPACITY,
ZPOOL_PROP_LOG_FREE,
ZPOOL_PROP_LOG_ALLOCATED,
ZPOOL_PROP_LOG_AVAILABLE,
ZPOOL_PROP_LOG_USABLE,
ZPOOL_PROP_LOG_USED,
ZPOOL_PROP_LOG_EXPANDSZ,
ZPOOL_PROP_LOG_FRAGMENTATION,
ZPOOL_PROP_ELOG_SIZE,
ZPOOL_PROP_ELOG_CAPACITY,
ZPOOL_PROP_ELOG_FREE,
ZPOOL_PROP_ELOG_ALLOCATED,
ZPOOL_PROP_ELOG_AVAILABLE,
ZPOOL_PROP_ELOG_USABLE,
ZPOOL_PROP_ELOG_USED,
ZPOOL_PROP_ELOG_EXPANDSZ,
ZPOOL_PROP_ELOG_FRAGMENTATION,
ZPOOL_PROP_SELOG_SIZE,
ZPOOL_PROP_SELOG_CAPACITY,
ZPOOL_PROP_SELOG_FREE,
ZPOOL_PROP_SELOG_ALLOCATED,
ZPOOL_PROP_SELOG_AVAILABLE,
ZPOOL_PROP_SELOG_USABLE,
ZPOOL_PROP_SELOG_USED,
ZPOOL_PROP_SELOG_EXPANDSZ,
ZPOOL_PROP_SELOG_FRAGMENTATION,
ZPOOL_NUM_PROPS
} zpool_prop_t;
/* Offsets for metaslab class properties. */
typedef enum {
ZPOOL_MC_PROP_SIZE,
ZPOOL_MC_PROP_CAPACITY,
ZPOOL_MC_PROP_FREE,
ZPOOL_MC_PROP_ALLOCATED,
ZPOOL_MC_PROP_AVAILABLE,
ZPOOL_MC_PROP_USABLE,
ZPOOL_MC_PROP_USED,
ZPOOL_MC_PROP_EXPANDSZ,
ZPOOL_MC_PROP_FRAGMENTATION,
ZPOOL_NUM_MC_PROPS
} zpool_mc_prop_t;
/* Offsets for metaslab class property groups. */
typedef enum {
ZPOOL_MC_PROPS_NORMAL = ZPOOL_PROP_NORMAL_SIZE,
ZPOOL_MC_PROPS_SPECIAL = ZPOOL_PROP_SPECIAL_SIZE,
ZPOOL_MC_PROPS_DEDUP = ZPOOL_PROP_DEDUP_SIZE,
ZPOOL_MC_PROPS_LOG = ZPOOL_PROP_LOG_SIZE,
ZPOOL_MC_PROPS_ELOG = ZPOOL_PROP_ELOG_SIZE,
ZPOOL_MC_PROPS_SELOG = ZPOOL_PROP_SELOG_SIZE,
} zpool_mc_props_t;
/* Small enough to not hog a whole line of printout in zpool(8). */
#define ZPROP_MAX_COMMENT 32
#define ZPROP_BOOLEAN_NA 2

View File

@ -3372,7 +3372,64 @@
<enumerator name='ZPOOL_PROP_LAST_SCRUBBED_TXG' value='39'/>
<enumerator name='ZPOOL_PROP_DEDUPUSED' value='40'/>
<enumerator name='ZPOOL_PROP_DEDUPSAVED' value='41'/>
<enumerator name='ZPOOL_NUM_PROPS' value='42'/>
<enumerator name='ZPOOL_PROP_AVAILABLE' value='42'/>
<enumerator name='ZPOOL_PROP_USABLE' value='43'/>
<enumerator name='ZPOOL_PROP_USED' value='44'/>
<enumerator name='ZPOOL_PROP_NORMAL_SIZE' value='45'/>
<enumerator name='ZPOOL_PROP_NORMAL_CAPACITY' value='46'/>
<enumerator name='ZPOOL_PROP_NORMAL_FREE' value='47'/>
<enumerator name='ZPOOL_PROP_NORMAL_ALLOCATED' value='48'/>
<enumerator name='ZPOOL_PROP_NORMAL_AVAILABLE' value='49'/>
<enumerator name='ZPOOL_PROP_NORMAL_USABLE' value='50'/>
<enumerator name='ZPOOL_PROP_NORMAL_USED' value='51'/>
<enumerator name='ZPOOL_PROP_NORMAL_EXPANDSZ' value='52'/>
<enumerator name='ZPOOL_PROP_NORMAL_FRAGMENTATION' value='53'/>
<enumerator name='ZPOOL_PROP_SPECIAL_SIZE' value='54'/>
<enumerator name='ZPOOL_PROP_SPECIAL_CAPACITY' value='55'/>
<enumerator name='ZPOOL_PROP_SPECIAL_FREE' value='56'/>
<enumerator name='ZPOOL_PROP_SPECIAL_ALLOCATED' value='57'/>
<enumerator name='ZPOOL_PROP_SPECIAL_AVAILABLE' value='58'/>
<enumerator name='ZPOOL_PROP_SPECIAL_USABLE' value='59'/>
<enumerator name='ZPOOL_PROP_SPECIAL_USED' value='60'/>
<enumerator name='ZPOOL_PROP_SPECIAL_EXPANDSZ' value='61'/>
<enumerator name='ZPOOL_PROP_SPECIAL_FRAGMENTATION' value='62'/>
<enumerator name='ZPOOL_PROP_DEDUP_SIZE' value='63'/>
<enumerator name='ZPOOL_PROP_DEDUP_CAPACITY' value='64'/>
<enumerator name='ZPOOL_PROP_DEDUP_FREE' value='65'/>
<enumerator name='ZPOOL_PROP_DEDUP_ALLOCATED' value='66'/>
<enumerator name='ZPOOL_PROP_DEDUP_AVAILABLE' value='67'/>
<enumerator name='ZPOOL_PROP_DEDUP_USABLE' value='68'/>
<enumerator name='ZPOOL_PROP_DEDUP_USED' value='69'/>
<enumerator name='ZPOOL_PROP_DEDUP_EXPANDSZ' value='70'/>
<enumerator name='ZPOOL_PROP_DEDUP_FRAGMENTATION' value='71'/>
<enumerator name='ZPOOL_PROP_LOG_SIZE' value='72'/>
<enumerator name='ZPOOL_PROP_LOG_CAPACITY' value='73'/>
<enumerator name='ZPOOL_PROP_LOG_FREE' value='74'/>
<enumerator name='ZPOOL_PROP_LOG_ALLOCATED' value='75'/>
<enumerator name='ZPOOL_PROP_LOG_AVAILABLE' value='76'/>
<enumerator name='ZPOOL_PROP_LOG_USABLE' value='77'/>
<enumerator name='ZPOOL_PROP_LOG_USED' value='78'/>
<enumerator name='ZPOOL_PROP_LOG_EXPANDSZ' value='79'/>
<enumerator name='ZPOOL_PROP_LOG_FRAGMENTATION' value='80'/>
<enumerator name='ZPOOL_PROP_ELOG_SIZE' value='81'/>
<enumerator name='ZPOOL_PROP_ELOG_CAPACITY' value='82'/>
<enumerator name='ZPOOL_PROP_ELOG_FREE' value='83'/>
<enumerator name='ZPOOL_PROP_ELOG_ALLOCATED' value='84'/>
<enumerator name='ZPOOL_PROP_ELOG_AVAILABLE' value='85'/>
<enumerator name='ZPOOL_PROP_ELOG_USABLE' value='86'/>
<enumerator name='ZPOOL_PROP_ELOG_USED' value='87'/>
<enumerator name='ZPOOL_PROP_ELOG_EXPANDSZ' value='88'/>
<enumerator name='ZPOOL_PROP_ELOG_FRAGMENTATION' value='89'/>
<enumerator name='ZPOOL_PROP_SELOG_SIZE' value='90'/>
<enumerator name='ZPOOL_PROP_SELOG_CAPACITY' value='91'/>
<enumerator name='ZPOOL_PROP_SELOG_FREE' value='92'/>
<enumerator name='ZPOOL_PROP_SELOG_ALLOCATED' value='93'/>
<enumerator name='ZPOOL_PROP_SELOG_AVAILABLE' value='94'/>
<enumerator name='ZPOOL_PROP_SELOG_USABLE' value='95'/>
<enumerator name='ZPOOL_PROP_SELOG_USED' value='96'/>
<enumerator name='ZPOOL_PROP_SELOG_EXPANDSZ' value='97'/>
<enumerator name='ZPOOL_PROP_SELOG_FRAGMENTATION' value='98'/>
<enumerator name='ZPOOL_NUM_PROPS' value='99'/>
</enum-decl>
<typedef-decl name='zpool_prop_t' type-id='af1ba157' id='5d0c23fb'/>
<typedef-decl name='regoff_t' type-id='95e97e5e' id='54a2a2a8'/>

View File

@ -370,8 +370,47 @@ zpool_get_prop(zpool_handle_t *zhp, zpool_prop_t prop, char *buf,
zfs_fallthrough;
case ZPOOL_PROP_SIZE:
case ZPOOL_PROP_NORMAL_SIZE:
case ZPOOL_PROP_SPECIAL_SIZE:
case ZPOOL_PROP_DEDUP_SIZE:
case ZPOOL_PROP_LOG_SIZE:
case ZPOOL_PROP_ELOG_SIZE:
case ZPOOL_PROP_SELOG_SIZE:
case ZPOOL_PROP_ALLOCATED:
case ZPOOL_PROP_NORMAL_ALLOCATED:
case ZPOOL_PROP_SPECIAL_ALLOCATED:
case ZPOOL_PROP_DEDUP_ALLOCATED:
case ZPOOL_PROP_LOG_ALLOCATED:
case ZPOOL_PROP_ELOG_ALLOCATED:
case ZPOOL_PROP_SELOG_ALLOCATED:
case ZPOOL_PROP_AVAILABLE:
case ZPOOL_PROP_NORMAL_AVAILABLE:
case ZPOOL_PROP_SPECIAL_AVAILABLE:
case ZPOOL_PROP_DEDUP_AVAILABLE:
case ZPOOL_PROP_LOG_AVAILABLE:
case ZPOOL_PROP_ELOG_AVAILABLE:
case ZPOOL_PROP_SELOG_AVAILABLE:
case ZPOOL_PROP_FREE:
case ZPOOL_PROP_NORMAL_FREE:
case ZPOOL_PROP_SPECIAL_FREE:
case ZPOOL_PROP_DEDUP_FREE:
case ZPOOL_PROP_LOG_FREE:
case ZPOOL_PROP_ELOG_FREE:
case ZPOOL_PROP_SELOG_FREE:
case ZPOOL_PROP_USABLE:
case ZPOOL_PROP_NORMAL_USABLE:
case ZPOOL_PROP_SPECIAL_USABLE:
case ZPOOL_PROP_DEDUP_USABLE:
case ZPOOL_PROP_LOG_USABLE:
case ZPOOL_PROP_ELOG_USABLE:
case ZPOOL_PROP_SELOG_USABLE:
case ZPOOL_PROP_USED:
case ZPOOL_PROP_NORMAL_USED:
case ZPOOL_PROP_SPECIAL_USED:
case ZPOOL_PROP_DEDUP_USED:
case ZPOOL_PROP_LOG_USED:
case ZPOOL_PROP_ELOG_USED:
case ZPOOL_PROP_SELOG_USED:
case ZPOOL_PROP_FREEING:
case ZPOOL_PROP_LEAKED:
case ZPOOL_PROP_ASHIFT:
@ -391,6 +430,12 @@ zpool_get_prop(zpool_handle_t *zhp, zpool_prop_t prop, char *buf,
break;
case ZPOOL_PROP_EXPANDSZ:
case ZPOOL_PROP_NORMAL_EXPANDSZ:
case ZPOOL_PROP_SPECIAL_EXPANDSZ:
case ZPOOL_PROP_DEDUP_EXPANDSZ:
case ZPOOL_PROP_LOG_EXPANDSZ:
case ZPOOL_PROP_ELOG_EXPANDSZ:
case ZPOOL_PROP_SELOG_EXPANDSZ:
case ZPOOL_PROP_CHECKPOINT:
if (intval == 0) {
(void) strlcpy(buf, "-", len);
@ -403,6 +448,12 @@ zpool_get_prop(zpool_handle_t *zhp, zpool_prop_t prop, char *buf,
break;
case ZPOOL_PROP_CAPACITY:
case ZPOOL_PROP_NORMAL_CAPACITY:
case ZPOOL_PROP_SPECIAL_CAPACITY:
case ZPOOL_PROP_DEDUP_CAPACITY:
case ZPOOL_PROP_LOG_CAPACITY:
case ZPOOL_PROP_ELOG_CAPACITY:
case ZPOOL_PROP_SELOG_CAPACITY:
if (literal) {
(void) snprintf(buf, len, "%llu",
(u_longlong_t)intval);
@ -413,7 +464,13 @@ zpool_get_prop(zpool_handle_t *zhp, zpool_prop_t prop, char *buf,
break;
case ZPOOL_PROP_FRAGMENTATION:
if (intval == UINT64_MAX) {
case ZPOOL_PROP_NORMAL_FRAGMENTATION:
case ZPOOL_PROP_SPECIAL_FRAGMENTATION:
case ZPOOL_PROP_DEDUP_FRAGMENTATION:
case ZPOOL_PROP_LOG_FRAGMENTATION:
case ZPOOL_PROP_ELOG_FRAGMENTATION:
case ZPOOL_PROP_SELOG_FRAGMENTATION:
if (intval == ZFS_FRAG_INVALID) {
(void) strlcpy(buf, "-", len);
} else if (literal) {
(void) snprintf(buf, len, "%llu",

View File

@ -27,9 +27,9 @@
.\" Copyright 2017 Nexenta Systems, Inc.
.\" Copyright (c) 2017 Open-E, Inc. All Rights Reserved.
.\" Copyright (c) 2021, Colm Buckley <colm@tuatha.org>
.\" Copyright (c) 2023, Klara Inc.
.\" Copyright (c) 2023, 2026, Klara Inc.
.\"
.Dd December 4, 2024
.Dd March 2, 2026
.Dt ZPOOLPROPS 7
.Os
.
@ -49,7 +49,7 @@ For more information about user properties, see the
section.
.Pp
The following are read-only properties:
.Bl -tag -width "unsupported@guid"
.Bl -tag -width "last_scrubbed_txg"
.It Sy allocated
Amount of storage used within the pool.
See
@ -57,6 +57,21 @@ See
and
.Sy free
for more information.
.It Sy available
The amount of free space available in the pool, adjusted for raidz parity
overhead.
The
.Sy available
property is calculated as:
.Pp
.Sy usable - used
.Pp
See
.Sy usable ,
.Sy used ,
and
.Sy free
for more information.
.It Sy bcloneratio
The ratio of the total amount of storage that would be required to store all
the cloned blocks without cloning to the actual storage used.
@ -184,6 +199,21 @@ Information about unsupported features that are enabled on the pool.
See
.Xr zpool-features 7
for details.
.It Sy usable
Estimate of total storage pool size, adjusted for raidz parity overhead.
The adjustment assumes a fixed 128KiB record size to compute a data-to-parity
ratio.
.Sy usable
is a heuristic for allocation and should not be interpreted as an exact measure
of usable space.
.It Sy used
Estimate of storage used within the storage pool, adjusted for raidz parity
overhead.
The adjustment assumes a fixed 128KiB record size to compute a data-to-parity
ratio.
.Sy used
is a heuristic for allocation and should not be interpreted as an exact measure
of used space.
.El
.Pp
The space usage properties report actual physical space available to the
@ -201,6 +231,121 @@ For non-full pools of a reasonable size, these effects should be invisible.
For small pools, or pools that are close to being completely full, these
discrepancies may become more noticeable.
.Pp
The following properties are read-only metrics for allocation classes:
.Bl -ohang
.It Xo Sy class_dedup_allocated , class_dedup_available , class_dedup_capacity ,
.Sy class_dedup_expandsize , class_dedup_fragmentation , class_dedup_free ,
.Sy class_dedup_size , class_dedup_usable , class_dedup_used
.Xc
.Bd -ragged -offset Ds -compact
Space usage properties of the pool's
.Sy dedup
metaslab allocator class.
.Ed
.It Xo Sy class_elog_allocated , class_elog_available , class_elog_capacity ,
.Sy class_elog_expandsize , class_elog_fragmentation , class_elog_free ,
.Sy class_elog_size , class_elog_usable , class_elog_used
.Xc
.Bd -ragged -offset Ds -compact
Space usage properties of the pool's
.Sy embedded_log
metaslab allocator class.
.Ed
.It Xo Sy class_log_allocated , class_log_available , class_log_capacity ,
.Sy class_log_expandsize , class_log_fragmentation , class_log_free ,
.Sy class_log_size , class_log_usable , class_log_used
.Xc
.Bd -ragged -offset Ds -compact
Space usage properties of the pool's
.Sy log
metaslab allocator class.
.Ed
.It Xo Sy class_normal_allocated , class_normal_available ,
.Sy class_normal_capacity , class_normal_expandsize ,
.Sy class_normal_fragmentation , class_normal_free , class_normal_size ,
.Sy class_normal_usable , class_normal_used
.Xc
.Bd -ragged -offset Ds -compact
Space usage properties of the pool's
.Sy normal
metaslab allocator class.
.Ed
.It Xo Sy class_special_allocated , class_special_available ,
.Sy class_special_capacity , class_special_expandsize ,
.Sy class_special_fragmentation , class_special_free , class_special_size ,
.Sy class_special_usable , class_special_used
.Xc
.Bd -ragged -offset Ds -compact
Space usage properties of the pool's
.Sy special
metaslab allocator class.
.Ed
.It Xo Sy class_special_elog_allocated , class_special_elog_available ,
.Sy class_special_elog_capacity , class_special_elog_expandsize ,
.Sy class_special_elog_fragmentation , class_special_elog_free ,
.Sy class_special_elog_size , class_special_elog_usable ,
.Sy class_special_elog_used
.Xc
.Bd -ragged -offset Ds -compact
Space usage properties of the pool's
.Sy special_embedded_log
metaslab allocator class.
.Ed
.El
.Pp
Each allocation class is described by these values:
.Bl -tag -width "fragmentation"
.It Sy allocated
Amount of storage used within the allocation class.
.It Sy available
Estimate of free space available in the allocation class, adjusted for raidz
parity overhead.
The adjustment assumes a fixed 128KiB record size to compute a data-to-parity
ratio.
.Sy available
is a heuristic for allocation and should not be interpreted as an exact measure
of usable space.
Actual usable space depends on a variety of factors such as dataset record size
and compression.
.It Sy capacity
Percentage of allocation class space used.
.It Sy expandsize
Amount of uninitialized space within the allocation class that can be used to
increase the capacity of the allocator.
See the pool-wide
.Sy expandsize
property.
.It Sy fragmentation
The amount of free space fragmentation in the allocation class.
See the pool-wide
.Sy fragmentation
property.
.It Sy free
The amount of free space available in the allocation class.
This value is not adjusted for factors such as dataset record size, compression,
or raidz parity overhead.
See the pool-wide
.Sy free
property.
.It Sy size
Total size of the allocation class.
.It Sy usable
Estimate of total allocation class size, adjusted for raidz parity overhead.
The adjustment assumes a fixed 128KiB record size to compute a data-to-parity
ratio.
.Sy usable
is a heuristic for allocation and should not be interpreted as an exact measure
of usable space.
.It Sy used
Estimate of storage used within the allocation class, adjusted for raidz parity
overhead.
The adjustment assumes a fixed 128KiB record size to compute a data-to-parity
ratio.
.Sy used
is a heuristic for allocation and should not be interpreted as an exact measure
of used space.
.El
.Pp
The following property can be set at creation time and import time:
.Bl -tag -width Ds
.It Sy altroot

View File

@ -50,6 +50,41 @@ zpool_prop_get_table(void)
return (zpool_prop_table);
}
/* BEGIN CSTYLED */
#define zprop_register_mc_props_impl(mcp, uprefix, lprefix, sfeatures) ({ \
zprop_register_number(mcp + ZPOOL_MC_PROP_SIZE, \
#lprefix "_size", 0, PROP_READONLY, ZFS_TYPE_POOL, "<size>", \
#uprefix "_SIZE", B_FALSE, sfeatures); \
zprop_register_number(mcp + ZPOOL_MC_PROP_CAPACITY, \
#lprefix "_capacity", 0, PROP_READONLY, ZFS_TYPE_POOL, \
"<percent>", #uprefix "_CAP", B_FALSE, sfeatures); \
zprop_register_number(mcp + ZPOOL_MC_PROP_FREE, \
#lprefix "_free", 0, PROP_READONLY, ZFS_TYPE_POOL, "<size>", \
#uprefix "_FREE", B_FALSE, sfeatures); \
zprop_register_number(mcp + ZPOOL_MC_PROP_ALLOCATED, \
#lprefix "_allocated", 0, PROP_READONLY, ZFS_TYPE_POOL, "<size>", \
#uprefix "_ALLOC", B_FALSE, sfeatures); \
zprop_register_number(mcp + ZPOOL_MC_PROP_AVAILABLE, \
#lprefix "_available", 0, PROP_READONLY, ZFS_TYPE_POOL, "<size>", \
#uprefix "_AVAIL", B_FALSE, sfeatures); \
zprop_register_number(mcp + ZPOOL_MC_PROP_USABLE, \
#lprefix "_usable", 0, PROP_READONLY, ZFS_TYPE_POOL, "<size>", \
#uprefix "_USABLE", B_FALSE, sfeatures); \
zprop_register_number(mcp + ZPOOL_MC_PROP_USED, \
#lprefix "_used", 0, PROP_READONLY, ZFS_TYPE_POOL, "<size>", \
#uprefix "_USED", B_FALSE, sfeatures); \
zprop_register_number(mcp + ZPOOL_MC_PROP_EXPANDSZ, \
#lprefix "_expandsize", 0, PROP_READONLY, ZFS_TYPE_POOL, "<size>", \
#uprefix "_EXPANDSZ", B_FALSE, sfeatures); \
zprop_register_number(mcp + ZPOOL_MC_PROP_FRAGMENTATION, \
#lprefix "_fragmentation", 0, PROP_READONLY, ZFS_TYPE_POOL, \
"<percent>", #uprefix "_FRAG", B_FALSE, sfeatures); \
})
#define zprop_register_mc_props(uclass, lclass, sfeatures) \
zprop_register_mc_props_impl(ZPOOL_MC_PROPS_##uclass, \
CLASS_##uclass, class_##lclass, sfeatures)
/* END CSTYLED */
void
zpool_prop_init(void)
{
@ -138,6 +173,20 @@ zpool_prop_init(void)
zprop_register_number(ZPOOL_PROP_LAST_SCRUBBED_TXG,
"last_scrubbed_txg", 0, PROP_READONLY, ZFS_TYPE_POOL, "<txg>",
"LAST_SCRUBBED_TXG", B_FALSE, sfeatures);
zprop_register_number(ZPOOL_PROP_AVAILABLE, "available", 0,
PROP_READONLY, ZFS_TYPE_POOL, "<size>", "AVAIL", B_FALSE,
sfeatures);
zprop_register_number(ZPOOL_PROP_USABLE, "usable", 0, PROP_READONLY,
ZFS_TYPE_POOL, "<size>", "USABLE", B_FALSE, sfeatures);
zprop_register_number(ZPOOL_PROP_USED, "used", 0, PROP_READONLY,
ZFS_TYPE_POOL, "<size>", "USED", B_FALSE, sfeatures);
zprop_register_mc_props(NORMAL, normal, sfeatures);
zprop_register_mc_props(SPECIAL, special, sfeatures);
zprop_register_mc_props(DEDUP, dedup, sfeatures);
zprop_register_mc_props(LOG, log, sfeatures);
zprop_register_mc_props(ELOG, elog, sfeatures);
zprop_register_mc_props(SELOG, special_elog, sfeatures);
/* default number properties */
zprop_register_number(ZPOOL_PROP_VERSION, "version", SPA_VERSION,

View File

@ -808,6 +808,12 @@ metaslab_class_fragmentation(metaslab_class_t *mc)
spa_config_enter(mc->mc_spa, SCL_VDEV, FTAG, RW_READER);
uint64_t space = metaslab_class_get_space(mc);
if (space == 0) {
spa_config_exit(mc->mc_spa, SCL_VDEV, FTAG);
return (ZFS_FRAG_INVALID);
}
for (int c = 0; c < rvd->vdev_children; c++) {
vdev_t *tvd = rvd->vdev_child[c];
metaslab_group_t *mg = tvd->vdev_mg;
@ -837,7 +843,7 @@ metaslab_class_fragmentation(metaslab_class_t *mc)
fragmentation += mg->mg_fragmentation *
metaslab_group_get_space(mg);
}
fragmentation /= metaslab_class_get_space(mc);
fragmentation /= space;
ASSERT3U(fragmentation, <=, 100);
spa_config_exit(mc->mc_spa, SCL_VDEV, FTAG);

View File

@ -417,6 +417,44 @@ spa_prop_get_nvlist(spa_t *spa, char **props, unsigned int n_props,
return (err);
}
/*
* Add metaslab class properties to an nvlist.
*/
static void
spa_prop_add_metaslab_class(nvlist_t *nv, metaslab_class_t *mc,
zpool_mc_props_t mcp, uint64_t *sizep, uint64_t *allocp, uint64_t *usablep,
uint64_t *usedp)
{
uint64_t size = metaslab_class_get_space(mc);
uint64_t alloc = metaslab_class_get_alloc(mc);
uint64_t dsize = metaslab_class_get_dspace(mc);
uint64_t dalloc = metaslab_class_get_dalloc(mc);
uint64_t cap = (size == 0) ? 0 : (alloc * 100 / size);
const zprop_source_t src = ZPROP_SRC_NONE;
spa_prop_add_list(nv, mcp + ZPOOL_MC_PROP_SIZE, NULL, size, src);
spa_prop_add_list(nv, mcp + ZPOOL_MC_PROP_ALLOCATED, NULL, alloc, src);
spa_prop_add_list(nv, mcp + ZPOOL_MC_PROP_USABLE, NULL, dsize, src);
spa_prop_add_list(nv, mcp + ZPOOL_MC_PROP_USED, NULL, dalloc, src);
spa_prop_add_list(nv, mcp + ZPOOL_MC_PROP_FRAGMENTATION, NULL,
metaslab_class_fragmentation(mc), src);
spa_prop_add_list(nv, mcp + ZPOOL_MC_PROP_EXPANDSZ, NULL,
metaslab_class_expandable_space(mc), src);
spa_prop_add_list(nv, mcp + ZPOOL_MC_PROP_FREE, NULL, size - alloc,
src);
spa_prop_add_list(nv, mcp + ZPOOL_MC_PROP_AVAILABLE, NULL,
dsize - dalloc, src);
spa_prop_add_list(nv, mcp + ZPOOL_MC_PROP_CAPACITY, NULL, cap, src);
if (sizep != NULL)
*sizep += size;
if (allocp != NULL)
*allocp += alloc;
if (usablep != NULL)
*usablep += dsize;
if (usedp != NULL)
*usedp += dalloc;
}
/*
* Add a user property (source=src, propname=propval) to an nvlist.
*/
@ -441,7 +479,7 @@ spa_prop_get_config(spa_t *spa, nvlist_t *nv)
{
vdev_t *rvd = spa->spa_root_vdev;
dsl_pool_t *pool = spa->spa_dsl_pool;
uint64_t size, alloc, cap, version;
uint64_t size, alloc, usable, used, cap, version;
const zprop_source_t src = ZPROP_SRC_NONE;
spa_config_dirent_t *dp;
metaslab_class_t *mc = spa_normal_class(spa);
@ -449,37 +487,42 @@ spa_prop_get_config(spa_t *spa, nvlist_t *nv)
ASSERT(MUTEX_HELD(&spa->spa_props_lock));
if (rvd != NULL) {
alloc = metaslab_class_get_alloc(mc);
alloc += metaslab_class_get_alloc(spa_special_class(spa));
alloc += metaslab_class_get_alloc(spa_dedup_class(spa));
alloc += metaslab_class_get_alloc(spa_embedded_log_class(spa));
alloc += metaslab_class_get_alloc(
spa_special_embedded_log_class(spa));
size = metaslab_class_get_space(mc);
size += metaslab_class_get_space(spa_special_class(spa));
size += metaslab_class_get_space(spa_dedup_class(spa));
size += metaslab_class_get_space(spa_embedded_log_class(spa));
size += metaslab_class_get_space(
spa_special_embedded_log_class(spa));
spa_prop_add_list(nv, ZPOOL_PROP_NAME, spa_name(spa), 0, src);
size = alloc = usable = used = 0;
spa_prop_add_metaslab_class(nv, mc, ZPOOL_MC_PROPS_NORMAL,
&size, &alloc, &usable, &used);
spa_prop_add_metaslab_class(nv, spa_special_class(spa),
ZPOOL_MC_PROPS_SPECIAL, &size, &alloc, &usable, &used);
spa_prop_add_metaslab_class(nv, spa_dedup_class(spa),
ZPOOL_MC_PROPS_DEDUP, &size, &alloc, &usable, &used);
spa_prop_add_metaslab_class(nv, spa_log_class(spa),
ZPOOL_MC_PROPS_LOG, NULL, NULL, NULL, NULL);
spa_prop_add_metaslab_class(nv, spa_embedded_log_class(spa),
ZPOOL_MC_PROPS_ELOG, &size, &alloc, &usable, &used);
spa_prop_add_metaslab_class(nv,
spa_special_embedded_log_class(spa), ZPOOL_MC_PROPS_SELOG,
&size, &alloc, &usable, &used);
spa_prop_add_list(nv, ZPOOL_PROP_SIZE, NULL, size, src);
spa_prop_add_list(nv, ZPOOL_PROP_ALLOCATED, NULL, alloc, src);
spa_prop_add_list(nv, ZPOOL_PROP_FREE, NULL,
size - alloc, src);
spa_prop_add_list(nv, ZPOOL_PROP_CHECKPOINT, NULL,
spa->spa_checkpoint_info.sci_dspace, src);
spa_prop_add_list(nv, ZPOOL_PROP_FRAGMENTATION, NULL,
metaslab_class_fragmentation(mc), src);
spa_prop_add_list(nv, ZPOOL_PROP_EXPANDSZ, NULL,
metaslab_class_expandable_space(mc), src);
spa_prop_add_list(nv, ZPOOL_PROP_READONLY, NULL,
(spa_mode(spa) == SPA_MODE_READ), src);
cap = (size == 0) ? 0 : (alloc * 100 / size);
spa_prop_add_list(nv, ZPOOL_PROP_CAPACITY, NULL, cap, src);
spa_prop_add_list(nv, ZPOOL_PROP_AVAILABLE, NULL, usable - used,
src);
spa_prop_add_list(nv, ZPOOL_PROP_USABLE, NULL, usable, src);
spa_prop_add_list(nv, ZPOOL_PROP_USED, NULL, used, src);
spa_prop_add_list(nv, ZPOOL_PROP_CHECKPOINT, NULL,
spa->spa_checkpoint_info.sci_dspace, src);
spa_prop_add_list(nv, ZPOOL_PROP_READONLY, NULL,
(spa_mode(spa) == SPA_MODE_READ), src);
spa_prop_add_list(nv, ZPOOL_PROP_DEDUPRATIO, NULL,
ddt_get_pool_dedup_ratio(spa), src);

View File

@ -456,8 +456,8 @@ tags = ['functional', 'cli_root', 'zpool_export']
[tests/functional/cli_root/zpool_get]
tests = ['zpool_get_001_pos', 'zpool_get_002_pos', 'zpool_get_003_pos',
'zpool_get_004_neg', 'zpool_get_005_pos', 'vdev_get_001_pos',
'vdev_get_all']
'zpool_get_004_neg', 'zpool_get_005_pos', 'zpool_get_006_pos',
'vdev_get_001_pos', 'vdev_get_all']
tags = ['functional', 'cli_root', 'zpool_get']
[tests/functional/cli_root/zpool_history]

View File

@ -1132,6 +1132,7 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \
functional/cli_root/zpool_get/zpool_get_003_pos.ksh \
functional/cli_root/zpool_get/zpool_get_004_neg.ksh \
functional/cli_root/zpool_get/zpool_get_005_pos.ksh \
functional/cli_root/zpool_get/zpool_get_006_pos.ksh \
functional/cli_root/zpool_history/cleanup.ksh \
functional/cli_root/zpool_history/setup.ksh \
functional/cli_root/zpool_history/zpool_history_001_neg.ksh \

View File

@ -67,6 +67,63 @@ typeset -a properties=(
"last_scrubbed_txg"
"dedupused"
"dedupsaved"
"available"
"usable"
"used"
"class_normal_size"
"class_normal_capacity"
"class_normal_free"
"class_normal_allocated"
"class_normal_available"
"class_normal_usable"
"class_normal_used"
"class_normal_expandsize"
"class_normal_fragmentation"
"class_special_size"
"class_special_capacity"
"class_special_free"
"class_special_allocated"
"class_special_available"
"class_special_usable"
"class_special_used"
"class_special_expandsize"
"class_special_fragmentation"
"class_dedup_size"
"class_dedup_capacity"
"class_dedup_free"
"class_dedup_allocated"
"class_dedup_available"
"class_dedup_usable"
"class_dedup_used"
"class_dedup_expandsize"
"class_dedup_fragmentation"
"class_log_size"
"class_log_capacity"
"class_log_free"
"class_log_allocated"
"class_log_available"
"class_log_usable"
"class_log_used"
"class_log_expandsize"
"class_log_fragmentation"
"class_elog_size"
"class_elog_capacity"
"class_elog_free"
"class_elog_allocated"
"class_elog_available"
"class_elog_usable"
"class_elog_used"
"class_elog_expandsize"
"class_elog_fragmentation"
"class_special_elog_size"
"class_special_elog_capacity"
"class_special_elog_free"
"class_special_elog_allocated"
"class_special_elog_available"
"class_special_elog_usable"
"class_special_elog_used"
"class_special_elog_expandsize"
"class_special_elog_fragmentation"
"feature@async_destroy"
"feature@empty_bpobj"
"feature@lz4_compress"

View File

@ -47,6 +47,8 @@ if ! is_global_zone ; then
fi
typeset -i i=0
typeset class="@(normal|special|dedup|log|elog|special_elog)"
typeset optclass="@(special|dedup|log|elog|special_elog)"
while [[ $i -lt "${#properties[@]}" ]]; do
log_note "Checking for parsable ${properties[$i]} property"
@ -61,10 +63,14 @@ while [[ $i -lt "${#properties[@]}" ]]; do
# All properties must be positive integers in order to be
# parsable (i.e. a return code of 0 or 1 from expr above).
# The only exception is "expandsize", which may be "-".
if [[ ! ($? -eq 0 || $? -eq 1 || \
("${properties[$i]}" = "expandsize" && "$v" = "-")) ]]; then
log_fail "${properties[$i]} is not parsable"
# The only exceptions are "expandsize", "class_<class>_expandsize",
# and "class_<optclass>_fragmentation", which may be "-".
if [[ ! ($? -eq 0 || $? -eq 1) ]]; then
case "${properties[$i]}" in
?(class_${class}_)expandsize) ;&
class_${optclass}_fragmentation) ;;
*) log_fail "${properties[$i]} is not parsable"
esac
fi
i=$(( $i + 1 ))

View File

@ -0,0 +1,416 @@
#!/bin/ksh -p
# SPDX-License-Identifier: CDDL-1.0
#
# 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 https://opensource.org/licenses/CDDL-1.0.
# 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) 2026 Klara, Inc.
#
. $STF_SUITE/include/libtest.shlib
verify_runnable "global"
#
# DESCRIPTION:
#
# Several zpool properties exist to expose metaslab allocation class space
# accounting.
#
# STRATEGY:
# 1. Create a pool with raidz (to validate expansion and deflation metrics).
# 2. For each allocation class:
# - Add any required vdevs for this allocation class.
# - Prepare a dataset configured to utilize this allocation class.
# - Validate metrics reported by pool properties for allocation classes.
# 3. For the whole pool, confirm that AVAIL, USABLE and USED report reasonable
# values.
#
bs=128K
count=100
function writefile
{
dd if=/dev/urandom of=$1 bs=$bs count=$count 2>/dev/null
}
nfiles=5
function writefiles # datadir [nfiles]
{
typeset datadir=$1
typeset -i n=${2:-$nfiles}
for i in {1..$n}; do
log_must writefile $TESTDIR/$datadir/file$i
done
}
pool=$TESTPOOL1
function get_class_prop
{
get_pool_prop "class_${1}_${2}" $pool
}
# Wrapper for test to give more context to logs
function check
{
shift 2 # class prop (test args)
test "$@"
}
function check_raidz_used # [mincap=1]
{
typeset -i mincap=${1:-1}
log_must check $class size $size -gt 0
log_must check $class capacity $cap -ge $mincap -a $cap -le 100
log_must check $class free $free -gt 0 -a $free -lt $size
log_must check $class allocated $alloc -gt 0 -a $alloc -lt $size
log_must check $class available $avail -gt 0 -a $avail -lt $free
log_must check $class usable $usable -gt 0 -a $usable -lt $size
log_must check $class used $used -gt 0 -a $used -lt $alloc
log_must check $class expandsize $expandsz = "-"
log_must check $class fragmentation $frag -lt 50
}
function check_raidz_unused
{
log_must check $class size $size -gt 0
log_must check $class capacity $cap -eq 0
log_must check $class free $free -eq $size
log_must check $class allocated $alloc -eq 0
log_must check $class available $avail -gt 0 -a $avail -lt $free
log_must check $class usable $usable -gt 0 -a $usable -lt $size
log_must check $class used $used -eq 0
log_must check $class expandsize $expandsz = "-"
log_must check $class fragmentation $frag -eq 0
}
function check_nonraidz_used # [mincap=1]
{
typeset -i mincap=${1:-1}
log_must check $class size $size -gt 0
log_must check $class capacity $cap -ge $mincap -a $cap -le 100
log_must check $class free $free -gt 0 -a $free -lt $size
log_must check $class allocated $alloc -gt 0 -a $alloc -lt $size
log_must check $class available $avail -eq $free
log_must check $class usable $usable -eq $size
log_must check $class used $used -eq $alloc
log_must check $class expandsize $expandsz = "-"
log_must check $class fragmentation $frag -lt 50
}
function check_nonraidz_unused
{
log_must check $class size $size -gt 0
log_must check $class capacity $cap -eq 0
log_must check $class free $free -eq $size
log_must check $class allocated $alloc -eq 0
log_must check $class available $avail -eq $free
log_must check $class usable $usable -eq $size
log_must check $class used $used -eq $alloc
log_must check $class expandsize $expandsz = "-"
log_must check $class fragmentation $frag -eq 0
}
# Log capacity tends to be >0% but <1% in these tests, so gets reported as 0.
# Let that slide and rely on allocated/free checks for sanity, rather than
# trying to tweak txg sync parameters to widen the race window.
function check_raidz_log_used
{
check_raidz_used 0
}
function check_nonraidz_log_used
{
check_nonraidz_used 0
}
function check_unavailable
{
log_must check $class size $size -eq 0
log_must check $class capacity $cap -eq 0
log_must check $class free $free -eq 0
log_must check $class allocated $alloc -eq 0
log_must check $class available $avail -eq 0
log_must check $class usable $usable -eq 0
log_must check $class used $used -eq 0
log_must check $class expandsize $expandsz = "-"
log_must check $class fragmentation $frag = "-"
}
typeset -a classes=("normal" "special" "dedup" "log" "elog" "special_elog")
normal_vdevs=$(seq -f $TEST_BASE_DIR/normal-vdev-%g 3)
normal_vdev_size=$((1 << 30)) # 1 GiB
special_vdevs=$(seq -f $TEST_BASE_DIR/special-vdev-%g 3)
special_vdev_size=$((512 << 20)) # 512 MiB
# Use a mirror for dedup to test expandsize.
dedup_vdevs=$(seq -f $TEST_BASE_DIR/dedup-vdev-%g 2)
dedup_vdev_size=$((256 << 20)) # 256 MiB
# The log class can't be raided or expanded, so we only need one vdev.
log_vdev="$TEST_BASE_DIR/log-vdev"
log_vdev_size=$((128 << 20)) # 128 MiB
embedded_slog_min_ms=$(get_tunable EMBEDDED_SLOG_MIN_MS)
function cleanup
{
zpool destroy -f $pool
rm -f $normal_vdevs $normal_expand_vdev
rm -f $special_vdevs $special_expand_vdev
rm -f $dedup_vdevs $dedup_expand_vdev
rm -f $log_vdev
set_tunable32 EMBEDDED_SLOG_MIN_MS $embedded_slog_min_ms
}
log_onexit cleanup
log_assert "zpool allocation class properties report metrics correctly"
# Lower the threshold for provisioning embedded log metaslabs on small vdevs.
log_must set_tunable32 EMBEDDED_SLOG_MIN_MS 8
log_must truncate -s $normal_vdev_size $normal_vdevs
log_must zpool create $pool \
raidz $normal_vdevs
log_must zfs set mountpoint=$TESTDIR $pool
log_note "Normal Class"
log_must zfs create \
$pool/normal
writefiles normal
sync_pool $pool
for class in "${classes[@]}"; do
typeset -il size=$(get_class_prop $class size)
typeset -i cap=$(get_class_prop $class capacity)
typeset -il free=$(get_class_prop $class free)
typeset -il alloc=$(get_class_prop $class allocated)
typeset -il avail=$(get_class_prop $class available)
typeset -il usable=$(get_class_prop $class usable)
typeset -il used=$(get_class_prop $class used)
typeset expandsz=$(get_class_prop $class expandsize)
typeset frag=$(get_class_prop $class fragmentation)
case $class in
normal)
check_raidz_used
;;
elog)
check_raidz_unused
;;
*)
check_unavailable
;;
esac
done
log_note "Embedded Log Class"
log_must zfs create \
-o sync=always \
$pool/elog
writefiles elog
for class in "${classes[@]}"; do
typeset -il size=$(get_class_prop $class size)
typeset -i cap=$(get_class_prop $class capacity)
typeset -il free=$(get_class_prop $class free)
typeset -il alloc=$(get_class_prop $class allocated)
typeset -il avail=$(get_class_prop $class available)
typeset -il usable=$(get_class_prop $class usable)
typeset -il used=$(get_class_prop $class used)
typeset expandsz=$(get_class_prop $class expandsize)
typeset frag=$(get_class_prop $class fragmentation)
case $class in
normal)
check_raidz_used
;;
elog)
check_raidz_log_used
;;
*)
check_unavailable
;;
esac
done
log_note "Special Class"
log_must truncate -s $special_vdev_size $special_vdevs
log_must zpool add $pool \
special raidz $special_vdevs
log_must zfs create \
-o recordsize=32K -o special_small_blocks=32K \
$pool/special
writefiles special
sync_pool $pool
for class in "${classes[@]}"; do
typeset -il size=$(get_class_prop $class size)
typeset -i cap=$(get_class_prop $class capacity)
typeset -il free=$(get_class_prop $class free)
typeset -il alloc=$(get_class_prop $class allocated)
typeset -il avail=$(get_class_prop $class available)
typeset -il usable=$(get_class_prop $class usable)
typeset -il used=$(get_class_prop $class used)
typeset expandsz=$(get_class_prop $class expandsize)
typeset frag=$(get_class_prop $class fragmentation)
case $class in
normal|special)
check_raidz_used
;;
elog)
check_raidz_log_used
;;
special_elog)
check_raidz_unused
;;
*)
check_unavailable
;;
esac
done
log_note "Special Embedded Log Class"
log_must zfs create \
-o recordsize=32K -o special_small_blocks=32K \
-o sync=always \
$pool/special_elog
writefiles special_elog
for class in "${classes[@]}"; do
typeset -il size=$(get_class_prop $class size)
typeset -i cap=$(get_class_prop $class capacity)
typeset -il free=$(get_class_prop $class free)
typeset -il alloc=$(get_class_prop $class allocated)
typeset -il avail=$(get_class_prop $class available)
typeset -il usable=$(get_class_prop $class usable)
typeset -il used=$(get_class_prop $class used)
typeset expandsz=$(get_class_prop $class expandsize)
typeset frag=$(get_class_prop $class fragmentation)
case $class in
normal|special)
check_raidz_used
;;
elog|special_elog)
check_raidz_log_used
;;
*)
check_unavailable
;;
esac
done
log_note "Log Class"
log_must truncate -s $log_vdev_size $log_vdev
log_must zpool add $pool \
log $log_vdev
log_must zfs create \
-o sync=always \
$pool/log
writefiles log
for class in "${classes[@]}"; do
typeset -il size=$(get_class_prop $class size)
typeset -i cap=$(get_class_prop $class capacity)
typeset -il free=$(get_class_prop $class free)
typeset -il alloc=$(get_class_prop $class allocated)
typeset -il avail=$(get_class_prop $class available)
typeset -il usable=$(get_class_prop $class usable)
typeset -il used=$(get_class_prop $class used)
typeset expandsz=$(get_class_prop $class expandsize)
typeset frag=$(get_class_prop $class fragmentation)
case $class in
normal|special)
check_raidz_used
;;
elog|special_elog)
check_raidz_log_used
;;
log)
check_nonraidz_log_used
;;
*)
check_unavailable
;;
esac
done
log_note "Dedup Class"
log_must truncate -s $dedup_vdev_size $dedup_vdevs
log_must zpool add $pool \
dedup mirror $dedup_vdevs
log_must zfs create \
-o dedup=on -o recordsize=4k \
$pool/dedup
writefiles dedup $((3 * nfiles))
sync_pool $pool
for class in "${classes[@]}"; do
typeset -il size=$(get_class_prop $class size)
typeset -i cap=$(get_class_prop $class capacity)
typeset -il free=$(get_class_prop $class free)
typeset -il alloc=$(get_class_prop $class allocated)
typeset -il avail=$(get_class_prop $class available)
typeset -il usable=$(get_class_prop $class usable)
typeset -il used=$(get_class_prop $class used)
typeset expandsz=$(get_class_prop $class expandsize)
typeset frag=$(get_class_prop $class fragmentation)
case $class in
normal|special)
check_raidz_used
;;
elog|special_elog)
check_raidz_log_used
;;
log)
check_nonraidz_log_used
;;
dedup)
check_nonraidz_used
;;
*)
log_fail "unhandled class: $class"
;;
esac
done
# Expansion
typeset -il delta=$((32 << 20)) # 32 MiB
log_must truncate -s $((dedup_vdev_size + delta)) $dedup_vdevs
typeset -a vdevs=($dedup_vdevs)
log_must zpool online -e $pool ${vdevs[0]}
typeset -il size=$(get_class_prop dedup size)
typeset -il expandsz=$(get_class_prop dedup expandsize)
log_must test $expandsz -eq $delta
# Pool-wide AVAIL/USABLE/USED
typeset -il free=$(get_pool_prop free $pool)
typeset -il avail=$(get_pool_prop available $pool)
log_must test $avail -gt 0 -a $avail -lt $free
typeset -il size=$(get_pool_prop size $pool)
typeset -il usable=$(get_pool_prop usable $pool)
log_must test $usable -gt 0 -a $usable -lt $size
typeset -il alloc=$(get_pool_prop alloc $pool)
typeset -il used=$(get_pool_prop used $pool)
log_must test $used -gt 0 -a $used -lt $alloc
cleanup

View File

@ -29,6 +29,75 @@
# Copyright (c) 2013, 2014 by Delphix. All rights reserved.
#
# Set the expected properties of zpool
typeset -a properties=("allocated" "bcloneused" "bclonesaved" "capacity"
"dedupused" "dedupsaved" "expandsize" "free" "freeing" "leaked" "size")
# Set the expected parsable properties of zpool
typeset -a properties=(
"size"
"capacity"
"free"
"allocated"
"expandsize"
"freeing"
"fragmentation"
"leaked"
"bcloneused"
"bclonesaved"
"dedupused"
"dedupsaved"
"available"
"usable"
"used"
"class_normal_size"
"class_normal_capacity"
"class_normal_free"
"class_normal_allocated"
"class_normal_available"
"class_normal_usable"
"class_normal_used"
"class_normal_expandsize"
"class_normal_fragmentation"
"class_special_size"
"class_special_capacity"
"class_special_free"
"class_special_allocated"
"class_special_available"
"class_special_usable"
"class_special_used"
"class_special_expandsize"
"class_special_fragmentation"
"class_dedup_size"
"class_dedup_capacity"
"class_dedup_free"
"class_dedup_allocated"
"class_dedup_available"
"class_dedup_usable"
"class_dedup_used"
"class_dedup_expandsize"
"class_dedup_fragmentation"
"class_log_size"
"class_log_capacity"
"class_log_free"
"class_log_allocated"
"class_log_available"
"class_log_usable"
"class_log_used"
"class_log_expandsize"
"class_log_fragmentation"
"class_elog_size"
"class_elog_capacity"
"class_elog_free"
"class_elog_allocated"
"class_elog_available"
"class_elog_usable"
"class_elog_used"
"class_elog_expandsize"
"class_elog_fragmentation"
"class_special_elog_size"
"class_special_elog_capacity"
"class_special_elog_free"
"class_special_elog_allocated"
"class_special_elog_available"
"class_special_elog_usable"
"class_special_elog_used"
"class_special_elog_expandsize"
"class_special_elog_fragmentation"
)