Skip to content

Commit

Permalink
Fix zfsd with the device_removal pool feature.
Browse files Browse the repository at this point in the history
Previously zfsd would crash in the presence of a pool with a
top-level-vdev that had previously been removed.  The crash happened
because the configuration nvlist of such a TLV contains an empty
ZPOOL_CONFIG_CHILDREN array, which led to a pop_front from an empty
list, which has undefined behavior.

The crash only happened in stable/14 and later, probably do to
differences in libcxx, but the change should be MFCed anyway.

PR:		273663
Reported by:	Marek Zarychta <[email protected]>
MFC after:	1 week
Sponsored by:	Axcient
Reviewed by:	mav
Differential Revision: https://reviews.freebsd.org/D41818
  • Loading branch information
asomers committed Sep 12, 2023
1 parent ff9c4ab commit 0b294a3
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 4 deletions.
37 changes: 37 additions & 0 deletions cddl/usr.sbin/zfsd/tests/zfsd_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -766,3 +766,40 @@ TEST_F(ReEvaluateByGuidTest, ReEvaluateByGuid_five)
delete CaseFile4;
delete CaseFile5;
}

/*
* Test VdevIterator
*/
class VdevIteratorTest : public ::testing::Test
{
};

bool VdevIteratorTestCB(Vdev &vdev, void *cbArg) {
return (false);
}

/*
* VdevIterator::Next should not crash when run on a pool that has a previously
* removed vdev. Regression for
* https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=273663
*/
TEST_F(VdevIteratorTest, VdevRemoval)
{
nvlist_t* poolConfig, *rootVdev;

ASSERT_EQ(0, nvlist_alloc(&rootVdev, NV_UNIQUE_NAME, 0));
ASSERT_EQ(0, nvlist_add_uint64(rootVdev, ZPOOL_CONFIG_GUID, 0x5678));
/*
* Note: pools with previously-removed top-level VDEVs will contain a
* TLV in their labels that has 0 children.
*/
ASSERT_EQ(0, nvlist_add_nvlist_array(rootVdev, ZPOOL_CONFIG_CHILDREN,
NULL, 0));
ASSERT_EQ(0, nvlist_alloc(&poolConfig, NV_UNIQUE_NAME, 0));
ASSERT_EQ(0, nvlist_add_uint64(poolConfig,
ZPOOL_CONFIG_POOL_GUID, 0x1234));
ASSERT_EQ(0, nvlist_add_nvlist(poolConfig, ZPOOL_CONFIG_VDEV_TREE,
rootVdev));

VdevIterator(poolConfig).Each(VdevIteratorTestCB, NULL);
}
5 changes: 1 addition & 4 deletions cddl/usr.sbin/zfsd/vdev_iterator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -109,10 +109,7 @@ VdevIterator::Next()
{
nvlist_t *vdevConfig;

if (m_vdevQueue.empty())
return (NULL);

for (;;) {
for (vdevConfig = NULL; !m_vdevQueue.empty();) {
nvlist_t **vdevChildren;
int result;
u_int numChildren;
Expand Down

0 comments on commit 0b294a3

Please sign in to comment.