Vdev Properties Feature

Add properties, similar to pool properties, to each vdev.
This makes use of the existing per-vdev ZAP that was added as
part of device evacuation/removal.

A large number of read-only properties are exposed,
many of the members of struct vdev_t, that provide useful
statistics.

Adds support for read-only "removing" vdev property.
Adds the "allocating" property that defaults to "on" and
can be set to "off" to prevent future allocations from that
top-level vdev.

Supports user-defined vdev properties.
Includes support for properties.vdev in SYSFS.

Co-authored-by: Allan Jude <allan@klarasystems.com>
Co-authored-by: Mark Maybee <mark.maybee@delphix.com>
Reviewed-by: Matthew Ahrens <mahrens@delphix.com>
Reviewed-by: Mark Maybee <mark.maybee@delphix.com>
Signed-off-by: Allan Jude <allan@klarasystems.com>
Closes #11711
This commit is contained in:
Allan Jude
2021-11-30 09:46:25 -05:00
committed by GitHub
parent 5f64bf7fde
commit 2a673e76a9
33 changed files with 2746 additions and 243 deletions
+1 -13
View File
@@ -723,18 +723,6 @@ zfs_name_to_prop(const char *propname)
return (zprop_name_to_prop(propname, ZFS_TYPE_DATASET));
}
/*
* For user property names, we allow all lowercase alphanumeric characters, plus
* a few useful punctuation characters.
*/
static int
valid_char(char c)
{
return ((c >= 'a' && c <= 'z') ||
(c >= '0' && c <= '9') ||
c == '-' || c == '_' || c == '.' || c == ':');
}
/*
* Returns true if this is a valid user-defined property (one with a ':').
*/
@@ -747,7 +735,7 @@ zfs_prop_user(const char *name)
for (i = 0; i < strlen(name); i++) {
c = name[i];
if (!valid_char(c))
if (!zprop_valid_char(c))
return (B_FALSE);
if (c == ':')
foundsep = B_TRUE;
+250
View File
@@ -23,6 +23,7 @@
* Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2012, 2018 by Delphix. All rights reserved.
* Copyright (c) 2021, Colm Buckley <colm@tuatha.org>
* Copyright (c) 2021, Klara Inc.
*/
#include <sys/zio.h>
@@ -40,6 +41,7 @@
#endif
static zprop_desc_t zpool_prop_table[ZPOOL_NUM_PROPS];
static zprop_desc_t vdev_prop_table[VDEV_NUM_PROPS];
zprop_desc_t *
zpool_prop_get_table(void)
@@ -260,12 +262,249 @@ zpool_prop_align_right(zpool_prop_t prop)
}
#endif
zprop_desc_t *
vdev_prop_get_table(void)
{
return (vdev_prop_table);
}
void
vdev_prop_init(void)
{
static zprop_index_t boolean_table[] = {
{ "off", 0},
{ "on", 1},
{ NULL }
};
static zprop_index_t boolean_na_table[] = {
{ "off", 0},
{ "on", 1},
{ "-", 2}, /* ZPROP_BOOLEAN_NA */
{ NULL }
};
/* string properties */
zprop_register_string(VDEV_PROP_COMMENT, "comment", NULL,
PROP_DEFAULT, ZFS_TYPE_VDEV, "<comment-string>", "COMMENT");
zprop_register_string(VDEV_PROP_PATH, "path", NULL,
PROP_DEFAULT, ZFS_TYPE_VDEV, "<device-path>", "PATH");
zprop_register_string(VDEV_PROP_DEVID, "devid", NULL,
PROP_READONLY, ZFS_TYPE_VDEV, "<devid>", "DEVID");
zprop_register_string(VDEV_PROP_PHYS_PATH, "physpath", NULL,
PROP_READONLY, ZFS_TYPE_VDEV, "<physpath>", "PHYSPATH");
zprop_register_string(VDEV_PROP_ENC_PATH, "encpath", NULL,
PROP_READONLY, ZFS_TYPE_VDEV, "<encpath>", "ENCPATH");
zprop_register_string(VDEV_PROP_FRU, "fru", NULL,
PROP_READONLY, ZFS_TYPE_VDEV, "<fru>", "FRU");
zprop_register_string(VDEV_PROP_PARENT, "parent", NULL,
PROP_READONLY, ZFS_TYPE_VDEV, "<parent>", "PARENT");
zprop_register_string(VDEV_PROP_CHILDREN, "children", NULL,
PROP_READONLY, ZFS_TYPE_VDEV, "<child[,...]>", "CHILDREN");
/* readonly number properties */
zprop_register_number(VDEV_PROP_SIZE, "size", 0, PROP_READONLY,
ZFS_TYPE_VDEV, "<size>", "SIZE");
zprop_register_number(VDEV_PROP_FREE, "free", 0, PROP_READONLY,
ZFS_TYPE_VDEV, "<size>", "FREE");
zprop_register_number(VDEV_PROP_ALLOCATED, "allocated", 0,
PROP_READONLY, ZFS_TYPE_VDEV, "<size>", "ALLOC");
zprop_register_number(VDEV_PROP_EXPANDSZ, "expandsize", 0,
PROP_READONLY, ZFS_TYPE_VDEV, "<size>", "EXPANDSZ");
zprop_register_number(VDEV_PROP_FRAGMENTATION, "fragmentation", 0,
PROP_READONLY, ZFS_TYPE_VDEV, "<percent>", "FRAG");
zprop_register_number(VDEV_PROP_CAPACITY, "capacity", 0, PROP_READONLY,
ZFS_TYPE_VDEV, "<size>", "CAP");
zprop_register_number(VDEV_PROP_GUID, "guid", 0, PROP_READONLY,
ZFS_TYPE_VDEV, "<guid>", "GUID");
zprop_register_number(VDEV_PROP_STATE, "state", 0, PROP_READONLY,
ZFS_TYPE_VDEV, "<state>", "STATE");
zprop_register_number(VDEV_PROP_BOOTSIZE, "bootsize", 0, PROP_READONLY,
ZFS_TYPE_VDEV, "<size>", "BOOTSIZE");
zprop_register_number(VDEV_PROP_ASIZE, "asize", 0, PROP_READONLY,
ZFS_TYPE_VDEV, "<asize>", "ASIZE");
zprop_register_number(VDEV_PROP_PSIZE, "psize", 0, PROP_READONLY,
ZFS_TYPE_VDEV, "<psize>", "PSIZE");
zprop_register_number(VDEV_PROP_ASHIFT, "ashift", 0, PROP_READONLY,
ZFS_TYPE_VDEV, "<ashift>", "ASHIFT");
zprop_register_number(VDEV_PROP_PARITY, "parity", 0, PROP_READONLY,
ZFS_TYPE_VDEV, "<parity>", "PARITY");
zprop_register_number(VDEV_PROP_NUMCHILDREN, "numchildren", 0,
PROP_READONLY, ZFS_TYPE_VDEV, "<number-of-children>", "NUMCHILD");
zprop_register_number(VDEV_PROP_READ_ERRORS, "read_errors", 0,
PROP_READONLY, ZFS_TYPE_VDEV, "<errors>", "RDERR");
zprop_register_number(VDEV_PROP_WRITE_ERRORS, "write_errors", 0,
PROP_READONLY, ZFS_TYPE_VDEV, "<errors>", "WRERR");
zprop_register_number(VDEV_PROP_CHECKSUM_ERRORS, "checksum_errors", 0,
PROP_READONLY, ZFS_TYPE_VDEV, "<errors>", "CKERR");
zprop_register_number(VDEV_PROP_INITIALIZE_ERRORS,
"initialize_errors", 0, PROP_READONLY, ZFS_TYPE_VDEV, "<errors>",
"INITERR");
zprop_register_number(VDEV_PROP_OPS_NULL, "null_ops", 0,
PROP_READONLY, ZFS_TYPE_VDEV, "<operations>", "NULLOP");
zprop_register_number(VDEV_PROP_OPS_READ, "read_ops", 0,
PROP_READONLY, ZFS_TYPE_VDEV, "<operations>", "READOP");
zprop_register_number(VDEV_PROP_OPS_WRITE, "write_ops", 0,
PROP_READONLY, ZFS_TYPE_VDEV, "<operations>", "WRITEOP");
zprop_register_number(VDEV_PROP_OPS_FREE, "free_ops", 0,
PROP_READONLY, ZFS_TYPE_VDEV, "<operations>", "FREEOP");
zprop_register_number(VDEV_PROP_OPS_CLAIM, "claim_ops", 0,
PROP_READONLY, ZFS_TYPE_VDEV, "<operations>", "CLAIMOP");
zprop_register_number(VDEV_PROP_OPS_TRIM, "trim_ops", 0,
PROP_READONLY, ZFS_TYPE_VDEV, "<operations>", "TRIMOP");
zprop_register_number(VDEV_PROP_BYTES_NULL, "null_bytes", 0,
PROP_READONLY, ZFS_TYPE_VDEV, "<bytes>", "NULLBYTE");
zprop_register_number(VDEV_PROP_BYTES_READ, "read_bytes", 0,
PROP_READONLY, ZFS_TYPE_VDEV, "<bytes>", "READBYTE");
zprop_register_number(VDEV_PROP_BYTES_WRITE, "write_bytes", 0,
PROP_READONLY, ZFS_TYPE_VDEV, "<bytes>", "WRITEBYTE");
zprop_register_number(VDEV_PROP_BYTES_FREE, "free_bytes", 0,
PROP_READONLY, ZFS_TYPE_VDEV, "<bytes>", "FREEBYTE");
zprop_register_number(VDEV_PROP_BYTES_CLAIM, "claim_bytes", 0,
PROP_READONLY, ZFS_TYPE_VDEV, "<bytes>", "CLAIMBYTE");
zprop_register_number(VDEV_PROP_BYTES_TRIM, "trim_bytes", 0,
PROP_READONLY, ZFS_TYPE_VDEV, "<bytes>", "TRIMBYTE");
/* default numeric properties */
/* default index (boolean) properties */
zprop_register_index(VDEV_PROP_REMOVING, "removing", 0,
PROP_READONLY, ZFS_TYPE_VDEV, "on | off", "REMOVING",
boolean_table);
zprop_register_index(VDEV_PROP_ALLOCATING, "allocating", 1,
PROP_DEFAULT, ZFS_TYPE_VDEV, "on | off", "ALLOCATING",
boolean_na_table);
/* default index properties */
/* hidden properties */
zprop_register_hidden(VDEV_PROP_NAME, "name", PROP_TYPE_STRING,
PROP_READONLY, ZFS_TYPE_VDEV, "NAME");
}
/*
* Given a property name and its type, returns the corresponding property ID.
*/
vdev_prop_t
vdev_name_to_prop(const char *propname)
{
return (zprop_name_to_prop(propname, ZFS_TYPE_VDEV));
}
/*
* Returns true if this is a valid user-defined property (one with a ':').
*/
boolean_t
vdev_prop_user(const char *name)
{
int i;
char c;
boolean_t foundsep = B_FALSE;
for (i = 0; i < strlen(name); i++) {
c = name[i];
if (!zprop_valid_char(c))
return (B_FALSE);
if (c == ':')
foundsep = B_TRUE;
}
return (foundsep);
}
/*
* Given a pool property ID, returns the corresponding name.
* Assuming the pool property ID is valid.
*/
const char *
vdev_prop_to_name(vdev_prop_t prop)
{
return (vdev_prop_table[prop].pd_name);
}
zprop_type_t
vdev_prop_get_type(vdev_prop_t prop)
{
return (vdev_prop_table[prop].pd_proptype);
}
boolean_t
vdev_prop_readonly(vdev_prop_t prop)
{
return (vdev_prop_table[prop].pd_attr == PROP_READONLY);
}
const char *
vdev_prop_default_string(vdev_prop_t prop)
{
return (vdev_prop_table[prop].pd_strdefault);
}
uint64_t
vdev_prop_default_numeric(vdev_prop_t prop)
{
return (vdev_prop_table[prop].pd_numdefault);
}
int
vdev_prop_string_to_index(vdev_prop_t prop, const char *string,
uint64_t *index)
{
return (zprop_string_to_index(prop, string, index, ZFS_TYPE_VDEV));
}
int
vdev_prop_index_to_string(vdev_prop_t prop, uint64_t index,
const char **string)
{
return (zprop_index_to_string(prop, index, string, ZFS_TYPE_VDEV));
}
/*
* Returns true if this is a valid vdev property.
*/
boolean_t
zpool_prop_vdev(const char *name)
{
return (vdev_name_to_prop(name) != VDEV_PROP_INVAL);
}
uint64_t
vdev_prop_random_value(vdev_prop_t prop, uint64_t seed)
{
return (zprop_random_value(prop, seed, ZFS_TYPE_VDEV));
}
#ifndef _KERNEL
const char *
vdev_prop_values(vdev_prop_t prop)
{
return (vdev_prop_table[prop].pd_values);
}
const char *
vdev_prop_column_name(vdev_prop_t prop)
{
return (vdev_prop_table[prop].pd_colname);
}
boolean_t
vdev_prop_align_right(vdev_prop_t prop)
{
return (vdev_prop_table[prop].pd_rightalign);
}
#endif
#if defined(_KERNEL)
/* zpool property functions */
EXPORT_SYMBOL(zpool_prop_init);
EXPORT_SYMBOL(zpool_prop_get_type);
EXPORT_SYMBOL(zpool_prop_get_table);
/* vdev property functions */
EXPORT_SYMBOL(vdev_prop_init);
EXPORT_SYMBOL(vdev_prop_get_type);
EXPORT_SYMBOL(vdev_prop_get_table);
/* Pool property functions shared between libzfs and kernel. */
EXPORT_SYMBOL(zpool_name_to_prop);
EXPORT_SYMBOL(zpool_prop_to_name);
@@ -276,4 +515,15 @@ EXPORT_SYMBOL(zpool_prop_feature);
EXPORT_SYMBOL(zpool_prop_unsupported);
EXPORT_SYMBOL(zpool_prop_index_to_string);
EXPORT_SYMBOL(zpool_prop_string_to_index);
EXPORT_SYMBOL(zpool_prop_vdev);
/* vdev property functions shared between libzfs and kernel. */
EXPORT_SYMBOL(vdev_name_to_prop);
EXPORT_SYMBOL(vdev_prop_user);
EXPORT_SYMBOL(vdev_prop_to_name);
EXPORT_SYMBOL(vdev_prop_default_string);
EXPORT_SYMBOL(vdev_prop_default_numeric);
EXPORT_SYMBOL(vdev_prop_readonly);
EXPORT_SYMBOL(vdev_prop_index_to_string);
EXPORT_SYMBOL(vdev_prop_string_to_index);
#endif
+21 -1
View File
@@ -53,6 +53,8 @@ zprop_get_proptable(zfs_type_t type)
{
if (type == ZFS_TYPE_POOL)
return (zpool_prop_get_table());
else if (type == ZFS_TYPE_VDEV)
return (vdev_prop_get_table());
else
return (zfs_prop_get_table());
}
@@ -62,6 +64,8 @@ zprop_get_numprops(zfs_type_t type)
{
if (type == ZFS_TYPE_POOL)
return (ZPOOL_NUM_PROPS);
else if (type == ZFS_TYPE_VDEV)
return (VDEV_NUM_PROPS);
else
return (ZFS_NUM_PROPS);
}
@@ -81,7 +85,8 @@ zfs_mod_supported_prop(const char *name, zfs_type_t type)
return (B_TRUE);
#else
return (zfs_mod_supported(type == ZFS_TYPE_POOL ?
ZFS_SYSFS_POOL_PROPERTIES : ZFS_SYSFS_DATASET_PROPERTIES, name));
ZFS_SYSFS_POOL_PROPERTIES : (type == ZFS_TYPE_VDEV ?
ZFS_SYSFS_VDEV_PROPERTIES : ZFS_SYSFS_DATASET_PROPERTIES), name));
#endif
}
@@ -235,6 +240,8 @@ propname_match(const char *p, size_t len, zprop_desc_t *prop_entry)
int c;
#endif
ASSERT(propname != NULL);
if (len == strlen(propname) &&
strncmp(p, propname, len) == 0)
return (B_TRUE);
@@ -391,6 +398,18 @@ zprop_valid_for_type(int prop, zfs_type_t type, boolean_t headcheck)
return ((prop_tbl[prop].pd_types & type) != 0);
}
/*
* For user property names, we allow all lowercase alphanumeric characters, plus
* a few useful punctuation characters.
*/
int
zprop_valid_char(char c)
{
return ((c >= 'a' && c <= 'z') ||
(c >= '0' && c <= '9') ||
c == '-' || c == '_' || c == '.' || c == ':');
}
#ifndef _KERNEL
/*
@@ -477,4 +496,5 @@ EXPORT_SYMBOL(zprop_index_to_string);
EXPORT_SYMBOL(zprop_random_value);
EXPORT_SYMBOL(zprop_values);
EXPORT_SYMBOL(zprop_valid_for_type);
EXPORT_SYMBOL(zprop_valid_char);
#endif