From owner-svn-src-projects@FreeBSD.ORG Mon Oct 14 23:36:12 2013 Return-Path: Delivered-To: svn-src-projects@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTP id 121F3287; Mon, 14 Oct 2013 23:36:12 +0000 (UTC) (envelope-from asomers@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.freebsd.org (Postfix) with ESMTPS id F37D72012; Mon, 14 Oct 2013 23:36:11 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.7/8.14.7) with ESMTP id r9ENaBHJ035755; Mon, 14 Oct 2013 23:36:11 GMT (envelope-from asomers@svn.freebsd.org) Received: (from asomers@localhost) by svn.freebsd.org (8.14.7/8.14.5/Submit) id r9ENaApY035748; Mon, 14 Oct 2013 23:36:10 GMT (envelope-from asomers@svn.freebsd.org) Message-Id: <201310142336.r9ENaApY035748@svn.freebsd.org> From: Alan Somers Date: Mon, 14 Oct 2013 23:36:10 +0000 (UTC) To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r256478 - projects/zfsd/head/cddl/sbin/zfsd X-SVN-Group: projects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-projects@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "SVN commit messages for the src " projects" tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 14 Oct 2013 23:36:12 -0000 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 #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 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 #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 #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(cbArg)); + + if (vdev.IsSpare()) { + std::list siblings; + std::list::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_ */