Date: Mon, 14 Oct 2013 23:36:10 +0000 (UTC) From: Alan Somers <asomers@FreeBSD.org> To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r256478 - projects/zfsd/head/cddl/sbin/zfsd Message-ID: <201310142336.r9ENaApY035748@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: asomers Date: Mon Oct 14 23:36:10 2013 New Revision: 256478 URL: http://svnweb.freebsd.org/changeset/base/256478 Log: Zfsd should deactivate a spare if the original device is replaced while the system is powered off. cddl/sbin/zfsd/case_file.cc cddl/sbin/zfsd/vdev.cc cddl/sbin/zfsd/vdev.h cddl/sbin/zfsd/vdev_iterator.h cddl/sbin/zfsd/zfsd.cc cddl/sbin/zfsd/zfsd_event.cc cddl/sbin/zfsd/zfsd_event.h When zfsd receives a misc.fs.zfs.resilver_finish event, it will iterate through all spare leaf vdevs on the pool. It will detach any that appear to be unnecessary. Submitted by: alans Approved by: ken (mentor) Sponsored by: Spectra Logic Corporation Modified: projects/zfsd/head/cddl/sbin/zfsd/case_file.cc projects/zfsd/head/cddl/sbin/zfsd/vdev.cc projects/zfsd/head/cddl/sbin/zfsd/vdev.h projects/zfsd/head/cddl/sbin/zfsd/vdev_iterator.h projects/zfsd/head/cddl/sbin/zfsd/zfsd.cc projects/zfsd/head/cddl/sbin/zfsd/zfsd_event.cc projects/zfsd/head/cddl/sbin/zfsd/zfsd_event.h Modified: projects/zfsd/head/cddl/sbin/zfsd/case_file.cc ============================================================================== --- projects/zfsd/head/cddl/sbin/zfsd/case_file.cc Mon Oct 14 23:32:56 2013 (r256477) +++ projects/zfsd/head/cddl/sbin/zfsd/case_file.cc Mon Oct 14 23:36:10 2013 (r256478) @@ -66,10 +66,10 @@ #include <devctl/reader.h> #include "callout.h" +#include "vdev_iterator.h" #include "zfsd_event.h" #include "case_file.h" #include "vdev.h" -#include "vdev_iterator.h" #include "zfsd.h" #include "zfsd_exception.h" #include "zpool_list.h" Modified: projects/zfsd/head/cddl/sbin/zfsd/vdev.cc ============================================================================== --- projects/zfsd/head/cddl/sbin/zfsd/vdev.cc Mon Oct 14 23:32:56 2013 (r256477) +++ projects/zfsd/head/cddl/sbin/zfsd/vdev.cc Mon Oct 14 23:36:10 2013 (r256478) @@ -141,6 +141,18 @@ Vdev::Vdev(nvlist_t *labelConfig) } } +bool +Vdev::IsSpare() const +{ + uint64_t is_spare(0); + + if (m_config == NULL) + return (false); + + (void)nvlist_lookup_uint64(m_config, ZPOOL_CONFIG_IS_SPARE, &is_spare); + return (bool(is_spare)); +} + vdev_state Vdev::State() const { Modified: projects/zfsd/head/cddl/sbin/zfsd/vdev.h ============================================================================== --- projects/zfsd/head/cddl/sbin/zfsd/vdev.h Mon Oct 14 23:32:56 2013 (r256477) +++ projects/zfsd/head/cddl/sbin/zfsd/vdev.h Mon Oct 14 23:36:10 2013 (r256478) @@ -116,6 +116,7 @@ public: std::list<Vdev> Children(); virtual DevCtl::Guid GUID() const; + bool IsSpare() const; virtual DevCtl::Guid PoolGUID() const; virtual vdev_state State() const; std::string Path() const; Modified: projects/zfsd/head/cddl/sbin/zfsd/vdev_iterator.h ============================================================================== --- projects/zfsd/head/cddl/sbin/zfsd/vdev_iterator.h Mon Oct 14 23:32:56 2013 (r256477) +++ projects/zfsd/head/cddl/sbin/zfsd/vdev_iterator.h Mon Oct 14 23:36:10 2013 (r256478) @@ -84,8 +84,8 @@ public: void Reset(); /** - * \brief Report the vdev at this iterator's cursor and increment - * the cursor to the next pool member. + * \brief Report the leaf vdev at this iterator's cursor and increment + * the cursor to the next leaf pool member. */ nvlist_t *Next(); Modified: projects/zfsd/head/cddl/sbin/zfsd/zfsd.cc ============================================================================== --- projects/zfsd/head/cddl/sbin/zfsd/zfsd.cc Mon Oct 14 23:32:56 2013 (r256477) +++ projects/zfsd/head/cddl/sbin/zfsd/zfsd.cc Mon Oct 14 23:36:10 2013 (r256478) @@ -66,6 +66,7 @@ #include <devctl/reader.h> #include "callout.h" +#include "vdev_iterator.h" #include "zfsd_event.h" #include "case_file.h" #include "vdev.h" Modified: projects/zfsd/head/cddl/sbin/zfsd/zfsd_event.cc ============================================================================== --- projects/zfsd/head/cddl/sbin/zfsd/zfsd_event.cc Mon Oct 14 23:32:56 2013 (r256477) +++ projects/zfsd/head/cddl/sbin/zfsd/zfsd_event.cc Mon Oct 14 23:36:10 2013 (r256478) @@ -54,10 +54,10 @@ #include <devctl/reader.h> #include "callout.h" +#include "vdev_iterator.h" #include "zfsd_event.h" #include "case_file.h" #include "vdev.h" -#include "vdev_iterator.h" #include "zfsd.h" #include "zfsd_exception.h" #include "zpool_list.h" @@ -346,6 +346,26 @@ ZfsEvent::ZfsEvent(const ZfsEvent &src) { } +/* + * Sometimes the kernel won't detach a spare when it is no longer needed. This + * can happen for example if a drive is removed, then either the pool is + * exported or the machine is powered off, then the drive is reinserted, then + * the machine is powered on or the pool is imported. ZFSD must detach these + * spares itself. + */ +void +ZfsEvent::CleanupSpares() const +{ + Guid poolGUID(PoolGUID()); + ZpoolList zpl(ZpoolList::ZpoolByGUID, &poolGUID); + if (!zpl.empty()) { + zpool_handle_t* hdl; + + hdl = zpl.front(); + VdevIterator(hdl).Each(TryDetach, (void*)hdl); + } +} + void ZfsEvent::ProcessPoolEvent() const { @@ -359,6 +379,15 @@ ZfsEvent::ProcessPoolEvent() const caseFile->ReEvaluate(*this); } + else if (Value("type") == "misc.fs.zfs.resilver_finish") + { + /* + * It's possible to get a resilver_finish event with no + * corresponding casefile. For example, if a damaged pool were + * exported, repaired, then reimported. + */ + CleanupSpares(); + } if (Value("type") == "misc.fs.zfs.vdev_remove" && degradedDevice == false) { @@ -366,3 +395,46 @@ ZfsEvent::ProcessPoolEvent() const ZfsDaemon::RequestSystemRescan(); } } + +bool +ZfsEvent::TryDetach(Vdev &vdev, void *cbArg) +{ + /* + * Outline: + * if this device is a spare, and its parent includes one healthy, + * non-spare child, then detach this device. + */ + zpool_handle_t *hdl(static_cast<zpool_handle_t*>(cbArg)); + + if (vdev.IsSpare()) { + std::list<Vdev> siblings; + std::list<Vdev>::iterator siblings_it; + boolean_t cleanup = B_FALSE; + + Vdev parent = vdev.Parent(); + siblings = parent.Children(); + + /* Determine whether the parent should be cleaned up */ + for (siblings_it = siblings.begin(); + siblings_it != siblings.end(); + siblings_it++) { + Vdev sibling = *siblings_it; + + if (!sibling.IsSpare() && + sibling.State() == VDEV_STATE_HEALTHY) { + cleanup = B_TRUE; + break; + } + } + + if (cleanup) { + syslog(LOG_INFO, "Detaching spare vdev %s from pool %s", + vdev.Path().c_str(), zpool_get_name(hdl)); + zpool_vdev_detach(hdl, vdev.Path().c_str()); + } + + } + + /* Always return false, because there may be other spares to detach */ + return (false); +} Modified: projects/zfsd/head/cddl/sbin/zfsd/zfsd_event.h ============================================================================== --- projects/zfsd/head/cddl/sbin/zfsd/zfsd_event.h Mon Oct 14 23:32:56 2013 (r256477) +++ projects/zfsd/head/cddl/sbin/zfsd/zfsd_event.h Mon Oct 14 23:36:10 2013 (r256478) @@ -140,7 +140,13 @@ protected: /** Constructor */ ZfsEvent(Type, DevCtl::NVPairMap &, const string &); + /** + * Detach any spares that are no longer needed, but were not + * automatically detached by the kernel + */ + virtual void CleanupSpares() const; virtual void ProcessPoolEvent() const; + static VdevCallback_t TryDetach; }; #endif /*_ZFSD_EVENT_H_ */
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201310142336.r9ENaApY035748>