svn commit: r256357 - projects/zfsd/head/cddl/sbin/zfsd
Alan Somers
asomers at FreeBSD.org
Fri Oct 11 22:44:17 UTC 2013
Author: asomers
Date: Fri Oct 11 22:44:15 2013
New Revision: 256357
URL: http://svnweb.freebsd.org/changeset/base/256357
Log:
zfsd will now try to activate a spare, if one is available, when a resource
dissapears. Other functionality, such as detaching the spare when the
original device returns, is TBD.
cddl/sbin/zfsd/vdev_iterator.h
cddl/sbin/zfsd/vdev_iterator.cc
cddl/sbin/zfsd/zpool_list.cc
cddl/sbin/zfsd/dev_ctl_event.h
cddl/sbin/zfsd/case_file.h
cddl/sbin/zfsd/case_file.cc
cddl/sbin/zfsd/vdev.h
cddl/sbin/zfsd/vdev.cc
Created a new Guid class that can have a None value.
Modified the Vdev class to be able to represent available
spares, which do not have pool or vdev guids.
cddl/sbin/zfsd/case_file.h
cddl/sbin/zfsd/case_file.cc
Abstract device replacement into the CaseFile::Replace
method, which is used by both ActivateSpare and replace by
physical path.
Try to active a hotspare whenever a vdev dissappears.
Submitted by: asomers
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/dev_ctl_event.cc
projects/zfsd/head/cddl/sbin/zfsd/dev_ctl_event.h
projects/zfsd/head/cddl/sbin/zfsd/vdev.cc
projects/zfsd/head/cddl/sbin/zfsd/vdev.h
projects/zfsd/head/cddl/sbin/zfsd/vdev_iterator.cc
projects/zfsd/head/cddl/sbin/zfsd/vdev_iterator.h
projects/zfsd/head/cddl/sbin/zfsd/zpool_list.cc
Modified: projects/zfsd/head/cddl/sbin/zfsd/case_file.cc
==============================================================================
--- projects/zfsd/head/cddl/sbin/zfsd/case_file.cc Fri Oct 11 22:19:45 2013 (r256356)
+++ projects/zfsd/head/cddl/sbin/zfsd/case_file.cc Fri Oct 11 22:44:15 2013 (r256357)
@@ -66,8 +66,9 @@ const string CaseFile::s_caseFilePath =
const timeval CaseFile::s_removeGracePeriod = { 60 /*sec*/, 0 /*usec*/};
//- CaseFile Static Public Methods ---------------------------------------------
+
CaseFile *
-CaseFile::Find(uint64_t poolGUID, uint64_t vdevGUID)
+CaseFile::Find(Guid poolGUID, Guid vdevGUID)
{
for (CaseFileList::iterator curCase = s_activeCases.begin();
curCase != s_activeCases.end(); curCase++) {
@@ -163,16 +164,17 @@ CaseFile::RefreshVdevState()
{
ZpoolList zpl(ZpoolList::ZpoolByGUID, &m_poolGUID);
if (zpl.empty()) {
- syslog(LOG_INFO,
- "CaseFile::RefreshVdevState: Unknown pool for "
- "Vdev(%ju,%ju).\n",
- m_poolGUID, m_vdevGUID);
- return (false);
+ stringstream msg;
+ msg << "CaseFile::RefreshVdevState: Unknown pool for Vdev(";
+ msg << m_poolGUID << "," << m_vdevGUID << ").";
+ syslog(LOG_INFO, msg.str().c_str());
+ 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());
@@ -288,55 +290,7 @@ CaseFile::ReEvaluate(const string &devPa
return (/*consumed*/false);
}
- /*
- * Build a root vdev/leaf vdev configuration suitable for
- * zpool_vdev_attach. Only enough data for the kernel to find
- * the device (i.e. type and disk device node path) are needed.
- */
- nvlist_t *nvroot(NULL);
- nvlist_t *newvd(NULL);
- if (nvlist_alloc(&nvroot, NV_UNIQUE_NAME, 0) != 0
- || nvlist_alloc(&newvd, NV_UNIQUE_NAME, 0) != 0) {
- syslog(LOG_ERR, "Replace vdev(%s/%s) by physical path: "
- "Unable to allocate configuration data.\n",
- zpool_get_name(pool), VdevGUIDString().c_str());
- if (nvroot != NULL)
- nvlist_free(nvroot);
- return (/*consumed*/false);
- }
-
- if (nvlist_add_string(newvd, ZPOOL_CONFIG_TYPE, VDEV_TYPE_DISK) != 0
- || nvlist_add_string(newvd, ZPOOL_CONFIG_PATH, devPath.c_str()) != 0
- || 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) by physical path: "
- "Unable to initialize configuration data.\n",
- zpool_get_name(pool), VdevGUIDString().c_str());
- nvlist_free(newvd);
- nvlist_free(nvroot);
- return (/*consumed*/true);
- }
-
- /* Data was copied when added to the root vdev. */
- nvlist_free(newvd);
-
- if (zpool_vdev_attach(pool, VdevGUIDString().c_str(),
- devPath.c_str(), nvroot,
- /*replace*/B_TRUE) != 0) {
- syslog(LOG_ERR,
- "Replace vdev(%s/%s) by physical path(attach): %s: %s\n",
- zpool_get_name(pool), VdevGUIDString().c_str(),
- libzfs_error_action(g_zfsHandle),
- libzfs_error_description(g_zfsHandle));
- } else {
- syslog(LOG_INFO, "Replacing vdev(%s/%s) with %s\n",
- zpool_get_name(pool), VdevGUIDString().c_str(),
- devPath.c_str());
- }
- nvlist_free(nvroot);
-
- return (true);
+ return (Replace(VDEV_TYPE_DISK, devPath.c_str()));
}
bool
@@ -385,6 +339,9 @@ CaseFile::ReEvaluate(const ZfsEvent &eve
*/
PurgeTentativeEvents();
+ /* Try to activate spares if they are available */
+ ActivateSpare();
+
/*
* Rescan the drives in the system to see if a recent
* drive arrival can be used to solve this case.
@@ -405,6 +362,83 @@ CaseFile::ReEvaluate(const ZfsEvent &eve
return (consumed || closed);
}
+
+bool
+CaseFile::ActivateSpare() {
+ nvlist_t *config, *nvroot;
+ nvlist_t **spares;
+ zpool_handle_t *zhp;
+ char *devPath, *vdev_type;
+ const char* poolname;
+ unsigned nspares, i;
+
+ ZpoolList zpl(ZpoolList::ZpoolByGUID, &m_poolGUID);
+ if (zpl.empty()) {
+ syslog(LOG_ERR, "CaseFile::Replace: could not find pool for "
+ "pool_guid %ju", (uint64_t)m_poolGUID);
+ return (false);
+ }
+ zhp = zpl.front();
+ poolname = zpool_get_name(zhp);
+ config = zpool_get_config(zhp, NULL);
+ if (config == NULL) {
+ syslog(LOG_ERR,
+ "ActivateSpare: Could not find pool config for pool %s",
+ poolname);
+ return (false);
+ }
+ if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, &nvroot) != 0){
+ syslog(LOG_ERR,
+ "ActivateSpare: Could not find vdev tree for pool %s",
+ poolname);
+ return (false);
+ }
+ nspares = 0;
+ nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES, &spares,
+ &nspares);
+ if (nspares == 0) {
+ /* The pool has no spares configured */
+ return (false);
+ }
+ for (i = 0; i < nspares; i++) {
+ vdev_stat_t *vs;
+ unsigned nstats;
+
+ if (nvlist_lookup_uint64_array(spares[i],
+ ZPOOL_CONFIG_VDEV_STATS, (uint64_t**)&vs, &nstats) != 0) {
+ syslog(LOG_ERR, "ActivateSpare: Could not find vdev "
+ "stats for pool %s, spare %d",
+ poolname, i);
+ return (false);
+ }
+
+ if ( (vs->vs_aux != VDEV_AUX_SPARED)
+ && (vs->vs_state == VDEV_STATE_HEALTHY)) {
+ /* We found a usable spare */
+ break;
+ }
+ }
+
+ if (i == nspares) {
+ /* No available spares were found */
+ return (false);
+ }
+
+ if (nvlist_lookup_string(spares[i], ZPOOL_CONFIG_PATH, &devPath) != 0){
+ syslog(LOG_ERR, "ActivateSpare: Cannot determine the path of "
+ "pool %s, spare %d", poolname, i);
+ return (false);
+ }
+
+ if (nvlist_lookup_string(spares[i], ZPOOL_CONFIG_TYPE, &vdev_type)!= 0){
+ syslog(LOG_ERR, "ActivateSpare: Cannot determine the vdev type "
+ "of pool %s, spare %d", poolname, i);
+ return (false);
+ }
+
+ return (Replace(vdev_type, devPath));
+}
+
void
CaseFile::RegisterCallout(const DevCtlEvent &event)
{
@@ -519,7 +553,7 @@ CaseFile::DeSerializeFile(const char *fi
sscanf(fileName, "pool_%ju_vdev_%ju.case",
&poolGUID, &vdevGUID);
- existingCaseFile = Find(poolGUID, vdevGUID);
+ existingCaseFile = Find(Guid(poolGUID), Guid(vdevGUID));
if (existingCaseFile != NULL) {
/*
* If the vdev is already degraded or faulted,
@@ -756,7 +790,7 @@ CaseFile::OnGracePeriodEnded()
}
/* Degrade the vdev and close the case. */
- if (zpool_vdev_degrade(zpl.front(), m_vdevGUID,
+ if (zpool_vdev_degrade(zpl.front(), (uint64_t)m_vdevGUID,
VDEV_AUX_ERR_EXCEEDED) == 0) {
Close();
return;
@@ -764,3 +798,69 @@ CaseFile::OnGracePeriodEnded()
}
Serialize();
}
+
+bool
+CaseFile::Replace(const char* vdev_type, const char* path) {
+ nvlist_t *nvroot, *newvd;
+ zpool_handle_t *zhp;
+ const char* poolname;
+
+ /* Figure out what pool we're working on */
+ ZpoolList zpl(ZpoolList::ZpoolByGUID, &m_poolGUID);
+ if (zpl.empty()) {
+ syslog(LOG_ERR, "CaseFile::Replace: could not find pool for "
+ "pool_guid %ju", (uint64_t)m_poolGUID);
+ return (false);
+ }
+ zhp = zpl.front();
+ poolname = zpool_get_name(zhp);
+
+ /*
+ * Build a root vdev/leaf vdev configuration suitable for
+ * zpool_vdev_attach. Only enough data for the kernel to find
+ * the device (i.e. type and disk device node path) are needed.
+ */
+ nvroot = NULL;
+ newvd = NULL;
+
+ if (nvlist_alloc(&nvroot, NV_UNIQUE_NAME, 0) != 0
+ || nvlist_alloc(&newvd, NV_UNIQUE_NAME, 0) != 0) {
+ syslog(LOG_ERR, "Replace vdev(%s/%s) by physical path: "
+ "Unable to allocate configuration data.\n",
+ poolname, VdevGUIDString().c_str());
+ if (nvroot != NULL)
+ nvlist_free(nvroot);
+ return (false);
+ }
+ if (nvlist_add_string(newvd, ZPOOL_CONFIG_TYPE, vdev_type) != 0
+ || nvlist_add_string(newvd, ZPOOL_CONFIG_PATH, path) != 0
+ || 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) by physical path: "
+ "Unable to initialize configuration data.\n",
+ poolname, VdevGUIDString().c_str());
+ nvlist_free(newvd);
+ nvlist_free(nvroot);
+ return (true);
+ }
+
+ /* 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) by physical path(attach): %s: %s\n",
+ poolname, VdevGUIDString().c_str(),
+ libzfs_error_action(g_zfsHandle),
+ libzfs_error_description(g_zfsHandle));
+ } else {
+ syslog(LOG_INFO, "Replacing vdev(%s/%s) with %s\n",
+ poolname, VdevGUIDString().c_str(),
+ path);
+ }
+ nvlist_free(nvroot);
+
+ return (true);
+}
Modified: projects/zfsd/head/cddl/sbin/zfsd/case_file.h
==============================================================================
--- projects/zfsd/head/cddl/sbin/zfsd/case_file.h Fri Oct 11 22:19:45 2013 (r256356)
+++ projects/zfsd/head/cddl/sbin/zfsd/case_file.h Fri Oct 11 22:44:15 2013 (r256357)
@@ -95,7 +95,7 @@ public:
* \return If found, a pointer to a valid CaseFile object.
* Otherwise NULL.
*/
- static CaseFile *Find(uint64_t poolGUID, uint64_t vdevGUID);
+ static CaseFile *Find(Guid poolGUID, Guid vdevGUID);
/**
* \brief Find a CaseFile object by a vdev's current/last known
@@ -137,8 +137,8 @@ public:
*/
static void PurgeAll();
- uint64_t PoolGUID() const;
- uint64_t VdevGUID() const;
+ Guid PoolGUID() const;
+ Guid VdevGUID() const;
vdev_state VdevState() const;
const string &PoolGUIDString() const;
const string &VdevGUIDString() const;
@@ -279,6 +279,30 @@ protected:
void OnGracePeriodEnded();
/**
+ * \brief Attempt to activate a spare on this case's pool.
+ *
+ * Call this whenever a pool becomes degraded. It will look for any
+ * spare devices and activate one to replace the casefile's vdev. It
+ * will _not_ close the casefile; that should only happen when the
+ * missing drive is replaced or the user promotes the spare.
+ *
+ * \return True if a spare was activated
+ */
+ bool ActivateSpare();
+
+ /**
+ * \brief replace a pool's vdev with another
+ *
+ * \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
+ *
+ * \return true iff the replacement was successful
+ *
+ */
+ bool Replace(const char* vdev_type, const char* path);
+
+ /**
* \brief All CaseFiles being tracked by ZFSD.
*/
static CaseFileList s_activeCases;
@@ -307,8 +331,8 @@ protected:
*/
DevCtlEventList m_tentativeEvents;
- uint64_t m_poolGUID;
- uint64_t m_vdevGUID;
+ Guid m_poolGUID;
+ Guid m_vdevGUID;
vdev_state m_vdevState;
string m_poolGUIDString;
string m_vdevGUIDString;
@@ -320,13 +344,13 @@ protected:
Callout m_tentativeTimer;
};
-inline uint64_t
+inline Guid
CaseFile::PoolGUID() const
{
return (m_poolGUID);
}
-inline uint64_t
+inline Guid
CaseFile::VdevGUID() const
{
return (m_vdevGUID);
Modified: projects/zfsd/head/cddl/sbin/zfsd/dev_ctl_event.cc
==============================================================================
--- projects/zfsd/head/cddl/sbin/zfsd/dev_ctl_event.cc Fri Oct 11 22:19:45 2013 (r256356)
+++ projects/zfsd/head/cddl/sbin/zfsd/dev_ctl_event.cc Fri Oct 11 22:44:15 2013 (r256357)
@@ -163,8 +163,11 @@ DevCtlEvent::CreateEvent(const string &e
EventFactoryKey key(type, nvpairs["system"]);
EventFactoryRegistry::iterator foundMethod(s_factoryRegistry.find(key));
- if (foundMethod == s_factoryRegistry.end())
+ if (foundMethod == s_factoryRegistry.end()) {
+ syslog(LOG_INFO, "DevCtlEvent::CreateEvent: unhandled event %s",
+ eventString.c_str());
return (NULL);
+ }
return ((foundMethod->second)(type, nvpairs, eventString));
}
@@ -633,11 +636,13 @@ ZfsEvent::Process() const
}
/* Skip events that can't be handled. */
- uint64_t poolGUID(PoolGUID());
+ Guid poolGUID(PoolGUID());
/* If there are no replicas for a pool, then it's not manageable. */
if (Value("class").find("fs.zfs.vdev.no_replicas") == 0) {
- syslog(LOG_INFO, "No replicas available for pool %ju"
- ", ignoring\n", (uintmax_t)poolGUID);
+ stringstream msg;
+ msg << "No replicas available for pool " << poolGUID;
+ msg << ", ignoring";
+ syslog(LOG_INFO, msg.str().c_str());
return;
}
@@ -647,21 +652,25 @@ ZfsEvent::Process() const
*/
ZpoolList zpl(ZpoolList::ZpoolByGUID, &poolGUID);
if (zpl.empty()) {
+ stringstream msg;
bool queued = ZfsDaemon::SaveEvent(*this);
int priority = queued ? LOG_INFO : LOG_ERR;
- syslog(priority,
- "ZfsEvent::Process: Event for unknown pool %ju %s",
- (uintmax_t)poolGUID, queued ? "queued" : "dropped");
+ msg << "ZfsEvent::Process: Event for unknown pool ";
+ msg << poolGUID << " ";
+ msg << (queued ? "queued" : "dropped");
+ syslog(priority, msg.str().c_str());
return;
}
nvlist_t *vdevConfig = VdevIterator(zpl.front()).Find(VdevGUID());
if (vdevConfig == NULL) {
+ stringstream msg;
bool queued = ZfsDaemon::SaveEvent(*this);
int priority = queued ? LOG_INFO : LOG_ERR;
- syslog(priority,
- "ZfsEvent::Process: Event for unknown vdev %ju %s",
- (uintmax_t)poolGUID, queued ? "queued" : "dropped");
+ msg << "ZfsEvent::Process: Event for unknown vdev ";
+ msg << VdevGUID() << " ";
+ msg << (queued ? "queued" : "dropped");
+ syslog(priority, msg.str().c_str());
return;
}
@@ -679,8 +688,18 @@ ZfsEvent::ZfsEvent(DevCtlEvent::Type typ
* These are zero on conversion failure as will happen if
* Value returns the empty string.
*/
- m_poolGUID = (uint64_t)strtoumax(Value("pool_guid").c_str(), NULL, 0);
- m_vdevGUID = (uint64_t)strtoumax(Value("vdev_guid").c_str(), NULL, 0);
+ if (Contains("pool_guid")) {
+ m_poolGUID = (uint64_t)strtoumax(Value("pool_guid").c_str(),
+ NULL, 0);
+ }
+ else
+ m_poolGUID = Guid();
+ if (Contains("vdev_guid")) {
+ m_vdevGUID = (uint64_t)strtoumax(Value("vdev_guid").c_str(),
+ NULL, 0);
+ }
+ else
+ m_vdevGUID = Guid();
}
ZfsEvent::ZfsEvent(const ZfsEvent &src)
Modified: projects/zfsd/head/cddl/sbin/zfsd/dev_ctl_event.h
==============================================================================
--- projects/zfsd/head/cddl/sbin/zfsd/dev_ctl_event.h Fri Oct 11 22:19:45 2013 (r256356)
+++ projects/zfsd/head/cddl/sbin/zfsd/dev_ctl_event.h Fri Oct 11 22:44:15 2013 (r256357)
@@ -49,6 +49,8 @@
#include <sys/fs/zfs.h>
#include <libzfs.h>
+#include "vdev.h"
+
/*============================ Namespace Control =============================*/
using std::map;
using std::pair;
@@ -473,8 +475,8 @@ public:
virtual void Process() const;
const string &PoolName() const;
- uint64_t PoolGUID() const;
- uint64_t VdevGUID() const;
+ Guid PoolGUID() const;
+ Guid VdevGUID() const;
protected:
/** Constructor */
@@ -485,8 +487,8 @@ protected:
void ProcessPoolEvent() const;
- uint64_t m_poolGUID;
- uint64_t m_vdevGUID;
+ Guid m_poolGUID;
+ Guid m_vdevGUID;
};
//- ZfsEvent Inline Public Methods --------------------------------------------
@@ -497,13 +499,13 @@ ZfsEvent::PoolName() const
return (Value("subsystem"));
}
-inline uint64_t
+inline Guid
ZfsEvent::PoolGUID() const
{
return (m_poolGUID);
}
-inline uint64_t
+inline Guid
ZfsEvent::VdevGUID() const
{
return (m_vdevGUID);
Modified: projects/zfsd/head/cddl/sbin/zfsd/vdev.cc
==============================================================================
--- projects/zfsd/head/cddl/sbin/zfsd/vdev.cc Fri Oct 11 22:19:45 2013 (r256356)
+++ projects/zfsd/head/cddl/sbin/zfsd/vdev.cc Fri Oct 11 22:44:15 2013 (r256357)
@@ -50,51 +50,76 @@ __FBSDID("$FreeBSD$");
using std::stringstream;
/*=========================== Class Implementations ==========================*/
+/*----------------------------------- Guid -----------------------------------*/
+std::ostream& operator<< (std::ostream& out, Guid g){
+ if (g.isValid())
+ out << (uint64_t) g;
+ else
+ out << "None";
+ return (out);
+}
+
+
/*----------------------------------- Vdev -----------------------------------*/
Vdev::Vdev(zpool_handle_t *pool, nvlist_t *config)
: m_poolConfig(zpool_get_config(pool, NULL)),
m_config(config)
{
+ uint64_t raw_guid;
if (nvlist_lookup_uint64(m_poolConfig, ZPOOL_CONFIG_POOL_GUID,
- &m_poolGUID) != 0)
+ &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, &m_vdevGUID) != 0)
+ 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;
}
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,
- &m_poolGUID) != 0)
+ &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, &m_vdevGUID) != 0)
+ 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;
}
Vdev::Vdev(nvlist_t *labelConfig)
: m_poolConfig(labelConfig)
{
+ uint64_t raw_guid;
if (nvlist_lookup_uint64(labelConfig, ZPOOL_CONFIG_POOL_GUID,
- &m_poolGUID) != 0)
- throw ZfsdException("Unable to extract pool GUID "
- "from vdev label data.");
+ &raw_guid) != 0)
+ m_vdevGUID = Guid();
+ else
+ m_poolGUID = raw_guid;
if (nvlist_lookup_uint64(labelConfig, ZPOOL_CONFIG_GUID,
- &m_vdevGUID) != 0)
+ &raw_guid) != 0)
throw ZfsdException("Unable to extract vdev GUID "
"from vdev label data.");
- m_config = VdevIterator(labelConfig).Find(m_vdevGUID);
- if (m_config == NULL)
- throw ZfsdException("Unable to find vdev config "
- "within vdev label data.");
+ m_vdevGUID = raw_guid;
+
+ try {
+ m_config = VdevIterator(labelConfig).Find(m_vdevGUID);
+ } catch (const ZfsdException &exp) {
+ /*
+ * When reading a spare's label, it is normal not to find
+ * a list of vdevs
+ */
+ m_config = NULL;
+ }
}
vdev_state
@@ -103,6 +128,18 @@ Vdev::State() const
vdev_stat_t *vs;
uint_t vsc;
+ if (m_config == NULL) {
+ /*
+ * If we couldn't find the list of vdevs, that normally means
+ * that this is an available hotspare. In that case, we will
+ * presume it to be healthy. Even if this spare had formerly
+ * been in use, been degraded, and been replaced, the act of
+ * replacement wipes the degraded bit from the label. So we
+ * have no choice but to presume that it is healthy.
+ */
+ return (VDEV_STATE_HEALTHY);
+ }
+
if (nvlist_lookup_uint64_array(m_config, ZPOOL_CONFIG_VDEV_STATS,
(uint64_t **)&vs, &vsc) == 0)
return (static_cast<vdev_state>(vs->vs_state));
@@ -136,7 +173,8 @@ Vdev::Path() const
{
char *path(NULL);
- if (nvlist_lookup_string(m_config, ZPOOL_CONFIG_PATH, &path) == 0)
+ if ((m_config != NULL)
+ && (nvlist_lookup_string(m_config, ZPOOL_CONFIG_PATH, &path) == 0))
return (path);
return ("");
@@ -147,7 +185,8 @@ Vdev::PhysicalPath() const
{
char *path(NULL);
- if (nvlist_lookup_string(m_config, ZPOOL_CONFIG_PHYS_PATH, &path) == 0)
+ if ((m_config != NULL) && (nvlist_lookup_string(m_config,
+ ZPOOL_CONFIG_PHYS_PATH, &path) == 0))
return (path);
return ("");
Modified: projects/zfsd/head/cddl/sbin/zfsd/vdev.h
==============================================================================
--- projects/zfsd/head/cddl/sbin/zfsd/vdev.h Fri Oct 11 22:19:45 2013 (r256356)
+++ projects/zfsd/head/cddl/sbin/zfsd/vdev.h Fri Oct 11 22:44:15 2013 (r256357)
@@ -40,11 +40,63 @@
#ifndef _VDEV_H_
#define _VDEV_H_
+#include <ostream>
#include <string>
#include <sys/fs/zfs.h>
#include <libzfs.h>
+
+/**
+ * \brief Object that represents guids.
+ *
+ * It can generally be manipulated as a uint64_t, but with a special value
+ * "None" that does not equal any valid guid.
+ *
+ * As of this writing, spa_generate_guid() in spa_misc.c explicitly refuses to
+ * return a guid of 0. So this class uses 0 as a flag value for "None". In the
+ * future, if 0 is allowed to be a valid guid, the implementation of this class
+ * must change.
+ */
+class Guid
+{
+public:
+ /* Constructors */
+ Guid(uint64_t guid) : m_GUID(guid) {};
+ Guid() { m_GUID = NONE_FLAG; };
+
+ /* Assignment */
+ Guid& operator=(const uint64_t& other) {
+ m_GUID = other;
+ return (*this);
+ };
+
+ /* Test the validity of this guid. */
+ bool isValid() const { return ((bool)m_GUID); };
+
+ /* Comparison to other Guid operators */
+ bool operator==(const Guid& other) const {
+ return (m_GUID == other.m_GUID);
+ };
+ bool operator!=(const Guid& other) const {
+ return (m_GUID != other.m_GUID);
+ };
+
+ /* Integer conversion operators */
+ operator uint64_t() const { return (m_GUID); };
+ operator bool() const { return (m_GUID != NONE_FLAG); };
+
+protected:
+ const static uint64_t NONE_FLAG = 0;
+ /* The stored value. 0 is a flag for "None" */
+ uint64_t m_GUID;
+};
+
+
+/** Convert the GUID into its string representation */
+std::ostream& operator<< (std::ostream& out, Guid g);
+
+
/**
* \brief Wrapper class for a vdev's name/value configuration list
* simplifying access to commonly used vdev attributes.
@@ -93,8 +145,8 @@ public:
*/
Vdev(nvlist_t *vdevConfig);
- uint64_t GUID() const;
- uint64_t PoolGUID() const;
+ Guid GUID() const;
+ Guid PoolGUID() const;
vdev_state State() const;
std::string Path() const;
std::string PhysicalPath() const;
@@ -103,19 +155,19 @@ public:
nvlist_t *Config() const;
private:
- uint64_t m_poolGUID;
- uint64_t m_vdevGUID;
+ Guid m_poolGUID;
+ Guid m_vdevGUID;
nvlist_t *m_poolConfig;
nvlist_t *m_config;
};
-inline uint64_t
+inline Guid
Vdev::PoolGUID() const
{
return (m_poolGUID);
}
-inline uint64_t
+inline Guid
Vdev::GUID() const
{
return (m_vdevGUID);
Modified: projects/zfsd/head/cddl/sbin/zfsd/vdev_iterator.cc
==============================================================================
--- projects/zfsd/head/cddl/sbin/zfsd/vdev_iterator.cc Fri Oct 11 22:19:45 2013 (r256356)
+++ projects/zfsd/head/cddl/sbin/zfsd/vdev_iterator.cc Fri Oct 11 22:44:15 2013 (r256357)
@@ -126,7 +126,7 @@ VdevIterator::Each(VdevCallback_t *callB
}
nvlist_t *
-VdevIterator::Find(uint64_t vdevGUID)
+VdevIterator::Find(Guid vdevGUID)
{
nvlist_t *vdevConfig;
Modified: projects/zfsd/head/cddl/sbin/zfsd/vdev_iterator.h
==============================================================================
--- projects/zfsd/head/cddl/sbin/zfsd/vdev_iterator.h Fri Oct 11 22:19:45 2013 (r256356)
+++ projects/zfsd/head/cddl/sbin/zfsd/vdev_iterator.h Fri Oct 11 22:44:15 2013 (r256357)
@@ -97,7 +97,7 @@ public:
* Upon return, the VdevIterator's cursor points to the vdev just
* past the returned vdev or end() if no matching vdev is found.
*/
- nvlist_t *Find(uint64_t vdevGUID);
+ nvlist_t *Find(Guid vdevGUID);
/**
* \brief Perform the specified operation on each leaf member of
Modified: projects/zfsd/head/cddl/sbin/zfsd/zpool_list.cc
==============================================================================
--- projects/zfsd/head/cddl/sbin/zfsd/zpool_list.cc Fri Oct 11 22:19:45 2013 (r256356)
+++ projects/zfsd/head/cddl/sbin/zfsd/zpool_list.cc Fri Oct 11 22:44:15 2013 (r256357)
@@ -35,6 +35,7 @@
*
* Implementation of the ZpoolList class.
*/
+#include "vdev.h"
#include "zpool_list.h"
#include "zfsd.h"
@@ -50,13 +51,13 @@ bool
ZpoolList::ZpoolByGUID(zpool_handle_t *pool, nvlist_t *poolConfig,
void *cbArg)
{
- uint64_t *desiredPoolGUID(static_cast<uint64_t *>(cbArg));
+ Guid *desiredPoolGUID(static_cast<Guid *>(cbArg));
uint64_t poolGUID;
/* We are only intested in the pool that matches our pool GUID. */
return (nvlist_lookup_uint64(poolConfig, ZPOOL_CONFIG_POOL_GUID,
&poolGUID) == 0
- && poolGUID == *desiredPoolGUID);
+ && poolGUID == (uint64_t)*desiredPoolGUID);
}
bool
More information about the svn-src-projects
mailing list