zfsd: add support for hotplugging spares

If you remove an unused spare and then reinsert it, zfsd will now online
it in all pools.

Signed-off-by: Ameer Hamza <ahamza@ixsystems.com>
This commit is contained in:
Ameer Hamza 2023-04-17 07:28:14 +05:00
parent 0b58a60509
commit f34365ed28
4 changed files with 69 additions and 8 deletions

View File

@ -116,6 +116,26 @@ CaseFile::Find(Guid poolGUID, Guid vdevGUID)
return (NULL); return (NULL);
} }
void
CaseFile::Find(Guid poolGUID, Guid vdevGUID, CaseFileList &cases)
{
for (CaseFileList::iterator curCase = s_activeCases.begin();
curCase != s_activeCases.end(); curCase++) {
if (((*curCase)->PoolGUID() != poolGUID &&
Guid::InvalidGuid() != poolGUID) ||
(*curCase)->VdevGUID() != vdevGUID)
continue;
/*
* We can have multiple cases for spare vdevs
*/
cases.push_back(*curCase);
if (!(*curCase)->IsSpare()) {
return;
}
}
}
CaseFile * CaseFile *
CaseFile::Find(const string &physPath) CaseFile::Find(const string &physPath)
{ {
@ -217,6 +237,12 @@ CaseFile::PurgeAll()
} }
int
CaseFile::IsSpare()
{
return (m_is_spare);
}
//- CaseFile Public Methods ---------------------------------------------------- //- CaseFile Public Methods ----------------------------------------------------
bool bool
CaseFile::RefreshVdevState() CaseFile::RefreshVdevState()
@ -240,6 +266,7 @@ CaseFile::ReEvaluate(const string &devPath, const string &physPath, Vdev *vdev)
{ {
ZpoolList zpl(ZpoolList::ZpoolByGUID, &m_poolGUID); ZpoolList zpl(ZpoolList::ZpoolByGUID, &m_poolGUID);
zpool_handle_t *pool(zpl.empty() ? NULL : zpl.front()); zpool_handle_t *pool(zpl.empty() ? NULL : zpl.front());
int flags = ZFS_ONLINE_CHECKREMOVE | ZFS_ONLINE_UNSPARE;
if (pool == NULL || !RefreshVdevState()) { if (pool == NULL || !RefreshVdevState()) {
/* /*
@ -280,9 +307,10 @@ CaseFile::ReEvaluate(const string &devPath, const string &physPath, Vdev *vdev)
|| vdev->PoolGUID() == Guid::InvalidGuid()) || vdev->PoolGUID() == Guid::InvalidGuid())
&& vdev->GUID() == m_vdevGUID) { && vdev->GUID() == m_vdevGUID) {
if (IsSpare())
flags |= ZFS_ONLINE_SPARE;
zpool_vdev_online(pool, vdev->GUIDString().c_str(), zpool_vdev_online(pool, vdev->GUIDString().c_str(),
ZFS_ONLINE_CHECKREMOVE | ZFS_ONLINE_UNSPARE, flags, &m_vdevState);
&m_vdevState);
syslog(LOG_INFO, "Onlined vdev(%s/%s:%s). State now %s.\n", syslog(LOG_INFO, "Onlined vdev(%s/%s:%s). State now %s.\n",
zpool_get_name(pool), vdev->GUIDString().c_str(), zpool_get_name(pool), vdev->GUIDString().c_str(),
devPath.c_str(), devPath.c_str(),
@ -783,7 +811,8 @@ CaseFile::CaseFile(const Vdev &vdev)
: m_poolGUID(vdev.PoolGUID()), : m_poolGUID(vdev.PoolGUID()),
m_vdevGUID(vdev.GUID()), m_vdevGUID(vdev.GUID()),
m_vdevState(vdev.State()), m_vdevState(vdev.State()),
m_vdevPhysPath(vdev.PhysicalPath()) m_vdevPhysPath(vdev.PhysicalPath()),
m_is_spare(vdev.IsSpare())
{ {
stringstream guidString; stringstream guidString;

View File

@ -98,6 +98,19 @@ public:
*/ */
static CaseFile *Find(DevdCtl::Guid poolGUID, DevdCtl::Guid vdevGUID); static CaseFile *Find(DevdCtl::Guid poolGUID, DevdCtl::Guid vdevGUID);
/**
* \brief Find multiple CaseFile objects by a vdev's pool/vdev
* GUID tuple (special case for spare vdevs)
*
* \param poolGUID Pool GUID for the vdev of the CaseFile to find.
* If InvalidGuid, then only match the vdev GUID
* instead of both pool and vdev GUIDs.
* \param vdevGUID Vdev GUID for the vdev of the CaseFile to find.
* \param caseList List of cases associated with the vdev.
*/
static void Find(DevdCtl::Guid poolGUID, DevdCtl::Guid vdevGUID,
CaseFileList &caseList);
/** /**
* \brief Find a CaseFile object by a vdev's current/last known * \brief Find a CaseFile object by a vdev's current/last known
* physical path. * physical path.
@ -219,6 +232,11 @@ public:
*/ */
bool ShouldFault() const; bool ShouldFault() const;
/**
* \brief If this vdev is spare
*/
int IsSpare();
protected: protected:
enum { enum {
/** /**
@ -384,6 +402,7 @@ protected:
string m_poolGUIDString; string m_poolGUIDString;
string m_vdevGUIDString; string m_vdevGUIDString;
string m_vdevPhysPath; string m_vdevPhysPath;
int m_is_spare;
/** /**
* \brief Callout activated when a grace period * \brief Callout activated when a grace period

View File

@ -78,8 +78,10 @@ VdevIterator::Reset()
{ {
nvlist_t *rootVdev; nvlist_t *rootVdev;
nvlist **cache_child; nvlist **cache_child;
nvlist **spare_child;
int result; int result;
uint_t cache_children; uint_t cache_children;
uint_t spare_children;
result = nvlist_lookup_nvlist(m_poolConfig, result = nvlist_lookup_nvlist(m_poolConfig,
ZPOOL_CONFIG_VDEV_TREE, ZPOOL_CONFIG_VDEV_TREE,
@ -95,6 +97,13 @@ VdevIterator::Reset()
if (result == 0) if (result == 0)
for (uint_t c = 0; c < cache_children; c++) for (uint_t c = 0; c < cache_children; c++)
m_vdevQueue.push_back(cache_child[c]); m_vdevQueue.push_back(cache_child[c]);
result = nvlist_lookup_nvlist_array(rootVdev,
ZPOOL_CONFIG_SPARES,
&spare_child,
&spare_children);
if (result == 0)
for (uint_t c = 0; c < spare_children; c++)
m_vdevQueue.push_back(spare_child[c]);
} }
nvlist_t * nvlist_t *

View File

@ -231,7 +231,9 @@ bool
GeomEvent::OnlineByLabel(const string &devPath, const string& physPath, GeomEvent::OnlineByLabel(const string &devPath, const string& physPath,
nvlist_t *devConfig) nvlist_t *devConfig)
{ {
bool ret = false;
try { try {
CaseFileList case_list;
/* /*
* A device with ZFS label information has been * A device with ZFS label information has been
* inserted. If it matches a device for which we * inserted. If it matches a device for which we
@ -240,10 +242,12 @@ GeomEvent::OnlineByLabel(const string &devPath, const string& physPath,
syslog(LOG_INFO, "Interrogating VDEV label for %s\n", syslog(LOG_INFO, "Interrogating VDEV label for %s\n",
devPath.c_str()); devPath.c_str());
Vdev vdev(devConfig); Vdev vdev(devConfig);
CaseFile *caseFile(CaseFile::Find(vdev.PoolGUID(), CaseFile::Find(vdev.PoolGUID(),vdev.GUID(), case_list);
vdev.GUID())); for (CaseFileList::iterator curr = case_list.begin();
if (caseFile != NULL) curr != case_list.end(); curr++) {
return (caseFile->ReEvaluate(devPath, physPath, &vdev)); ret |= (*curr)->ReEvaluate(devPath, physPath, &vdev);
}
return (ret);
} catch (ZfsdException &exp) { } catch (ZfsdException &exp) {
string context("GeomEvent::OnlineByLabel: " + devPath + ": "); string context("GeomEvent::OnlineByLabel: " + devPath + ": ");
@ -251,7 +255,7 @@ GeomEvent::OnlineByLabel(const string &devPath, const string& physPath,
exp.GetString().insert(0, context); exp.GetString().insert(0, context);
exp.Log(); exp.Log();
} }
return (false); return (ret);
} }