xref: /freebsd/cddl/usr.sbin/zfsd/zfsd_event.cc (revision 1d386b48a555f61cb7325543adbbb5c3f3407a66)
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 &degraded)
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