Date: Fri, 11 Oct 2013 22:44:15 +0000 (UTC) From: Alan Somers <asomers@FreeBSD.org> To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r256357 - projects/zfsd/head/cddl/sbin/zfsd Message-ID: <201310112244.r9BMiFrs064972@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
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
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201310112244.r9BMiFrs064972>