Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

US1533 replacing disk in a pool #47

Merged
merged 1 commit into from
May 21, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 42 additions & 36 deletions module/zfs/zfs_ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -2021,7 +2021,41 @@ zfs_ioc_vdev_remove(zfs_cmd_t *zc)
return (error);
}

#if defined(_KERNEL)
static int
zfs_ioc_vdev_attach(zfs_cmd_t *zc)
{
spa_t *spa;
int replacing = zc->zc_cookie;
nvlist_t *config;
int error;

if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
return (error);

if ((error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size,
zc->zc_iflags, &config)) == 0) {
error = spa_vdev_attach(spa, zc->zc_guid, config, replacing);
nvlist_free(config);
}

spa_close(spa, FTAG);
return (error);
}

static int
zfs_ioc_vdev_detach(zfs_cmd_t *zc)
{
spa_t *spa;
int error;

if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
return (error);

error = spa_vdev_detach(spa, zc->zc_guid, 0, B_FALSE);

spa_close(spa, FTAG);
return (error);
}

static int
zfs_ioc_vdev_set_state(zfs_cmd_t *zc)
Expand Down Expand Up @@ -2066,41 +2100,7 @@ zfs_ioc_vdev_set_state(zfs_cmd_t *zc)
return (error);
}

static int
zfs_ioc_vdev_attach(zfs_cmd_t *zc)
{
spa_t *spa;
int replacing = zc->zc_cookie;
nvlist_t *config;
int error;

if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
return (error);

if ((error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size,
zc->zc_iflags, &config)) == 0) {
error = spa_vdev_attach(spa, zc->zc_guid, config, replacing);
nvlist_free(config);
}

spa_close(spa, FTAG);
return (error);
}

static int
zfs_ioc_vdev_detach(zfs_cmd_t *zc)
{
spa_t *spa;
int error;

if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
return (error);

error = spa_vdev_detach(spa, zc->zc_guid, 0, B_FALSE);

spa_close(spa, FTAG);
return (error);
}
#if defined(_KERNEL)

static int
zfs_ioc_vdev_split(zfs_cmd_t *zc)
Expand Down Expand Up @@ -7279,6 +7279,12 @@ uzfs_handle_ioctl(const char *pool, zfs_cmd_t *zc, uzfs_info_t *ucmd_info)
return (zfs_ioc_vdev_add(zc));
case ZFS_IOC_VDEV_REMOVE:
return (zfs_ioc_vdev_remove(zc));
case ZFS_IOC_VDEV_ATTACH:
return (zfs_ioc_vdev_attach(zc));
case ZFS_IOC_VDEV_DETACH:
return (zfs_ioc_vdev_detach(zc));
case ZFS_IOC_VDEV_SET_STATE:
return (zfs_ioc_vdev_set_state(zc));
}
return (err);
}
Expand Down
120 changes: 103 additions & 17 deletions tests/cbtest/gtest/test_zrepl_prot.cc
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
#include <netinet/tcp.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <algorithm>

#include <zrepl_prot.h>
#include "gtest_utils.h"
Expand Down Expand Up @@ -420,6 +421,17 @@ static void graceful_close(int sockfd)
close(sockfd);
}

static std::string getPoolState(std::string pname)
{
std::string s;

s = execCmd("zpool", std::string("list -Ho health ") + pname);
// Trim white space at the end of string
s.erase(std::find_if(s.rbegin(), s.rend(),
std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end());
return (s);
}

/*
* zrepl program wrapper.
*
Expand Down Expand Up @@ -566,23 +578,13 @@ class Target {
int m_listenfd;
};

/*
* Class simplifying test zfs pool creation and creation of zvols on it.
* Automatic pool destruction takes place when object goes out of scope.
*/
class TestPool {
class Vdev {
public:
TestPool(std::string poolname) {
m_name = poolname;
m_path = std::string("/tmp/") + m_name;
Vdev(std::string name) {
m_path = std::string("/tmp/") + name;
}

~TestPool() {
//try {
execCmd("zpool", std::string("destroy -f ") + m_name);
//} catch (std::runtime_error re) {
//;
//}
~Vdev() {
unlink(m_path.c_str());
}

Expand All @@ -599,8 +601,35 @@ class TestPool {
if (rc != 0)
throw std::system_error(errno, std::system_category(),
"Cannot truncate vdev file");
}

std::string m_path;
};

/*
* Class simplifying test zfs pool creation and creation of zvols on it.
* Automatic pool destruction takes place when object goes out of scope.
*/
class TestPool {
public:
TestPool(std::string poolname) {
m_name = poolname;
m_vdev = new Vdev(std::string("disk-for-") + poolname);
}

~TestPool() {
//try {
execCmd("zpool", std::string("destroy -f ") + m_name);
//} catch (std::runtime_error re) {
//;
//}
delete m_vdev;
}

void create() {
m_vdev->create();
execCmd("zpool", std::string("create ") + m_name + " " +
m_path);
m_vdev->m_path);
}

void import() {
Expand All @@ -621,8 +650,8 @@ class TestPool {
return (m_name + "/" + name);
}

Vdev *m_vdev;
std::string m_name;
std::string m_path;
};

class ZreplHandshakeTest : public testing::Test {
Expand Down Expand Up @@ -1338,7 +1367,6 @@ class ZreplBlockSizeTest : public testing::Test {
protected:
/*
* Shared setup hook for all zrepl block size tests - called just once.
* Creates a zvol with 4k block size.
*/
static void SetUpTestCase() {
zvol_io_hdr_t hdr_out, hdr_in;
Expand Down Expand Up @@ -1434,3 +1462,61 @@ TEST_F(ZreplBlockSizeTest, SetDifferentMetaBlockSizes) {
do_data_connection(m_data_fd, m_host, m_port, m_zvol_name, 512, 120,
ZVOL_OP_STATUS_FAILED);
}

/*
* Test disk replacement
*/
TEST(DiskReplaceTest, SpareReplacement) {
Zrepl zrepl;
Target target;
int rc, data_fd, control_fd;
std::string host;
uint16_t port;
int ioseq;
Vdev vdev2("vdev2");
Vdev spare("spare");
TestPool pool("rplcpool");

zrepl.start();
vdev2.create();
spare.create();
pool.create();
pool.createZvol("vol", "-o io.openebs:targetip=127.0.0.1");

rc = target.listen();
ASSERT_GE(rc, 0);
control_fd = target.accept(-1);
ASSERT_GE(control_fd, 0);
do_handshake(pool.getZvolName("vol"), host, port, NULL, control_fd,
ZVOL_OP_STATUS_OK);
do_data_connection(data_fd, host, port, pool.getZvolName("vol"));
write_data_and_verify_resp(data_fd, ioseq, 0, 10);

// construct mirrored pool with a spare
execCmd("zpool", std::string("attach ") + pool.m_name + " " +
pool.m_vdev->m_path + " " + vdev2.m_path);
write_data_and_verify_resp(data_fd, ioseq, 0, 10);
execCmd("zpool", std::string("add ") + pool.m_name + " spare " +
spare.m_path);
write_data_and_verify_resp(data_fd, ioseq, 0, 10);
ASSERT_STREQ(getPoolState(pool.m_name).c_str(), "ONLINE");

// fail one of the disks in the mirror
execCmd("zpool", std::string("offline ") + pool.m_name + " " +
vdev2.m_path);
write_data_and_verify_resp(data_fd, ioseq, 0, 10);
ASSERT_STREQ(getPoolState(pool.m_name).c_str(), "DEGRADED");

// replace failed disk by the spare and remove it from mirror
execCmd("zpool", std::string("replace ") + pool.m_name + " " +
vdev2.m_path + " " + spare.m_path);
write_data_and_verify_resp(data_fd, ioseq, 0, 10);
execCmd("zpool", std::string("detach ") + pool.m_name + " " +
vdev2.m_path);
ASSERT_STREQ(getPoolState(pool.m_name).c_str(), "ONLINE");

//std::cout << execCmd("zpool", std::string("status ") + pool.m_name);

graceful_close(data_fd);
graceful_close(control_fd);
}