svn commit: r256476 - projects/zfsd/head/cddl/sbin/zfsd
Alan Somers
asomers at FreeBSD.org
Mon Oct 14 23:31:19 UTC 2013
Author: asomers
Date: Mon Oct 14 23:31:18 2013
New Revision: 256476
URL: http://svnweb.freebsd.org/changeset/base/256476
Log:
Improve zfsd's spare handling.
Zfsd can now:
- Spare broken spares, whether a case file is created for the
original drive or for the previous spare.
- Avoid sparing spares that are either resilvering or healthy. This
enables failover of multiple devices in a pool. It also means
that zfsd doesn't require more spares than are actually needed to
make a pool whole again.
cddl/sbin/zfsd/vdev.h:
cddl/sbin/zfsd/vdev.cc:
- Add NonexistentVdev, a singleton instance of Vdev that represents
a vdev that doesn't exist. Supporting this are new methods:
- Vdev::Vdev(), an empty copy constructor.
- Vdev::DoesNotExist(), which returns true if the vdev doesn't
exist.
- Add vdev tree methods of use for purposes for which VdevIterator
is not appropriate:
- Vdev::Children(), which returns a list of the vdev's children.
- Vdev::RootVdev(), which returns the root vdev of the vdev's pool.
- Vdev::Parent(), which returns the vdev's parent. This works by
traversing the tree until it finds a vdev whose children include
the caller object.
- Add several useful vdev instance methods:
- Vdev::IsAvailableSpare(), which returns whether the vdev is an
unassigned and usable spare.
- Vdev::Name(), which returns the vdev's name; it can be made to
return a "verbose" name too (e.g. "spare" vs. "spare-1").
- Vdev::IsSpare(), Vdev::IsActiveSpare(), and Vdev::IsResilvering().
- While I'm here, refactor Vdev::Vdev(*) so that common
initialization code only exists in one place.
cddl/sbin/zfsd/case_file.h:
cddl/sbin/zfsd/case_file.cc:
- Add CaseFile::BeingReplacedBy(), which returns the device
replacing the current device, if one exists. Performing this
requires finding the vdev's parent and checking the state of its
children.
- Change CaseFile::Replace() to allow the caller to specify whether
the case's vdev is being replaced by a spare. This enables
Replace() to detect the appropriate device to perform the actual
replace on.
- Add CaseFile::CaseVdev() to obtain a Vdev for the case file, and
use it in several places that perform the operation.
cddl/sbin/zfsd/case_file.cc:
- Improve logging for case file evaluation so that the action chosen
is always logged.
- While I'm here, make zpool lookups consistent and always generate
a zpool_handle_t * local to the function where it's needed.
cddl/sbin/zfsd/vdev.h:
cddl/sbin/zfsd/zfsd_exception.cc:
- Add <list>, now required because of Vdev::Children() in vdev.h.
Submitted by: will
Approved by: ken (mentor)
Sponsored by: Spectra Logic Corporation
Modified:
projects/zfsd/head/cddl/sbin/zfsd/case_file.cc
projects/zfsd/head/cddl/sbin/zfsd/case_file.h
projects/zfsd/head/cddl/sbin/zfsd/vdev.cc
projects/zfsd/head/cddl/sbin/zfsd/vdev.h
projects/zfsd/head/cddl/sbin/zfsd/zfsd_exception.cc
Modified: projects/zfsd/head/cddl/sbin/zfsd/case_file.cc
==============================================================================
--- projects/zfsd/head/cddl/sbin/zfsd/case_file.cc Mon Oct 14 23:24:53 2013 (r256475)
+++ projects/zfsd/head/cddl/sbin/zfsd/case_file.cc Mon Oct 14 23:31:18 2013 (r256476)
@@ -233,27 +233,16 @@ bool
CaseFile::RefreshVdevState()
{
ZpoolList zpl(ZpoolList::ZpoolByGUID, &m_poolGUID);
- if (zpl.empty()) {
- stringstream msg;
- msg << "CaseFile::RefreshVdevState: Unknown pool for Vdev(";
- msg << m_poolGUID << "," << m_vdevGUID << ").";
- syslog(LOG_INFO, "%s", msg.str().c_str());
- return (false);
- }
+ zpool_handle_t *casePool(zpl.empty() ? NULL : zpl.front());
+ if (casePool == NULL)
+ return (false);
- zpool_handle_t *casePool(zpl.front());
- nvlist_t *vdevConfig = VdevIterator(casePool).Find(VdevGUID());
- if (vdevConfig == NULL) {
- stringstream msg;
- syslog(LOG_INFO,
- "CaseFile::RefreshVdevState: Unknown Vdev(%s,%s).\n",
- PoolGUIDString().c_str(), PoolGUIDString().c_str());
+ Vdev vd(casePool, CaseVdev(casePool));
+ if (vd.DoesNotExist())
return (false);
- }
- Vdev caseVdev(casePool, vdevConfig);
- m_vdevState = caseVdev.State();
- m_vdevPhysPath = caseVdev.PhysicalPath();
+ m_vdevState = vd.State();
+ m_vdevPhysPath = vd.PhysicalPath();
return (true);
}
@@ -261,8 +250,9 @@ bool
CaseFile::ReEvaluate(const string &devPath, const string &physPath, Vdev *vdev)
{
ZpoolList zpl(ZpoolList::ZpoolByGUID, &m_poolGUID);
+ zpool_handle_t *pool(zpl.empty() ? NULL : zpl.front());
- if (zpl.empty() || !RefreshVdevState()) {
+ if (pool == NULL || !RefreshVdevState()) {
/*
* The pool or vdev for this case file is no longer
* part of the configuration. This can happen
@@ -283,7 +273,6 @@ CaseFile::ReEvaluate(const string &devPa
*/
return (/*consumed*/false);
}
- zpool_handle_t *pool(zpl.front());
if (VdevState() > VDEV_STATE_CANT_OPEN) {
/*
@@ -292,6 +281,8 @@ CaseFile::ReEvaluate(const string &devPa
* use a newly inserted spare to replace a degraded
* or faulted device.
*/
+ syslog(LOG_INFO, "CaseFile::ReEvaluate(%s,%s): Pool/Vdev ignored",
+ PoolGUIDString().c_str(), VdevGUIDString().c_str());
return (/*consumed*/false);
}
@@ -360,7 +351,10 @@ CaseFile::ReEvaluate(const string &devPa
return (/*consumed*/false);
}
- return (Replace(VDEV_TYPE_DISK, devPath.c_str()));
+ syslog(LOG_INFO, "CaseFile::ReEvaluate(%s/%s): Replacing with %s",
+ PoolGUIDString().c_str(), VdevGUIDString().c_str(),
+ devPath.c_str());
+ return (Replace(VDEV_TYPE_DISK, devPath.c_str(), /*isspare*/false));
}
bool
@@ -378,6 +372,7 @@ CaseFile::ReEvaluate(const ZfsEvent &eve
return (/*consumed*/true);
}
else if (event.Value("type") == "misc.fs.zfs.config_sync") {
+ RefreshVdevState();
if (VdevState() < VDEV_STATE_HEALTHY)
consumed = ActivateSpare();
}
@@ -460,27 +455,22 @@ CaseFile::ReEvaluate(const ZfsEvent &eve
}
-/*
- * TODO: ensure that we don't activate a spare for a vdev that is already being
- * replaced by another spare.
- */
bool
CaseFile::ActivateSpare() {
nvlist_t *config, *nvroot;
nvlist_t **spares;
- zpool_handle_t *zhp;
char *devPath, *vdev_type;
const char *poolname;
u_int nspares, i;
int error;
ZpoolList zpl(ZpoolList::ZpoolByGUID, &m_poolGUID);
- if (zpl.empty()) {
+ zpool_handle_t *zhp(zpl.empty() ? NULL : zpl.front());
+ if (zhp == NULL) {
syslog(LOG_ERR, "CaseFile::ActivateSpare: Could not find pool "
"for pool_guid %"PRIu64".", (uint64_t)m_poolGUID);
return (false);
}
- zhp = zpl.front();
poolname = zpool_get_name(zhp);
config = zpool_get_config(zhp, NULL);
if (config == NULL) {
@@ -545,7 +535,7 @@ CaseFile::ActivateSpare() {
return (false);
}
- return (Replace(vdev_type, devPath));
+ return (Replace(vdev_type, devPath, /*isspare*/true));
}
void
@@ -909,13 +899,15 @@ CaseFile::OnGracePeriodEnded()
{
bool should_fault, should_degrade;
ZpoolList zpl(ZpoolList::ZpoolByGUID, &m_poolGUID);
+ zpool_handle_t *zhp(zpl.empty() ? NULL : zpl.front());
+
m_events.splice(m_events.begin(), m_tentativeEvents);
should_fault = ShouldFault();
should_degrade = ShouldDegrade();
if (should_fault || should_degrade) {
- if (zpl.empty()
- || (VdevIterator(zpl.front()).Find(m_vdevGUID)) == NULL) {
+ if (zhp == NULL
+ || (VdevIterator(zhp).Find(m_vdevGUID)) == NULL) {
/*
* Either the pool no longer exists
* or this vdev is no longer a member of
@@ -930,7 +922,7 @@ CaseFile::OnGracePeriodEnded()
/* A fault condition has priority over a degrade condition */
if (ShouldFault()) {
/* Fault the vdev and close the case. */
- if (zpool_vdev_fault(zpl.front(), (uint64_t)m_vdevGUID,
+ if (zpool_vdev_fault(zhp, (uint64_t)m_vdevGUID,
VDEV_AUX_ERR_EXCEEDED) == 0) {
syslog(LOG_INFO, "Faulting vdev(%s/%s)",
PoolGUIDString().c_str(),
@@ -948,7 +940,7 @@ CaseFile::OnGracePeriodEnded()
}
else if (ShouldDegrade()) {
/* Degrade the vdev and close the case. */
- if (zpool_vdev_degrade(zpl.front(), (uint64_t)m_vdevGUID,
+ if (zpool_vdev_degrade(zhp, (uint64_t)m_vdevGUID,
VDEV_AUX_ERR_EXCEEDED) == 0) {
syslog(LOG_INFO, "Degrading vdev(%s/%s)",
PoolGUIDString().c_str(),
@@ -967,22 +959,86 @@ CaseFile::OnGracePeriodEnded()
Serialize();
}
+Vdev
+CaseFile::BeingReplacedBy(zpool_handle_t *zhp) {
+ Vdev vd(zhp, CaseVdev(zhp));
+ std::list<Vdev> children;
+ std::list<Vdev>::iterator children_it;
+
+ Vdev parent(vd.Parent());
+ Vdev replacing(NonexistentVdev);
+
+ /*
+ * To determine whether we are being replaced by another spare that
+ * is still working, then make sure that it is currently spared and
+ * that the spare is either resilvering or healthy. If any of these
+ * conditions fail, then we are not being replaced by a spare.
+ *
+ * If the spare is healthy, then the case file should be closed very
+ * soon after this check.
+ */
+ if (parent.DoesNotExist()
+ || parent.Name(zhp, /*verbose*/false) != "spare")
+ return (NonexistentVdev);
+
+ children = parent.Children();
+ children_it = children.begin();
+ for (;children_it != children.end(); children_it++) {
+ Vdev child = *children_it;
+
+ /* Skip our vdev. */
+ if (child.GUID() == VdevGUID())
+ continue;
+ /*
+ * Accept the first child that doesn't match our GUID, or
+ * any resilvering/healthy device if one exists.
+ */
+ if (replacing.DoesNotExist() || child.IsResilvering()
+ || child.State() == VDEV_STATE_HEALTHY)
+ replacing = child;
+ }
+
+ return (replacing);
+}
+
bool
-CaseFile::Replace(const char* vdev_type, const char* path) {
+CaseFile::Replace(const char* vdev_type, const char* path, bool isspare) {
nvlist_t *nvroot, *newvd;
- zpool_handle_t *zhp;
- const char* poolname;
+ const char *poolname;
+ string oldstr(VdevGUIDString());
bool retval = true;
/* Figure out what pool we're working on */
ZpoolList zpl(ZpoolList::ZpoolByGUID, &m_poolGUID);
- if (zpl.empty()) {
+ zpool_handle_t *zhp(zpl.empty() ? NULL : zpl.front());
+ if (zhp == NULL) {
syslog(LOG_ERR, "CaseFile::Replace: could not find pool for "
"pool_guid %"PRIu64".", (uint64_t)m_poolGUID);
return (false);
}
- zhp = zpl.front();
poolname = zpool_get_name(zhp);
+ Vdev vd(zhp, CaseVdev(zhp));
+ Vdev replaced(BeingReplacedBy(zhp));
+
+ if (!vd.IsSpare() && !replaced.DoesNotExist()) {
+ /* If we are already being replaced by a working spare, pass. */
+ if (replaced.IsResilvering()
+ || replaced.State() == VDEV_STATE_HEALTHY) {
+ syslog(LOG_INFO, "CaseFile::Replace(%s->%s): already "
+ "replaced", VdevGUIDString().c_str(), path);
+ return (/*consumed*/false);
+ }
+ /*
+ * If we have already been replaced by a spare, but that spare
+ * is broken, we must spare the spare, not the original device.
+ */
+ if (isspare) {
+ oldstr = replaced.GUIDString();
+ syslog(LOG_INFO, "CaseFile::Replace(%s->%s): sparing "
+ "broken spare %s instead", VdevGUIDString().c_str(),
+ path, oldstr.c_str());
+ }
+ }
/*
* Build a root vdev/leaf vdev configuration suitable for
@@ -994,9 +1050,8 @@ CaseFile::Replace(const char* vdev_type,
if (nvlist_alloc(&nvroot, NV_UNIQUE_NAME, 0) != 0
|| nvlist_alloc(&newvd, NV_UNIQUE_NAME, 0) != 0) {
- syslog(LOG_ERR, "Replace vdev(%s/%s): "
- "Unable to allocate configuration data.\n",
- poolname, VdevGUIDString().c_str());
+ syslog(LOG_ERR, "Replace vdev(%s/%s): Unable to allocate "
+ "configuration data.", poolname, oldstr.c_str());
if (nvroot != NULL)
nvlist_free(nvroot);
return (false);
@@ -1006,9 +1061,8 @@ CaseFile::Replace(const char* vdev_type,
|| nvlist_add_string(nvroot, ZPOOL_CONFIG_TYPE, VDEV_TYPE_ROOT) != 0
|| nvlist_add_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN,
&newvd, 1) != 0) {
- syslog(LOG_ERR, "Replace vdev(%s/%s): "
- "Unable to initialize configuration data.\n",
- poolname, VdevGUIDString().c_str());
+ syslog(LOG_ERR, "Replace vdev(%s/%s): Unable to initialize "
+ "configuration data.", poolname, oldstr.c_str());
nvlist_free(newvd);
nvlist_free(nvroot);
return (true);
@@ -1017,19 +1071,15 @@ CaseFile::Replace(const char* vdev_type,
/* Data was copied when added to the root vdev. */
nvlist_free(newvd);
- if (zpool_vdev_attach(zhp, VdevGUIDString().c_str(),
- path, nvroot, /*replace*/B_TRUE) != 0) {
- syslog(LOG_ERR,
- "Replace vdev(%s/%s): %s: %s\n",
- poolname, VdevGUIDString().c_str(),
- libzfs_error_action(g_zfsHandle),
- libzfs_error_description(g_zfsHandle));
- retval = false;
- } else {
+ retval = (zpool_vdev_attach(zhp, oldstr.c_str(), path, nvroot,
+ /*replace*/B_TRUE) == 0);
+ if (retval)
syslog(LOG_INFO, "Replacing vdev(%s/%s) with %s\n",
- poolname, VdevGUIDString().c_str(),
- path);
- }
+ poolname, oldstr.c_str(), path);
+ else
+ syslog(LOG_ERR, "Replace vdev(%s/%s): %s: %s\n",
+ poolname, oldstr.c_str(), libzfs_error_action(g_zfsHandle),
+ libzfs_error_description(g_zfsHandle));
nvlist_free(nvroot);
return (retval);
@@ -1062,3 +1112,9 @@ CaseFile::ShouldFault() const
return (std::count_if(m_events.begin(), m_events.end(),
IsIOEvent) > ZFS_DEGRADE_IO_COUNT);
}
+
+nvlist_t *
+CaseFile::CaseVdev(zpool_handle_t *zhp) const
+{
+ return (VdevIterator(zhp).Find(VdevGUID()));
+}
Modified: projects/zfsd/head/cddl/sbin/zfsd/case_file.h
==============================================================================
--- projects/zfsd/head/cddl/sbin/zfsd/case_file.h Mon Oct 14 23:24:53 2013 (r256475)
+++ projects/zfsd/head/cddl/sbin/zfsd/case_file.h Mon Oct 14 23:31:18 2013 (r256476)
@@ -326,10 +326,21 @@ protected:
* \param vdev_type The type of the new vdev. Usually either
* VDEV_TYPE_DISK or VDEV_TYPE_FILE
* \param path The file system path to the new vdev
+ * \param isspare Whether the new vdev is a spare
*
* \return true iff the replacement was successful
*/
- bool Replace(const char* vdev_type, const char* path);
+ bool Replace(const char* vdev_type, const char* path, bool isspare);
+
+ /**
+ * \brief Which vdev, if any, is replacing ours.
+ *
+ * \param zhp Pool handle state from the caller context
+ *
+ * \return the vdev that is currently replacing ours,
+ * or NonexistentVdev if there isn't one.
+ */
+ Vdev BeingReplacedBy(zpool_handle_t *zhp);
/**
* \brief All CaseFiles being tracked by ZFSD.
@@ -371,6 +382,9 @@ protected:
* \brief Callout activated when a grace period
*/
Callout m_tentativeTimer;
+
+private:
+ nvlist_t *CaseVdev(zpool_handle_t *zhp) const;
};
inline DevCtl::Guid
Modified: projects/zfsd/head/cddl/sbin/zfsd/vdev.cc
==============================================================================
--- projects/zfsd/head/cddl/sbin/zfsd/vdev.cc Mon Oct 14 23:24:53 2013 (r256475)
+++ projects/zfsd/head/cddl/sbin/zfsd/vdev.cc Mon Oct 14 23:31:18 2013 (r256476)
@@ -37,6 +37,7 @@
*
* Implementation of the Vdev class.
*/
+#include <syslog.h>
#include <sys/cdefs.h>
#include <sys/fs/zfs.h>
@@ -58,68 +59,76 @@
#include "vdev_iterator.h"
#include "zfsd.h"
#include "zfsd_exception.h"
+#include "zpool_list.h"
__FBSDID("$FreeBSD$");
/*============================ Namespace Control =============================*/
using std::string;
using std::stringstream;
+//- Special objects -----------------------------------------------------------
+Vdev NonexistentVdev;
+
+//- Vdev Inline Public Methods ------------------------------------------------
/*=========================== Class Implementations ==========================*/
/*----------------------------------- Vdev -----------------------------------*/
-Vdev::Vdev(zpool_handle_t *pool, nvlist_t *config)
- : m_poolConfig(zpool_get_config(pool, NULL)),
- m_config(config)
+
+/* Special constructor for NonexistentVdev. */
+Vdev::Vdev()
+ : m_poolConfig(NULL),
+ m_config(NULL)
+{}
+
+bool
+Vdev::VdevLookupPoolGuid()
{
- uint64_t raw_guid;
- if (nvlist_lookup_uint64(m_poolConfig, ZPOOL_CONFIG_POOL_GUID,
- &raw_guid) != 0)
- throw ZfsdException("Unable to extract pool GUID "
- "from pool handle.");
- m_poolGUID = raw_guid;
+ uint64_t guid;
+ if (nvlist_lookup_uint64(m_poolConfig, ZPOOL_CONFIG_POOL_GUID, &guid))
+ return (false);
+ m_poolGUID = guid;
+ return (true);
+}
- if (nvlist_lookup_uint64(m_config, ZPOOL_CONFIG_GUID, &raw_guid) != 0)
+void
+Vdev::VdevLookupGuid()
+{
+ uint64_t guid;
+ if (nvlist_lookup_uint64(m_config, ZPOOL_CONFIG_GUID, &guid) != 0)
throw ZfsdException("Unable to extract vdev GUID "
"from vdev config data.");
- m_vdevGUID = raw_guid;
+ m_vdevGUID = guid;
+}
+
+Vdev::Vdev(zpool_handle_t *pool, nvlist_t *config)
+ : m_poolConfig(zpool_get_config(pool, NULL)),
+ m_config(config)
+{
+ if (!VdevLookupPoolGuid())
+ throw ZfsdException("Can't extract pool GUID from handle.");
+ VdevLookupGuid();
}
Vdev::Vdev(nvlist_t *poolConfig, nvlist_t *config)
: m_poolConfig(poolConfig),
m_config(config)
{
- uint64_t raw_guid;
- if (nvlist_lookup_uint64(m_poolConfig, ZPOOL_CONFIG_POOL_GUID,
- &raw_guid) != 0)
- throw ZfsdException("Unable to extract pool GUID "
- "from pool handle.");
- m_poolGUID = raw_guid;
-
- if (nvlist_lookup_uint64(m_config, ZPOOL_CONFIG_GUID, &raw_guid) != 0)
- throw ZfsdException("Unable to extract vdev GUID "
- "from vdev config data.");
- m_vdevGUID = raw_guid;
+ if (!VdevLookupPoolGuid())
+ throw ZfsdException("Can't extract pool GUID from config.");
+ VdevLookupGuid();
}
Vdev::Vdev(nvlist_t *labelConfig)
- : m_poolConfig(labelConfig)
+ : m_poolConfig(labelConfig),
+ m_config(labelConfig)
{
- uint64_t raw_guid;
-
/*
* Spares do not have a Pool GUID. Tolerate its absence.
* Code accessing this Vdev in a context where the Pool GUID is
* required will find it invalid (as it is upon Vdev construction)
* and act accordingly.
*/
- if (nvlist_lookup_uint64(labelConfig, ZPOOL_CONFIG_POOL_GUID,
- &raw_guid) == 0)
- m_poolGUID = raw_guid;
-
- if (nvlist_lookup_uint64(labelConfig, ZPOOL_CONFIG_GUID,
- &raw_guid) != 0)
- throw ZfsdException("Unable to extract vdev GUID "
- "from vdev label data.");
- m_vdevGUID = raw_guid;
+ (void) VdevLookupPoolGuid();
+ VdevLookupGuid();
try {
m_config = VdevIterator(labelConfig).Find(m_vdevGUID);
@@ -172,6 +181,125 @@ Vdev::State() const
return (VDEV_STATE_HEALTHY);
}
+std::list<Vdev>
+Vdev::Children()
+{
+ nvlist_t **vdevChildren;
+ int result;
+ u_int numChildren;
+ std::list<Vdev> children;
+
+ if (m_poolConfig == NULL || m_config == NULL)
+ return (children);
+
+ result = nvlist_lookup_nvlist_array(m_config,
+ ZPOOL_CONFIG_CHILDREN, &vdevChildren, &numChildren);
+ if (result != 0)
+ return (children);
+
+ for (u_int c = 0;c < numChildren; c++)
+ children.push_back(Vdev(m_poolConfig, vdevChildren[c]));
+
+ return (children);
+}
+
+Vdev
+Vdev::RootVdev()
+{
+ nvlist_t *rootVdev;
+
+ if (m_poolConfig == NULL)
+ return (NonexistentVdev);
+
+ if (nvlist_lookup_nvlist(m_poolConfig, ZPOOL_CONFIG_VDEV_TREE,
+ &rootVdev) != 0)
+ return (NonexistentVdev);
+ return (Vdev(m_poolConfig, rootVdev));
+}
+
+/*
+ * Find our parent. This requires doing a traversal of the config; we can't
+ * cache it as leaf vdevs may change their pool config location (spare,
+ * replacing, mirror, etc).
+ */
+Vdev
+Vdev::Parent()
+{
+ std::list<Vdev> to_examine;
+ std::list<Vdev> children;
+ std::list<Vdev>::iterator children_it;
+
+ to_examine.push_back(RootVdev());
+ for (;;) {
+ if (to_examine.empty())
+ return (NonexistentVdev);
+ Vdev vd = to_examine.front();
+ if (vd.DoesNotExist())
+ return (NonexistentVdev);
+ to_examine.pop_front();
+ children = vd.Children();
+ children_it = children.begin();
+ for (;children_it != children.end(); children_it++) {
+ Vdev child = *children_it;
+
+ if (child.GUID() == GUID())
+ return (vd);
+ to_examine.push_front(child);
+ }
+ }
+}
+
+bool
+Vdev::IsAvailableSpare() const
+{
+ /* If we have a pool guid, we cannot be an available spare. */
+ if (PoolGUID())
+ return (false);
+
+ return (true);
+}
+
+bool
+Vdev::IsSpare()
+{
+ uint64_t spare;
+ if (nvlist_lookup_uint64(m_config, ZPOOL_CONFIG_IS_SPARE, &spare) != 0)
+ return (false);
+ return (spare != 0);
+}
+
+bool
+Vdev::IsActiveSpare() const
+{
+ vdev_stat_t *vs;
+ uint_t c;
+
+ if (m_poolConfig == NULL)
+ return (false);
+
+ (void) nvlist_lookup_uint64_array(m_config, ZPOOL_CONFIG_VDEV_STATS,
+ reinterpret_cast<uint64_t **>(&vs), &c);
+ if (vs == NULL || vs->vs_aux != VDEV_AUX_SPARED)
+ return (false);
+ return (true);
+}
+
+bool
+Vdev::IsResilvering() const
+{
+ pool_scan_stat_t *ps = NULL;
+ uint_t c;
+
+ if (State() != VDEV_STATE_HEALTHY)
+ return (false);
+
+ (void) nvlist_lookup_uint64_array(m_config, ZPOOL_CONFIG_SCAN_STATS,
+ reinterpret_cast<uint64_t **>(&ps), &c);
+ if (ps == NULL || ps->pss_func != POOL_SCAN_RESILVER)
+ return (false);
+ return (true);
+}
+
string
Vdev::GUIDString() const
{
@@ -182,6 +310,13 @@ Vdev::GUIDString() const
}
string
+Vdev::Name(zpool_handle_t *zhp, bool verbose) const
+{
+ return (zpool_vdev_name(g_zfsHandle, zhp, m_config,
+ verbose ? B_TRUE : B_FALSE));
+}
+
+string
Vdev::Path() const
{
char *path(NULL);
Modified: projects/zfsd/head/cddl/sbin/zfsd/vdev.h
==============================================================================
--- projects/zfsd/head/cddl/sbin/zfsd/vdev.h Mon Oct 14 23:24:53 2013 (r256475)
+++ projects/zfsd/head/cddl/sbin/zfsd/vdev.h Mon Oct 14 23:31:18 2013 (r256476)
@@ -40,6 +40,7 @@
* Header requirements:
*
* #include <string>
+ * #include <list>
*
* #include <devctl/guid.h>
*/
@@ -103,6 +104,17 @@ public:
*/
Vdev(nvlist_t *vdevConfig);
+ /**
+ * \brief No-op copy constructor for nonexistent vdevs.
+ */
+ Vdev();
+ bool DoesNotExist() const;
+
+ /**
+ * \brief Return a list of the vdev's children.
+ */
+ std::list<Vdev> Children();
+
virtual DevCtl::Guid GUID() const;
virtual DevCtl::Guid PoolGUID() const;
virtual vdev_state State() const;
@@ -111,14 +123,26 @@ public:
std::string GUIDString() const;
nvlist_t *PoolConfig() const;
nvlist_t *Config() const;
+ Vdev Parent();
+ Vdev RootVdev();
+ std::string Name(zpool_handle_t *, bool verbose) const;
+ bool IsSpare();
+ bool IsAvailableSpare() const;
+ bool IsActiveSpare() const;
+ bool IsResilvering() const;
private:
- DevCtl::Guid m_poolGUID;
- DevCtl::Guid m_vdevGUID;
- nvlist_t *m_poolConfig;
- nvlist_t *m_config;
+ void VdevLookupGuid();
+ bool VdevLookupPoolGuid();
+ DevCtl::Guid m_poolGUID;
+ DevCtl::Guid m_vdevGUID;
+ nvlist_t *m_poolConfig;
+ nvlist_t *m_config;
};
+//- Special objects -----------------------------------------------------------
+extern Vdev NonexistentVdev;
+
//- Vdev Inline Public Methods ------------------------------------------------
inline DevCtl::Guid
Vdev::PoolGUID() const
@@ -144,4 +168,10 @@ Vdev::Config() const
return (m_config);
}
+inline bool
+Vdev::DoesNotExist() const
+{
+ return (m_config == NULL);
+}
+
#endif /* _VDEV_H_ */
Modified: projects/zfsd/head/cddl/sbin/zfsd/zfsd_exception.cc
==============================================================================
--- projects/zfsd/head/cddl/sbin/zfsd/zfsd_exception.cc Mon Oct 14 23:24:53 2013 (r256475)
+++ projects/zfsd/head/cddl/sbin/zfsd/zfsd_exception.cc Mon Oct 14 23:31:18 2013 (r256476)
@@ -41,6 +41,7 @@
#include <syslog.h>
#include <string>
+#include <list>
#include <sstream>
#include <devctl/exception.h>
More information about the svn-src-projects
mailing list