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);
}
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::Find(const string &physPath)
{
@ -217,6 +237,12 @@ CaseFile::PurgeAll()
}
int
CaseFile::IsSpare()
{
return (m_is_spare);
}
//- CaseFile Public Methods ----------------------------------------------------
bool
CaseFile::RefreshVdevState()
@ -240,6 +266,7 @@ CaseFile::ReEvaluate(const string &devPath, const string &physPath, Vdev *vdev)
{
ZpoolList zpl(ZpoolList::ZpoolByGUID, &m_poolGUID);
zpool_handle_t *pool(zpl.empty() ? NULL : zpl.front());
int flags = ZFS_ONLINE_CHECKREMOVE | ZFS_ONLINE_UNSPARE;
if (pool == NULL || !RefreshVdevState()) {
/*
@ -280,9 +307,10 @@ CaseFile::ReEvaluate(const string &devPath, const string &physPath, Vdev *vdev)
|| vdev->PoolGUID() == Guid::InvalidGuid())
&& vdev->GUID() == m_vdevGUID) {
if (IsSpare())
flags |= ZFS_ONLINE_SPARE;
zpool_vdev_online(pool, vdev->GUIDString().c_str(),
ZFS_ONLINE_CHECKREMOVE | ZFS_ONLINE_UNSPARE,
&m_vdevState);
flags, &m_vdevState);
syslog(LOG_INFO, "Onlined vdev(%s/%s:%s). State now %s.\n",
zpool_get_name(pool), vdev->GUIDString().c_str(),
devPath.c_str(),
@ -783,7 +811,8 @@ CaseFile::CaseFile(const Vdev &vdev)
: m_poolGUID(vdev.PoolGUID()),
m_vdevGUID(vdev.GUID()),
m_vdevState(vdev.State()),
m_vdevPhysPath(vdev.PhysicalPath())
m_vdevPhysPath(vdev.PhysicalPath()),
m_is_spare(vdev.IsSpare())
{
stringstream guidString;

View File

@ -98,6 +98,19 @@ public:
*/
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
* physical path.
@ -219,6 +232,11 @@ public:
*/
bool ShouldFault() const;
/**
* \brief If this vdev is spare
*/
int IsSpare();
protected:
enum {
/**
@ -384,6 +402,7 @@ protected:
string m_poolGUIDString;
string m_vdevGUIDString;
string m_vdevPhysPath;
int m_is_spare;
/**
* \brief Callout activated when a grace period

View File

@ -78,8 +78,10 @@ VdevIterator::Reset()
{
nvlist_t *rootVdev;
nvlist **cache_child;
nvlist **spare_child;
int result;
uint_t cache_children;
uint_t spare_children;
result = nvlist_lookup_nvlist(m_poolConfig,
ZPOOL_CONFIG_VDEV_TREE,
@ -95,6 +97,13 @@ VdevIterator::Reset()
if (result == 0)
for (uint_t c = 0; c < cache_children; 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 *

View File

@ -231,7 +231,9 @@ bool
GeomEvent::OnlineByLabel(const string &devPath, const string& physPath,
nvlist_t *devConfig)
{
bool ret = false;
try {
CaseFileList case_list;
/*
* A device with ZFS label information has been
* 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",
devPath.c_str());
Vdev vdev(devConfig);
CaseFile *caseFile(CaseFile::Find(vdev.PoolGUID(),
vdev.GUID()));
if (caseFile != NULL)
return (caseFile->ReEvaluate(devPath, physPath, &vdev));
CaseFile::Find(vdev.PoolGUID(),vdev.GUID(), case_list);
for (CaseFileList::iterator curr = case_list.begin();
curr != case_list.end(); curr++) {
ret |= (*curr)->ReEvaluate(devPath, physPath, &vdev);
}
return (ret);
} catch (ZfsdException &exp) {
string context("GeomEvent::OnlineByLabel: " + devPath + ": ");
@ -251,7 +255,7 @@ GeomEvent::OnlineByLabel(const string &devPath, const string& physPath,
exp.GetString().insert(0, context);
exp.Log();
}
return (false);
return (ret);
}