Skip site navigation (1)Skip section navigation (2)
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>