17a0c41d5SAlan Somers /*-
27a0c41d5SAlan Somers * Copyright (c) 2011, 2012, 2013, 2014, 2016 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 zfsd_event.cc
357a0c41d5SAlan Somers */
367a0c41d5SAlan Somers #include <sys/cdefs.h>
379e5787d2SMatt Macy #include <sys/byteorder.h>
387a0c41d5SAlan Somers #include <sys/time.h>
397a0c41d5SAlan Somers #include <sys/fs/zfs.h>
40e6c8b3c9SAlan Somers #include <sys/vdev_impl.h>
417a0c41d5SAlan Somers
427a0c41d5SAlan Somers #include <syslog.h>
437a0c41d5SAlan Somers
447a0c41d5SAlan Somers #include <libzfs.h>
459e5787d2SMatt Macy #include <libzutil.h>
467a0c41d5SAlan Somers /*
477a0c41d5SAlan Somers * Undefine flush, defined by cpufunc.h on sparc64, because it conflicts with
487a0c41d5SAlan Somers * C++ flush methods
497a0c41d5SAlan Somers */
507a0c41d5SAlan Somers #undef flush
519e5787d2SMatt Macy #undef __init
527a0c41d5SAlan Somers #include <list>
537a0c41d5SAlan Somers #include <map>
547a0c41d5SAlan Somers #include <sstream>
557a0c41d5SAlan Somers #include <string>
567a0c41d5SAlan Somers
577a0c41d5SAlan Somers #include <devdctl/guid.h>
587a0c41d5SAlan Somers #include <devdctl/event.h>
597a0c41d5SAlan Somers #include <devdctl/event_factory.h>
607a0c41d5SAlan Somers #include <devdctl/exception.h>
617a0c41d5SAlan Somers #include <devdctl/consumer.h>
627a0c41d5SAlan Somers
637a0c41d5SAlan Somers #include "callout.h"
647a0c41d5SAlan Somers #include "vdev_iterator.h"
657a0c41d5SAlan Somers #include "zfsd_event.h"
667a0c41d5SAlan Somers #include "case_file.h"
677a0c41d5SAlan Somers #include "vdev.h"
687a0c41d5SAlan Somers #include "zfsd.h"
697a0c41d5SAlan Somers #include "zfsd_exception.h"
707a0c41d5SAlan Somers #include "zpool_list.h"
717a0c41d5SAlan Somers /*============================ Namespace Control =============================*/
727a0c41d5SAlan Somers using DevdCtl::Event;
737a0c41d5SAlan Somers using DevdCtl::Guid;
747a0c41d5SAlan Somers using DevdCtl::NVPairMap;
757a0c41d5SAlan Somers using std::stringstream;
767a0c41d5SAlan Somers
777a0c41d5SAlan Somers /*=========================== Class Implementations ==========================*/
787a0c41d5SAlan Somers
79a07d59d1SAlan Somers /*-------------------------------- GeomEvent --------------------------------*/
807a0c41d5SAlan Somers
81a07d59d1SAlan Somers //- GeomEvent Static Public Methods -------------------------------------------
827a0c41d5SAlan Somers Event *
Builder(Event::Type type,NVPairMap & nvPairs,const string & eventString)83a07d59d1SAlan Somers GeomEvent::Builder(Event::Type type,
847a0c41d5SAlan Somers NVPairMap &nvPairs,
857a0c41d5SAlan Somers const string &eventString)
867a0c41d5SAlan Somers {
87a07d59d1SAlan Somers return (new GeomEvent(type, nvPairs, eventString));
887a0c41d5SAlan Somers }
897a0c41d5SAlan Somers
90a07d59d1SAlan Somers //- GeomEvent Virtual Public Methods ------------------------------------------
91a07d59d1SAlan Somers Event *
DeepCopy() const92a07d59d1SAlan Somers GeomEvent::DeepCopy() const
93a07d59d1SAlan Somers {
94a07d59d1SAlan Somers return (new GeomEvent(*this));
95a07d59d1SAlan Somers }
96a07d59d1SAlan Somers
97a07d59d1SAlan Somers bool
Process() const98a07d59d1SAlan Somers GeomEvent::Process() const
99a07d59d1SAlan Somers {
100a07d59d1SAlan Somers /*
101d727d8b0SAlan Somers * We only use GEOM events to repair damaged pools. So return early if
102d727d8b0SAlan Somers * there are no damaged pools
103d727d8b0SAlan Somers */
104d727d8b0SAlan Somers if (CaseFile::Empty())
105d727d8b0SAlan Somers return (false);
106d727d8b0SAlan Somers
107d727d8b0SAlan Somers /*
108d727d8b0SAlan Somers * We are only concerned with arrivals and physical path changes,
109d727d8b0SAlan Somers * because those can be used to satisfy online and autoreplace
110d727d8b0SAlan Somers * operations
111a07d59d1SAlan Somers */
112a07d59d1SAlan Somers if (Value("type") != "GEOM::physpath" && Value("type") != "CREATE")
113a07d59d1SAlan Somers return (false);
114a07d59d1SAlan Somers
115a07d59d1SAlan Somers /* Log the event since it is of interest. */
116a07d59d1SAlan Somers Log(LOG_INFO);
117a07d59d1SAlan Somers
118a07d59d1SAlan Somers string devPath;
119a07d59d1SAlan Somers if (!DevPath(devPath))
120a07d59d1SAlan Somers return (false);
121a07d59d1SAlan Somers
122a07d59d1SAlan Somers int devFd(open(devPath.c_str(), O_RDONLY));
123a07d59d1SAlan Somers if (devFd == -1)
124a07d59d1SAlan Somers return (false);
125a07d59d1SAlan Somers
126a07d59d1SAlan Somers bool inUse;
127a07d59d1SAlan Somers bool degraded;
128a07d59d1SAlan Somers nvlist_t *devLabel(ReadLabel(devFd, inUse, degraded));
129a07d59d1SAlan Somers
130a07d59d1SAlan Somers string physPath;
131a07d59d1SAlan Somers bool havePhysPath(PhysicalPath(physPath));
132a07d59d1SAlan Somers
133a07d59d1SAlan Somers string devName;
134a07d59d1SAlan Somers DevName(devName);
135a07d59d1SAlan Somers close(devFd);
136a07d59d1SAlan Somers
137a07d59d1SAlan Somers if (inUse && devLabel != NULL) {
138a07d59d1SAlan Somers OnlineByLabel(devPath, physPath, devLabel);
139a07d59d1SAlan Somers } else if (degraded) {
140a07d59d1SAlan Somers syslog(LOG_INFO, "%s is marked degraded. Ignoring "
141a07d59d1SAlan Somers "as a replace by physical path candidate.\n",
142a07d59d1SAlan Somers devName.c_str());
143a07d59d1SAlan Somers } else if (havePhysPath) {
144a07d59d1SAlan Somers /*
145a07d59d1SAlan Somers * TODO: attempt to resolve events using every casefile
146a07d59d1SAlan Somers * that matches this physpath
147a07d59d1SAlan Somers */
148a07d59d1SAlan Somers CaseFile *caseFile(CaseFile::Find(physPath));
149a07d59d1SAlan Somers if (caseFile != NULL) {
150a07d59d1SAlan Somers syslog(LOG_INFO,
151a07d59d1SAlan Somers "Found CaseFile(%s:%s:%s) - ReEvaluating\n",
152a07d59d1SAlan Somers caseFile->PoolGUIDString().c_str(),
153a07d59d1SAlan Somers caseFile->VdevGUIDString().c_str(),
154a07d59d1SAlan Somers zpool_state_to_name(caseFile->VdevState(),
155a07d59d1SAlan Somers VDEV_AUX_NONE));
156a07d59d1SAlan Somers caseFile->ReEvaluate(devPath, physPath, /*vdev*/NULL);
157a07d59d1SAlan Somers }
158a07d59d1SAlan Somers }
159a07d59d1SAlan Somers return (false);
160a07d59d1SAlan Somers }
161a07d59d1SAlan Somers
162a07d59d1SAlan Somers //- GeomEvent Protected Methods -----------------------------------------------
GeomEvent(Event::Type type,NVPairMap & nvpairs,const string & eventString)163a07d59d1SAlan Somers GeomEvent::GeomEvent(Event::Type type, NVPairMap &nvpairs,
164a07d59d1SAlan Somers const string &eventString)
165a07d59d1SAlan Somers : DevdCtl::GeomEvent(type, nvpairs, eventString)
166a07d59d1SAlan Somers {
167a07d59d1SAlan Somers }
168a07d59d1SAlan Somers
GeomEvent(const GeomEvent & src)169a07d59d1SAlan Somers GeomEvent::GeomEvent(const GeomEvent &src)
170a07d59d1SAlan Somers : DevdCtl::GeomEvent::GeomEvent(src)
171a07d59d1SAlan Somers {
172a07d59d1SAlan Somers }
173a07d59d1SAlan Somers
1747a0c41d5SAlan Somers nvlist_t *
ReadLabel(int devFd,bool & inUse,bool & degraded)175a07d59d1SAlan Somers GeomEvent::ReadLabel(int devFd, bool &inUse, bool °raded)
1767a0c41d5SAlan Somers {
1777a0c41d5SAlan Somers pool_state_t poolState;
1787a0c41d5SAlan Somers char *poolName;
1797a0c41d5SAlan Somers boolean_t b_inuse;
180e6c8b3c9SAlan Somers int nlabels;
1817a0c41d5SAlan Somers
1827a0c41d5SAlan Somers inUse = false;
1837a0c41d5SAlan Somers degraded = false;
1847a0c41d5SAlan Somers poolName = NULL;
1857a0c41d5SAlan Somers if (zpool_in_use(g_zfsHandle, devFd, &poolState,
1867a0c41d5SAlan Somers &poolName, &b_inuse) == 0) {
18776f9ab74SAlan Somers nvlist_t *devLabel = NULL;
1887a0c41d5SAlan Somers
1897a0c41d5SAlan Somers inUse = b_inuse == B_TRUE;
1907a0c41d5SAlan Somers if (poolName != NULL)
1917a0c41d5SAlan Somers free(poolName);
1927a0c41d5SAlan Somers
1939e5787d2SMatt Macy if (zpool_read_label(devFd, &devLabel, &nlabels) != 0)
1949e5787d2SMatt Macy return (NULL);
195e6c8b3c9SAlan Somers /*
196e6c8b3c9SAlan Somers * If we find a disk with fewer than the maximum number of
197e6c8b3c9SAlan Somers * labels, it might be the whole disk of a partitioned disk
198e6c8b3c9SAlan Somers * where ZFS resides on a partition. In that case, we should do
199e6c8b3c9SAlan Somers * nothing and wait for the partition to appear. Or, the disk
200e6c8b3c9SAlan Somers * might be damaged. In that case, zfsd should do nothing and
201e6c8b3c9SAlan Somers * wait for the sysadmin to decide.
202e6c8b3c9SAlan Somers */
20376f9ab74SAlan Somers if (nlabels != VDEV_LABELS || devLabel == NULL) {
20476f9ab74SAlan Somers nvlist_free(devLabel);
2057a0c41d5SAlan Somers return (NULL);
20676f9ab74SAlan Somers }
2077a0c41d5SAlan Somers
2087a0c41d5SAlan Somers try {
2097a0c41d5SAlan Somers Vdev vdev(devLabel);
2107a0c41d5SAlan Somers degraded = vdev.State() != VDEV_STATE_HEALTHY;
2117a0c41d5SAlan Somers return (devLabel);
2127a0c41d5SAlan Somers } catch (ZfsdException &exp) {
2137a0c41d5SAlan Somers string devName = fdevname(devFd);
2147a0c41d5SAlan Somers string devPath = _PATH_DEV + devName;
215a07d59d1SAlan Somers string context("GeomEvent::ReadLabel: "
2167a0c41d5SAlan Somers + devPath + ": ");
2177a0c41d5SAlan Somers
2187a0c41d5SAlan Somers exp.GetString().insert(0, context);
2197a0c41d5SAlan Somers exp.Log();
22076f9ab74SAlan Somers nvlist_free(devLabel);
2217a0c41d5SAlan Somers }
2227a0c41d5SAlan Somers }
2237a0c41d5SAlan Somers return (NULL);
2247a0c41d5SAlan Somers }
2257a0c41d5SAlan Somers
2267a0c41d5SAlan Somers bool
OnlineByLabel(const string & devPath,const string & physPath,nvlist_t * devConfig)227a07d59d1SAlan Somers GeomEvent::OnlineByLabel(const string &devPath, const string& physPath,
2287a0c41d5SAlan Somers nvlist_t *devConfig)
2297a0c41d5SAlan Somers {
230f698c1e9SAlan Somers bool ret = false;
2317a0c41d5SAlan Somers try {
232f698c1e9SAlan Somers CaseFileList case_list;
2337a0c41d5SAlan Somers /*
2347a0c41d5SAlan Somers * A device with ZFS label information has been
2357a0c41d5SAlan Somers * inserted. If it matches a device for which we
2367a0c41d5SAlan Somers * have a case, see if we can solve that case.
2377a0c41d5SAlan Somers */
2387a0c41d5SAlan Somers syslog(LOG_INFO, "Interrogating VDEV label for %s\n",
2397a0c41d5SAlan Somers devPath.c_str());
2407a0c41d5SAlan Somers Vdev vdev(devConfig);
241f698c1e9SAlan Somers CaseFile::Find(vdev.PoolGUID(),vdev.GUID(), case_list);
242f698c1e9SAlan Somers for (CaseFileList::iterator curr = case_list.begin();
243f698c1e9SAlan Somers curr != case_list.end(); curr++) {
244f698c1e9SAlan Somers ret |= (*curr)->ReEvaluate(devPath, physPath, &vdev);
245f698c1e9SAlan Somers }
246f698c1e9SAlan Somers return (ret);
2477a0c41d5SAlan Somers
2487a0c41d5SAlan Somers } catch (ZfsdException &exp) {
249a07d59d1SAlan Somers string context("GeomEvent::OnlineByLabel: " + devPath + ": ");
2507a0c41d5SAlan Somers
2517a0c41d5SAlan Somers exp.GetString().insert(0, context);
2527a0c41d5SAlan Somers exp.Log();
2537a0c41d5SAlan Somers }
254f698c1e9SAlan Somers return (ret);
2557a0c41d5SAlan Somers }
2567a0c41d5SAlan Somers
2577a0c41d5SAlan Somers
2587a0c41d5SAlan Somers /*--------------------------------- ZfsEvent ---------------------------------*/
2597a0c41d5SAlan Somers //- ZfsEvent Static Public Methods ---------------------------------------------
2607a0c41d5SAlan Somers DevdCtl::Event *
Builder(Event::Type type,NVPairMap & nvpairs,const string & eventString)2617a0c41d5SAlan Somers ZfsEvent::Builder(Event::Type type, NVPairMap &nvpairs,
2627a0c41d5SAlan Somers const string &eventString)
2637a0c41d5SAlan Somers {
2647a0c41d5SAlan Somers return (new ZfsEvent(type, nvpairs, eventString));
2657a0c41d5SAlan Somers }
2667a0c41d5SAlan Somers
2677a0c41d5SAlan Somers //- ZfsEvent Virtual Public Methods --------------------------------------------
2687a0c41d5SAlan Somers Event *
DeepCopy() const2697a0c41d5SAlan Somers ZfsEvent::DeepCopy() const
2707a0c41d5SAlan Somers {
2717a0c41d5SAlan Somers return (new ZfsEvent(*this));
2727a0c41d5SAlan Somers }
2737a0c41d5SAlan Somers
2747a0c41d5SAlan Somers bool
Process() const2757a0c41d5SAlan Somers ZfsEvent::Process() const
2767a0c41d5SAlan Somers {
2777a0c41d5SAlan Somers string logstr("");
2787a0c41d5SAlan Somers
2797a0c41d5SAlan Somers if (!Contains("class") && !Contains("type")) {
2807a0c41d5SAlan Somers syslog(LOG_ERR,
2817a0c41d5SAlan Somers "ZfsEvent::Process: Missing class or type data.");
2827a0c41d5SAlan Somers return (false);
2837a0c41d5SAlan Somers }
2847a0c41d5SAlan Somers
2857a0c41d5SAlan Somers /* On config syncs, replay any queued events first. */
286*92642bbaSAlan Somers if (Value("type").find("sysevent.fs.zfs.config_sync") == 0) {
2877a0c41d5SAlan Somers /*
2887a0c41d5SAlan Somers * Even if saved events are unconsumed the second time
2897a0c41d5SAlan Somers * around, drop them. Any events that still can't be
2907a0c41d5SAlan Somers * consumed are probably referring to vdevs or pools that
2917a0c41d5SAlan Somers * no longer exist.
2927a0c41d5SAlan Somers */
2937a0c41d5SAlan Somers ZfsDaemon::Get().ReplayUnconsumedEvents(/*discard*/true);
2947a0c41d5SAlan Somers CaseFile::ReEvaluateByGuid(PoolGUID(), *this);
2957a0c41d5SAlan Somers }
2967a0c41d5SAlan Somers
297*92642bbaSAlan Somers if (Value("type").find("sysevent.fs.zfs.") == 0) {
2987a0c41d5SAlan Somers /* Configuration changes, resilver events, etc. */
2997a0c41d5SAlan Somers ProcessPoolEvent();
3007a0c41d5SAlan Somers return (false);
3017a0c41d5SAlan Somers }
3027a0c41d5SAlan Somers
3037a0c41d5SAlan Somers if (!Contains("pool_guid") || !Contains("vdev_guid")) {
3047a0c41d5SAlan Somers /* Only currently interested in Vdev related events. */
3057a0c41d5SAlan Somers return (false);
3067a0c41d5SAlan Somers }
3077a0c41d5SAlan Somers
3087a0c41d5SAlan Somers CaseFile *caseFile(CaseFile::Find(PoolGUID(), VdevGUID()));
3097a0c41d5SAlan Somers if (caseFile != NULL) {
3107a0c41d5SAlan Somers Log(LOG_INFO);
3117a0c41d5SAlan Somers syslog(LOG_INFO, "Evaluating existing case file\n");
3127a0c41d5SAlan Somers caseFile->ReEvaluate(*this);
3137a0c41d5SAlan Somers return (false);
3147a0c41d5SAlan Somers }
3157a0c41d5SAlan Somers
3167a0c41d5SAlan Somers /* Skip events that can't be handled. */
3177a0c41d5SAlan Somers Guid poolGUID(PoolGUID());
3187a0c41d5SAlan Somers /* If there are no replicas for a pool, then it's not manageable. */
3197a0c41d5SAlan Somers if (Value("class").find("fs.zfs.vdev.no_replicas") == 0) {
3207a0c41d5SAlan Somers stringstream msg;
3217a0c41d5SAlan Somers msg << "No replicas available for pool " << poolGUID;
3227a0c41d5SAlan Somers msg << ", ignoring";
3237a0c41d5SAlan Somers Log(LOG_INFO);
3247a0c41d5SAlan Somers syslog(LOG_INFO, "%s", msg.str().c_str());
3257a0c41d5SAlan Somers return (false);
3267a0c41d5SAlan Somers }
3277a0c41d5SAlan Somers
3287a0c41d5SAlan Somers /*
3297a0c41d5SAlan Somers * Create a case file for this vdev, and have it
3307a0c41d5SAlan Somers * evaluate the event.
3317a0c41d5SAlan Somers */
3327a0c41d5SAlan Somers ZpoolList zpl(ZpoolList::ZpoolByGUID, &poolGUID);
3337a0c41d5SAlan Somers if (zpl.empty()) {
3347a0c41d5SAlan Somers stringstream msg;
3357a0c41d5SAlan Somers int priority = LOG_INFO;
3367a0c41d5SAlan Somers msg << "ZfsEvent::Process: Event for unknown pool ";
3377a0c41d5SAlan Somers msg << poolGUID << " ";
3387a0c41d5SAlan Somers msg << "queued";
3397a0c41d5SAlan Somers Log(LOG_INFO);
3407a0c41d5SAlan Somers syslog(priority, "%s", msg.str().c_str());
3417a0c41d5SAlan Somers return (true);
3427a0c41d5SAlan Somers }
3437a0c41d5SAlan Somers
3447a0c41d5SAlan Somers nvlist_t *vdevConfig = VdevIterator(zpl.front()).Find(VdevGUID());
3457a0c41d5SAlan Somers if (vdevConfig == NULL) {
3467a0c41d5SAlan Somers stringstream msg;
3477a0c41d5SAlan Somers int priority = LOG_INFO;
3487a0c41d5SAlan Somers msg << "ZfsEvent::Process: Event for unknown vdev ";
3497a0c41d5SAlan Somers msg << VdevGUID() << " ";
3507a0c41d5SAlan Somers msg << "queued";
3517a0c41d5SAlan Somers Log(LOG_INFO);
3527a0c41d5SAlan Somers syslog(priority, "%s", msg.str().c_str());
3537a0c41d5SAlan Somers return (true);
3547a0c41d5SAlan Somers }
3557a0c41d5SAlan Somers
3567a0c41d5SAlan Somers Vdev vdev(zpl.front(), vdevConfig);
3577a0c41d5SAlan Somers caseFile = &CaseFile::Create(vdev);
3587a0c41d5SAlan Somers if (caseFile->ReEvaluate(*this) == false) {
3597a0c41d5SAlan Somers stringstream msg;
3607a0c41d5SAlan Somers int priority = LOG_INFO;
3617a0c41d5SAlan Somers msg << "ZfsEvent::Process: Unconsumed event for vdev(";
3627a0c41d5SAlan Somers msg << zpool_get_name(zpl.front()) << ",";
3637a0c41d5SAlan Somers msg << vdev.GUID() << ") ";
3647a0c41d5SAlan Somers msg << "queued";
3657a0c41d5SAlan Somers Log(LOG_INFO);
3667a0c41d5SAlan Somers syslog(priority, "%s", msg.str().c_str());
3677a0c41d5SAlan Somers return (true);
3687a0c41d5SAlan Somers }
3697a0c41d5SAlan Somers return (false);
3707a0c41d5SAlan Somers }
3717a0c41d5SAlan Somers
3727a0c41d5SAlan Somers //- ZfsEvent Protected Methods -------------------------------------------------
ZfsEvent(Event::Type type,NVPairMap & nvpairs,const string & eventString)3737a0c41d5SAlan Somers ZfsEvent::ZfsEvent(Event::Type type, NVPairMap &nvpairs,
3747a0c41d5SAlan Somers const string &eventString)
3757a0c41d5SAlan Somers : DevdCtl::ZfsEvent(type, nvpairs, eventString)
3767a0c41d5SAlan Somers {
3777a0c41d5SAlan Somers }
3787a0c41d5SAlan Somers
ZfsEvent(const ZfsEvent & src)3797a0c41d5SAlan Somers ZfsEvent::ZfsEvent(const ZfsEvent &src)
3807a0c41d5SAlan Somers : DevdCtl::ZfsEvent(src)
3817a0c41d5SAlan Somers {
3827a0c41d5SAlan Somers }
3837a0c41d5SAlan Somers
3847a0c41d5SAlan Somers /*
3857a0c41d5SAlan Somers * Sometimes the kernel won't detach a spare when it is no longer needed. This
3867a0c41d5SAlan Somers * can happen for example if a drive is removed, then either the pool is
3877a0c41d5SAlan Somers * exported or the machine is powered off, then the drive is reinserted, then
3887a0c41d5SAlan Somers * the machine is powered on or the pool is imported. ZFSD must detach these
3897a0c41d5SAlan Somers * spares itself.
3907a0c41d5SAlan Somers */
3917a0c41d5SAlan Somers void
CleanupSpares() const3927a0c41d5SAlan Somers ZfsEvent::CleanupSpares() const
3937a0c41d5SAlan Somers {
3947a0c41d5SAlan Somers Guid poolGUID(PoolGUID());
3957a0c41d5SAlan Somers ZpoolList zpl(ZpoolList::ZpoolByGUID, &poolGUID);
3967a0c41d5SAlan Somers if (!zpl.empty()) {
3977a0c41d5SAlan Somers zpool_handle_t* hdl;
3987a0c41d5SAlan Somers
3997a0c41d5SAlan Somers hdl = zpl.front();
4007a0c41d5SAlan Somers VdevIterator(hdl).Each(TryDetach, (void*)hdl);
4017a0c41d5SAlan Somers }
4027a0c41d5SAlan Somers }
4037a0c41d5SAlan Somers
4047a0c41d5SAlan Somers void
ProcessPoolEvent() const4057a0c41d5SAlan Somers ZfsEvent::ProcessPoolEvent() const
4067a0c41d5SAlan Somers {
4077a0c41d5SAlan Somers bool degradedDevice(false);
4087a0c41d5SAlan Somers
4097a0c41d5SAlan Somers /* The pool is destroyed. Discard any open cases */
410*92642bbaSAlan Somers if (Value("type") == "sysevent.fs.zfs.pool_destroy") {
4117a0c41d5SAlan Somers Log(LOG_INFO);
4127a0c41d5SAlan Somers CaseFile::ReEvaluateByGuid(PoolGUID(), *this);
4137a0c41d5SAlan Somers return;
4147a0c41d5SAlan Somers }
4157a0c41d5SAlan Somers
4167a0c41d5SAlan Somers CaseFile *caseFile(CaseFile::Find(PoolGUID(), VdevGUID()));
4177a0c41d5SAlan Somers if (caseFile != NULL) {
4187a0c41d5SAlan Somers if (caseFile->VdevState() != VDEV_STATE_UNKNOWN
4197a0c41d5SAlan Somers && caseFile->VdevState() < VDEV_STATE_HEALTHY)
4207a0c41d5SAlan Somers degradedDevice = true;
4217a0c41d5SAlan Somers
4227a0c41d5SAlan Somers Log(LOG_INFO);
4237a0c41d5SAlan Somers caseFile->ReEvaluate(*this);
4247a0c41d5SAlan Somers }
425*92642bbaSAlan Somers else if (Value("type") == "sysevent.fs.zfs.resilver_finish")
4267a0c41d5SAlan Somers {
4277a0c41d5SAlan Somers /*
4287a0c41d5SAlan Somers * It's possible to get a resilver_finish event with no
4297a0c41d5SAlan Somers * corresponding casefile. For example, if a damaged pool were
4307a0c41d5SAlan Somers * exported, repaired, then reimported.
4317a0c41d5SAlan Somers */
4327a0c41d5SAlan Somers Log(LOG_INFO);
4337a0c41d5SAlan Somers CleanupSpares();
4347a0c41d5SAlan Somers }
4357a0c41d5SAlan Somers
436*92642bbaSAlan Somers if (Value("type") == "sysevent.fs.zfs.vdev_remove"
4377a0c41d5SAlan Somers && degradedDevice == false) {
4387a0c41d5SAlan Somers
4397a0c41d5SAlan Somers /* See if any other cases can make use of this device. */
4407a0c41d5SAlan Somers Log(LOG_INFO);
4417a0c41d5SAlan Somers ZfsDaemon::RequestSystemRescan();
4427a0c41d5SAlan Somers }
4437a0c41d5SAlan Somers }
4447a0c41d5SAlan Somers
4457a0c41d5SAlan Somers bool
TryDetach(Vdev & vdev,void * cbArg)4467a0c41d5SAlan Somers ZfsEvent::TryDetach(Vdev &vdev, void *cbArg)
4477a0c41d5SAlan Somers {
4487a0c41d5SAlan Somers /*
4497a0c41d5SAlan Somers * Outline:
4507a0c41d5SAlan Somers * if this device is a spare, and its parent includes one healthy,
4517a0c41d5SAlan Somers * non-spare child, then detach this device.
4527a0c41d5SAlan Somers */
4537a0c41d5SAlan Somers zpool_handle_t *hdl(static_cast<zpool_handle_t*>(cbArg));
4547a0c41d5SAlan Somers
4557a0c41d5SAlan Somers if (vdev.IsSpare()) {
4567a0c41d5SAlan Somers std::list<Vdev> siblings;
4577a0c41d5SAlan Somers std::list<Vdev>::iterator siblings_it;
4587a0c41d5SAlan Somers boolean_t cleanup = B_FALSE;
4597a0c41d5SAlan Somers
4607a0c41d5SAlan Somers Vdev parent = vdev.Parent();
4617a0c41d5SAlan Somers siblings = parent.Children();
4627a0c41d5SAlan Somers
4637a0c41d5SAlan Somers /* Determine whether the parent should be cleaned up */
4647a0c41d5SAlan Somers for (siblings_it = siblings.begin();
4657a0c41d5SAlan Somers siblings_it != siblings.end();
4667a0c41d5SAlan Somers siblings_it++) {
4677a0c41d5SAlan Somers Vdev sibling = *siblings_it;
4687a0c41d5SAlan Somers
4697a0c41d5SAlan Somers if (!sibling.IsSpare() &&
4707a0c41d5SAlan Somers sibling.State() == VDEV_STATE_HEALTHY) {
4717a0c41d5SAlan Somers cleanup = B_TRUE;
4727a0c41d5SAlan Somers break;
4737a0c41d5SAlan Somers }
4747a0c41d5SAlan Somers }
4757a0c41d5SAlan Somers
4767a0c41d5SAlan Somers if (cleanup) {
4777a0c41d5SAlan Somers syslog(LOG_INFO, "Detaching spare vdev %s from pool %s",
4787a0c41d5SAlan Somers vdev.Path().c_str(), zpool_get_name(hdl));
4797a0c41d5SAlan Somers zpool_vdev_detach(hdl, vdev.Path().c_str());
4807a0c41d5SAlan Somers }
4817a0c41d5SAlan Somers
4827a0c41d5SAlan Somers }
4837a0c41d5SAlan Somers
4847a0c41d5SAlan Somers /* Always return false, because there may be other spares to detach */
4857a0c41d5SAlan Somers return (false);
4867a0c41d5SAlan Somers }
487