zfsd_event.cc revision 300906
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> 39300906Sasomers 40300906Sasomers#include <syslog.h> 41300906Sasomers 42300906Sasomers#include <libzfs.h> 43300906Sasomers/* 44300906Sasomers * Undefine flush, defined by cpufunc.h on sparc64, because it conflicts with 45300906Sasomers * C++ flush methods 46300906Sasomers */ 47300906Sasomers#undef flush 48300906Sasomers 49300906Sasomers#include <list> 50300906Sasomers#include <map> 51300906Sasomers#include <sstream> 52300906Sasomers#include <string> 53300906Sasomers 54300906Sasomers#include <devdctl/guid.h> 55300906Sasomers#include <devdctl/event.h> 56300906Sasomers#include <devdctl/event_factory.h> 57300906Sasomers#include <devdctl/exception.h> 58300906Sasomers#include <devdctl/consumer.h> 59300906Sasomers 60300906Sasomers#include "callout.h" 61300906Sasomers#include "vdev_iterator.h" 62300906Sasomers#include "zfsd_event.h" 63300906Sasomers#include "case_file.h" 64300906Sasomers#include "vdev.h" 65300906Sasomers#include "zfsd.h" 66300906Sasomers#include "zfsd_exception.h" 67300906Sasomers#include "zpool_list.h" 68300906Sasomers 69300906Sasomers__FBSDID("$FreeBSD: head/cddl/usr.sbin/zfsd/zfsd_event.cc 300906 2016-05-28 17:43:40Z asomers $"); 70300906Sasomers/*============================ Namespace Control =============================*/ 71300906Sasomersusing DevdCtl::Event; 72300906Sasomersusing DevdCtl::Guid; 73300906Sasomersusing DevdCtl::NVPairMap; 74300906Sasomersusing std::stringstream; 75300906Sasomers 76300906Sasomers/*=========================== Class Implementations ==========================*/ 77300906Sasomers 78300906Sasomers/*-------------------------------- DevfsEvent --------------------------------*/ 79300906Sasomers 80300906Sasomers//- DevfsEvent Static Public Methods ------------------------------------------- 81300906SasomersEvent * 82300906SasomersDevfsEvent::Builder(Event::Type type, 83300906Sasomers NVPairMap &nvPairs, 84300906Sasomers const string &eventString) 85300906Sasomers{ 86300906Sasomers return (new DevfsEvent(type, nvPairs, eventString)); 87300906Sasomers} 88300906Sasomers 89300906Sasomers//- DevfsEvent Static Protected Methods ---------------------------------------- 90300906Sasomersnvlist_t * 91300906SasomersDevfsEvent::ReadLabel(int devFd, bool &inUse, bool °raded) 92300906Sasomers{ 93300906Sasomers pool_state_t poolState; 94300906Sasomers char *poolName; 95300906Sasomers boolean_t b_inuse; 96300906Sasomers 97300906Sasomers inUse = false; 98300906Sasomers degraded = false; 99300906Sasomers poolName = NULL; 100300906Sasomers if (zpool_in_use(g_zfsHandle, devFd, &poolState, 101300906Sasomers &poolName, &b_inuse) == 0) { 102300906Sasomers nvlist_t *devLabel; 103300906Sasomers 104300906Sasomers inUse = b_inuse == B_TRUE; 105300906Sasomers if (poolName != NULL) 106300906Sasomers free(poolName); 107300906Sasomers 108300906Sasomers if (zpool_read_label(devFd, &devLabel) != 0 109300906Sasomers || devLabel == NULL) 110300906Sasomers return (NULL); 111300906Sasomers 112300906Sasomers try { 113300906Sasomers Vdev vdev(devLabel); 114300906Sasomers degraded = vdev.State() != VDEV_STATE_HEALTHY; 115300906Sasomers return (devLabel); 116300906Sasomers } catch (ZfsdException &exp) { 117300906Sasomers string devName = fdevname(devFd); 118300906Sasomers string devPath = _PATH_DEV + devName; 119300906Sasomers string context("DevfsEvent::ReadLabel: " 120300906Sasomers + devPath + ": "); 121300906Sasomers 122300906Sasomers exp.GetString().insert(0, context); 123300906Sasomers exp.Log(); 124300906Sasomers } 125300906Sasomers } 126300906Sasomers return (NULL); 127300906Sasomers} 128300906Sasomers 129300906Sasomersbool 130300906SasomersDevfsEvent::OnlineByLabel(const string &devPath, const string& physPath, 131300906Sasomers nvlist_t *devConfig) 132300906Sasomers{ 133300906Sasomers try { 134300906Sasomers /* 135300906Sasomers * A device with ZFS label information has been 136300906Sasomers * inserted. If it matches a device for which we 137300906Sasomers * have a case, see if we can solve that case. 138300906Sasomers */ 139300906Sasomers syslog(LOG_INFO, "Interrogating VDEV label for %s\n", 140300906Sasomers devPath.c_str()); 141300906Sasomers Vdev vdev(devConfig); 142300906Sasomers CaseFile *caseFile(CaseFile::Find(vdev.PoolGUID(), 143300906Sasomers vdev.GUID())); 144300906Sasomers if (caseFile != NULL) 145300906Sasomers return (caseFile->ReEvaluate(devPath, physPath, &vdev)); 146300906Sasomers 147300906Sasomers } catch (ZfsdException &exp) { 148300906Sasomers string context("DevfsEvent::OnlineByLabel: " + devPath + ": "); 149300906Sasomers 150300906Sasomers exp.GetString().insert(0, context); 151300906Sasomers exp.Log(); 152300906Sasomers } 153300906Sasomers return (false); 154300906Sasomers} 155300906Sasomers 156300906Sasomers//- DevfsEvent Virtual Public Methods ------------------------------------------ 157300906SasomersEvent * 158300906SasomersDevfsEvent::DeepCopy() const 159300906Sasomers{ 160300906Sasomers return (new DevfsEvent(*this)); 161300906Sasomers} 162300906Sasomers 163300906Sasomersbool 164300906SasomersDevfsEvent::Process() const 165300906Sasomers{ 166300906Sasomers /* 167300906Sasomers * We are only concerned with newly discovered 168300906Sasomers * devices that can be ZFS vdevs. 169300906Sasomers */ 170300906Sasomers if (Value("type") != "CREATE" || !IsDiskDev()) 171300906Sasomers return (false); 172300906Sasomers 173300906Sasomers /* Log the event since it is of interest. */ 174300906Sasomers Log(LOG_INFO); 175300906Sasomers 176300906Sasomers string devPath; 177300906Sasomers if (!DevPath(devPath)) 178300906Sasomers return (false); 179300906Sasomers 180300906Sasomers int devFd(open(devPath.c_str(), O_RDONLY)); 181300906Sasomers if (devFd == -1) 182300906Sasomers return (false); 183300906Sasomers 184300906Sasomers bool inUse; 185300906Sasomers bool degraded; 186300906Sasomers nvlist_t *devLabel(ReadLabel(devFd, inUse, degraded)); 187300906Sasomers 188300906Sasomers string physPath; 189300906Sasomers bool havePhysPath(PhysicalPath(physPath)); 190300906Sasomers 191300906Sasomers string devName; 192300906Sasomers DevName(devName); 193300906Sasomers close(devFd); 194300906Sasomers 195300906Sasomers if (inUse && devLabel != NULL) { 196300906Sasomers OnlineByLabel(devPath, physPath, devLabel); 197300906Sasomers } else if (degraded) { 198300906Sasomers syslog(LOG_INFO, "%s is marked degraded. Ignoring " 199300906Sasomers "as a replace by physical path candidate.\n", 200300906Sasomers devName.c_str()); 201300906Sasomers } else if (havePhysPath && IsWholeDev()) { 202300906Sasomers /* 203300906Sasomers * TODO: attempt to resolve events using every casefile 204300906Sasomers * that matches this physpath 205300906Sasomers */ 206300906Sasomers CaseFile *caseFile(CaseFile::Find(physPath)); 207300906Sasomers if (caseFile != NULL) { 208300906Sasomers syslog(LOG_INFO, 209300906Sasomers "Found CaseFile(%s:%s:%s) - ReEvaluating\n", 210300906Sasomers caseFile->PoolGUIDString().c_str(), 211300906Sasomers caseFile->VdevGUIDString().c_str(), 212300906Sasomers zpool_state_to_name(caseFile->VdevState(), 213300906Sasomers VDEV_AUX_NONE)); 214300906Sasomers caseFile->ReEvaluate(devPath, physPath, /*vdev*/NULL); 215300906Sasomers } 216300906Sasomers } 217300906Sasomers if (devLabel != NULL) 218300906Sasomers nvlist_free(devLabel); 219300906Sasomers return (false); 220300906Sasomers} 221300906Sasomers 222300906Sasomers//- DevfsEvent Protected Methods ----------------------------------------------- 223300906SasomersDevfsEvent::DevfsEvent(Event::Type type, NVPairMap &nvpairs, 224300906Sasomers const string &eventString) 225300906Sasomers : DevdCtl::DevfsEvent(type, nvpairs, eventString) 226300906Sasomers{ 227300906Sasomers} 228300906Sasomers 229300906SasomersDevfsEvent::DevfsEvent(const DevfsEvent &src) 230300906Sasomers : DevdCtl::DevfsEvent::DevfsEvent(src) 231300906Sasomers{ 232300906Sasomers} 233300906Sasomers 234300906Sasomers/*-------------------------------- GeomEvent --------------------------------*/ 235300906Sasomers 236300906Sasomers//- GeomEvent Static Public Methods ------------------------------------------- 237300906SasomersEvent * 238300906SasomersGeomEvent::Builder(Event::Type type, 239300906Sasomers NVPairMap &nvPairs, 240300906Sasomers const string &eventString) 241300906Sasomers{ 242300906Sasomers return (new GeomEvent(type, nvPairs, eventString)); 243300906Sasomers} 244300906Sasomers 245300906Sasomers//- GeomEvent Virtual Public Methods ------------------------------------------ 246300906SasomersEvent * 247300906SasomersGeomEvent::DeepCopy() const 248300906Sasomers{ 249300906Sasomers return (new GeomEvent(*this)); 250300906Sasomers} 251300906Sasomers 252300906Sasomersbool 253300906SasomersGeomEvent::Process() const 254300906Sasomers{ 255300906Sasomers /* 256300906Sasomers * We are only concerned with physical path changes, because those can 257300906Sasomers * be used to satisfy autoreplace operations 258300906Sasomers */ 259300906Sasomers if (Value("type") != "GEOM::physpath" || !IsDiskDev()) 260300906Sasomers return (false); 261300906Sasomers 262300906Sasomers /* Log the event since it is of interest. */ 263300906Sasomers Log(LOG_INFO); 264300906Sasomers 265300906Sasomers string devPath; 266300906Sasomers if (!DevPath(devPath)) 267300906Sasomers return (false); 268300906Sasomers 269300906Sasomers string physPath; 270300906Sasomers bool havePhysPath(PhysicalPath(physPath)); 271300906Sasomers 272300906Sasomers string devName; 273300906Sasomers DevName(devName); 274300906Sasomers 275300906Sasomers if (havePhysPath) { 276300906Sasomers /* 277300906Sasomers * TODO: attempt to resolve events using every casefile 278300906Sasomers * that matches this physpath 279300906Sasomers */ 280300906Sasomers CaseFile *caseFile(CaseFile::Find(physPath)); 281300906Sasomers if (caseFile != NULL) { 282300906Sasomers syslog(LOG_INFO, 283300906Sasomers "Found CaseFile(%s:%s:%s) - ReEvaluating\n", 284300906Sasomers caseFile->PoolGUIDString().c_str(), 285300906Sasomers caseFile->VdevGUIDString().c_str(), 286300906Sasomers zpool_state_to_name(caseFile->VdevState(), 287300906Sasomers VDEV_AUX_NONE)); 288300906Sasomers caseFile->ReEvaluate(devPath, physPath, /*vdev*/NULL); 289300906Sasomers } 290300906Sasomers } 291300906Sasomers return (false); 292300906Sasomers} 293300906Sasomers 294300906Sasomers//- GeomEvent Protected Methods ----------------------------------------------- 295300906SasomersGeomEvent::GeomEvent(Event::Type type, NVPairMap &nvpairs, 296300906Sasomers const string &eventString) 297300906Sasomers : DevdCtl::GeomEvent(type, nvpairs, eventString) 298300906Sasomers{ 299300906Sasomers} 300300906Sasomers 301300906SasomersGeomEvent::GeomEvent(const GeomEvent &src) 302300906Sasomers : DevdCtl::GeomEvent::GeomEvent(src) 303300906Sasomers{ 304300906Sasomers} 305300906Sasomers 306300906Sasomers 307300906Sasomers/*--------------------------------- ZfsEvent ---------------------------------*/ 308300906Sasomers//- ZfsEvent Static Public Methods --------------------------------------------- 309300906SasomersDevdCtl::Event * 310300906SasomersZfsEvent::Builder(Event::Type type, NVPairMap &nvpairs, 311300906Sasomers const string &eventString) 312300906Sasomers{ 313300906Sasomers return (new ZfsEvent(type, nvpairs, eventString)); 314300906Sasomers} 315300906Sasomers 316300906Sasomers//- ZfsEvent Virtual Public Methods -------------------------------------------- 317300906SasomersEvent * 318300906SasomersZfsEvent::DeepCopy() const 319300906Sasomers{ 320300906Sasomers return (new ZfsEvent(*this)); 321300906Sasomers} 322300906Sasomers 323300906Sasomersbool 324300906SasomersZfsEvent::Process() const 325300906Sasomers{ 326300906Sasomers string logstr(""); 327300906Sasomers 328300906Sasomers if (!Contains("class") && !Contains("type")) { 329300906Sasomers syslog(LOG_ERR, 330300906Sasomers "ZfsEvent::Process: Missing class or type data."); 331300906Sasomers return (false); 332300906Sasomers } 333300906Sasomers 334300906Sasomers /* On config syncs, replay any queued events first. */ 335300906Sasomers if (Value("type").find("misc.fs.zfs.config_sync") == 0) { 336300906Sasomers /* 337300906Sasomers * Even if saved events are unconsumed the second time 338300906Sasomers * around, drop them. Any events that still can't be 339300906Sasomers * consumed are probably referring to vdevs or pools that 340300906Sasomers * no longer exist. 341300906Sasomers */ 342300906Sasomers ZfsDaemon::Get().ReplayUnconsumedEvents(/*discard*/true); 343300906Sasomers CaseFile::ReEvaluateByGuid(PoolGUID(), *this); 344300906Sasomers } 345300906Sasomers 346300906Sasomers if (Value("type").find("misc.fs.zfs.") == 0) { 347300906Sasomers /* Configuration changes, resilver events, etc. */ 348300906Sasomers ProcessPoolEvent(); 349300906Sasomers return (false); 350300906Sasomers } 351300906Sasomers 352300906Sasomers if (!Contains("pool_guid") || !Contains("vdev_guid")) { 353300906Sasomers /* Only currently interested in Vdev related events. */ 354300906Sasomers return (false); 355300906Sasomers } 356300906Sasomers 357300906Sasomers CaseFile *caseFile(CaseFile::Find(PoolGUID(), VdevGUID())); 358300906Sasomers if (caseFile != NULL) { 359300906Sasomers Log(LOG_INFO); 360300906Sasomers syslog(LOG_INFO, "Evaluating existing case file\n"); 361300906Sasomers caseFile->ReEvaluate(*this); 362300906Sasomers return (false); 363300906Sasomers } 364300906Sasomers 365300906Sasomers /* Skip events that can't be handled. */ 366300906Sasomers Guid poolGUID(PoolGUID()); 367300906Sasomers /* If there are no replicas for a pool, then it's not manageable. */ 368300906Sasomers if (Value("class").find("fs.zfs.vdev.no_replicas") == 0) { 369300906Sasomers stringstream msg; 370300906Sasomers msg << "No replicas available for pool " << poolGUID; 371300906Sasomers msg << ", ignoring"; 372300906Sasomers Log(LOG_INFO); 373300906Sasomers syslog(LOG_INFO, "%s", msg.str().c_str()); 374300906Sasomers return (false); 375300906Sasomers } 376300906Sasomers 377300906Sasomers /* 378300906Sasomers * Create a case file for this vdev, and have it 379300906Sasomers * evaluate the event. 380300906Sasomers */ 381300906Sasomers ZpoolList zpl(ZpoolList::ZpoolByGUID, &poolGUID); 382300906Sasomers if (zpl.empty()) { 383300906Sasomers stringstream msg; 384300906Sasomers int priority = LOG_INFO; 385300906Sasomers msg << "ZfsEvent::Process: Event for unknown pool "; 386300906Sasomers msg << poolGUID << " "; 387300906Sasomers msg << "queued"; 388300906Sasomers Log(LOG_INFO); 389300906Sasomers syslog(priority, "%s", msg.str().c_str()); 390300906Sasomers return (true); 391300906Sasomers } 392300906Sasomers 393300906Sasomers nvlist_t *vdevConfig = VdevIterator(zpl.front()).Find(VdevGUID()); 394300906Sasomers if (vdevConfig == NULL) { 395300906Sasomers stringstream msg; 396300906Sasomers int priority = LOG_INFO; 397300906Sasomers msg << "ZfsEvent::Process: Event for unknown vdev "; 398300906Sasomers msg << VdevGUID() << " "; 399300906Sasomers msg << "queued"; 400300906Sasomers Log(LOG_INFO); 401300906Sasomers syslog(priority, "%s", msg.str().c_str()); 402300906Sasomers return (true); 403300906Sasomers } 404300906Sasomers 405300906Sasomers Vdev vdev(zpl.front(), vdevConfig); 406300906Sasomers caseFile = &CaseFile::Create(vdev); 407300906Sasomers if (caseFile->ReEvaluate(*this) == false) { 408300906Sasomers stringstream msg; 409300906Sasomers int priority = LOG_INFO; 410300906Sasomers msg << "ZfsEvent::Process: Unconsumed event for vdev("; 411300906Sasomers msg << zpool_get_name(zpl.front()) << ","; 412300906Sasomers msg << vdev.GUID() << ") "; 413300906Sasomers msg << "queued"; 414300906Sasomers Log(LOG_INFO); 415300906Sasomers syslog(priority, "%s", msg.str().c_str()); 416300906Sasomers return (true); 417300906Sasomers } 418300906Sasomers return (false); 419300906Sasomers} 420300906Sasomers 421300906Sasomers//- ZfsEvent Protected Methods ------------------------------------------------- 422300906SasomersZfsEvent::ZfsEvent(Event::Type type, NVPairMap &nvpairs, 423300906Sasomers const string &eventString) 424300906Sasomers : DevdCtl::ZfsEvent(type, nvpairs, eventString) 425300906Sasomers{ 426300906Sasomers} 427300906Sasomers 428300906SasomersZfsEvent::ZfsEvent(const ZfsEvent &src) 429300906Sasomers : DevdCtl::ZfsEvent(src) 430300906Sasomers{ 431300906Sasomers} 432300906Sasomers 433300906Sasomers/* 434300906Sasomers * Sometimes the kernel won't detach a spare when it is no longer needed. This 435300906Sasomers * can happen for example if a drive is removed, then either the pool is 436300906Sasomers * exported or the machine is powered off, then the drive is reinserted, then 437300906Sasomers * the machine is powered on or the pool is imported. ZFSD must detach these 438300906Sasomers * spares itself. 439300906Sasomers */ 440300906Sasomersvoid 441300906SasomersZfsEvent::CleanupSpares() const 442300906Sasomers{ 443300906Sasomers Guid poolGUID(PoolGUID()); 444300906Sasomers ZpoolList zpl(ZpoolList::ZpoolByGUID, &poolGUID); 445300906Sasomers if (!zpl.empty()) { 446300906Sasomers zpool_handle_t* hdl; 447300906Sasomers 448300906Sasomers hdl = zpl.front(); 449300906Sasomers VdevIterator(hdl).Each(TryDetach, (void*)hdl); 450300906Sasomers } 451300906Sasomers} 452300906Sasomers 453300906Sasomersvoid 454300906SasomersZfsEvent::ProcessPoolEvent() const 455300906Sasomers{ 456300906Sasomers bool degradedDevice(false); 457300906Sasomers 458300906Sasomers /* The pool is destroyed. Discard any open cases */ 459300906Sasomers if (Value("type") == "misc.fs.zfs.pool_destroy") { 460300906Sasomers Log(LOG_INFO); 461300906Sasomers CaseFile::ReEvaluateByGuid(PoolGUID(), *this); 462300906Sasomers return; 463300906Sasomers } 464300906Sasomers 465300906Sasomers CaseFile *caseFile(CaseFile::Find(PoolGUID(), VdevGUID())); 466300906Sasomers if (caseFile != NULL) { 467300906Sasomers if (caseFile->VdevState() != VDEV_STATE_UNKNOWN 468300906Sasomers && caseFile->VdevState() < VDEV_STATE_HEALTHY) 469300906Sasomers degradedDevice = true; 470300906Sasomers 471300906Sasomers Log(LOG_INFO); 472300906Sasomers caseFile->ReEvaluate(*this); 473300906Sasomers } 474300906Sasomers else if (Value("type") == "misc.fs.zfs.resilver_finish") 475300906Sasomers { 476300906Sasomers /* 477300906Sasomers * It's possible to get a resilver_finish event with no 478300906Sasomers * corresponding casefile. For example, if a damaged pool were 479300906Sasomers * exported, repaired, then reimported. 480300906Sasomers */ 481300906Sasomers Log(LOG_INFO); 482300906Sasomers CleanupSpares(); 483300906Sasomers } 484300906Sasomers 485300906Sasomers if (Value("type") == "misc.fs.zfs.vdev_remove" 486300906Sasomers && degradedDevice == false) { 487300906Sasomers 488300906Sasomers /* See if any other cases can make use of this device. */ 489300906Sasomers Log(LOG_INFO); 490300906Sasomers ZfsDaemon::RequestSystemRescan(); 491300906Sasomers } 492300906Sasomers} 493300906Sasomers 494300906Sasomersbool 495300906SasomersZfsEvent::TryDetach(Vdev &vdev, void *cbArg) 496300906Sasomers{ 497300906Sasomers /* 498300906Sasomers * Outline: 499300906Sasomers * if this device is a spare, and its parent includes one healthy, 500300906Sasomers * non-spare child, then detach this device. 501300906Sasomers */ 502300906Sasomers zpool_handle_t *hdl(static_cast<zpool_handle_t*>(cbArg)); 503300906Sasomers 504300906Sasomers if (vdev.IsSpare()) { 505300906Sasomers std::list<Vdev> siblings; 506300906Sasomers std::list<Vdev>::iterator siblings_it; 507300906Sasomers boolean_t cleanup = B_FALSE; 508300906Sasomers 509300906Sasomers Vdev parent = vdev.Parent(); 510300906Sasomers siblings = parent.Children(); 511300906Sasomers 512300906Sasomers /* Determine whether the parent should be cleaned up */ 513300906Sasomers for (siblings_it = siblings.begin(); 514300906Sasomers siblings_it != siblings.end(); 515300906Sasomers siblings_it++) { 516300906Sasomers Vdev sibling = *siblings_it; 517300906Sasomers 518300906Sasomers if (!sibling.IsSpare() && 519300906Sasomers sibling.State() == VDEV_STATE_HEALTHY) { 520300906Sasomers cleanup = B_TRUE; 521300906Sasomers break; 522300906Sasomers } 523300906Sasomers } 524300906Sasomers 525300906Sasomers if (cleanup) { 526300906Sasomers syslog(LOG_INFO, "Detaching spare vdev %s from pool %s", 527300906Sasomers vdev.Path().c_str(), zpool_get_name(hdl)); 528300906Sasomers zpool_vdev_detach(hdl, vdev.Path().c_str()); 529300906Sasomers } 530300906Sasomers 531300906Sasomers } 532300906Sasomers 533300906Sasomers /* Always return false, because there may be other spares to detach */ 534300906Sasomers return (false); 535300906Sasomers} 536