zfsd_event.cc revision 326298
1300906Sasomers/*- 2300906Sasomers * Copyright (c) 2011, 2012, 2013, 2014, 2016 Spectra Logic Corporation 3300906Sasomers * All rights reserved. 4300906Sasomers * 5300906Sasomers * Redistribution and use in source and binary forms, with or without 6300906Sasomers * modification, are permitted provided that the following conditions 7300906Sasomers * are met: 8300906Sasomers * 1. Redistributions of source code must retain the above copyright 9300906Sasomers * notice, this list of conditions, and the following disclaimer, 10300906Sasomers * without modification. 11300906Sasomers * 2. Redistributions in binary form must reproduce at minimum a disclaimer 12300906Sasomers * substantially similar to the "NO WARRANTY" disclaimer below 13300906Sasomers * ("Disclaimer") and any redistribution must be conditioned upon 14300906Sasomers * including a substantially similar Disclaimer requirement for further 15300906Sasomers * binary redistribution. 16300906Sasomers * 17300906Sasomers * NO WARRANTY 18300906Sasomers * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19300906Sasomers * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20300906Sasomers * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 21300906Sasomers * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22300906Sasomers * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23300906Sasomers * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24300906Sasomers * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25300906Sasomers * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 26300906Sasomers * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 27300906Sasomers * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28300906Sasomers * POSSIBILITY OF SUCH DAMAGES. 29300906Sasomers * 30300906Sasomers * Authors: Justin T. Gibbs (Spectra Logic Corporation) 31300906Sasomers */ 32300906Sasomers 33300906Sasomers/** 34300906Sasomers * \file zfsd_event.cc 35300906Sasomers */ 36300906Sasomers#include <sys/cdefs.h> 37300906Sasomers#include <sys/time.h> 38300906Sasomers#include <sys/fs/zfs.h> 39326298Sasomers#include <sys/vdev_impl.h> 40300906Sasomers 41300906Sasomers#include <syslog.h> 42300906Sasomers 43300906Sasomers#include <libzfs.h> 44300906Sasomers/* 45300906Sasomers * Undefine flush, defined by cpufunc.h on sparc64, because it conflicts with 46300906Sasomers * C++ flush methods 47300906Sasomers */ 48300906Sasomers#undef flush 49300906Sasomers 50300906Sasomers#include <list> 51300906Sasomers#include <map> 52300906Sasomers#include <sstream> 53300906Sasomers#include <string> 54300906Sasomers 55300906Sasomers#include <devdctl/guid.h> 56300906Sasomers#include <devdctl/event.h> 57300906Sasomers#include <devdctl/event_factory.h> 58300906Sasomers#include <devdctl/exception.h> 59300906Sasomers#include <devdctl/consumer.h> 60300906Sasomers 61300906Sasomers#include "callout.h" 62300906Sasomers#include "vdev_iterator.h" 63300906Sasomers#include "zfsd_event.h" 64300906Sasomers#include "case_file.h" 65300906Sasomers#include "vdev.h" 66300906Sasomers#include "zfsd.h" 67300906Sasomers#include "zfsd_exception.h" 68300906Sasomers#include "zpool_list.h" 69300906Sasomers 70300906Sasomers__FBSDID("$FreeBSD: stable/11/cddl/usr.sbin/zfsd/zfsd_event.cc 326298 2017-11-28 00:19:04Z asomers $"); 71300906Sasomers/*============================ Namespace Control =============================*/ 72300906Sasomersusing DevdCtl::Event; 73300906Sasomersusing DevdCtl::Guid; 74300906Sasomersusing DevdCtl::NVPairMap; 75300906Sasomersusing std::stringstream; 76300906Sasomers 77300906Sasomers/*=========================== Class Implementations ==========================*/ 78300906Sasomers 79300906Sasomers/*-------------------------------- DevfsEvent --------------------------------*/ 80300906Sasomers 81300906Sasomers//- DevfsEvent Static Public Methods ------------------------------------------- 82300906SasomersEvent * 83300906SasomersDevfsEvent::Builder(Event::Type type, 84300906Sasomers NVPairMap &nvPairs, 85300906Sasomers const string &eventString) 86300906Sasomers{ 87300906Sasomers return (new DevfsEvent(type, nvPairs, eventString)); 88300906Sasomers} 89300906Sasomers 90300906Sasomers//- DevfsEvent Static Protected Methods ---------------------------------------- 91300906Sasomersnvlist_t * 92300906SasomersDevfsEvent::ReadLabel(int devFd, bool &inUse, bool °raded) 93300906Sasomers{ 94300906Sasomers pool_state_t poolState; 95300906Sasomers char *poolName; 96300906Sasomers boolean_t b_inuse; 97326298Sasomers int nlabels; 98300906Sasomers 99300906Sasomers inUse = false; 100300906Sasomers degraded = false; 101300906Sasomers poolName = NULL; 102300906Sasomers if (zpool_in_use(g_zfsHandle, devFd, &poolState, 103300906Sasomers &poolName, &b_inuse) == 0) { 104326298Sasomers nvlist_t *devLabel = NULL; 105300906Sasomers 106300906Sasomers inUse = b_inuse == B_TRUE; 107300906Sasomers if (poolName != NULL) 108300906Sasomers free(poolName); 109300906Sasomers 110326298Sasomers nlabels = zpool_read_all_labels(devFd, &devLabel); 111326298Sasomers /* 112326298Sasomers * If we find a disk with fewer than the maximum number of 113326298Sasomers * labels, it might be the whole disk of a partitioned disk 114326298Sasomers * where ZFS resides on a partition. In that case, we should do 115326298Sasomers * nothing and wait for the partition to appear. Or, the disk 116326298Sasomers * might be damaged. In that case, zfsd should do nothing and 117326298Sasomers * wait for the sysadmin to decide. 118326298Sasomers */ 119326298Sasomers if (nlabels != VDEV_LABELS || devLabel == NULL) { 120326298Sasomers nvlist_free(devLabel); 121300906Sasomers return (NULL); 122326298Sasomers } 123300906Sasomers 124300906Sasomers try { 125300906Sasomers Vdev vdev(devLabel); 126300906Sasomers degraded = vdev.State() != VDEV_STATE_HEALTHY; 127300906Sasomers return (devLabel); 128300906Sasomers } catch (ZfsdException &exp) { 129300906Sasomers string devName = fdevname(devFd); 130300906Sasomers string devPath = _PATH_DEV + devName; 131300906Sasomers string context("DevfsEvent::ReadLabel: " 132300906Sasomers + devPath + ": "); 133300906Sasomers 134300906Sasomers exp.GetString().insert(0, context); 135300906Sasomers exp.Log(); 136326298Sasomers nvlist_free(devLabel); 137300906Sasomers } 138300906Sasomers } 139300906Sasomers return (NULL); 140300906Sasomers} 141300906Sasomers 142300906Sasomersbool 143300906SasomersDevfsEvent::OnlineByLabel(const string &devPath, const string& physPath, 144300906Sasomers nvlist_t *devConfig) 145300906Sasomers{ 146300906Sasomers try { 147300906Sasomers /* 148300906Sasomers * A device with ZFS label information has been 149300906Sasomers * inserted. If it matches a device for which we 150300906Sasomers * have a case, see if we can solve that case. 151300906Sasomers */ 152300906Sasomers syslog(LOG_INFO, "Interrogating VDEV label for %s\n", 153300906Sasomers devPath.c_str()); 154300906Sasomers Vdev vdev(devConfig); 155300906Sasomers CaseFile *caseFile(CaseFile::Find(vdev.PoolGUID(), 156300906Sasomers vdev.GUID())); 157300906Sasomers if (caseFile != NULL) 158300906Sasomers return (caseFile->ReEvaluate(devPath, physPath, &vdev)); 159300906Sasomers 160300906Sasomers } catch (ZfsdException &exp) { 161300906Sasomers string context("DevfsEvent::OnlineByLabel: " + devPath + ": "); 162300906Sasomers 163300906Sasomers exp.GetString().insert(0, context); 164300906Sasomers exp.Log(); 165300906Sasomers } 166300906Sasomers return (false); 167300906Sasomers} 168300906Sasomers 169300906Sasomers//- DevfsEvent Virtual Public Methods ------------------------------------------ 170300906SasomersEvent * 171300906SasomersDevfsEvent::DeepCopy() const 172300906Sasomers{ 173300906Sasomers return (new DevfsEvent(*this)); 174300906Sasomers} 175300906Sasomers 176300906Sasomersbool 177300906SasomersDevfsEvent::Process() const 178300906Sasomers{ 179300906Sasomers /* 180300906Sasomers * We are only concerned with newly discovered 181300906Sasomers * devices that can be ZFS vdevs. 182300906Sasomers */ 183300906Sasomers if (Value("type") != "CREATE" || !IsDiskDev()) 184300906Sasomers return (false); 185300906Sasomers 186300906Sasomers /* Log the event since it is of interest. */ 187300906Sasomers Log(LOG_INFO); 188300906Sasomers 189300906Sasomers string devPath; 190300906Sasomers if (!DevPath(devPath)) 191300906Sasomers return (false); 192300906Sasomers 193300906Sasomers int devFd(open(devPath.c_str(), O_RDONLY)); 194300906Sasomers if (devFd == -1) 195300906Sasomers return (false); 196300906Sasomers 197300906Sasomers bool inUse; 198300906Sasomers bool degraded; 199300906Sasomers nvlist_t *devLabel(ReadLabel(devFd, inUse, degraded)); 200300906Sasomers 201300906Sasomers string physPath; 202300906Sasomers bool havePhysPath(PhysicalPath(physPath)); 203300906Sasomers 204300906Sasomers string devName; 205300906Sasomers DevName(devName); 206300906Sasomers close(devFd); 207300906Sasomers 208300906Sasomers if (inUse && devLabel != NULL) { 209300906Sasomers OnlineByLabel(devPath, physPath, devLabel); 210300906Sasomers } else if (degraded) { 211300906Sasomers syslog(LOG_INFO, "%s is marked degraded. Ignoring " 212300906Sasomers "as a replace by physical path candidate.\n", 213300906Sasomers devName.c_str()); 214300906Sasomers } else if (havePhysPath && IsWholeDev()) { 215300906Sasomers /* 216300906Sasomers * TODO: attempt to resolve events using every casefile 217300906Sasomers * that matches this physpath 218300906Sasomers */ 219300906Sasomers CaseFile *caseFile(CaseFile::Find(physPath)); 220300906Sasomers if (caseFile != NULL) { 221300906Sasomers syslog(LOG_INFO, 222300906Sasomers "Found CaseFile(%s:%s:%s) - ReEvaluating\n", 223300906Sasomers caseFile->PoolGUIDString().c_str(), 224300906Sasomers caseFile->VdevGUIDString().c_str(), 225300906Sasomers zpool_state_to_name(caseFile->VdevState(), 226300906Sasomers VDEV_AUX_NONE)); 227300906Sasomers caseFile->ReEvaluate(devPath, physPath, /*vdev*/NULL); 228300906Sasomers } 229300906Sasomers } 230300906Sasomers if (devLabel != NULL) 231300906Sasomers nvlist_free(devLabel); 232300906Sasomers return (false); 233300906Sasomers} 234300906Sasomers 235300906Sasomers//- DevfsEvent Protected Methods ----------------------------------------------- 236300906SasomersDevfsEvent::DevfsEvent(Event::Type type, NVPairMap &nvpairs, 237300906Sasomers const string &eventString) 238300906Sasomers : DevdCtl::DevfsEvent(type, nvpairs, eventString) 239300906Sasomers{ 240300906Sasomers} 241300906Sasomers 242300906SasomersDevfsEvent::DevfsEvent(const DevfsEvent &src) 243300906Sasomers : DevdCtl::DevfsEvent::DevfsEvent(src) 244300906Sasomers{ 245300906Sasomers} 246300906Sasomers 247300906Sasomers/*-------------------------------- GeomEvent --------------------------------*/ 248300906Sasomers 249300906Sasomers//- GeomEvent Static Public Methods ------------------------------------------- 250300906SasomersEvent * 251300906SasomersGeomEvent::Builder(Event::Type type, 252300906Sasomers NVPairMap &nvPairs, 253300906Sasomers const string &eventString) 254300906Sasomers{ 255300906Sasomers return (new GeomEvent(type, nvPairs, eventString)); 256300906Sasomers} 257300906Sasomers 258300906Sasomers//- GeomEvent Virtual Public Methods ------------------------------------------ 259300906SasomersEvent * 260300906SasomersGeomEvent::DeepCopy() const 261300906Sasomers{ 262300906Sasomers return (new GeomEvent(*this)); 263300906Sasomers} 264300906Sasomers 265300906Sasomersbool 266300906SasomersGeomEvent::Process() const 267300906Sasomers{ 268300906Sasomers /* 269300906Sasomers * We are only concerned with physical path changes, because those can 270300906Sasomers * be used to satisfy autoreplace operations 271300906Sasomers */ 272300906Sasomers if (Value("type") != "GEOM::physpath" || !IsDiskDev()) 273300906Sasomers return (false); 274300906Sasomers 275300906Sasomers /* Log the event since it is of interest. */ 276300906Sasomers Log(LOG_INFO); 277300906Sasomers 278300906Sasomers string devPath; 279300906Sasomers if (!DevPath(devPath)) 280300906Sasomers return (false); 281300906Sasomers 282300906Sasomers string physPath; 283300906Sasomers bool havePhysPath(PhysicalPath(physPath)); 284300906Sasomers 285300906Sasomers string devName; 286300906Sasomers DevName(devName); 287300906Sasomers 288300906Sasomers if (havePhysPath) { 289300906Sasomers /* 290300906Sasomers * TODO: attempt to resolve events using every casefile 291300906Sasomers * that matches this physpath 292300906Sasomers */ 293300906Sasomers CaseFile *caseFile(CaseFile::Find(physPath)); 294300906Sasomers if (caseFile != NULL) { 295300906Sasomers syslog(LOG_INFO, 296300906Sasomers "Found CaseFile(%s:%s:%s) - ReEvaluating\n", 297300906Sasomers caseFile->PoolGUIDString().c_str(), 298300906Sasomers caseFile->VdevGUIDString().c_str(), 299300906Sasomers zpool_state_to_name(caseFile->VdevState(), 300300906Sasomers VDEV_AUX_NONE)); 301300906Sasomers caseFile->ReEvaluate(devPath, physPath, /*vdev*/NULL); 302300906Sasomers } 303300906Sasomers } 304300906Sasomers return (false); 305300906Sasomers} 306300906Sasomers 307300906Sasomers//- GeomEvent Protected Methods ----------------------------------------------- 308300906SasomersGeomEvent::GeomEvent(Event::Type type, NVPairMap &nvpairs, 309300906Sasomers const string &eventString) 310300906Sasomers : DevdCtl::GeomEvent(type, nvpairs, eventString) 311300906Sasomers{ 312300906Sasomers} 313300906Sasomers 314300906SasomersGeomEvent::GeomEvent(const GeomEvent &src) 315300906Sasomers : DevdCtl::GeomEvent::GeomEvent(src) 316300906Sasomers{ 317300906Sasomers} 318300906Sasomers 319300906Sasomers 320300906Sasomers/*--------------------------------- ZfsEvent ---------------------------------*/ 321300906Sasomers//- ZfsEvent Static Public Methods --------------------------------------------- 322300906SasomersDevdCtl::Event * 323300906SasomersZfsEvent::Builder(Event::Type type, NVPairMap &nvpairs, 324300906Sasomers const string &eventString) 325300906Sasomers{ 326300906Sasomers return (new ZfsEvent(type, nvpairs, eventString)); 327300906Sasomers} 328300906Sasomers 329300906Sasomers//- ZfsEvent Virtual Public Methods -------------------------------------------- 330300906SasomersEvent * 331300906SasomersZfsEvent::DeepCopy() const 332300906Sasomers{ 333300906Sasomers return (new ZfsEvent(*this)); 334300906Sasomers} 335300906Sasomers 336300906Sasomersbool 337300906SasomersZfsEvent::Process() const 338300906Sasomers{ 339300906Sasomers string logstr(""); 340300906Sasomers 341300906Sasomers if (!Contains("class") && !Contains("type")) { 342300906Sasomers syslog(LOG_ERR, 343300906Sasomers "ZfsEvent::Process: Missing class or type data."); 344300906Sasomers return (false); 345300906Sasomers } 346300906Sasomers 347300906Sasomers /* On config syncs, replay any queued events first. */ 348300906Sasomers if (Value("type").find("misc.fs.zfs.config_sync") == 0) { 349300906Sasomers /* 350300906Sasomers * Even if saved events are unconsumed the second time 351300906Sasomers * around, drop them. Any events that still can't be 352300906Sasomers * consumed are probably referring to vdevs or pools that 353300906Sasomers * no longer exist. 354300906Sasomers */ 355300906Sasomers ZfsDaemon::Get().ReplayUnconsumedEvents(/*discard*/true); 356300906Sasomers CaseFile::ReEvaluateByGuid(PoolGUID(), *this); 357300906Sasomers } 358300906Sasomers 359300906Sasomers if (Value("type").find("misc.fs.zfs.") == 0) { 360300906Sasomers /* Configuration changes, resilver events, etc. */ 361300906Sasomers ProcessPoolEvent(); 362300906Sasomers return (false); 363300906Sasomers } 364300906Sasomers 365300906Sasomers if (!Contains("pool_guid") || !Contains("vdev_guid")) { 366300906Sasomers /* Only currently interested in Vdev related events. */ 367300906Sasomers return (false); 368300906Sasomers } 369300906Sasomers 370300906Sasomers CaseFile *caseFile(CaseFile::Find(PoolGUID(), VdevGUID())); 371300906Sasomers if (caseFile != NULL) { 372300906Sasomers Log(LOG_INFO); 373300906Sasomers syslog(LOG_INFO, "Evaluating existing case file\n"); 374300906Sasomers caseFile->ReEvaluate(*this); 375300906Sasomers return (false); 376300906Sasomers } 377300906Sasomers 378300906Sasomers /* Skip events that can't be handled. */ 379300906Sasomers Guid poolGUID(PoolGUID()); 380300906Sasomers /* If there are no replicas for a pool, then it's not manageable. */ 381300906Sasomers if (Value("class").find("fs.zfs.vdev.no_replicas") == 0) { 382300906Sasomers stringstream msg; 383300906Sasomers msg << "No replicas available for pool " << poolGUID; 384300906Sasomers msg << ", ignoring"; 385300906Sasomers Log(LOG_INFO); 386300906Sasomers syslog(LOG_INFO, "%s", msg.str().c_str()); 387300906Sasomers return (false); 388300906Sasomers } 389300906Sasomers 390300906Sasomers /* 391300906Sasomers * Create a case file for this vdev, and have it 392300906Sasomers * evaluate the event. 393300906Sasomers */ 394300906Sasomers ZpoolList zpl(ZpoolList::ZpoolByGUID, &poolGUID); 395300906Sasomers if (zpl.empty()) { 396300906Sasomers stringstream msg; 397300906Sasomers int priority = LOG_INFO; 398300906Sasomers msg << "ZfsEvent::Process: Event for unknown pool "; 399300906Sasomers msg << poolGUID << " "; 400300906Sasomers msg << "queued"; 401300906Sasomers Log(LOG_INFO); 402300906Sasomers syslog(priority, "%s", msg.str().c_str()); 403300906Sasomers return (true); 404300906Sasomers } 405300906Sasomers 406300906Sasomers nvlist_t *vdevConfig = VdevIterator(zpl.front()).Find(VdevGUID()); 407300906Sasomers if (vdevConfig == NULL) { 408300906Sasomers stringstream msg; 409300906Sasomers int priority = LOG_INFO; 410300906Sasomers msg << "ZfsEvent::Process: Event for unknown vdev "; 411300906Sasomers msg << VdevGUID() << " "; 412300906Sasomers msg << "queued"; 413300906Sasomers Log(LOG_INFO); 414300906Sasomers syslog(priority, "%s", msg.str().c_str()); 415300906Sasomers return (true); 416300906Sasomers } 417300906Sasomers 418300906Sasomers Vdev vdev(zpl.front(), vdevConfig); 419300906Sasomers caseFile = &CaseFile::Create(vdev); 420300906Sasomers if (caseFile->ReEvaluate(*this) == false) { 421300906Sasomers stringstream msg; 422300906Sasomers int priority = LOG_INFO; 423300906Sasomers msg << "ZfsEvent::Process: Unconsumed event for vdev("; 424300906Sasomers msg << zpool_get_name(zpl.front()) << ","; 425300906Sasomers msg << vdev.GUID() << ") "; 426300906Sasomers msg << "queued"; 427300906Sasomers Log(LOG_INFO); 428300906Sasomers syslog(priority, "%s", msg.str().c_str()); 429300906Sasomers return (true); 430300906Sasomers } 431300906Sasomers return (false); 432300906Sasomers} 433300906Sasomers 434300906Sasomers//- ZfsEvent Protected Methods ------------------------------------------------- 435300906SasomersZfsEvent::ZfsEvent(Event::Type type, NVPairMap &nvpairs, 436300906Sasomers const string &eventString) 437300906Sasomers : DevdCtl::ZfsEvent(type, nvpairs, eventString) 438300906Sasomers{ 439300906Sasomers} 440300906Sasomers 441300906SasomersZfsEvent::ZfsEvent(const ZfsEvent &src) 442300906Sasomers : DevdCtl::ZfsEvent(src) 443300906Sasomers{ 444300906Sasomers} 445300906Sasomers 446300906Sasomers/* 447300906Sasomers * Sometimes the kernel won't detach a spare when it is no longer needed. This 448300906Sasomers * can happen for example if a drive is removed, then either the pool is 449300906Sasomers * exported or the machine is powered off, then the drive is reinserted, then 450300906Sasomers * the machine is powered on or the pool is imported. ZFSD must detach these 451300906Sasomers * spares itself. 452300906Sasomers */ 453300906Sasomersvoid 454300906SasomersZfsEvent::CleanupSpares() const 455300906Sasomers{ 456300906Sasomers Guid poolGUID(PoolGUID()); 457300906Sasomers ZpoolList zpl(ZpoolList::ZpoolByGUID, &poolGUID); 458300906Sasomers if (!zpl.empty()) { 459300906Sasomers zpool_handle_t* hdl; 460300906Sasomers 461300906Sasomers hdl = zpl.front(); 462300906Sasomers VdevIterator(hdl).Each(TryDetach, (void*)hdl); 463300906Sasomers } 464300906Sasomers} 465300906Sasomers 466300906Sasomersvoid 467300906SasomersZfsEvent::ProcessPoolEvent() const 468300906Sasomers{ 469300906Sasomers bool degradedDevice(false); 470300906Sasomers 471300906Sasomers /* The pool is destroyed. Discard any open cases */ 472300906Sasomers if (Value("type") == "misc.fs.zfs.pool_destroy") { 473300906Sasomers Log(LOG_INFO); 474300906Sasomers CaseFile::ReEvaluateByGuid(PoolGUID(), *this); 475300906Sasomers return; 476300906Sasomers } 477300906Sasomers 478300906Sasomers CaseFile *caseFile(CaseFile::Find(PoolGUID(), VdevGUID())); 479300906Sasomers if (caseFile != NULL) { 480300906Sasomers if (caseFile->VdevState() != VDEV_STATE_UNKNOWN 481300906Sasomers && caseFile->VdevState() < VDEV_STATE_HEALTHY) 482300906Sasomers degradedDevice = true; 483300906Sasomers 484300906Sasomers Log(LOG_INFO); 485300906Sasomers caseFile->ReEvaluate(*this); 486300906Sasomers } 487300906Sasomers else if (Value("type") == "misc.fs.zfs.resilver_finish") 488300906Sasomers { 489300906Sasomers /* 490300906Sasomers * It's possible to get a resilver_finish event with no 491300906Sasomers * corresponding casefile. For example, if a damaged pool were 492300906Sasomers * exported, repaired, then reimported. 493300906Sasomers */ 494300906Sasomers Log(LOG_INFO); 495300906Sasomers CleanupSpares(); 496300906Sasomers } 497300906Sasomers 498300906Sasomers if (Value("type") == "misc.fs.zfs.vdev_remove" 499300906Sasomers && degradedDevice == false) { 500300906Sasomers 501300906Sasomers /* See if any other cases can make use of this device. */ 502300906Sasomers Log(LOG_INFO); 503300906Sasomers ZfsDaemon::RequestSystemRescan(); 504300906Sasomers } 505300906Sasomers} 506300906Sasomers 507300906Sasomersbool 508300906SasomersZfsEvent::TryDetach(Vdev &vdev, void *cbArg) 509300906Sasomers{ 510300906Sasomers /* 511300906Sasomers * Outline: 512300906Sasomers * if this device is a spare, and its parent includes one healthy, 513300906Sasomers * non-spare child, then detach this device. 514300906Sasomers */ 515300906Sasomers zpool_handle_t *hdl(static_cast<zpool_handle_t*>(cbArg)); 516300906Sasomers 517300906Sasomers if (vdev.IsSpare()) { 518300906Sasomers std::list<Vdev> siblings; 519300906Sasomers std::list<Vdev>::iterator siblings_it; 520300906Sasomers boolean_t cleanup = B_FALSE; 521300906Sasomers 522300906Sasomers Vdev parent = vdev.Parent(); 523300906Sasomers siblings = parent.Children(); 524300906Sasomers 525300906Sasomers /* Determine whether the parent should be cleaned up */ 526300906Sasomers for (siblings_it = siblings.begin(); 527300906Sasomers siblings_it != siblings.end(); 528300906Sasomers siblings_it++) { 529300906Sasomers Vdev sibling = *siblings_it; 530300906Sasomers 531300906Sasomers if (!sibling.IsSpare() && 532300906Sasomers sibling.State() == VDEV_STATE_HEALTHY) { 533300906Sasomers cleanup = B_TRUE; 534300906Sasomers break; 535300906Sasomers } 536300906Sasomers } 537300906Sasomers 538300906Sasomers if (cleanup) { 539300906Sasomers syslog(LOG_INFO, "Detaching spare vdev %s from pool %s", 540300906Sasomers vdev.Path().c_str(), zpool_get_name(hdl)); 541300906Sasomers zpool_vdev_detach(hdl, vdev.Path().c_str()); 542300906Sasomers } 543300906Sasomers 544300906Sasomers } 545300906Sasomers 546300906Sasomers /* Always return false, because there may be other spares to detach */ 547300906Sasomers return (false); 548300906Sasomers} 549