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

OpenZFS 7614 - zfs device evacuation/removal #6900

Closed
wants to merge 7 commits into from
Closed
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
698 changes: 636 additions & 62 deletions cmd/zdb/zdb.c

Large diffs are not rendered by default.

25 changes: 24 additions & 1 deletion cmd/zfs/zfs_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ static int zfs_do_release(int argc, char **argv);
static int zfs_do_diff(int argc, char **argv);
static int zfs_do_bookmark(int argc, char **argv);
static int zfs_do_channel_program(int argc, char **argv);
static int zfs_do_remap(int argc, char **argv);
static int zfs_do_load_key(int argc, char **argv);
static int zfs_do_unload_key(int argc, char **argv);
static int zfs_do_change_key(int argc, char **argv);
Expand Down Expand Up @@ -163,6 +164,7 @@ typedef enum {
HELP_HOLDS,
HELP_RELEASE,
HELP_DIFF,
HELP_REMAP,
HELP_BOOKMARK,
HELP_CHANNEL_PROGRAM,
HELP_LOAD_KEY,
Expand Down Expand Up @@ -226,6 +228,7 @@ static zfs_command_t command_table[] = {
{ "holds", zfs_do_holds, HELP_HOLDS },
{ "release", zfs_do_release, HELP_RELEASE },
{ "diff", zfs_do_diff, HELP_DIFF },
{ "remap", zfs_do_remap, HELP_REMAP },
{ "load-key", zfs_do_load_key, HELP_LOAD_KEY },
{ "unload-key", zfs_do_unload_key, HELP_UNLOAD_KEY },
{ "change-key", zfs_do_change_key, HELP_CHANGE_KEY },
Expand Down Expand Up @@ -356,6 +359,8 @@ get_usage(zfs_help_t idx)
case HELP_DIFF:
return (gettext("\tdiff [-FHt] <snapshot> "
"[snapshot|filesystem]\n"));
case HELP_REMAP:
return (gettext("\tremap <filesystem | volume>\n"));
case HELP_BOOKMARK:
return (gettext("\tbookmark <snapshot> <bookmark>\n"));
case HELP_CHANNEL_PROGRAM:
Expand Down Expand Up @@ -4363,6 +4368,7 @@ zfs_do_receive(int argc, char **argv)
#define ZFS_DELEG_PERM_RELEASE "release"
#define ZFS_DELEG_PERM_DIFF "diff"
#define ZFS_DELEG_PERM_BOOKMARK "bookmark"
#define ZFS_DELEG_PERM_REMAP "remap"
#define ZFS_DELEG_PERM_LOAD_KEY "load-key"
#define ZFS_DELEG_PERM_CHANGE_KEY "change-key"

Expand Down Expand Up @@ -4390,6 +4396,7 @@ static zfs_deleg_perm_tab_t zfs_deleg_perm_tbl[] = {
{ ZFS_DELEG_PERM_SHARE, ZFS_DELEG_NOTE_SHARE },
{ ZFS_DELEG_PERM_SNAPSHOT, ZFS_DELEG_NOTE_SNAPSHOT },
{ ZFS_DELEG_PERM_BOOKMARK, ZFS_DELEG_NOTE_BOOKMARK },
{ ZFS_DELEG_PERM_REMAP, ZFS_DELEG_NOTE_REMAP },
{ ZFS_DELEG_PERM_LOAD_KEY, ZFS_DELEG_NOTE_LOAD_KEY },
{ ZFS_DELEG_PERM_CHANGE_KEY, ZFS_DELEG_NOTE_CHANGE_KEY },

Expand Down Expand Up @@ -7059,7 +7066,7 @@ zfs_do_diff(int argc, char **argv)

if (argc < 1) {
(void) fprintf(stderr,
gettext("must provide at least one snapshot name\n"));
gettext("must provide at least one snapshot name\n"));
usage(B_FALSE);
}

Expand Down Expand Up @@ -7101,6 +7108,22 @@ zfs_do_diff(int argc, char **argv)
return (err != 0);
}

static int
zfs_do_remap(int argc, char **argv)
{
const char *fsname;
int err = 0;
if (argc != 2) {
(void) fprintf(stderr, gettext("wrong number of arguments\n"));
usage(B_FALSE);
}

fsname = argv[1];
err = zfs_remap_indirects(g_zfs, fsname);

return (err);
}

/*
* zfs bookmark <fs@snap> <fs#bmark>
*
Expand Down
207 changes: 193 additions & 14 deletions cmd/zpool/zpool_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,7 @@ get_usage(zpool_help_t idx)
return (gettext("\treplace [-f] [-o property=value] "
"<pool> <device> [new-device]\n"));
case HELP_REMOVE:
return (gettext("\tremove <pool> <device> ...\n"));
return (gettext("\tremove [-nps] <pool> <device> ...\n"));
case HELP_REOPEN:
return (gettext("\treopen [-n] <pool>\n"));
case HELP_SCRUB:
Expand Down Expand Up @@ -782,37 +782,95 @@ zpool_do_add(int argc, char **argv)
/*
* zpool remove <pool> <vdev> ...
*
* Removes the given vdev from the pool. Currently, this supports removing
* spares, cache, and log devices from the pool.
* Removes the given vdev from the pool.
*/
int
zpool_do_remove(int argc, char **argv)
{
char *poolname;
int i, ret = 0;
zpool_handle_t *zhp = NULL;
boolean_t stop = B_FALSE;
char c;
boolean_t noop = B_FALSE;
boolean_t parsable = B_FALSE;

argc--;
argv++;
/* check options */
while ((c = getopt(argc, argv, "nps")) != -1) {
switch (c) {
case 'n':
noop = B_TRUE;
break;
case 'p':
parsable = B_TRUE;
break;
case 's':
stop = B_TRUE;
break;
case '?':
(void) fprintf(stderr, gettext("invalid option '%c'\n"),
optopt);
usage(B_FALSE);
}
}

argc -= optind;
argv += optind;

/* get pool name and check number of arguments */
if (argc < 1) {
(void) fprintf(stderr, gettext("missing pool name argument\n"));
usage(B_FALSE);
}
if (argc < 2) {
(void) fprintf(stderr, gettext("missing device\n"));
usage(B_FALSE);
}

poolname = argv[0];

if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
return (1);

for (i = 1; i < argc; i++) {
if (zpool_vdev_remove(zhp, argv[i]) != 0)
if (stop && noop) {
(void) fprintf(stderr, gettext("stop request ignored\n"));
return (0);
}

if (stop) {
if (argc > 1) {
(void) fprintf(stderr, gettext("too many arguments\n"));
usage(B_FALSE);
}
if (zpool_vdev_remove_cancel(zhp) != 0)
ret = 1;
} else {
if (argc < 2) {
(void) fprintf(stderr, gettext("missing device\n"));
usage(B_FALSE);
}

for (i = 1; i < argc; i++) {
if (noop) {
uint64_t size;

if (zpool_vdev_indirect_size(zhp, argv[i],
&size) != 0) {
ret = 1;
break;
}
if (parsable) {
(void) printf("%s %llu\n",
argv[i], (unsigned long long)size);
} else {
char valstr[32];
zfs_nicenum(size, valstr,
sizeof (valstr));
(void) printf("Memory that will be "
"used after removing %s: %s\n",
argv[i], valstr);
}
} else {
if (zpool_vdev_remove(zhp, argv[i]) != 0)
ret = 1;
}
}
}
zpool_close(zhp);

Expand Down Expand Up @@ -1655,6 +1713,7 @@ print_status_config(zpool_handle_t *zhp, status_cbdata_t *cb, const char *name,
uint64_t notpresent;
spare_cbdata_t spare_cb;
const char *state;
char *type;
char *path = NULL;

if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
Expand All @@ -1664,6 +1723,11 @@ print_status_config(zpool_handle_t *zhp, status_cbdata_t *cb, const char *name,
verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS,
(uint64_t **)&vs, &c) == 0);

verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0);

if (strcmp(type, VDEV_TYPE_INDIRECT) == 0)
return;

state = zpool_state_to_name(vs->vs_state, vs->vs_aux);
if (isspare) {
/*
Expand Down Expand Up @@ -3668,6 +3732,9 @@ print_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv,

calcvs = safe_malloc(sizeof (*calcvs));

if (strcmp(name, VDEV_TYPE_INDIRECT) == 0)
return (ret);

if (oldnv != NULL) {
verify(nvlist_lookup_uint64_array(oldnv,
ZPOOL_CONFIG_VDEV_STATS, (uint64_t **)&oldvs, &c) == 0);
Expand Down Expand Up @@ -4964,6 +5031,9 @@ print_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
else
format = ZFS_NICENUM_1024;

if (strcmp(name, VDEV_TYPE_INDIRECT) == 0)
return;

if (scripted)
(void) printf("\t%s", name);
else if (strlen(name) + depth > cb->cb_namewidth)
Expand Down Expand Up @@ -5982,7 +6052,7 @@ zpool_do_scrub(int argc, char **argv)
/*
* Print out detailed scrub status.
*/
void
static void
print_scan_status(pool_scan_stat_t *ps)
{
time_t start, end, pause;
Expand Down Expand Up @@ -6129,6 +6199,111 @@ print_scan_status(pool_scan_stat_t *ps)
}
}

/*
* Print out detailed removal status.
*/
static void
print_removal_status(zpool_handle_t *zhp, pool_removal_stat_t *prs)
{
char copied_buf[7], examined_buf[7], total_buf[7], rate_buf[7];
time_t start, end;
nvlist_t *config, *nvroot;
nvlist_t **child;
uint_t children;
char *vdev_name;

if (prs == NULL || prs->prs_state == DSS_NONE)
return;

/*
* Determine name of vdev.
*/
config = zpool_get_config(zhp, NULL);
nvroot = fnvlist_lookup_nvlist(config,
ZPOOL_CONFIG_VDEV_TREE);
verify(nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN,
&child, &children) == 0);
assert(prs->prs_removing_vdev < children);
vdev_name = zpool_vdev_name(g_zfs, zhp,
child[prs->prs_removing_vdev], B_TRUE);

(void) printf(gettext("remove: "));

start = prs->prs_start_time;
end = prs->prs_end_time;
zfs_nicenum(prs->prs_copied, copied_buf, sizeof (copied_buf));

/*
* Removal is finished or canceled.
*/
if (prs->prs_state == DSS_FINISHED) {
uint64_t minutes_taken = (end - start) / 60;

(void) printf(gettext("Removal of vdev %llu copied %s "
"in %lluh%um, completed on %s"),
(longlong_t)prs->prs_removing_vdev,
copied_buf,
(u_longlong_t)(minutes_taken / 60),
(uint_t)(minutes_taken % 60),
ctime((time_t *)&end));
} else if (prs->prs_state == DSS_CANCELED) {
(void) printf(gettext("Removal of %s canceled on %s"),
vdev_name, ctime(&end));
} else {
uint64_t copied, total, elapsed, mins_left, hours_left;
double fraction_done;
uint_t rate;

assert(prs->prs_state == DSS_SCANNING);

/*
* Removal is in progress.
*/
(void) printf(gettext(
"Evacuation of %s in progress since %s"),
vdev_name, ctime(&start));

copied = prs->prs_copied > 0 ? prs->prs_copied : 1;
total = prs->prs_to_copy;
fraction_done = (double)copied / total;

/* elapsed time for this pass */
elapsed = time(NULL) - prs->prs_start_time;
elapsed = elapsed > 0 ? elapsed : 1;
rate = copied / elapsed;
rate = rate > 0 ? rate : 1;
mins_left = ((total - copied) / rate) / 60;
hours_left = mins_left / 60;

zfs_nicenum(copied, examined_buf, sizeof (examined_buf));
zfs_nicenum(total, total_buf, sizeof (total_buf));
zfs_nicenum(rate, rate_buf, sizeof (rate_buf));

/*
* do not print estimated time if hours_left is more than
* 30 days
*/
(void) printf(gettext(" %s copied out of %s at %s/s, "
"%.2f%% done"),
examined_buf, total_buf, rate_buf, 100 * fraction_done);
if (hours_left < (30 * 24)) {
(void) printf(gettext(", %lluh%um to go\n"),
(u_longlong_t)hours_left, (uint_t)(mins_left % 60));
} else {
(void) printf(gettext(
", (copy is slow, no estimated time)\n"));
}
}

if (prs->prs_mapping_memory > 0) {
char mem_buf[7];
zfs_nicenum(prs->prs_mapping_memory, mem_buf, sizeof (mem_buf));
(void) printf(gettext(" %s memory used for "
"removed device mappings\n"),
mem_buf);
}
}

static void
print_error_log(zpool_handle_t *zhp)
{
Expand Down Expand Up @@ -6294,8 +6469,7 @@ status_callback(zpool_handle_t *zhp, void *data)
else
(void) printf("\n");

verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
&nvroot) == 0);
nvroot = fnvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE);
verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS,
(uint64_t **)&vs, &c) == 0);
health = zpool_state_to_name(vs->vs_state, vs->vs_aux);
Expand Down Expand Up @@ -6555,11 +6729,16 @@ status_callback(zpool_handle_t *zhp, void *data)
nvlist_t **spares, **l2cache;
uint_t nspares, nl2cache;
pool_scan_stat_t *ps = NULL;
pool_removal_stat_t *prs = NULL;

(void) nvlist_lookup_uint64_array(nvroot,
ZPOOL_CONFIG_SCAN_STATS, (uint64_t **)&ps, &c);
print_scan_status(ps);

(void) nvlist_lookup_uint64_array(nvroot,
ZPOOL_CONFIG_REMOVAL_STATS, (uint64_t **)&prs, &c);
print_removal_status(zhp, prs);

cbp->cb_namewidth = max_width(zhp, nvroot, 0, 0,
cbp->cb_name_flags | VDEV_NAME_TYPE_ID);
if (cbp->cb_namewidth < 10)
Expand Down
Loading