17a0c41d5SAlan Somers /*-
27a0c41d5SAlan Somers * Copyright (c) 2011, 2012, 2013, 2014 Spectra Logic Corporation
37a0c41d5SAlan Somers * All rights reserved.
47a0c41d5SAlan Somers *
57a0c41d5SAlan Somers * Redistribution and use in source and binary forms, with or without
67a0c41d5SAlan Somers * modification, are permitted provided that the following conditions
77a0c41d5SAlan Somers * are met:
87a0c41d5SAlan Somers * 1. Redistributions of source code must retain the above copyright
97a0c41d5SAlan Somers * notice, this list of conditions, and the following disclaimer,
107a0c41d5SAlan Somers * without modification.
117a0c41d5SAlan Somers * 2. Redistributions in binary form must reproduce at minimum a disclaimer
127a0c41d5SAlan Somers * substantially similar to the "NO WARRANTY" disclaimer below
137a0c41d5SAlan Somers * ("Disclaimer") and any redistribution must be conditioned upon
147a0c41d5SAlan Somers * including a substantially similar Disclaimer requirement for further
157a0c41d5SAlan Somers * binary redistribution.
167a0c41d5SAlan Somers *
177a0c41d5SAlan Somers * NO WARRANTY
187a0c41d5SAlan Somers * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
197a0c41d5SAlan Somers * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
207a0c41d5SAlan Somers * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
217a0c41d5SAlan Somers * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
227a0c41d5SAlan Somers * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
237a0c41d5SAlan Somers * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
247a0c41d5SAlan Somers * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
257a0c41d5SAlan Somers * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
267a0c41d5SAlan Somers * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
277a0c41d5SAlan Somers * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
287a0c41d5SAlan Somers * POSSIBILITY OF SUCH DAMAGES.
297a0c41d5SAlan Somers *
307a0c41d5SAlan Somers * Authors: Justin T. Gibbs (Spectra Logic Corporation)
317a0c41d5SAlan Somers */
327a0c41d5SAlan Somers
337a0c41d5SAlan Somers /**
347a0c41d5SAlan Somers * \file vdev.cc
357a0c41d5SAlan Somers *
367a0c41d5SAlan Somers * Implementation of the Vdev class.
377a0c41d5SAlan Somers */
387a0c41d5SAlan Somers #include <syslog.h>
397a0c41d5SAlan Somers #include <sys/cdefs.h>
409e5787d2SMatt Macy #include <sys/byteorder.h>
417a0c41d5SAlan Somers #include <sys/fs/zfs.h>
427a0c41d5SAlan Somers
437a0c41d5SAlan Somers #include <libzfs.h>
447a0c41d5SAlan Somers /*
457a0c41d5SAlan Somers * Undefine flush, defined by cpufunc.h on sparc64, because it conflicts with
467a0c41d5SAlan Somers * C++ flush methods
477a0c41d5SAlan Somers */
487a0c41d5SAlan Somers #undef flush
497a0c41d5SAlan Somers
507a0c41d5SAlan Somers #include <list>
517a0c41d5SAlan Somers #include <map>
527a0c41d5SAlan Somers #include <string>
537a0c41d5SAlan Somers #include <sstream>
547a0c41d5SAlan Somers
557a0c41d5SAlan Somers #include <devdctl/guid.h>
567a0c41d5SAlan Somers #include <devdctl/event.h>
577a0c41d5SAlan Somers #include <devdctl/event_factory.h>
587a0c41d5SAlan Somers #include <devdctl/exception.h>
597a0c41d5SAlan Somers #include <devdctl/consumer.h>
607a0c41d5SAlan Somers
617a0c41d5SAlan Somers #include "vdev.h"
627a0c41d5SAlan Somers #include "vdev_iterator.h"
637a0c41d5SAlan Somers #include "zfsd.h"
647a0c41d5SAlan Somers #include "zfsd_exception.h"
657a0c41d5SAlan Somers #include "zpool_list.h"
667a0c41d5SAlan Somers /*============================ Namespace Control =============================*/
677a0c41d5SAlan Somers using std::string;
687a0c41d5SAlan Somers using std::stringstream;
697a0c41d5SAlan Somers
707a0c41d5SAlan Somers //- Special objects -----------------------------------------------------------
717a0c41d5SAlan Somers Vdev NonexistentVdev;
727a0c41d5SAlan Somers
737a0c41d5SAlan Somers //- Vdev Inline Public Methods ------------------------------------------------
747a0c41d5SAlan Somers /*=========================== Class Implementations ==========================*/
757a0c41d5SAlan Somers /*----------------------------------- Vdev -----------------------------------*/
767a0c41d5SAlan Somers
777a0c41d5SAlan Somers /* Special constructor for NonexistentVdev. */
Vdev()787a0c41d5SAlan Somers Vdev::Vdev()
797a0c41d5SAlan Somers : m_poolConfig(NULL),
807a0c41d5SAlan Somers m_config(NULL)
817a0c41d5SAlan Somers {}
827a0c41d5SAlan Somers
837a0c41d5SAlan Somers bool
VdevLookupPoolGuid()847a0c41d5SAlan Somers Vdev::VdevLookupPoolGuid()
857a0c41d5SAlan Somers {
867a0c41d5SAlan Somers uint64_t guid;
877a0c41d5SAlan Somers if (nvlist_lookup_uint64(m_poolConfig, ZPOOL_CONFIG_POOL_GUID, &guid))
887a0c41d5SAlan Somers return (false);
897a0c41d5SAlan Somers m_poolGUID = guid;
907a0c41d5SAlan Somers return (true);
917a0c41d5SAlan Somers }
927a0c41d5SAlan Somers
937a0c41d5SAlan Somers void
VdevLookupGuid()947a0c41d5SAlan Somers Vdev::VdevLookupGuid()
957a0c41d5SAlan Somers {
967a0c41d5SAlan Somers uint64_t guid;
977a0c41d5SAlan Somers if (nvlist_lookup_uint64(m_config, ZPOOL_CONFIG_GUID, &guid) != 0)
987a0c41d5SAlan Somers throw ZfsdException("Unable to extract vdev GUID "
997a0c41d5SAlan Somers "from vdev config data.");
1007a0c41d5SAlan Somers m_vdevGUID = guid;
1017a0c41d5SAlan Somers }
1027a0c41d5SAlan Somers
Vdev(zpool_handle_t * pool,nvlist_t * config)1037a0c41d5SAlan Somers Vdev::Vdev(zpool_handle_t *pool, nvlist_t *config)
1047a0c41d5SAlan Somers : m_poolConfig(zpool_get_config(pool, NULL)),
1057a0c41d5SAlan Somers m_config(config)
1067a0c41d5SAlan Somers {
1077a0c41d5SAlan Somers if (!VdevLookupPoolGuid())
1087a0c41d5SAlan Somers throw ZfsdException("Can't extract pool GUID from handle.");
1097a0c41d5SAlan Somers VdevLookupGuid();
1107a0c41d5SAlan Somers }
1117a0c41d5SAlan Somers
Vdev(nvlist_t * poolConfig,nvlist_t * config)1127a0c41d5SAlan Somers Vdev::Vdev(nvlist_t *poolConfig, nvlist_t *config)
1137a0c41d5SAlan Somers : m_poolConfig(poolConfig),
1147a0c41d5SAlan Somers m_config(config)
1157a0c41d5SAlan Somers {
1167a0c41d5SAlan Somers if (!VdevLookupPoolGuid())
1177a0c41d5SAlan Somers throw ZfsdException("Can't extract pool GUID from config.");
1187a0c41d5SAlan Somers VdevLookupGuid();
1197a0c41d5SAlan Somers }
1207a0c41d5SAlan Somers
Vdev(nvlist_t * labelConfig)1217a0c41d5SAlan Somers Vdev::Vdev(nvlist_t *labelConfig)
1227a0c41d5SAlan Somers : m_poolConfig(labelConfig),
1237a0c41d5SAlan Somers m_config(labelConfig)
1247a0c41d5SAlan Somers {
1257a0c41d5SAlan Somers /*
1267a0c41d5SAlan Somers * Spares do not have a Pool GUID. Tolerate its absence.
1277a0c41d5SAlan Somers * Code accessing this Vdev in a context where the Pool GUID is
1287a0c41d5SAlan Somers * required will find it invalid (as it is upon Vdev construction)
1297a0c41d5SAlan Somers * and act accordingly.
1307a0c41d5SAlan Somers */
1317a0c41d5SAlan Somers (void) VdevLookupPoolGuid();
1327a0c41d5SAlan Somers VdevLookupGuid();
1337a0c41d5SAlan Somers
1347a0c41d5SAlan Somers try {
1357a0c41d5SAlan Somers m_config = VdevIterator(labelConfig).Find(m_vdevGUID);
1367a0c41d5SAlan Somers } catch (const ZfsdException &exp) {
1377a0c41d5SAlan Somers /*
1387a0c41d5SAlan Somers * When reading a spare's label, it is normal not to find
1397a0c41d5SAlan Somers * a list of vdevs
1407a0c41d5SAlan Somers */
1417a0c41d5SAlan Somers m_config = NULL;
1427a0c41d5SAlan Somers }
1437a0c41d5SAlan Somers }
1447a0c41d5SAlan Somers
1457a0c41d5SAlan Somers bool
IsSpare() const1467a0c41d5SAlan Somers Vdev::IsSpare() const
1477a0c41d5SAlan Somers {
1487a0c41d5SAlan Somers uint64_t is_spare(0);
1497a0c41d5SAlan Somers
1507a0c41d5SAlan Somers if (m_config == NULL)
1517a0c41d5SAlan Somers return (false);
1527a0c41d5SAlan Somers
1537a0c41d5SAlan Somers (void)nvlist_lookup_uint64(m_config, ZPOOL_CONFIG_IS_SPARE, &is_spare);
1547a0c41d5SAlan Somers return (bool(is_spare));
1557a0c41d5SAlan Somers }
1567a0c41d5SAlan Somers
1577a0c41d5SAlan Somers vdev_state
State() const1587a0c41d5SAlan Somers Vdev::State() const
1597a0c41d5SAlan Somers {
1607a0c41d5SAlan Somers uint64_t *nvlist_array;
1617a0c41d5SAlan Somers vdev_stat_t *vs;
1627a0c41d5SAlan Somers uint_t vsc;
1637a0c41d5SAlan Somers
1647a0c41d5SAlan Somers if (m_config == NULL) {
1657a0c41d5SAlan Somers /*
1667a0c41d5SAlan Somers * If we couldn't find the list of vdevs, that normally means
1677a0c41d5SAlan Somers * that this is an available hotspare. In that case, we will
1687a0c41d5SAlan Somers * presume it to be healthy. Even if this spare had formerly
1697a0c41d5SAlan Somers * been in use, been degraded, and been replaced, the act of
1707a0c41d5SAlan Somers * replacement wipes the degraded bit from the label. So we
1717a0c41d5SAlan Somers * have no choice but to presume that it is healthy.
1727a0c41d5SAlan Somers */
1737a0c41d5SAlan Somers return (VDEV_STATE_HEALTHY);
1747a0c41d5SAlan Somers }
1757a0c41d5SAlan Somers
1767a0c41d5SAlan Somers if (nvlist_lookup_uint64_array(m_config, ZPOOL_CONFIG_VDEV_STATS,
1777a0c41d5SAlan Somers &nvlist_array, &vsc) == 0) {
1787a0c41d5SAlan Somers vs = reinterpret_cast<vdev_stat_t *>(nvlist_array);
1797a0c41d5SAlan Somers return (static_cast<vdev_state>(vs->vs_state));
1807a0c41d5SAlan Somers }
1817a0c41d5SAlan Somers
1827a0c41d5SAlan Somers /*
1837a0c41d5SAlan Somers * Stats are not available. This vdev was created from a label.
1847a0c41d5SAlan Somers * Synthesize a state based on available data.
1857a0c41d5SAlan Somers */
1867a0c41d5SAlan Somers uint64_t faulted(0);
1877a0c41d5SAlan Somers uint64_t degraded(0);
1887a0c41d5SAlan Somers (void)nvlist_lookup_uint64(m_config, ZPOOL_CONFIG_FAULTED, &faulted);
1897a0c41d5SAlan Somers (void)nvlist_lookup_uint64(m_config, ZPOOL_CONFIG_DEGRADED, °raded);
1907a0c41d5SAlan Somers if (faulted)
1917a0c41d5SAlan Somers return (VDEV_STATE_FAULTED);
1927a0c41d5SAlan Somers if (degraded)
1937a0c41d5SAlan Somers return (VDEV_STATE_DEGRADED);
1947a0c41d5SAlan Somers return (VDEV_STATE_HEALTHY);
1957a0c41d5SAlan Somers }
1967a0c41d5SAlan Somers
1977a0c41d5SAlan Somers std::list<Vdev>
Children()1987a0c41d5SAlan Somers Vdev::Children()
1997a0c41d5SAlan Somers {
2007a0c41d5SAlan Somers nvlist_t **vdevChildren;
2017a0c41d5SAlan Somers int result;
2027a0c41d5SAlan Somers u_int numChildren;
2037a0c41d5SAlan Somers std::list<Vdev> children;
2047a0c41d5SAlan Somers
2057a0c41d5SAlan Somers if (m_poolConfig == NULL || m_config == NULL)
2067a0c41d5SAlan Somers return (children);
2077a0c41d5SAlan Somers
2087a0c41d5SAlan Somers result = nvlist_lookup_nvlist_array(m_config,
2097a0c41d5SAlan Somers ZPOOL_CONFIG_CHILDREN, &vdevChildren, &numChildren);
2107a0c41d5SAlan Somers if (result != 0)
2117a0c41d5SAlan Somers return (children);
2127a0c41d5SAlan Somers
2137a0c41d5SAlan Somers for (u_int c = 0;c < numChildren; c++)
2147a0c41d5SAlan Somers children.push_back(Vdev(m_poolConfig, vdevChildren[c]));
2157a0c41d5SAlan Somers
2167a0c41d5SAlan Somers return (children);
2177a0c41d5SAlan Somers }
2187a0c41d5SAlan Somers
2197a0c41d5SAlan Somers Vdev
RootVdev()2207a0c41d5SAlan Somers Vdev::RootVdev()
2217a0c41d5SAlan Somers {
2227a0c41d5SAlan Somers nvlist_t *rootVdev;
2237a0c41d5SAlan Somers
2247a0c41d5SAlan Somers if (m_poolConfig == NULL)
2257a0c41d5SAlan Somers return (NonexistentVdev);
2267a0c41d5SAlan Somers
2277a0c41d5SAlan Somers if (nvlist_lookup_nvlist(m_poolConfig, ZPOOL_CONFIG_VDEV_TREE,
2287a0c41d5SAlan Somers &rootVdev) != 0)
2297a0c41d5SAlan Somers return (NonexistentVdev);
2307a0c41d5SAlan Somers return (Vdev(m_poolConfig, rootVdev));
2317a0c41d5SAlan Somers }
2327a0c41d5SAlan Somers
2337a0c41d5SAlan Somers /*
2347a0c41d5SAlan Somers * Find our parent. This requires doing a traversal of the config; we can't
2357a0c41d5SAlan Somers * cache it as leaf vdevs may change their pool config location (spare,
2367a0c41d5SAlan Somers * replacing, mirror, etc).
2377a0c41d5SAlan Somers */
2387a0c41d5SAlan Somers Vdev
Parent()2397a0c41d5SAlan Somers Vdev::Parent()
2407a0c41d5SAlan Somers {
2417a0c41d5SAlan Somers std::list<Vdev> to_examine;
2427a0c41d5SAlan Somers std::list<Vdev> children;
2437a0c41d5SAlan Somers std::list<Vdev>::iterator children_it;
2447a0c41d5SAlan Somers
2457a0c41d5SAlan Somers to_examine.push_back(RootVdev());
2467a0c41d5SAlan Somers for (;;) {
2477a0c41d5SAlan Somers if (to_examine.empty())
2487a0c41d5SAlan Somers return (NonexistentVdev);
2497a0c41d5SAlan Somers Vdev vd = to_examine.front();
2507a0c41d5SAlan Somers if (vd.DoesNotExist())
2517a0c41d5SAlan Somers return (NonexistentVdev);
2527a0c41d5SAlan Somers to_examine.pop_front();
2537a0c41d5SAlan Somers children = vd.Children();
2547a0c41d5SAlan Somers children_it = children.begin();
2557a0c41d5SAlan Somers for (;children_it != children.end(); children_it++) {
2567a0c41d5SAlan Somers Vdev child = *children_it;
2577a0c41d5SAlan Somers
2587a0c41d5SAlan Somers if (child.GUID() == GUID())
2597a0c41d5SAlan Somers return (vd);
2607a0c41d5SAlan Somers to_examine.push_front(child);
2617a0c41d5SAlan Somers }
2627a0c41d5SAlan Somers }
2637a0c41d5SAlan Somers }
2647a0c41d5SAlan Somers
2657a0c41d5SAlan Somers bool
IsAvailableSpare() const2667a0c41d5SAlan Somers Vdev::IsAvailableSpare() const
2677a0c41d5SAlan Somers {
2687a0c41d5SAlan Somers /* If we have a pool guid, we cannot be an available spare. */
2697a0c41d5SAlan Somers if (PoolGUID())
2707a0c41d5SAlan Somers return (false);
2717a0c41d5SAlan Somers
2727a0c41d5SAlan Somers return (true);
2737a0c41d5SAlan Somers }
2747a0c41d5SAlan Somers
2757a0c41d5SAlan Somers bool
IsSpare()2767a0c41d5SAlan Somers Vdev::IsSpare()
2777a0c41d5SAlan Somers {
2787a0c41d5SAlan Somers uint64_t spare;
2797a0c41d5SAlan Somers if (nvlist_lookup_uint64(m_config, ZPOOL_CONFIG_IS_SPARE, &spare) != 0)
2807a0c41d5SAlan Somers return (false);
2817a0c41d5SAlan Somers return (spare != 0);
2827a0c41d5SAlan Somers }
2837a0c41d5SAlan Somers
2847a0c41d5SAlan Somers bool
IsActiveSpare() const2857a0c41d5SAlan Somers Vdev::IsActiveSpare() const
2867a0c41d5SAlan Somers {
2877a0c41d5SAlan Somers vdev_stat_t *vs;
2887a0c41d5SAlan Somers uint_t c;
2897a0c41d5SAlan Somers
2907a0c41d5SAlan Somers if (m_poolConfig == NULL)
2917a0c41d5SAlan Somers return (false);
2927a0c41d5SAlan Somers
2937a0c41d5SAlan Somers (void) nvlist_lookup_uint64_array(m_config, ZPOOL_CONFIG_VDEV_STATS,
2947a0c41d5SAlan Somers reinterpret_cast<uint64_t **>(&vs), &c);
2957a0c41d5SAlan Somers if (vs == NULL || vs->vs_aux != VDEV_AUX_SPARED)
2967a0c41d5SAlan Somers return (false);
2977a0c41d5SAlan Somers return (true);
2987a0c41d5SAlan Somers }
2997a0c41d5SAlan Somers
3007a0c41d5SAlan Somers bool
IsResilvering() const3017a0c41d5SAlan Somers Vdev::IsResilvering() const
3027a0c41d5SAlan Somers {
3037a0c41d5SAlan Somers pool_scan_stat_t *ps = NULL;
3047a0c41d5SAlan Somers uint_t c;
3057a0c41d5SAlan Somers
3067a0c41d5SAlan Somers if (State() != VDEV_STATE_HEALTHY)
3077a0c41d5SAlan Somers return (false);
3087a0c41d5SAlan Somers
3097a0c41d5SAlan Somers (void) nvlist_lookup_uint64_array(m_config, ZPOOL_CONFIG_SCAN_STATS,
3107a0c41d5SAlan Somers reinterpret_cast<uint64_t **>(&ps), &c);
3117a0c41d5SAlan Somers if (ps == NULL || ps->pss_func != POOL_SCAN_RESILVER)
3127a0c41d5SAlan Somers return (false);
3137a0c41d5SAlan Somers return (true);
3147a0c41d5SAlan Somers }
3157a0c41d5SAlan Somers
3167a0c41d5SAlan Somers string
GUIDString() const3177a0c41d5SAlan Somers Vdev::GUIDString() const
3187a0c41d5SAlan Somers {
3197a0c41d5SAlan Somers stringstream vdevGUIDString;
3207a0c41d5SAlan Somers
3217a0c41d5SAlan Somers vdevGUIDString << GUID();
3227a0c41d5SAlan Somers return (vdevGUIDString.str());
3237a0c41d5SAlan Somers }
3247a0c41d5SAlan Somers
3257a0c41d5SAlan Somers string
Name(zpool_handle_t * zhp,bool verbose) const3267a0c41d5SAlan Somers Vdev::Name(zpool_handle_t *zhp, bool verbose) const
3277a0c41d5SAlan Somers {
3287a0c41d5SAlan Somers return (zpool_vdev_name(g_zfsHandle, zhp, m_config,
3297a0c41d5SAlan Somers verbose ? B_TRUE : B_FALSE));
3307a0c41d5SAlan Somers }
3317a0c41d5SAlan Somers
3327a0c41d5SAlan Somers string
Path() const3337a0c41d5SAlan Somers Vdev::Path() const
3347a0c41d5SAlan Somers {
335*2a58b312SMartin Matuska const char *path(NULL);
3367a0c41d5SAlan Somers
3377a0c41d5SAlan Somers if ((m_config != NULL)
3387a0c41d5SAlan Somers && (nvlist_lookup_string(m_config, ZPOOL_CONFIG_PATH, &path) == 0))
3397a0c41d5SAlan Somers return (path);
3407a0c41d5SAlan Somers
3417a0c41d5SAlan Somers return ("");
3427a0c41d5SAlan Somers }
3437a0c41d5SAlan Somers
3447a0c41d5SAlan Somers string
PhysicalPath() const3457a0c41d5SAlan Somers Vdev::PhysicalPath() const
3467a0c41d5SAlan Somers {
347*2a58b312SMartin Matuska const char *path(NULL);
3487a0c41d5SAlan Somers
3497a0c41d5SAlan Somers if ((m_config != NULL) && (nvlist_lookup_string(m_config,
3507a0c41d5SAlan Somers ZPOOL_CONFIG_PHYS_PATH, &path) == 0))
3517a0c41d5SAlan Somers return (path);
3527a0c41d5SAlan Somers
3537a0c41d5SAlan Somers return ("");
3547a0c41d5SAlan Somers }
355