svn commit: r256478 - projects/zfsd/head/cddl/sbin/zfsd
Alan Somers
asomers at FreeBSD.org
Mon Oct 14 23:36:12 UTC 2013
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_ */
More information about the svn-src-projects
mailing list