zpool_main.c revision 289536
1168404Spjd/* 2168404Spjd * CDDL HEADER START 3168404Spjd * 4168404Spjd * The contents of this file are subject to the terms of the 5168404Spjd * Common Development and Distribution License (the "License"). 6168404Spjd * You may not use this file except in compliance with the License. 7168404Spjd * 8168404Spjd * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9168404Spjd * or http://www.opensolaris.org/os/licensing. 10168404Spjd * See the License for the specific language governing permissions 11168404Spjd * and limitations under the License. 12168404Spjd * 13168404Spjd * When distributing Covered Code, include this CDDL HEADER in each 14168404Spjd * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15168404Spjd * If applicable, add the following below this CDDL HEADER, with the 16168404Spjd * fields enclosed by brackets "[]" replaced with your own identifying 17168404Spjd * information: Portions Copyright [yyyy] [name of copyright owner] 18168404Spjd * 19168404Spjd * CDDL HEADER END 20168404Spjd */ 21168404Spjd 22168404Spjd/* 23219089Spjd * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 24227497Smm * Copyright 2011 Nexenta Systems, Inc. All rights reserved. 25286708Smav * Copyright (c) 2011, 2015 by Delphix. All rights reserved. 26236145Smm * Copyright (c) 2012 by Frederik Wessels. All rights reserved. 27236155Smm * Copyright (c) 2012 Martin Matuska <mm@FreeBSD.org>. All rights reserved. 28254758Sdelphij * Copyright (c) 2013 by Prasad Joshi (sTec). All rights reserved. 29168404Spjd */ 30168404Spjd 31168404Spjd#include <solaris.h> 32168404Spjd#include <assert.h> 33168404Spjd#include <ctype.h> 34168404Spjd#include <dirent.h> 35168404Spjd#include <errno.h> 36168404Spjd#include <fcntl.h> 37168404Spjd#include <libgen.h> 38168404Spjd#include <libintl.h> 39168404Spjd#include <libuutil.h> 40168404Spjd#include <locale.h> 41168404Spjd#include <stdio.h> 42168404Spjd#include <stdlib.h> 43168404Spjd#include <string.h> 44168404Spjd#include <strings.h> 45168404Spjd#include <unistd.h> 46168404Spjd#include <priv.h> 47185029Spjd#include <pwd.h> 48185029Spjd#include <zone.h> 49168404Spjd#include <sys/time.h> 50236155Smm#include <zfs_prop.h> 51168404Spjd#include <sys/fs/zfs.h> 52168404Spjd#include <sys/stat.h> 53168404Spjd 54168404Spjd#include <libzfs.h> 55168404Spjd 56168404Spjd#include "zpool_util.h" 57185029Spjd#include "zfs_comutil.h" 58236884Smm#include "zfeature_common.h" 59168404Spjd 60219089Spjd#include "statcommon.h" 61219089Spjd 62168404Spjdstatic int zpool_do_create(int, char **); 63168404Spjdstatic int zpool_do_destroy(int, char **); 64168404Spjd 65168404Spjdstatic int zpool_do_add(int, char **); 66168404Spjdstatic int zpool_do_remove(int, char **); 67224171Sgibbsstatic int zpool_do_labelclear(int, char **); 68168404Spjd 69168404Spjdstatic int zpool_do_list(int, char **); 70168404Spjdstatic int zpool_do_iostat(int, char **); 71168404Spjdstatic int zpool_do_status(int, char **); 72168404Spjd 73168404Spjdstatic int zpool_do_online(int, char **); 74168404Spjdstatic int zpool_do_offline(int, char **); 75168404Spjdstatic int zpool_do_clear(int, char **); 76236155Smmstatic int zpool_do_reopen(int, char **); 77168404Spjd 78228103Smmstatic int zpool_do_reguid(int, char **); 79228103Smm 80168404Spjdstatic int zpool_do_attach(int, char **); 81168404Spjdstatic int zpool_do_detach(int, char **); 82168404Spjdstatic int zpool_do_replace(int, char **); 83219089Spjdstatic int zpool_do_split(int, char **); 84168404Spjd 85168404Spjdstatic int zpool_do_scrub(int, char **); 86168404Spjd 87168404Spjdstatic int zpool_do_import(int, char **); 88168404Spjdstatic int zpool_do_export(int, char **); 89168404Spjd 90168404Spjdstatic int zpool_do_upgrade(int, char **); 91168404Spjd 92168404Spjdstatic int zpool_do_history(int, char **); 93168404Spjd 94168404Spjdstatic int zpool_do_get(int, char **); 95168404Spjdstatic int zpool_do_set(int, char **); 96168404Spjd 97168404Spjd/* 98168404Spjd * These libumem hooks provide a reasonable set of defaults for the allocator's 99168404Spjd * debugging facilities. 100168404Spjd */ 101185029Spjd 102185029Spjd#ifdef DEBUG 103168404Spjdconst char * 104168404Spjd_umem_debug_init(void) 105168404Spjd{ 106168404Spjd return ("default,verbose"); /* $UMEM_DEBUG setting */ 107168404Spjd} 108168404Spjd 109168404Spjdconst char * 110168404Spjd_umem_logging_init(void) 111168404Spjd{ 112168404Spjd return ("fail,contents"); /* $UMEM_LOGGING setting */ 113168404Spjd} 114185029Spjd#endif 115168404Spjd 116168404Spjdtypedef enum { 117168404Spjd HELP_ADD, 118168404Spjd HELP_ATTACH, 119168404Spjd HELP_CLEAR, 120168404Spjd HELP_CREATE, 121168404Spjd HELP_DESTROY, 122168404Spjd HELP_DETACH, 123168404Spjd HELP_EXPORT, 124168404Spjd HELP_HISTORY, 125168404Spjd HELP_IMPORT, 126168404Spjd HELP_IOSTAT, 127224171Sgibbs HELP_LABELCLEAR, 128168404Spjd HELP_LIST, 129168404Spjd HELP_OFFLINE, 130168404Spjd HELP_ONLINE, 131168404Spjd HELP_REPLACE, 132168404Spjd HELP_REMOVE, 133168404Spjd HELP_SCRUB, 134168404Spjd HELP_STATUS, 135168404Spjd HELP_UPGRADE, 136168404Spjd HELP_GET, 137219089Spjd HELP_SET, 138228103Smm HELP_SPLIT, 139236155Smm HELP_REGUID, 140236155Smm HELP_REOPEN 141168404Spjd} zpool_help_t; 142168404Spjd 143168404Spjd 144168404Spjdtypedef struct zpool_command { 145168404Spjd const char *name; 146168404Spjd int (*func)(int, char **); 147168404Spjd zpool_help_t usage; 148168404Spjd} zpool_command_t; 149168404Spjd 150168404Spjd/* 151168404Spjd * Master command table. Each ZFS command has a name, associated function, and 152168404Spjd * usage message. The usage messages need to be internationalized, so we have 153168404Spjd * to have a function to return the usage message based on a command index. 154168404Spjd * 155168404Spjd * These commands are organized according to how they are displayed in the usage 156168404Spjd * message. An empty command (one with a NULL name) indicates an empty line in 157168404Spjd * the generic usage message. 158168404Spjd */ 159168404Spjdstatic zpool_command_t command_table[] = { 160168404Spjd { "create", zpool_do_create, HELP_CREATE }, 161168404Spjd { "destroy", zpool_do_destroy, HELP_DESTROY }, 162168404Spjd { NULL }, 163168404Spjd { "add", zpool_do_add, HELP_ADD }, 164168404Spjd { "remove", zpool_do_remove, HELP_REMOVE }, 165168404Spjd { NULL }, 166224171Sgibbs { "labelclear", zpool_do_labelclear, HELP_LABELCLEAR }, 167224171Sgibbs { NULL }, 168168404Spjd { "list", zpool_do_list, HELP_LIST }, 169168404Spjd { "iostat", zpool_do_iostat, HELP_IOSTAT }, 170168404Spjd { "status", zpool_do_status, HELP_STATUS }, 171168404Spjd { NULL }, 172168404Spjd { "online", zpool_do_online, HELP_ONLINE }, 173168404Spjd { "offline", zpool_do_offline, HELP_OFFLINE }, 174168404Spjd { "clear", zpool_do_clear, HELP_CLEAR }, 175236155Smm { "reopen", zpool_do_reopen, HELP_REOPEN }, 176168404Spjd { NULL }, 177168404Spjd { "attach", zpool_do_attach, HELP_ATTACH }, 178168404Spjd { "detach", zpool_do_detach, HELP_DETACH }, 179168404Spjd { "replace", zpool_do_replace, HELP_REPLACE }, 180219089Spjd { "split", zpool_do_split, HELP_SPLIT }, 181168404Spjd { NULL }, 182168404Spjd { "scrub", zpool_do_scrub, HELP_SCRUB }, 183168404Spjd { NULL }, 184168404Spjd { "import", zpool_do_import, HELP_IMPORT }, 185168404Spjd { "export", zpool_do_export, HELP_EXPORT }, 186168404Spjd { "upgrade", zpool_do_upgrade, HELP_UPGRADE }, 187228103Smm { "reguid", zpool_do_reguid, HELP_REGUID }, 188168404Spjd { NULL }, 189168404Spjd { "history", zpool_do_history, HELP_HISTORY }, 190168404Spjd { "get", zpool_do_get, HELP_GET }, 191168404Spjd { "set", zpool_do_set, HELP_SET }, 192168404Spjd}; 193168404Spjd 194168404Spjd#define NCOMMAND (sizeof (command_table) / sizeof (command_table[0])) 195168404Spjd 196248571Smmstatic zpool_command_t *current_command; 197185029Spjdstatic char history_str[HIS_MAX_RECORD_LEN]; 198248571Smmstatic boolean_t log_history = B_TRUE; 199219089Spjdstatic uint_t timestamp_fmt = NODATE; 200219089Spjd 201168404Spjdstatic const char * 202168404Spjdget_usage(zpool_help_t idx) { 203168404Spjd switch (idx) { 204168404Spjd case HELP_ADD: 205168404Spjd return (gettext("\tadd [-fn] <pool> <vdev> ...\n")); 206168404Spjd case HELP_ATTACH: 207168404Spjd return (gettext("\tattach [-f] <pool> <device> " 208185029Spjd "<new-device>\n")); 209168404Spjd case HELP_CLEAR: 210219089Spjd return (gettext("\tclear [-nF] <pool> [device]\n")); 211168404Spjd case HELP_CREATE: 212236884Smm return (gettext("\tcreate [-fnd] [-o property=value] ... \n" 213185029Spjd "\t [-O file-system-property=value] ... \n" 214185029Spjd "\t [-m mountpoint] [-R root] <pool> <vdev> ...\n")); 215168404Spjd case HELP_DESTROY: 216168404Spjd return (gettext("\tdestroy [-f] <pool>\n")); 217168404Spjd case HELP_DETACH: 218168404Spjd return (gettext("\tdetach <pool> <device>\n")); 219168404Spjd case HELP_EXPORT: 220168404Spjd return (gettext("\texport [-f] <pool> ...\n")); 221168404Spjd case HELP_HISTORY: 222185029Spjd return (gettext("\thistory [-il] [<pool>] ...\n")); 223168404Spjd case HELP_IMPORT: 224168404Spjd return (gettext("\timport [-d dir] [-D]\n" 225219089Spjd "\timport [-d dir | -c cachefile] [-F [-n]] <pool | id>\n" 226185029Spjd "\timport [-o mntopts] [-o property=value] ... \n" 227219089Spjd "\t [-d dir | -c cachefile] [-D] [-f] [-m] [-N] " 228219089Spjd "[-R root] [-F [-n]] -a\n" 229185029Spjd "\timport [-o mntopts] [-o property=value] ... \n" 230219089Spjd "\t [-d dir | -c cachefile] [-D] [-f] [-m] [-N] " 231219089Spjd "[-R root] [-F [-n]]\n" 232219089Spjd "\t <pool | id> [newpool]\n")); 233168404Spjd case HELP_IOSTAT: 234219089Spjd return (gettext("\tiostat [-v] [-T d|u] [pool] ... [interval " 235168404Spjd "[count]]\n")); 236224171Sgibbs case HELP_LABELCLEAR: 237224171Sgibbs return (gettext("\tlabelclear [-f] <vdev>\n")); 238168404Spjd case HELP_LIST: 239263889Sdelphij return (gettext("\tlist [-Hpv] [-o property[,...]] " 240219089Spjd "[-T d|u] [pool] ... [interval [count]]\n")); 241168404Spjd case HELP_OFFLINE: 242168404Spjd return (gettext("\toffline [-t] <pool> <device> ...\n")); 243168404Spjd case HELP_ONLINE: 244228020Smm return (gettext("\tonline [-e] <pool> <device> ...\n")); 245168404Spjd case HELP_REPLACE: 246168404Spjd return (gettext("\treplace [-f] <pool> <device> " 247185029Spjd "[new-device]\n")); 248168404Spjd case HELP_REMOVE: 249185029Spjd return (gettext("\tremove <pool> <device> ...\n")); 250236155Smm case HELP_REOPEN: 251260138Sdelphij return (gettext("\treopen <pool>\n")); 252168404Spjd case HELP_SCRUB: 253168404Spjd return (gettext("\tscrub [-s] <pool> ...\n")); 254168404Spjd case HELP_STATUS: 255219089Spjd return (gettext("\tstatus [-vx] [-T d|u] [pool] ... [interval " 256219089Spjd "[count]]\n")); 257168404Spjd case HELP_UPGRADE: 258228020Smm return (gettext("\tupgrade [-v]\n" 259185029Spjd "\tupgrade [-V version] <-a | pool ...>\n")); 260168404Spjd case HELP_GET: 261263889Sdelphij return (gettext("\tget [-Hp] [-o \"all\" | field[,...]] " 262263889Sdelphij "<\"all\" | property[,...]> <pool> ...\n")); 263168404Spjd case HELP_SET: 264168404Spjd return (gettext("\tset <property=value> <pool> \n")); 265219089Spjd case HELP_SPLIT: 266219089Spjd return (gettext("\tsplit [-n] [-R altroot] [-o mntopts]\n" 267219089Spjd "\t [-o property=value] <pool> <newpool> " 268219089Spjd "[<device> ...]\n")); 269228103Smm case HELP_REGUID: 270228103Smm return (gettext("\treguid <pool>\n")); 271168404Spjd } 272168404Spjd 273168404Spjd abort(); 274168404Spjd /* NOTREACHED */ 275168404Spjd} 276168404Spjd 277168404Spjd 278168404Spjd/* 279168404Spjd * Callback routine that will print out a pool property value. 280168404Spjd */ 281185029Spjdstatic int 282185029Spjdprint_prop_cb(int prop, void *cb) 283168404Spjd{ 284168404Spjd FILE *fp = cb; 285168404Spjd 286219089Spjd (void) fprintf(fp, "\t%-15s ", zpool_prop_to_name(prop)); 287168404Spjd 288185029Spjd if (zpool_prop_readonly(prop)) 289185029Spjd (void) fprintf(fp, " NO "); 290185029Spjd else 291219089Spjd (void) fprintf(fp, " YES "); 292185029Spjd 293168404Spjd if (zpool_prop_values(prop) == NULL) 294168404Spjd (void) fprintf(fp, "-\n"); 295168404Spjd else 296168404Spjd (void) fprintf(fp, "%s\n", zpool_prop_values(prop)); 297168404Spjd 298185029Spjd return (ZPROP_CONT); 299168404Spjd} 300168404Spjd 301168404Spjd/* 302168404Spjd * Display usage message. If we're inside a command, display only the usage for 303168404Spjd * that command. Otherwise, iterate over the entire command table and display 304168404Spjd * a complete usage message. 305168404Spjd */ 306168404Spjdvoid 307168404Spjdusage(boolean_t requested) 308168404Spjd{ 309168404Spjd FILE *fp = requested ? stdout : stderr; 310168404Spjd 311168404Spjd if (current_command == NULL) { 312168404Spjd int i; 313168404Spjd 314168404Spjd (void) fprintf(fp, gettext("usage: zpool command args ...\n")); 315168404Spjd (void) fprintf(fp, 316168404Spjd gettext("where 'command' is one of the following:\n\n")); 317168404Spjd 318168404Spjd for (i = 0; i < NCOMMAND; i++) { 319168404Spjd if (command_table[i].name == NULL) 320168404Spjd (void) fprintf(fp, "\n"); 321168404Spjd else 322168404Spjd (void) fprintf(fp, "%s", 323168404Spjd get_usage(command_table[i].usage)); 324168404Spjd } 325168404Spjd } else { 326168404Spjd (void) fprintf(fp, gettext("usage:\n")); 327168404Spjd (void) fprintf(fp, "%s", get_usage(current_command->usage)); 328168404Spjd } 329168404Spjd 330168404Spjd if (current_command != NULL && 331168404Spjd ((strcmp(current_command->name, "set") == 0) || 332185029Spjd (strcmp(current_command->name, "get") == 0) || 333185029Spjd (strcmp(current_command->name, "list") == 0))) { 334168404Spjd 335168404Spjd (void) fprintf(fp, 336168404Spjd gettext("\nthe following properties are supported:\n")); 337168404Spjd 338219089Spjd (void) fprintf(fp, "\n\t%-15s %s %s\n\n", 339185029Spjd "PROPERTY", "EDIT", "VALUES"); 340168404Spjd 341168404Spjd /* Iterate over all properties */ 342185029Spjd (void) zprop_iter(print_prop_cb, fp, B_FALSE, B_TRUE, 343185029Spjd ZFS_TYPE_POOL); 344236884Smm 345236884Smm (void) fprintf(fp, "\t%-15s ", "feature@..."); 346236884Smm (void) fprintf(fp, "YES disabled | enabled | active\n"); 347236884Smm 348236884Smm (void) fprintf(fp, gettext("\nThe feature@ properties must be " 349243014Smm "appended with a feature name.\nSee zpool-features(7).\n")); 350168404Spjd } 351168404Spjd 352168404Spjd /* 353168404Spjd * See comments at end of main(). 354168404Spjd */ 355168404Spjd if (getenv("ZFS_ABORT") != NULL) { 356168404Spjd (void) printf("dumping core by request\n"); 357168404Spjd abort(); 358168404Spjd } 359168404Spjd 360168404Spjd exit(requested ? 0 : 2); 361168404Spjd} 362168404Spjd 363168404Spjdvoid 364185029Spjdprint_vdev_tree(zpool_handle_t *zhp, const char *name, nvlist_t *nv, int indent, 365185029Spjd boolean_t print_logs) 366168404Spjd{ 367168404Spjd nvlist_t **child; 368168404Spjd uint_t c, children; 369168404Spjd char *vname; 370168404Spjd 371168404Spjd if (name != NULL) 372168404Spjd (void) printf("\t%*s%s\n", indent, "", name); 373168404Spjd 374168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 375168404Spjd &child, &children) != 0) 376168404Spjd return; 377168404Spjd 378168404Spjd for (c = 0; c < children; c++) { 379185029Spjd uint64_t is_log = B_FALSE; 380185029Spjd 381185029Spjd (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 382185029Spjd &is_log); 383185029Spjd if ((is_log && !print_logs) || (!is_log && print_logs)) 384185029Spjd continue; 385185029Spjd 386219089Spjd vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE); 387185029Spjd print_vdev_tree(zhp, vname, child[c], indent + 2, 388185029Spjd B_FALSE); 389168404Spjd free(vname); 390168404Spjd } 391168404Spjd} 392168404Spjd 393238926Smmstatic boolean_t 394238926Smmprop_list_contains_feature(nvlist_t *proplist) 395238926Smm{ 396238926Smm nvpair_t *nvp; 397238926Smm for (nvp = nvlist_next_nvpair(proplist, NULL); NULL != nvp; 398238926Smm nvp = nvlist_next_nvpair(proplist, nvp)) { 399238926Smm if (zpool_prop_feature(nvpair_name(nvp))) 400238926Smm return (B_TRUE); 401238926Smm } 402238926Smm return (B_FALSE); 403238926Smm} 404238926Smm 405168404Spjd/* 406185029Spjd * Add a property pair (name, string-value) into a property nvlist. 407185029Spjd */ 408185029Spjdstatic int 409185029Spjdadd_prop_list(const char *propname, char *propval, nvlist_t **props, 410185029Spjd boolean_t poolprop) 411185029Spjd{ 412185029Spjd zpool_prop_t prop = ZPROP_INVAL; 413185029Spjd zfs_prop_t fprop; 414185029Spjd nvlist_t *proplist; 415185029Spjd const char *normnm; 416185029Spjd char *strval; 417185029Spjd 418185029Spjd if (*props == NULL && 419185029Spjd nvlist_alloc(props, NV_UNIQUE_NAME, 0) != 0) { 420185029Spjd (void) fprintf(stderr, 421185029Spjd gettext("internal error: out of memory\n")); 422185029Spjd return (1); 423185029Spjd } 424185029Spjd 425185029Spjd proplist = *props; 426185029Spjd 427185029Spjd if (poolprop) { 428238926Smm const char *vname = zpool_prop_to_name(ZPOOL_PROP_VERSION); 429238926Smm 430236884Smm if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL && 431236884Smm !zpool_prop_feature(propname)) { 432185029Spjd (void) fprintf(stderr, gettext("property '%s' is " 433185029Spjd "not a valid pool property\n"), propname); 434185029Spjd return (2); 435185029Spjd } 436238926Smm 437238926Smm /* 438238926Smm * feature@ properties and version should not be specified 439238926Smm * at the same time. 440238926Smm */ 441238926Smm if ((prop == ZPROP_INVAL && zpool_prop_feature(propname) && 442238926Smm nvlist_exists(proplist, vname)) || 443238926Smm (prop == ZPOOL_PROP_VERSION && 444238926Smm prop_list_contains_feature(proplist))) { 445238926Smm (void) fprintf(stderr, gettext("'feature@' and " 446238926Smm "'version' properties cannot be specified " 447238926Smm "together\n")); 448238926Smm return (2); 449238926Smm } 450238926Smm 451238926Smm 452236884Smm if (zpool_prop_feature(propname)) 453236884Smm normnm = propname; 454236884Smm else 455236884Smm normnm = zpool_prop_to_name(prop); 456185029Spjd } else { 457209962Smm if ((fprop = zfs_name_to_prop(propname)) != ZPROP_INVAL) { 458209962Smm normnm = zfs_prop_to_name(fprop); 459209962Smm } else { 460209962Smm normnm = propname; 461185029Spjd } 462185029Spjd } 463185029Spjd 464185029Spjd if (nvlist_lookup_string(proplist, normnm, &strval) == 0 && 465185029Spjd prop != ZPOOL_PROP_CACHEFILE) { 466185029Spjd (void) fprintf(stderr, gettext("property '%s' " 467185029Spjd "specified multiple times\n"), propname); 468185029Spjd return (2); 469185029Spjd } 470185029Spjd 471185029Spjd if (nvlist_add_string(proplist, normnm, propval) != 0) { 472185029Spjd (void) fprintf(stderr, gettext("internal " 473185029Spjd "error: out of memory\n")); 474185029Spjd return (1); 475185029Spjd } 476185029Spjd 477185029Spjd return (0); 478185029Spjd} 479185029Spjd 480185029Spjd/* 481168404Spjd * zpool add [-fn] <pool> <vdev> ... 482168404Spjd * 483168404Spjd * -f Force addition of devices, even if they appear in use 484168404Spjd * -n Do not add the devices, but display the resulting layout if 485168404Spjd * they were to be added. 486168404Spjd * 487168404Spjd * Adds the given vdevs to 'pool'. As with create, the bulk of this work is 488168404Spjd * handled by get_vdev_spec(), which constructs the nvlist needed to pass to 489168404Spjd * libzfs. 490168404Spjd */ 491168404Spjdint 492168404Spjdzpool_do_add(int argc, char **argv) 493168404Spjd{ 494168404Spjd boolean_t force = B_FALSE; 495168404Spjd boolean_t dryrun = B_FALSE; 496168404Spjd int c; 497168404Spjd nvlist_t *nvroot; 498168404Spjd char *poolname; 499168404Spjd int ret; 500168404Spjd zpool_handle_t *zhp; 501168404Spjd nvlist_t *config; 502168404Spjd 503168404Spjd /* check options */ 504168404Spjd while ((c = getopt(argc, argv, "fn")) != -1) { 505168404Spjd switch (c) { 506168404Spjd case 'f': 507168404Spjd force = B_TRUE; 508168404Spjd break; 509168404Spjd case 'n': 510168404Spjd dryrun = B_TRUE; 511168404Spjd break; 512168404Spjd case '?': 513168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 514168404Spjd optopt); 515168404Spjd usage(B_FALSE); 516168404Spjd } 517168404Spjd } 518168404Spjd 519168404Spjd argc -= optind; 520168404Spjd argv += optind; 521168404Spjd 522168404Spjd /* get pool name and check number of arguments */ 523168404Spjd if (argc < 1) { 524168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 525168404Spjd usage(B_FALSE); 526168404Spjd } 527168404Spjd if (argc < 2) { 528168404Spjd (void) fprintf(stderr, gettext("missing vdev specification\n")); 529168404Spjd usage(B_FALSE); 530168404Spjd } 531168404Spjd 532168404Spjd poolname = argv[0]; 533168404Spjd 534168404Spjd argc--; 535168404Spjd argv++; 536168404Spjd 537168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 538168404Spjd return (1); 539168404Spjd 540168404Spjd if ((config = zpool_get_config(zhp, NULL)) == NULL) { 541168404Spjd (void) fprintf(stderr, gettext("pool '%s' is unavailable\n"), 542168404Spjd poolname); 543168404Spjd zpool_close(zhp); 544168404Spjd return (1); 545168404Spjd } 546168404Spjd 547168404Spjd /* pass off to get_vdev_spec for processing */ 548185029Spjd nvroot = make_root_vdev(zhp, force, !force, B_FALSE, dryrun, 549185029Spjd argc, argv); 550168404Spjd if (nvroot == NULL) { 551168404Spjd zpool_close(zhp); 552168404Spjd return (1); 553168404Spjd } 554168404Spjd 555168404Spjd if (dryrun) { 556168404Spjd nvlist_t *poolnvroot; 557168404Spjd 558168404Spjd verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 559168404Spjd &poolnvroot) == 0); 560168404Spjd 561168404Spjd (void) printf(gettext("would update '%s' to the following " 562168404Spjd "configuration:\n"), zpool_get_name(zhp)); 563168404Spjd 564185029Spjd /* print original main pool and new tree */ 565185029Spjd print_vdev_tree(zhp, poolname, poolnvroot, 0, B_FALSE); 566185029Spjd print_vdev_tree(zhp, NULL, nvroot, 0, B_FALSE); 567168404Spjd 568185029Spjd /* Do the same for the logs */ 569185029Spjd if (num_logs(poolnvroot) > 0) { 570185029Spjd print_vdev_tree(zhp, "logs", poolnvroot, 0, B_TRUE); 571185029Spjd print_vdev_tree(zhp, NULL, nvroot, 0, B_TRUE); 572185029Spjd } else if (num_logs(nvroot) > 0) { 573185029Spjd print_vdev_tree(zhp, "logs", nvroot, 0, B_TRUE); 574185029Spjd } 575185029Spjd 576168404Spjd ret = 0; 577168404Spjd } else { 578168404Spjd ret = (zpool_add(zhp, nvroot) != 0); 579168404Spjd } 580168404Spjd 581168404Spjd nvlist_free(nvroot); 582168404Spjd zpool_close(zhp); 583168404Spjd 584168404Spjd return (ret); 585168404Spjd} 586168404Spjd 587168404Spjd/* 588219089Spjd * zpool remove <pool> <vdev> ... 589168404Spjd * 590219089Spjd * Removes the given vdev from the pool. Currently, this supports removing 591219089Spjd * spares, cache, and log devices from the pool. 592168404Spjd */ 593168404Spjdint 594168404Spjdzpool_do_remove(int argc, char **argv) 595168404Spjd{ 596168404Spjd char *poolname; 597185029Spjd int i, ret = 0; 598168404Spjd zpool_handle_t *zhp; 599168404Spjd 600168404Spjd argc--; 601168404Spjd argv++; 602168404Spjd 603168404Spjd /* get pool name and check number of arguments */ 604168404Spjd if (argc < 1) { 605168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 606168404Spjd usage(B_FALSE); 607168404Spjd } 608168404Spjd if (argc < 2) { 609168404Spjd (void) fprintf(stderr, gettext("missing device\n")); 610168404Spjd usage(B_FALSE); 611168404Spjd } 612168404Spjd 613168404Spjd poolname = argv[0]; 614168404Spjd 615168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 616168404Spjd return (1); 617168404Spjd 618185029Spjd for (i = 1; i < argc; i++) { 619185029Spjd if (zpool_vdev_remove(zhp, argv[i]) != 0) 620185029Spjd ret = 1; 621168404Spjd } 622168404Spjd 623168404Spjd return (ret); 624168404Spjd} 625168404Spjd 626168404Spjd/* 627224171Sgibbs * zpool labelclear <vdev> 628224171Sgibbs * 629224171Sgibbs * Verifies that the vdev is not active and zeros out the label information 630224171Sgibbs * on the device. 631224171Sgibbs */ 632224171Sgibbsint 633224171Sgibbszpool_do_labelclear(int argc, char **argv) 634224171Sgibbs{ 635224171Sgibbs char *vdev, *name; 636224171Sgibbs int c, fd = -1, ret = 0; 637224171Sgibbs pool_state_t state; 638224171Sgibbs boolean_t inuse = B_FALSE; 639224171Sgibbs boolean_t force = B_FALSE; 640224171Sgibbs 641224171Sgibbs /* check options */ 642224171Sgibbs while ((c = getopt(argc, argv, "f")) != -1) { 643224171Sgibbs switch (c) { 644224171Sgibbs case 'f': 645224171Sgibbs force = B_TRUE; 646224171Sgibbs break; 647224171Sgibbs default: 648224171Sgibbs (void) fprintf(stderr, gettext("invalid option '%c'\n"), 649224171Sgibbs optopt); 650224171Sgibbs usage(B_FALSE); 651224171Sgibbs } 652224171Sgibbs } 653224171Sgibbs 654224171Sgibbs argc -= optind; 655224171Sgibbs argv += optind; 656224171Sgibbs 657224171Sgibbs /* get vdev name */ 658224171Sgibbs if (argc < 1) { 659224171Sgibbs (void) fprintf(stderr, gettext("missing vdev device name\n")); 660224171Sgibbs usage(B_FALSE); 661224171Sgibbs } 662224171Sgibbs 663224171Sgibbs vdev = argv[0]; 664224171Sgibbs if ((fd = open(vdev, O_RDWR)) < 0) { 665224171Sgibbs (void) fprintf(stderr, gettext("Unable to open %s\n"), vdev); 666224171Sgibbs return (B_FALSE); 667224171Sgibbs } 668224171Sgibbs 669224171Sgibbs name = NULL; 670224171Sgibbs if (zpool_in_use(g_zfs, fd, &state, &name, &inuse) != 0) { 671224171Sgibbs if (force) 672224171Sgibbs goto wipe_label; 673224171Sgibbs 674224171Sgibbs (void) fprintf(stderr, 675224171Sgibbs gettext("Unable to determine pool state for %s\n" 676224171Sgibbs "Use -f to force the clearing any label data\n"), vdev); 677224171Sgibbs 678224171Sgibbs return (1); 679224171Sgibbs } 680224171Sgibbs 681224171Sgibbs if (inuse) { 682224171Sgibbs switch (state) { 683224171Sgibbs default: 684224171Sgibbs case POOL_STATE_ACTIVE: 685224171Sgibbs case POOL_STATE_SPARE: 686224171Sgibbs case POOL_STATE_L2CACHE: 687224171Sgibbs (void) fprintf(stderr, 688224171Sgibbsgettext("labelclear operation failed.\n" 689224171Sgibbs "\tVdev %s is a member (%s), of pool \"%s\".\n" 690224171Sgibbs "\tTo remove label information from this device, export or destroy\n" 691224171Sgibbs "\tthe pool, or remove %s from the configuration of this pool\n" 692224171Sgibbs "\tand retry the labelclear operation\n"), 693224171Sgibbs vdev, zpool_pool_state_to_name(state), name, vdev); 694224171Sgibbs ret = 1; 695224171Sgibbs goto errout; 696224171Sgibbs 697224171Sgibbs case POOL_STATE_EXPORTED: 698224171Sgibbs if (force) 699224171Sgibbs break; 700224171Sgibbs 701224171Sgibbs (void) fprintf(stderr, 702224171Sgibbsgettext("labelclear operation failed.\n" 703224171Sgibbs "\tVdev %s is a member of the exported pool \"%s\".\n" 704224171Sgibbs "\tUse \"zpool labelclear -f %s\" to force the removal of label\n" 705224171Sgibbs "\tinformation.\n"), 706224171Sgibbs vdev, name, vdev); 707224171Sgibbs ret = 1; 708224171Sgibbs goto errout; 709224171Sgibbs 710224171Sgibbs case POOL_STATE_POTENTIALLY_ACTIVE: 711224171Sgibbs if (force) 712224171Sgibbs break; 713224171Sgibbs 714224171Sgibbs (void) fprintf(stderr, 715224171Sgibbsgettext("labelclear operation failed.\n" 716224171Sgibbs "\tVdev %s is a member of the pool \"%s\".\n" 717224171Sgibbs "\tThis pool is unknown to this system, but may be active on\n" 718224171Sgibbs "\tanother system. Use \'zpool labelclear -f %s\' to force the\n" 719224171Sgibbs "\tremoval of label information.\n"), 720224171Sgibbs vdev, name, vdev); 721224171Sgibbs ret = 1; 722224171Sgibbs goto errout; 723224171Sgibbs 724224171Sgibbs case POOL_STATE_DESTROYED: 725224171Sgibbs /* inuse should never be set for a destoryed pool... */ 726224171Sgibbs break; 727224171Sgibbs } 728224171Sgibbs } 729224171Sgibbs 730224171Sgibbswipe_label: 731224171Sgibbs if (zpool_clear_label(fd) != 0) { 732224171Sgibbs (void) fprintf(stderr, 733224171Sgibbs gettext("Label clear failed on vdev %s\n"), vdev); 734224171Sgibbs ret = 1; 735224171Sgibbs } 736224171Sgibbs 737224171Sgibbserrout: 738224171Sgibbs close(fd); 739224171Sgibbs if (name != NULL) 740224171Sgibbs free(name); 741224171Sgibbs 742224171Sgibbs return (ret); 743224171Sgibbs} 744224171Sgibbs 745224171Sgibbs/* 746236884Smm * zpool create [-fnd] [-o property=value] ... 747185029Spjd * [-O file-system-property=value] ... 748185029Spjd * [-R root] [-m mountpoint] <pool> <dev> ... 749168404Spjd * 750168404Spjd * -f Force creation, even if devices appear in use 751168404Spjd * -n Do not create the pool, but display the resulting layout if it 752168404Spjd * were to be created. 753168404Spjd * -R Create a pool under an alternate root 754168404Spjd * -m Set default mountpoint for the root dataset. By default it's 755236884Smm * '/<pool>' 756185029Spjd * -o Set property=value. 757236884Smm * -d Don't automatically enable all supported pool features 758236884Smm * (individual features can be enabled with -o). 759185029Spjd * -O Set fsproperty=value in the pool's root file system 760168404Spjd * 761168404Spjd * Creates the named pool according to the given vdev specification. The 762168404Spjd * bulk of the vdev processing is done in get_vdev_spec() in zpool_vdev.c. Once 763168404Spjd * we get the nvlist back from get_vdev_spec(), we either print out the contents 764168404Spjd * (if '-n' was specified), or pass it to libzfs to do the creation. 765168404Spjd */ 766168404Spjdint 767168404Spjdzpool_do_create(int argc, char **argv) 768168404Spjd{ 769168404Spjd boolean_t force = B_FALSE; 770168404Spjd boolean_t dryrun = B_FALSE; 771236884Smm boolean_t enable_all_pool_feat = B_TRUE; 772168404Spjd int c; 773185029Spjd nvlist_t *nvroot = NULL; 774168404Spjd char *poolname; 775185029Spjd int ret = 1; 776168404Spjd char *altroot = NULL; 777168404Spjd char *mountpoint = NULL; 778185029Spjd nvlist_t *fsprops = NULL; 779185029Spjd nvlist_t *props = NULL; 780185029Spjd char *propval; 781168404Spjd 782168404Spjd /* check options */ 783236884Smm while ((c = getopt(argc, argv, ":fndR:m:o:O:")) != -1) { 784168404Spjd switch (c) { 785168404Spjd case 'f': 786168404Spjd force = B_TRUE; 787168404Spjd break; 788168404Spjd case 'n': 789168404Spjd dryrun = B_TRUE; 790168404Spjd break; 791236884Smm case 'd': 792236884Smm enable_all_pool_feat = B_FALSE; 793236884Smm break; 794168404Spjd case 'R': 795168404Spjd altroot = optarg; 796185029Spjd if (add_prop_list(zpool_prop_to_name( 797185029Spjd ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE)) 798185029Spjd goto errout; 799185029Spjd if (nvlist_lookup_string(props, 800185029Spjd zpool_prop_to_name(ZPOOL_PROP_CACHEFILE), 801185029Spjd &propval) == 0) 802185029Spjd break; 803185029Spjd if (add_prop_list(zpool_prop_to_name( 804185029Spjd ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE)) 805185029Spjd goto errout; 806168404Spjd break; 807168404Spjd case 'm': 808251634Sdelphij /* Equivalent to -O mountpoint=optarg */ 809168404Spjd mountpoint = optarg; 810168404Spjd break; 811185029Spjd case 'o': 812185029Spjd if ((propval = strchr(optarg, '=')) == NULL) { 813185029Spjd (void) fprintf(stderr, gettext("missing " 814185029Spjd "'=' for -o option\n")); 815185029Spjd goto errout; 816185029Spjd } 817185029Spjd *propval = '\0'; 818185029Spjd propval++; 819185029Spjd 820185029Spjd if (add_prop_list(optarg, propval, &props, B_TRUE)) 821185029Spjd goto errout; 822236884Smm 823236884Smm /* 824236884Smm * If the user is creating a pool that doesn't support 825236884Smm * feature flags, don't enable any features. 826236884Smm */ 827236884Smm if (zpool_name_to_prop(optarg) == ZPOOL_PROP_VERSION) { 828236884Smm char *end; 829236884Smm u_longlong_t ver; 830236884Smm 831236884Smm ver = strtoull(propval, &end, 10); 832236884Smm if (*end == '\0' && 833236884Smm ver < SPA_VERSION_FEATURES) { 834236884Smm enable_all_pool_feat = B_FALSE; 835236884Smm } 836236884Smm } 837279366Sdelphij if (zpool_name_to_prop(optarg) == ZPOOL_PROP_ALTROOT) 838279366Sdelphij altroot = propval; 839185029Spjd break; 840185029Spjd case 'O': 841185029Spjd if ((propval = strchr(optarg, '=')) == NULL) { 842185029Spjd (void) fprintf(stderr, gettext("missing " 843185029Spjd "'=' for -O option\n")); 844185029Spjd goto errout; 845185029Spjd } 846185029Spjd *propval = '\0'; 847185029Spjd propval++; 848185029Spjd 849251634Sdelphij /* 850251634Sdelphij * Mountpoints are checked and then added later. 851251634Sdelphij * Uniquely among properties, they can be specified 852251634Sdelphij * more than once, to avoid conflict with -m. 853251634Sdelphij */ 854251634Sdelphij if (0 == strcmp(optarg, 855251634Sdelphij zfs_prop_to_name(ZFS_PROP_MOUNTPOINT))) { 856251634Sdelphij mountpoint = propval; 857251634Sdelphij } else if (add_prop_list(optarg, propval, &fsprops, 858251634Sdelphij B_FALSE)) { 859185029Spjd goto errout; 860251634Sdelphij } 861185029Spjd break; 862168404Spjd case ':': 863168404Spjd (void) fprintf(stderr, gettext("missing argument for " 864168404Spjd "'%c' option\n"), optopt); 865185029Spjd goto badusage; 866168404Spjd case '?': 867168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 868168404Spjd optopt); 869185029Spjd goto badusage; 870168404Spjd } 871168404Spjd } 872168404Spjd 873168404Spjd argc -= optind; 874168404Spjd argv += optind; 875168404Spjd 876168404Spjd /* get pool name and check number of arguments */ 877168404Spjd if (argc < 1) { 878168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 879185029Spjd goto badusage; 880168404Spjd } 881168404Spjd if (argc < 2) { 882168404Spjd (void) fprintf(stderr, gettext("missing vdev specification\n")); 883185029Spjd goto badusage; 884168404Spjd } 885168404Spjd 886168404Spjd poolname = argv[0]; 887168404Spjd 888168404Spjd /* 889168404Spjd * As a special case, check for use of '/' in the name, and direct the 890168404Spjd * user to use 'zfs create' instead. 891168404Spjd */ 892168404Spjd if (strchr(poolname, '/') != NULL) { 893168404Spjd (void) fprintf(stderr, gettext("cannot create '%s': invalid " 894168404Spjd "character '/' in pool name\n"), poolname); 895168404Spjd (void) fprintf(stderr, gettext("use 'zfs create' to " 896168404Spjd "create a dataset\n")); 897185029Spjd goto errout; 898168404Spjd } 899168404Spjd 900168404Spjd /* pass off to get_vdev_spec for bulk processing */ 901185029Spjd nvroot = make_root_vdev(NULL, force, !force, B_FALSE, dryrun, 902185029Spjd argc - 1, argv + 1); 903168404Spjd if (nvroot == NULL) 904185029Spjd goto errout; 905168404Spjd 906168404Spjd /* make_root_vdev() allows 0 toplevel children if there are spares */ 907185029Spjd if (!zfs_allocatable_devs(nvroot)) { 908168404Spjd (void) fprintf(stderr, gettext("invalid vdev " 909168404Spjd "specification: at least one toplevel vdev must be " 910168404Spjd "specified\n")); 911185029Spjd goto errout; 912168404Spjd } 913168404Spjd 914168404Spjd if (altroot != NULL && altroot[0] != '/') { 915168404Spjd (void) fprintf(stderr, gettext("invalid alternate root '%s': " 916168404Spjd "must be an absolute path\n"), altroot); 917185029Spjd goto errout; 918168404Spjd } 919168404Spjd 920168404Spjd /* 921168404Spjd * Check the validity of the mountpoint and direct the user to use the 922168404Spjd * '-m' mountpoint option if it looks like its in use. 923244857Spjd * Ignore the checks if the '-f' option is given. 924168404Spjd */ 925244857Spjd if (!force && (mountpoint == NULL || 926168404Spjd (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0 && 927244857Spjd strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) != 0))) { 928168404Spjd char buf[MAXPATHLEN]; 929185029Spjd DIR *dirp; 930168404Spjd 931168404Spjd if (mountpoint && mountpoint[0] != '/') { 932168404Spjd (void) fprintf(stderr, gettext("invalid mountpoint " 933168404Spjd "'%s': must be an absolute path, 'legacy', or " 934168404Spjd "'none'\n"), mountpoint); 935185029Spjd goto errout; 936168404Spjd } 937168404Spjd 938168404Spjd if (mountpoint == NULL) { 939168404Spjd if (altroot != NULL) 940168404Spjd (void) snprintf(buf, sizeof (buf), "%s/%s", 941168404Spjd altroot, poolname); 942168404Spjd else 943168404Spjd (void) snprintf(buf, sizeof (buf), "/%s", 944168404Spjd poolname); 945168404Spjd } else { 946168404Spjd if (altroot != NULL) 947168404Spjd (void) snprintf(buf, sizeof (buf), "%s%s", 948168404Spjd altroot, mountpoint); 949168404Spjd else 950168404Spjd (void) snprintf(buf, sizeof (buf), "%s", 951168404Spjd mountpoint); 952168404Spjd } 953168404Spjd 954185029Spjd if ((dirp = opendir(buf)) == NULL && errno != ENOENT) { 955185029Spjd (void) fprintf(stderr, gettext("mountpoint '%s' : " 956185029Spjd "%s\n"), buf, strerror(errno)); 957185029Spjd (void) fprintf(stderr, gettext("use '-m' " 958185029Spjd "option to provide a different default\n")); 959185029Spjd goto errout; 960185029Spjd } else if (dirp) { 961185029Spjd int count = 0; 962185029Spjd 963185029Spjd while (count < 3 && readdir(dirp) != NULL) 964185029Spjd count++; 965185029Spjd (void) closedir(dirp); 966185029Spjd 967185029Spjd if (count > 2) { 968168404Spjd (void) fprintf(stderr, gettext("mountpoint " 969168404Spjd "'%s' exists and is not empty\n"), buf); 970185029Spjd (void) fprintf(stderr, gettext("use '-m' " 971185029Spjd "option to provide a " 972185029Spjd "different default\n")); 973185029Spjd goto errout; 974185029Spjd } 975168404Spjd } 976168404Spjd } 977168404Spjd 978251634Sdelphij /* 979251634Sdelphij * Now that the mountpoint's validity has been checked, ensure that 980251634Sdelphij * the property is set appropriately prior to creating the pool. 981251634Sdelphij */ 982251634Sdelphij if (mountpoint != NULL) { 983251634Sdelphij ret = add_prop_list(zfs_prop_to_name(ZFS_PROP_MOUNTPOINT), 984251634Sdelphij mountpoint, &fsprops, B_FALSE); 985251634Sdelphij if (ret != 0) 986251634Sdelphij goto errout; 987251634Sdelphij } 988251634Sdelphij 989251634Sdelphij ret = 1; 990168404Spjd if (dryrun) { 991168404Spjd /* 992168404Spjd * For a dry run invocation, print out a basic message and run 993168404Spjd * through all the vdevs in the list and print out in an 994168404Spjd * appropriate hierarchy. 995168404Spjd */ 996168404Spjd (void) printf(gettext("would create '%s' with the " 997168404Spjd "following layout:\n\n"), poolname); 998168404Spjd 999185029Spjd print_vdev_tree(NULL, poolname, nvroot, 0, B_FALSE); 1000185029Spjd if (num_logs(nvroot) > 0) 1001185029Spjd print_vdev_tree(NULL, "logs", nvroot, 0, B_TRUE); 1002168404Spjd 1003168404Spjd ret = 0; 1004168404Spjd } else { 1005168404Spjd /* 1006168404Spjd * Hand off to libzfs. 1007168404Spjd */ 1008236884Smm if (enable_all_pool_feat) { 1009259813Sdelphij spa_feature_t i; 1010236884Smm for (i = 0; i < SPA_FEATURES; i++) { 1011236884Smm char propname[MAXPATHLEN]; 1012236884Smm zfeature_info_t *feat = &spa_feature_table[i]; 1013236884Smm 1014236884Smm (void) snprintf(propname, sizeof (propname), 1015236884Smm "feature@%s", feat->fi_uname); 1016236884Smm 1017236884Smm /* 1018236884Smm * Skip feature if user specified it manually 1019236884Smm * on the command line. 1020236884Smm */ 1021236884Smm if (nvlist_exists(props, propname)) 1022236884Smm continue; 1023236884Smm 1024251634Sdelphij ret = add_prop_list(propname, 1025251634Sdelphij ZFS_FEATURE_ENABLED, &props, B_TRUE); 1026251634Sdelphij if (ret != 0) 1027236884Smm goto errout; 1028236884Smm } 1029236884Smm } 1030251634Sdelphij 1031251634Sdelphij ret = 1; 1032185029Spjd if (zpool_create(g_zfs, poolname, 1033185029Spjd nvroot, props, fsprops) == 0) { 1034168404Spjd zfs_handle_t *pool = zfs_open(g_zfs, poolname, 1035168404Spjd ZFS_TYPE_FILESYSTEM); 1036168404Spjd if (pool != NULL) { 1037168404Spjd if (zfs_mount(pool, NULL, 0) == 0) 1038185029Spjd ret = zfs_shareall(pool); 1039168404Spjd zfs_close(pool); 1040168404Spjd } 1041168404Spjd } else if (libzfs_errno(g_zfs) == EZFS_INVALIDNAME) { 1042168404Spjd (void) fprintf(stderr, gettext("pool name may have " 1043168404Spjd "been omitted\n")); 1044168404Spjd } 1045168404Spjd } 1046168404Spjd 1047185029Spjderrout: 1048168404Spjd nvlist_free(nvroot); 1049185029Spjd nvlist_free(fsprops); 1050185029Spjd nvlist_free(props); 1051168404Spjd return (ret); 1052185029Spjdbadusage: 1053185029Spjd nvlist_free(fsprops); 1054185029Spjd nvlist_free(props); 1055185029Spjd usage(B_FALSE); 1056185029Spjd return (2); 1057168404Spjd} 1058168404Spjd 1059168404Spjd/* 1060168404Spjd * zpool destroy <pool> 1061168404Spjd * 1062168404Spjd * -f Forcefully unmount any datasets 1063168404Spjd * 1064168404Spjd * Destroy the given pool. Automatically unmounts any datasets in the pool. 1065168404Spjd */ 1066168404Spjdint 1067168404Spjdzpool_do_destroy(int argc, char **argv) 1068168404Spjd{ 1069168404Spjd boolean_t force = B_FALSE; 1070168404Spjd int c; 1071168404Spjd char *pool; 1072168404Spjd zpool_handle_t *zhp; 1073168404Spjd int ret; 1074168404Spjd 1075168404Spjd /* check options */ 1076168404Spjd while ((c = getopt(argc, argv, "f")) != -1) { 1077168404Spjd switch (c) { 1078168404Spjd case 'f': 1079168404Spjd force = B_TRUE; 1080168404Spjd break; 1081168404Spjd case '?': 1082168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1083168404Spjd optopt); 1084168404Spjd usage(B_FALSE); 1085168404Spjd } 1086168404Spjd } 1087168404Spjd 1088168404Spjd argc -= optind; 1089168404Spjd argv += optind; 1090168404Spjd 1091168404Spjd /* check arguments */ 1092168404Spjd if (argc < 1) { 1093168404Spjd (void) fprintf(stderr, gettext("missing pool argument\n")); 1094168404Spjd usage(B_FALSE); 1095168404Spjd } 1096168404Spjd if (argc > 1) { 1097168404Spjd (void) fprintf(stderr, gettext("too many arguments\n")); 1098168404Spjd usage(B_FALSE); 1099168404Spjd } 1100168404Spjd 1101168404Spjd pool = argv[0]; 1102168404Spjd 1103168404Spjd if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) { 1104168404Spjd /* 1105168404Spjd * As a special case, check for use of '/' in the name, and 1106168404Spjd * direct the user to use 'zfs destroy' instead. 1107168404Spjd */ 1108168404Spjd if (strchr(pool, '/') != NULL) 1109168404Spjd (void) fprintf(stderr, gettext("use 'zfs destroy' to " 1110168404Spjd "destroy a dataset\n")); 1111168404Spjd return (1); 1112168404Spjd } 1113168404Spjd 1114168404Spjd if (zpool_disable_datasets(zhp, force) != 0) { 1115168404Spjd (void) fprintf(stderr, gettext("could not destroy '%s': " 1116168404Spjd "could not unmount datasets\n"), zpool_get_name(zhp)); 1117168404Spjd return (1); 1118168404Spjd } 1119168404Spjd 1120248571Smm /* The history must be logged as part of the export */ 1121248571Smm log_history = B_FALSE; 1122168404Spjd 1123248571Smm ret = (zpool_destroy(zhp, history_str) != 0); 1124248571Smm 1125168404Spjd zpool_close(zhp); 1126168404Spjd 1127168404Spjd return (ret); 1128168404Spjd} 1129168404Spjd 1130168404Spjd/* 1131168404Spjd * zpool export [-f] <pool> ... 1132168404Spjd * 1133168404Spjd * -f Forcefully unmount datasets 1134168404Spjd * 1135168404Spjd * Export the given pools. By default, the command will attempt to cleanly 1136168404Spjd * unmount any active datasets within the pool. If the '-f' flag is specified, 1137168404Spjd * then the datasets will be forcefully unmounted. 1138168404Spjd */ 1139168404Spjdint 1140168404Spjdzpool_do_export(int argc, char **argv) 1141168404Spjd{ 1142168404Spjd boolean_t force = B_FALSE; 1143207670Smm boolean_t hardforce = B_FALSE; 1144168404Spjd int c; 1145168404Spjd zpool_handle_t *zhp; 1146168404Spjd int ret; 1147168404Spjd int i; 1148168404Spjd 1149168404Spjd /* check options */ 1150207670Smm while ((c = getopt(argc, argv, "fF")) != -1) { 1151168404Spjd switch (c) { 1152168404Spjd case 'f': 1153168404Spjd force = B_TRUE; 1154168404Spjd break; 1155207670Smm case 'F': 1156207670Smm hardforce = B_TRUE; 1157207670Smm break; 1158168404Spjd case '?': 1159168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1160168404Spjd optopt); 1161168404Spjd usage(B_FALSE); 1162168404Spjd } 1163168404Spjd } 1164168404Spjd 1165168404Spjd argc -= optind; 1166168404Spjd argv += optind; 1167168404Spjd 1168168404Spjd /* check arguments */ 1169168404Spjd if (argc < 1) { 1170168404Spjd (void) fprintf(stderr, gettext("missing pool argument\n")); 1171168404Spjd usage(B_FALSE); 1172168404Spjd } 1173168404Spjd 1174168404Spjd ret = 0; 1175168404Spjd for (i = 0; i < argc; i++) { 1176168404Spjd if ((zhp = zpool_open_canfail(g_zfs, argv[i])) == NULL) { 1177168404Spjd ret = 1; 1178168404Spjd continue; 1179168404Spjd } 1180168404Spjd 1181168404Spjd if (zpool_disable_datasets(zhp, force) != 0) { 1182168404Spjd ret = 1; 1183168404Spjd zpool_close(zhp); 1184168404Spjd continue; 1185168404Spjd } 1186168404Spjd 1187248571Smm /* The history must be logged as part of the export */ 1188248571Smm log_history = B_FALSE; 1189248571Smm 1190207670Smm if (hardforce) { 1191248571Smm if (zpool_export_force(zhp, history_str) != 0) 1192207670Smm ret = 1; 1193248571Smm } else if (zpool_export(zhp, force, history_str) != 0) { 1194168404Spjd ret = 1; 1195207670Smm } 1196168404Spjd 1197168404Spjd zpool_close(zhp); 1198168404Spjd } 1199168404Spjd 1200168404Spjd return (ret); 1201168404Spjd} 1202168404Spjd 1203168404Spjd/* 1204168404Spjd * Given a vdev configuration, determine the maximum width needed for the device 1205168404Spjd * name column. 1206168404Spjd */ 1207168404Spjdstatic int 1208168404Spjdmax_width(zpool_handle_t *zhp, nvlist_t *nv, int depth, int max) 1209168404Spjd{ 1210219089Spjd char *name = zpool_vdev_name(g_zfs, zhp, nv, B_TRUE); 1211168404Spjd nvlist_t **child; 1212168404Spjd uint_t c, children; 1213168404Spjd int ret; 1214168404Spjd 1215168404Spjd if (strlen(name) + depth > max) 1216168404Spjd max = strlen(name) + depth; 1217168404Spjd 1218168404Spjd free(name); 1219168404Spjd 1220168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, 1221168404Spjd &child, &children) == 0) { 1222168404Spjd for (c = 0; c < children; c++) 1223168404Spjd if ((ret = max_width(zhp, child[c], depth + 2, 1224168404Spjd max)) > max) 1225168404Spjd max = ret; 1226168404Spjd } 1227168404Spjd 1228185029Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE, 1229185029Spjd &child, &children) == 0) { 1230185029Spjd for (c = 0; c < children; c++) 1231185029Spjd if ((ret = max_width(zhp, child[c], depth + 2, 1232185029Spjd max)) > max) 1233185029Spjd max = ret; 1234185029Spjd } 1235185029Spjd 1236168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 1237168404Spjd &child, &children) == 0) { 1238168404Spjd for (c = 0; c < children; c++) 1239168404Spjd if ((ret = max_width(zhp, child[c], depth + 2, 1240168404Spjd max)) > max) 1241168404Spjd max = ret; 1242168404Spjd } 1243168404Spjd 1244168404Spjd 1245168404Spjd return (max); 1246168404Spjd} 1247168404Spjd 1248213197Smmtypedef struct spare_cbdata { 1249213197Smm uint64_t cb_guid; 1250213197Smm zpool_handle_t *cb_zhp; 1251213197Smm} spare_cbdata_t; 1252168404Spjd 1253213197Smmstatic boolean_t 1254213197Smmfind_vdev(nvlist_t *nv, uint64_t search) 1255213197Smm{ 1256213197Smm uint64_t guid; 1257213197Smm nvlist_t **child; 1258213197Smm uint_t c, children; 1259213197Smm 1260213197Smm if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &guid) == 0 && 1261213197Smm search == guid) 1262213197Smm return (B_TRUE); 1263213197Smm 1264213197Smm if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 1265213197Smm &child, &children) == 0) { 1266213197Smm for (c = 0; c < children; c++) 1267213197Smm if (find_vdev(child[c], search)) 1268213197Smm return (B_TRUE); 1269213197Smm } 1270213197Smm 1271213197Smm return (B_FALSE); 1272213197Smm} 1273213197Smm 1274213197Smmstatic int 1275213197Smmfind_spare(zpool_handle_t *zhp, void *data) 1276213197Smm{ 1277213197Smm spare_cbdata_t *cbp = data; 1278213197Smm nvlist_t *config, *nvroot; 1279213197Smm 1280213197Smm config = zpool_get_config(zhp, NULL); 1281213197Smm verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 1282213197Smm &nvroot) == 0); 1283213197Smm 1284213197Smm if (find_vdev(nvroot, cbp->cb_guid)) { 1285213197Smm cbp->cb_zhp = zhp; 1286213197Smm return (1); 1287213197Smm } 1288213197Smm 1289213197Smm zpool_close(zhp); 1290213197Smm return (0); 1291213197Smm} 1292213197Smm 1293168404Spjd/* 1294213197Smm * Print out configuration state as requested by status_callback. 1295213197Smm */ 1296213197Smmvoid 1297213197Smmprint_status_config(zpool_handle_t *zhp, const char *name, nvlist_t *nv, 1298213197Smm int namewidth, int depth, boolean_t isspare) 1299213197Smm{ 1300213197Smm nvlist_t **child; 1301254591Sgibbs uint_t c, vsc, children; 1302219089Spjd pool_scan_stat_t *ps = NULL; 1303213197Smm vdev_stat_t *vs; 1304219089Spjd char rbuf[6], wbuf[6], cbuf[6]; 1305213197Smm char *vname; 1306213197Smm uint64_t notpresent; 1307254591Sgibbs uint64_t ashift; 1308213197Smm spare_cbdata_t cb; 1309224169Sgibbs const char *state; 1310213197Smm 1311213197Smm if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 1312213197Smm &child, &children) != 0) 1313213197Smm children = 0; 1314213197Smm 1315219089Spjd verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS, 1316254591Sgibbs (uint64_t **)&vs, &vsc) == 0); 1317219089Spjd 1318213197Smm state = zpool_state_to_name(vs->vs_state, vs->vs_aux); 1319213197Smm if (isspare) { 1320213197Smm /* 1321213197Smm * For hot spares, we use the terms 'INUSE' and 'AVAILABLE' for 1322213197Smm * online drives. 1323213197Smm */ 1324213197Smm if (vs->vs_aux == VDEV_AUX_SPARED) 1325213197Smm state = "INUSE"; 1326213197Smm else if (vs->vs_state == VDEV_STATE_HEALTHY) 1327213197Smm state = "AVAIL"; 1328213197Smm } 1329213197Smm 1330213197Smm (void) printf("\t%*s%-*s %-8s", depth, "", namewidth - depth, 1331213197Smm name, state); 1332213197Smm 1333213197Smm if (!isspare) { 1334213197Smm zfs_nicenum(vs->vs_read_errors, rbuf, sizeof (rbuf)); 1335213197Smm zfs_nicenum(vs->vs_write_errors, wbuf, sizeof (wbuf)); 1336213197Smm zfs_nicenum(vs->vs_checksum_errors, cbuf, sizeof (cbuf)); 1337213197Smm (void) printf(" %5s %5s %5s", rbuf, wbuf, cbuf); 1338213197Smm } 1339213197Smm 1340213197Smm if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT, 1341224170Sgibbs ¬present) == 0 || 1342224170Sgibbs vs->vs_state <= VDEV_STATE_CANT_OPEN) { 1343213197Smm char *path; 1344224170Sgibbs if (nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0) 1345224170Sgibbs (void) printf(" was %s", path); 1346213197Smm } else if (vs->vs_aux != 0) { 1347213197Smm (void) printf(" "); 1348213197Smm 1349213197Smm switch (vs->vs_aux) { 1350213197Smm case VDEV_AUX_OPEN_FAILED: 1351213197Smm (void) printf(gettext("cannot open")); 1352213197Smm break; 1353213197Smm 1354213197Smm case VDEV_AUX_BAD_GUID_SUM: 1355213197Smm (void) printf(gettext("missing device")); 1356213197Smm break; 1357213197Smm 1358213197Smm case VDEV_AUX_NO_REPLICAS: 1359213197Smm (void) printf(gettext("insufficient replicas")); 1360213197Smm break; 1361213197Smm 1362213197Smm case VDEV_AUX_VERSION_NEWER: 1363213197Smm (void) printf(gettext("newer version")); 1364213197Smm break; 1365213197Smm 1366236884Smm case VDEV_AUX_UNSUP_FEAT: 1367236884Smm (void) printf(gettext("unsupported feature(s)")); 1368236884Smm break; 1369236884Smm 1370254591Sgibbs case VDEV_AUX_ASHIFT_TOO_BIG: 1371254591Sgibbs (void) printf(gettext("unsupported minimum blocksize")); 1372254591Sgibbs break; 1373254591Sgibbs 1374213197Smm case VDEV_AUX_SPARED: 1375213197Smm verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, 1376213197Smm &cb.cb_guid) == 0); 1377213197Smm if (zpool_iter(g_zfs, find_spare, &cb) == 1) { 1378213197Smm if (strcmp(zpool_get_name(cb.cb_zhp), 1379213197Smm zpool_get_name(zhp)) == 0) 1380213197Smm (void) printf(gettext("currently in " 1381213197Smm "use")); 1382213197Smm else 1383213197Smm (void) printf(gettext("in use by " 1384213197Smm "pool '%s'"), 1385213197Smm zpool_get_name(cb.cb_zhp)); 1386213197Smm zpool_close(cb.cb_zhp); 1387213197Smm } else { 1388213197Smm (void) printf(gettext("currently in use")); 1389213197Smm } 1390213197Smm break; 1391213197Smm 1392213197Smm case VDEV_AUX_ERR_EXCEEDED: 1393213197Smm (void) printf(gettext("too many errors")); 1394213197Smm break; 1395213197Smm 1396213197Smm case VDEV_AUX_IO_FAILURE: 1397213197Smm (void) printf(gettext("experienced I/O failures")); 1398213197Smm break; 1399213197Smm 1400213197Smm case VDEV_AUX_BAD_LOG: 1401213197Smm (void) printf(gettext("bad intent log")); 1402213197Smm break; 1403213197Smm 1404219089Spjd case VDEV_AUX_EXTERNAL: 1405219089Spjd (void) printf(gettext("external device fault")); 1406219089Spjd break; 1407219089Spjd 1408219089Spjd case VDEV_AUX_SPLIT_POOL: 1409219089Spjd (void) printf(gettext("split into new pool")); 1410219089Spjd break; 1411219089Spjd 1412213197Smm default: 1413213197Smm (void) printf(gettext("corrupted data")); 1414213197Smm break; 1415213197Smm } 1416254591Sgibbs } else if (children == 0 && !isspare && 1417254591Sgibbs VDEV_STAT_VALID(vs_physical_ashift, vsc) && 1418254591Sgibbs vs->vs_configured_ashift < vs->vs_physical_ashift) { 1419254591Sgibbs (void) printf( 1420254591Sgibbs gettext(" block size: %dB configured, %dB native"), 1421254591Sgibbs 1 << vs->vs_configured_ashift, 1 << vs->vs_physical_ashift); 1422213197Smm } 1423213197Smm 1424219089Spjd (void) nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_SCAN_STATS, 1425219089Spjd (uint64_t **)&ps, &c); 1426219089Spjd 1427219089Spjd if (ps && ps->pss_state == DSS_SCANNING && 1428219089Spjd vs->vs_scan_processed != 0 && children == 0) { 1429219089Spjd (void) printf(gettext(" (%s)"), 1430219089Spjd (ps->pss_func == POOL_SCAN_RESILVER) ? 1431219089Spjd "resilvering" : "repairing"); 1432219089Spjd } 1433219089Spjd 1434213197Smm (void) printf("\n"); 1435213197Smm 1436213197Smm for (c = 0; c < children; c++) { 1437219089Spjd uint64_t islog = B_FALSE, ishole = B_FALSE; 1438213197Smm 1439219089Spjd /* Don't print logs or holes here */ 1440213197Smm (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 1441219089Spjd &islog); 1442219089Spjd (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_HOLE, 1443219089Spjd &ishole); 1444219089Spjd if (islog || ishole) 1445213197Smm continue; 1446219089Spjd vname = zpool_vdev_name(g_zfs, zhp, child[c], B_TRUE); 1447213197Smm print_status_config(zhp, vname, child[c], 1448213197Smm namewidth, depth + 2, isspare); 1449213197Smm free(vname); 1450213197Smm } 1451213197Smm} 1452213197Smm 1453213197Smm 1454213197Smm/* 1455168404Spjd * Print the configuration of an exported pool. Iterate over all vdevs in the 1456168404Spjd * pool, printing out the name and status for each one. 1457168404Spjd */ 1458168404Spjdvoid 1459213197Smmprint_import_config(const char *name, nvlist_t *nv, int namewidth, int depth) 1460168404Spjd{ 1461168404Spjd nvlist_t **child; 1462168404Spjd uint_t c, children; 1463168404Spjd vdev_stat_t *vs; 1464168404Spjd char *type, *vname; 1465168404Spjd 1466168404Spjd verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0); 1467219089Spjd if (strcmp(type, VDEV_TYPE_MISSING) == 0 || 1468219089Spjd strcmp(type, VDEV_TYPE_HOLE) == 0) 1469168404Spjd return; 1470168404Spjd 1471219089Spjd verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS, 1472168404Spjd (uint64_t **)&vs, &c) == 0); 1473168404Spjd 1474168404Spjd (void) printf("\t%*s%-*s", depth, "", namewidth - depth, name); 1475185029Spjd (void) printf(" %s", zpool_state_to_name(vs->vs_state, vs->vs_aux)); 1476168404Spjd 1477168404Spjd if (vs->vs_aux != 0) { 1478185029Spjd (void) printf(" "); 1479168404Spjd 1480168404Spjd switch (vs->vs_aux) { 1481168404Spjd case VDEV_AUX_OPEN_FAILED: 1482168404Spjd (void) printf(gettext("cannot open")); 1483168404Spjd break; 1484168404Spjd 1485168404Spjd case VDEV_AUX_BAD_GUID_SUM: 1486168404Spjd (void) printf(gettext("missing device")); 1487168404Spjd break; 1488168404Spjd 1489168404Spjd case VDEV_AUX_NO_REPLICAS: 1490168404Spjd (void) printf(gettext("insufficient replicas")); 1491168404Spjd break; 1492168404Spjd 1493168404Spjd case VDEV_AUX_VERSION_NEWER: 1494168404Spjd (void) printf(gettext("newer version")); 1495168404Spjd break; 1496168404Spjd 1497236884Smm case VDEV_AUX_UNSUP_FEAT: 1498236884Smm (void) printf(gettext("unsupported feature(s)")); 1499236884Smm break; 1500236884Smm 1501185029Spjd case VDEV_AUX_ERR_EXCEEDED: 1502185029Spjd (void) printf(gettext("too many errors")); 1503185029Spjd break; 1504185029Spjd 1505168404Spjd default: 1506168404Spjd (void) printf(gettext("corrupted data")); 1507168404Spjd break; 1508168404Spjd } 1509168404Spjd } 1510168404Spjd (void) printf("\n"); 1511168404Spjd 1512168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 1513168404Spjd &child, &children) != 0) 1514168404Spjd return; 1515168404Spjd 1516168404Spjd for (c = 0; c < children; c++) { 1517185029Spjd uint64_t is_log = B_FALSE; 1518185029Spjd 1519185029Spjd (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 1520185029Spjd &is_log); 1521213197Smm if (is_log) 1522185029Spjd continue; 1523185029Spjd 1524219089Spjd vname = zpool_vdev_name(g_zfs, NULL, child[c], B_TRUE); 1525213197Smm print_import_config(vname, child[c], namewidth, depth + 2); 1526168404Spjd free(vname); 1527168404Spjd } 1528168404Spjd 1529185029Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE, 1530185029Spjd &child, &children) == 0) { 1531185029Spjd (void) printf(gettext("\tcache\n")); 1532185029Spjd for (c = 0; c < children; c++) { 1533219089Spjd vname = zpool_vdev_name(g_zfs, NULL, child[c], B_FALSE); 1534185029Spjd (void) printf("\t %s\n", vname); 1535185029Spjd free(vname); 1536185029Spjd } 1537185029Spjd } 1538185029Spjd 1539168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, 1540185029Spjd &child, &children) == 0) { 1541185029Spjd (void) printf(gettext("\tspares\n")); 1542185029Spjd for (c = 0; c < children; c++) { 1543219089Spjd vname = zpool_vdev_name(g_zfs, NULL, child[c], B_FALSE); 1544185029Spjd (void) printf("\t %s\n", vname); 1545185029Spjd free(vname); 1546185029Spjd } 1547168404Spjd } 1548168404Spjd} 1549168404Spjd 1550168404Spjd/* 1551213197Smm * Print log vdevs. 1552213197Smm * Logs are recorded as top level vdevs in the main pool child array 1553213197Smm * but with "is_log" set to 1. We use either print_status_config() or 1554213197Smm * print_import_config() to print the top level logs then any log 1555213197Smm * children (eg mirrored slogs) are printed recursively - which 1556213197Smm * works because only the top level vdev is marked "is_log" 1557213197Smm */ 1558213197Smmstatic void 1559213197Smmprint_logs(zpool_handle_t *zhp, nvlist_t *nv, int namewidth, boolean_t verbose) 1560213197Smm{ 1561213197Smm uint_t c, children; 1562213197Smm nvlist_t **child; 1563213197Smm 1564213197Smm if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, &child, 1565213197Smm &children) != 0) 1566213197Smm return; 1567213197Smm 1568213197Smm (void) printf(gettext("\tlogs\n")); 1569213197Smm 1570213197Smm for (c = 0; c < children; c++) { 1571213197Smm uint64_t is_log = B_FALSE; 1572213197Smm char *name; 1573213197Smm 1574213197Smm (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 1575213197Smm &is_log); 1576213197Smm if (!is_log) 1577213197Smm continue; 1578219089Spjd name = zpool_vdev_name(g_zfs, zhp, child[c], B_TRUE); 1579213197Smm if (verbose) 1580213197Smm print_status_config(zhp, name, child[c], namewidth, 1581213197Smm 2, B_FALSE); 1582213197Smm else 1583213197Smm print_import_config(name, child[c], namewidth, 2); 1584213197Smm free(name); 1585213197Smm } 1586213197Smm} 1587219089Spjd 1588213197Smm/* 1589168404Spjd * Display the status for the given pool. 1590168404Spjd */ 1591168404Spjdstatic void 1592168404Spjdshow_import(nvlist_t *config) 1593168404Spjd{ 1594168404Spjd uint64_t pool_state; 1595168404Spjd vdev_stat_t *vs; 1596168404Spjd char *name; 1597168404Spjd uint64_t guid; 1598168404Spjd char *msgid; 1599168404Spjd nvlist_t *nvroot; 1600168404Spjd int reason; 1601168404Spjd const char *health; 1602168404Spjd uint_t vsc; 1603168404Spjd int namewidth; 1604228103Smm char *comment; 1605168404Spjd 1606168404Spjd verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, 1607168404Spjd &name) == 0); 1608168404Spjd verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, 1609168404Spjd &guid) == 0); 1610168404Spjd verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE, 1611168404Spjd &pool_state) == 0); 1612168404Spjd verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 1613168404Spjd &nvroot) == 0); 1614168404Spjd 1615219089Spjd verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS, 1616168404Spjd (uint64_t **)&vs, &vsc) == 0); 1617185029Spjd health = zpool_state_to_name(vs->vs_state, vs->vs_aux); 1618168404Spjd 1619168404Spjd reason = zpool_import_status(config, &msgid); 1620168404Spjd 1621228103Smm (void) printf(gettext(" pool: %s\n"), name); 1622228103Smm (void) printf(gettext(" id: %llu\n"), (u_longlong_t)guid); 1623228103Smm (void) printf(gettext(" state: %s"), health); 1624168404Spjd if (pool_state == POOL_STATE_DESTROYED) 1625168404Spjd (void) printf(gettext(" (DESTROYED)")); 1626168404Spjd (void) printf("\n"); 1627168404Spjd 1628168404Spjd switch (reason) { 1629168404Spjd case ZPOOL_STATUS_MISSING_DEV_R: 1630168404Spjd case ZPOOL_STATUS_MISSING_DEV_NR: 1631168404Spjd case ZPOOL_STATUS_BAD_GUID_SUM: 1632228103Smm (void) printf(gettext(" status: One or more devices are " 1633228103Smm "missing from the system.\n")); 1634168404Spjd break; 1635168404Spjd 1636168404Spjd case ZPOOL_STATUS_CORRUPT_LABEL_R: 1637168404Spjd case ZPOOL_STATUS_CORRUPT_LABEL_NR: 1638228103Smm (void) printf(gettext(" status: One or more devices contains " 1639168404Spjd "corrupted data.\n")); 1640168404Spjd break; 1641168404Spjd 1642168404Spjd case ZPOOL_STATUS_CORRUPT_DATA: 1643228103Smm (void) printf( 1644228103Smm gettext(" status: The pool data is corrupted.\n")); 1645168404Spjd break; 1646168404Spjd 1647168404Spjd case ZPOOL_STATUS_OFFLINE_DEV: 1648228103Smm (void) printf(gettext(" status: One or more devices " 1649168404Spjd "are offlined.\n")); 1650168404Spjd break; 1651168404Spjd 1652168404Spjd case ZPOOL_STATUS_CORRUPT_POOL: 1653228103Smm (void) printf(gettext(" status: The pool metadata is " 1654168404Spjd "corrupted.\n")); 1655168404Spjd break; 1656168404Spjd 1657168404Spjd case ZPOOL_STATUS_VERSION_OLDER: 1658238926Smm (void) printf(gettext(" status: The pool is formatted using a " 1659238926Smm "legacy on-disk version.\n")); 1660168404Spjd break; 1661168404Spjd 1662168404Spjd case ZPOOL_STATUS_VERSION_NEWER: 1663228103Smm (void) printf(gettext(" status: The pool is formatted using an " 1664168404Spjd "incompatible version.\n")); 1665168404Spjd break; 1666168404Spjd 1667238926Smm case ZPOOL_STATUS_FEAT_DISABLED: 1668238926Smm (void) printf(gettext(" status: Some supported features are " 1669238926Smm "not enabled on the pool.\n")); 1670238926Smm break; 1671238926Smm 1672236884Smm case ZPOOL_STATUS_UNSUP_FEAT_READ: 1673236884Smm (void) printf(gettext("status: The pool uses the following " 1674236884Smm "feature(s) not supported on this sytem:\n")); 1675236884Smm zpool_print_unsup_feat(config); 1676236884Smm break; 1677236884Smm 1678236884Smm case ZPOOL_STATUS_UNSUP_FEAT_WRITE: 1679236884Smm (void) printf(gettext("status: The pool can only be accessed " 1680236884Smm "in read-only mode on this system. It\n\tcannot be " 1681236884Smm "accessed in read-write mode because it uses the " 1682236884Smm "following\n\tfeature(s) not supported on this system:\n")); 1683236884Smm zpool_print_unsup_feat(config); 1684236884Smm break; 1685236884Smm 1686168498Spjd case ZPOOL_STATUS_HOSTID_MISMATCH: 1687228103Smm (void) printf(gettext(" status: The pool was last accessed by " 1688168498Spjd "another system.\n")); 1689168498Spjd break; 1690185029Spjd 1691185029Spjd case ZPOOL_STATUS_FAULTED_DEV_R: 1692185029Spjd case ZPOOL_STATUS_FAULTED_DEV_NR: 1693228103Smm (void) printf(gettext(" status: One or more devices are " 1694185029Spjd "faulted.\n")); 1695185029Spjd break; 1696185029Spjd 1697185029Spjd case ZPOOL_STATUS_BAD_LOG: 1698228103Smm (void) printf(gettext(" status: An intent log record cannot be " 1699185029Spjd "read.\n")); 1700185029Spjd break; 1701185029Spjd 1702219089Spjd case ZPOOL_STATUS_RESILVERING: 1703228103Smm (void) printf(gettext(" status: One or more devices were being " 1704219089Spjd "resilvered.\n")); 1705219089Spjd break; 1706219089Spjd 1707259131Sdelphij case ZPOOL_STATUS_NON_NATIVE_ASHIFT: 1708259131Sdelphij (void) printf(gettext("status: One or more devices were " 1709259131Sdelphij "configured to use a non-native block size.\n" 1710259131Sdelphij "\tExpect reduced performance.\n")); 1711259131Sdelphij break; 1712259131Sdelphij 1713168404Spjd default: 1714168404Spjd /* 1715168404Spjd * No other status can be seen when importing pools. 1716168404Spjd */ 1717168404Spjd assert(reason == ZPOOL_STATUS_OK); 1718168404Spjd } 1719168404Spjd 1720168404Spjd /* 1721168404Spjd * Print out an action according to the overall state of the pool. 1722168404Spjd */ 1723168404Spjd if (vs->vs_state == VDEV_STATE_HEALTHY) { 1724238926Smm if (reason == ZPOOL_STATUS_VERSION_OLDER || 1725238926Smm reason == ZPOOL_STATUS_FEAT_DISABLED) { 1726228103Smm (void) printf(gettext(" action: The pool can be " 1727168404Spjd "imported using its name or numeric identifier, " 1728168404Spjd "though\n\tsome features will not be available " 1729168404Spjd "without an explicit 'zpool upgrade'.\n")); 1730238926Smm } else if (reason == ZPOOL_STATUS_HOSTID_MISMATCH) { 1731228103Smm (void) printf(gettext(" action: The pool can be " 1732168498Spjd "imported using its name or numeric " 1733168498Spjd "identifier and\n\tthe '-f' flag.\n")); 1734238926Smm } else { 1735228103Smm (void) printf(gettext(" action: The pool can be " 1736168404Spjd "imported using its name or numeric " 1737168404Spjd "identifier.\n")); 1738238926Smm } 1739168404Spjd } else if (vs->vs_state == VDEV_STATE_DEGRADED) { 1740228103Smm (void) printf(gettext(" action: The pool can be imported " 1741168404Spjd "despite missing or damaged devices. The\n\tfault " 1742168404Spjd "tolerance of the pool may be compromised if imported.\n")); 1743168404Spjd } else { 1744168404Spjd switch (reason) { 1745168404Spjd case ZPOOL_STATUS_VERSION_NEWER: 1746228103Smm (void) printf(gettext(" action: The pool cannot be " 1747168404Spjd "imported. Access the pool on a system running " 1748168404Spjd "newer\n\tsoftware, or recreate the pool from " 1749168404Spjd "backup.\n")); 1750168404Spjd break; 1751236884Smm case ZPOOL_STATUS_UNSUP_FEAT_READ: 1752236884Smm (void) printf(gettext("action: The pool cannot be " 1753236884Smm "imported. Access the pool on a system that " 1754236884Smm "supports\n\tthe required feature(s), or recreate " 1755236884Smm "the pool from backup.\n")); 1756236884Smm break; 1757236884Smm case ZPOOL_STATUS_UNSUP_FEAT_WRITE: 1758236884Smm (void) printf(gettext("action: The pool cannot be " 1759236884Smm "imported in read-write mode. Import the pool " 1760236884Smm "with\n" 1761236884Smm "\t\"-o readonly=on\", access the pool on a system " 1762236884Smm "that supports the\n\trequired feature(s), or " 1763236884Smm "recreate the pool from backup.\n")); 1764236884Smm break; 1765168404Spjd case ZPOOL_STATUS_MISSING_DEV_R: 1766168404Spjd case ZPOOL_STATUS_MISSING_DEV_NR: 1767168404Spjd case ZPOOL_STATUS_BAD_GUID_SUM: 1768228103Smm (void) printf(gettext(" action: The pool cannot be " 1769168404Spjd "imported. Attach the missing\n\tdevices and try " 1770168404Spjd "again.\n")); 1771168404Spjd break; 1772168404Spjd default: 1773228103Smm (void) printf(gettext(" action: The pool cannot be " 1774168404Spjd "imported due to damaged devices or data.\n")); 1775168404Spjd } 1776168404Spjd } 1777168404Spjd 1778228103Smm /* Print the comment attached to the pool. */ 1779228103Smm if (nvlist_lookup_string(config, ZPOOL_CONFIG_COMMENT, &comment) == 0) 1780228103Smm (void) printf(gettext("comment: %s\n"), comment); 1781228103Smm 1782168404Spjd /* 1783168404Spjd * If the state is "closed" or "can't open", and the aux state 1784168404Spjd * is "corrupt data": 1785168404Spjd */ 1786168404Spjd if (((vs->vs_state == VDEV_STATE_CLOSED) || 1787168404Spjd (vs->vs_state == VDEV_STATE_CANT_OPEN)) && 1788168404Spjd (vs->vs_aux == VDEV_AUX_CORRUPT_DATA)) { 1789168404Spjd if (pool_state == POOL_STATE_DESTROYED) 1790168404Spjd (void) printf(gettext("\tThe pool was destroyed, " 1791168404Spjd "but can be imported using the '-Df' flags.\n")); 1792168404Spjd else if (pool_state != POOL_STATE_EXPORTED) 1793168404Spjd (void) printf(gettext("\tThe pool may be active on " 1794185029Spjd "another system, but can be imported using\n\t" 1795168404Spjd "the '-f' flag.\n")); 1796168404Spjd } 1797168404Spjd 1798168404Spjd if (msgid != NULL) 1799236146Smm (void) printf(gettext(" see: http://illumos.org/msg/%s\n"), 1800168404Spjd msgid); 1801168404Spjd 1802228103Smm (void) printf(gettext(" config:\n\n")); 1803168404Spjd 1804168404Spjd namewidth = max_width(NULL, nvroot, 0, 0); 1805168404Spjd if (namewidth < 10) 1806168404Spjd namewidth = 10; 1807168404Spjd 1808213197Smm print_import_config(name, nvroot, namewidth, 0); 1809213197Smm if (num_logs(nvroot) > 0) 1810213197Smm print_logs(NULL, nvroot, namewidth, B_FALSE); 1811185029Spjd 1812168404Spjd if (reason == ZPOOL_STATUS_BAD_GUID_SUM) { 1813168404Spjd (void) printf(gettext("\n\tAdditional devices are known to " 1814168404Spjd "be part of this pool, though their\n\texact " 1815168404Spjd "configuration cannot be determined.\n")); 1816168404Spjd } 1817168404Spjd} 1818168404Spjd 1819168404Spjd/* 1820168404Spjd * Perform the import for the given configuration. This passes the heavy 1821185029Spjd * lifting off to zpool_import_props(), and then mounts the datasets contained 1822185029Spjd * within the pool. 1823168404Spjd */ 1824168404Spjdstatic int 1825168404Spjddo_import(nvlist_t *config, const char *newname, const char *mntopts, 1826219089Spjd nvlist_t *props, int flags) 1827168404Spjd{ 1828168404Spjd zpool_handle_t *zhp; 1829168404Spjd char *name; 1830168404Spjd uint64_t state; 1831168404Spjd uint64_t version; 1832168404Spjd 1833168404Spjd verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, 1834168404Spjd &name) == 0); 1835168404Spjd 1836168404Spjd verify(nvlist_lookup_uint64(config, 1837168404Spjd ZPOOL_CONFIG_POOL_STATE, &state) == 0); 1838168404Spjd verify(nvlist_lookup_uint64(config, 1839168404Spjd ZPOOL_CONFIG_VERSION, &version) == 0); 1840236884Smm if (!SPA_VERSION_IS_SUPPORTED(version)) { 1841168404Spjd (void) fprintf(stderr, gettext("cannot import '%s': pool " 1842236884Smm "is formatted using an unsupported ZFS version\n"), name); 1843168404Spjd return (1); 1844219089Spjd } else if (state != POOL_STATE_EXPORTED && 1845219089Spjd !(flags & ZFS_IMPORT_ANY_HOST)) { 1846168498Spjd uint64_t hostid; 1847168498Spjd 1848168498Spjd if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID, 1849168498Spjd &hostid) == 0) { 1850168498Spjd if ((unsigned long)hostid != gethostid()) { 1851168498Spjd char *hostname; 1852168498Spjd uint64_t timestamp; 1853168498Spjd time_t t; 1854168498Spjd 1855168498Spjd verify(nvlist_lookup_string(config, 1856168498Spjd ZPOOL_CONFIG_HOSTNAME, &hostname) == 0); 1857168498Spjd verify(nvlist_lookup_uint64(config, 1858168498Spjd ZPOOL_CONFIG_TIMESTAMP, ×tamp) == 0); 1859168498Spjd t = timestamp; 1860168498Spjd (void) fprintf(stderr, gettext("cannot import " 1861168498Spjd "'%s': pool may be in use from other " 1862168498Spjd "system, it was last accessed by %s " 1863168498Spjd "(hostid: 0x%lx) on %s"), name, hostname, 1864168498Spjd (unsigned long)hostid, 1865168498Spjd asctime(localtime(&t))); 1866168498Spjd (void) fprintf(stderr, gettext("use '-f' to " 1867168498Spjd "import anyway\n")); 1868168498Spjd return (1); 1869168498Spjd } 1870168498Spjd } else { 1871168498Spjd (void) fprintf(stderr, gettext("cannot import '%s': " 1872168498Spjd "pool may be in use from other system\n"), name); 1873168498Spjd (void) fprintf(stderr, gettext("use '-f' to import " 1874168498Spjd "anyway\n")); 1875168498Spjd return (1); 1876168498Spjd } 1877168404Spjd } 1878168404Spjd 1879219089Spjd if (zpool_import_props(g_zfs, config, newname, props, flags) != 0) 1880168404Spjd return (1); 1881168404Spjd 1882168404Spjd if (newname != NULL) 1883168404Spjd name = (char *)newname; 1884168404Spjd 1885209962Smm if ((zhp = zpool_open_canfail(g_zfs, name)) == NULL) 1886209962Smm return (1); 1887168404Spjd 1888209962Smm if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL && 1889219089Spjd !(flags & ZFS_IMPORT_ONLY) && 1890209962Smm zpool_enable_datasets(zhp, mntopts, 0) != 0) { 1891168404Spjd zpool_close(zhp); 1892168404Spjd return (1); 1893168404Spjd } 1894168404Spjd 1895168404Spjd zpool_close(zhp); 1896219089Spjd return (0); 1897168404Spjd} 1898168404Spjd 1899168404Spjd/* 1900168404Spjd * zpool import [-d dir] [-D] 1901185029Spjd * import [-o mntopts] [-o prop=value] ... [-R root] [-D] 1902185029Spjd * [-d dir | -c cachefile] [-f] -a 1903185029Spjd * import [-o mntopts] [-o prop=value] ... [-R root] [-D] 1904219089Spjd * [-d dir | -c cachefile] [-f] [-n] [-F] <pool | id> [newpool] 1905168404Spjd * 1906185029Spjd * -c Read pool information from a cachefile instead of searching 1907185029Spjd * devices. 1908185029Spjd * 1909168404Spjd * -d Scan in a specific directory, other than /dev/dsk. More than 1910168404Spjd * one directory can be specified using multiple '-d' options. 1911168404Spjd * 1912168404Spjd * -D Scan for previously destroyed pools or import all or only 1913168404Spjd * specified destroyed pools. 1914168404Spjd * 1915168404Spjd * -R Temporarily import the pool, with all mountpoints relative to 1916168404Spjd * the given root. The pool will remain exported when the machine 1917168404Spjd * is rebooted. 1918168404Spjd * 1919219089Spjd * -V Import even in the presence of faulted vdevs. This is an 1920185029Spjd * intentionally undocumented option for testing purposes, and 1921185029Spjd * treats the pool configuration as complete, leaving any bad 1922209962Smm * vdevs in the FAULTED state. In other words, it does verbatim 1923209962Smm * import. 1924185029Spjd * 1925219089Spjd * -f Force import, even if it appears that the pool is active. 1926219089Spjd * 1927219089Spjd * -F Attempt rewind if necessary. 1928219089Spjd * 1929219089Spjd * -n See if rewind would work, but don't actually rewind. 1930219089Spjd * 1931219089Spjd * -N Import the pool but don't mount datasets. 1932219089Spjd * 1933219089Spjd * -T Specify a starting txg to use for import. This option is 1934219089Spjd * intentionally undocumented option for testing purposes. 1935219089Spjd * 1936168404Spjd * -a Import all pools found. 1937168404Spjd * 1938185029Spjd * -o Set property=value and/or temporary mount options (without '='). 1939185029Spjd * 1940168404Spjd * The import command scans for pools to import, and import pools based on pool 1941168404Spjd * name and GUID. The pool can also be renamed as part of the import process. 1942168404Spjd */ 1943168404Spjdint 1944168404Spjdzpool_do_import(int argc, char **argv) 1945168404Spjd{ 1946168404Spjd char **searchdirs = NULL; 1947168404Spjd int nsearch = 0; 1948168404Spjd int c; 1949219089Spjd int err = 0; 1950185029Spjd nvlist_t *pools = NULL; 1951168404Spjd boolean_t do_all = B_FALSE; 1952168404Spjd boolean_t do_destroyed = B_FALSE; 1953168404Spjd char *mntopts = NULL; 1954168404Spjd nvpair_t *elem; 1955168404Spjd nvlist_t *config; 1956185029Spjd uint64_t searchguid = 0; 1957185029Spjd char *searchname = NULL; 1958185029Spjd char *propval; 1959168404Spjd nvlist_t *found_config; 1960219089Spjd nvlist_t *policy = NULL; 1961185029Spjd nvlist_t *props = NULL; 1962168404Spjd boolean_t first; 1963219089Spjd int flags = ZFS_IMPORT_NORMAL; 1964219089Spjd uint32_t rewind_policy = ZPOOL_NO_REWIND; 1965219089Spjd boolean_t dryrun = B_FALSE; 1966219089Spjd boolean_t do_rewind = B_FALSE; 1967219089Spjd boolean_t xtreme_rewind = B_FALSE; 1968219089Spjd uint64_t pool_state, txg = -1ULL; 1969185029Spjd char *cachefile = NULL; 1970219089Spjd importargs_t idata = { 0 }; 1971219089Spjd char *endptr; 1972168404Spjd 1973168404Spjd /* check options */ 1974263385Sdelphij while ((c = getopt(argc, argv, ":aCc:d:DEfFmnNo:R:T:VX")) != -1) { 1975168404Spjd switch (c) { 1976168404Spjd case 'a': 1977168404Spjd do_all = B_TRUE; 1978168404Spjd break; 1979185029Spjd case 'c': 1980185029Spjd cachefile = optarg; 1981185029Spjd break; 1982168404Spjd case 'd': 1983168404Spjd if (searchdirs == NULL) { 1984168404Spjd searchdirs = safe_malloc(sizeof (char *)); 1985168404Spjd } else { 1986168404Spjd char **tmp = safe_malloc((nsearch + 1) * 1987168404Spjd sizeof (char *)); 1988168404Spjd bcopy(searchdirs, tmp, nsearch * 1989168404Spjd sizeof (char *)); 1990168404Spjd free(searchdirs); 1991168404Spjd searchdirs = tmp; 1992168404Spjd } 1993168404Spjd searchdirs[nsearch++] = optarg; 1994168404Spjd break; 1995168404Spjd case 'D': 1996168404Spjd do_destroyed = B_TRUE; 1997168404Spjd break; 1998168404Spjd case 'f': 1999219089Spjd flags |= ZFS_IMPORT_ANY_HOST; 2000168404Spjd break; 2001185029Spjd case 'F': 2002219089Spjd do_rewind = B_TRUE; 2003185029Spjd break; 2004219089Spjd case 'm': 2005219089Spjd flags |= ZFS_IMPORT_MISSING_LOG; 2006219089Spjd break; 2007219089Spjd case 'n': 2008219089Spjd dryrun = B_TRUE; 2009219089Spjd break; 2010219089Spjd case 'N': 2011219089Spjd flags |= ZFS_IMPORT_ONLY; 2012219089Spjd break; 2013168404Spjd case 'o': 2014185029Spjd if ((propval = strchr(optarg, '=')) != NULL) { 2015185029Spjd *propval = '\0'; 2016185029Spjd propval++; 2017185029Spjd if (add_prop_list(optarg, propval, 2018185029Spjd &props, B_TRUE)) 2019185029Spjd goto error; 2020185029Spjd } else { 2021185029Spjd mntopts = optarg; 2022185029Spjd } 2023168404Spjd break; 2024168404Spjd case 'R': 2025185029Spjd if (add_prop_list(zpool_prop_to_name( 2026185029Spjd ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE)) 2027185029Spjd goto error; 2028185029Spjd if (nvlist_lookup_string(props, 2029185029Spjd zpool_prop_to_name(ZPOOL_PROP_CACHEFILE), 2030185029Spjd &propval) == 0) 2031185029Spjd break; 2032185029Spjd if (add_prop_list(zpool_prop_to_name( 2033185029Spjd ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE)) 2034185029Spjd goto error; 2035168404Spjd break; 2036219089Spjd case 'T': 2037219089Spjd errno = 0; 2038268720Sdelphij txg = strtoull(optarg, &endptr, 0); 2039219089Spjd if (errno != 0 || *endptr != '\0') { 2040219089Spjd (void) fprintf(stderr, 2041219089Spjd gettext("invalid txg value\n")); 2042219089Spjd usage(B_FALSE); 2043219089Spjd } 2044219089Spjd rewind_policy = ZPOOL_DO_REWIND | ZPOOL_EXTREME_REWIND; 2045219089Spjd break; 2046219089Spjd case 'V': 2047219089Spjd flags |= ZFS_IMPORT_VERBATIM; 2048219089Spjd break; 2049219089Spjd case 'X': 2050219089Spjd xtreme_rewind = B_TRUE; 2051219089Spjd break; 2052168404Spjd case ':': 2053168404Spjd (void) fprintf(stderr, gettext("missing argument for " 2054168404Spjd "'%c' option\n"), optopt); 2055168404Spjd usage(B_FALSE); 2056168404Spjd break; 2057168404Spjd case '?': 2058168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2059168404Spjd optopt); 2060168404Spjd usage(B_FALSE); 2061168404Spjd } 2062168404Spjd } 2063168404Spjd 2064168404Spjd argc -= optind; 2065168404Spjd argv += optind; 2066168404Spjd 2067185029Spjd if (cachefile && nsearch != 0) { 2068185029Spjd (void) fprintf(stderr, gettext("-c is incompatible with -d\n")); 2069185029Spjd usage(B_FALSE); 2070185029Spjd } 2071185029Spjd 2072219089Spjd if ((dryrun || xtreme_rewind) && !do_rewind) { 2073219089Spjd (void) fprintf(stderr, 2074219089Spjd gettext("-n or -X only meaningful with -F\n")); 2075219089Spjd usage(B_FALSE); 2076219089Spjd } 2077219089Spjd if (dryrun) 2078219089Spjd rewind_policy = ZPOOL_TRY_REWIND; 2079219089Spjd else if (do_rewind) 2080219089Spjd rewind_policy = ZPOOL_DO_REWIND; 2081219089Spjd if (xtreme_rewind) 2082219089Spjd rewind_policy |= ZPOOL_EXTREME_REWIND; 2083219089Spjd 2084219089Spjd /* In the future, we can capture further policy and include it here */ 2085219089Spjd if (nvlist_alloc(&policy, NV_UNIQUE_NAME, 0) != 0 || 2086219089Spjd nvlist_add_uint64(policy, ZPOOL_REWIND_REQUEST_TXG, txg) != 0 || 2087219089Spjd nvlist_add_uint32(policy, ZPOOL_REWIND_REQUEST, rewind_policy) != 0) 2088219089Spjd goto error; 2089219089Spjd 2090168404Spjd if (searchdirs == NULL) { 2091168404Spjd searchdirs = safe_malloc(sizeof (char *)); 2092235478Savg searchdirs[0] = "/dev"; 2093168404Spjd nsearch = 1; 2094168404Spjd } 2095168404Spjd 2096168404Spjd /* check argument count */ 2097168404Spjd if (do_all) { 2098168404Spjd if (argc != 0) { 2099168404Spjd (void) fprintf(stderr, gettext("too many arguments\n")); 2100168404Spjd usage(B_FALSE); 2101168404Spjd } 2102168404Spjd } else { 2103168404Spjd if (argc > 2) { 2104168404Spjd (void) fprintf(stderr, gettext("too many arguments\n")); 2105168404Spjd usage(B_FALSE); 2106168404Spjd } 2107168404Spjd 2108168404Spjd /* 2109168404Spjd * Check for the SYS_CONFIG privilege. We do this explicitly 2110168404Spjd * here because otherwise any attempt to discover pools will 2111168404Spjd * silently fail. 2112168404Spjd */ 2113168404Spjd if (argc == 0 && !priv_ineffect(PRIV_SYS_CONFIG)) { 2114168404Spjd (void) fprintf(stderr, gettext("cannot " 2115168404Spjd "discover pools: permission denied\n")); 2116168404Spjd free(searchdirs); 2117219089Spjd nvlist_free(policy); 2118168404Spjd return (1); 2119168404Spjd } 2120168404Spjd } 2121168404Spjd 2122168404Spjd /* 2123168404Spjd * Depending on the arguments given, we do one of the following: 2124168404Spjd * 2125168404Spjd * <none> Iterate through all pools and display information about 2126168404Spjd * each one. 2127168404Spjd * 2128168404Spjd * -a Iterate through all pools and try to import each one. 2129168404Spjd * 2130168404Spjd * <id> Find the pool that corresponds to the given GUID/pool 2131168404Spjd * name and import that one. 2132168404Spjd * 2133168404Spjd * -D Above options applies only to destroyed pools. 2134168404Spjd */ 2135168404Spjd if (argc != 0) { 2136168404Spjd char *endptr; 2137168404Spjd 2138168404Spjd errno = 0; 2139168404Spjd searchguid = strtoull(argv[0], &endptr, 10); 2140254758Sdelphij if (errno != 0 || *endptr != '\0') { 2141168404Spjd searchname = argv[0]; 2142254758Sdelphij searchguid = 0; 2143254758Sdelphij } 2144168404Spjd found_config = NULL; 2145168404Spjd 2146185029Spjd /* 2147219089Spjd * User specified a name or guid. Ensure it's unique. 2148185029Spjd */ 2149219089Spjd idata.unique = B_TRUE; 2150185029Spjd } 2151185029Spjd 2152219089Spjd 2153219089Spjd idata.path = searchdirs; 2154219089Spjd idata.paths = nsearch; 2155219089Spjd idata.poolname = searchname; 2156219089Spjd idata.guid = searchguid; 2157219089Spjd idata.cachefile = cachefile; 2158219089Spjd 2159219089Spjd pools = zpool_search_import(g_zfs, &idata); 2160219089Spjd 2161219089Spjd if (pools != NULL && idata.exists && 2162219089Spjd (argc == 1 || strcmp(argv[0], argv[1]) == 0)) { 2163219089Spjd (void) fprintf(stderr, gettext("cannot import '%s': " 2164219089Spjd "a pool with that name already exists\n"), 2165219089Spjd argv[0]); 2166219089Spjd (void) fprintf(stderr, gettext("use the form '%s " 2167219089Spjd "<pool | id> <newpool>' to give it a new name\n"), 2168219089Spjd "zpool import"); 2169219089Spjd err = 1; 2170219089Spjd } else if (pools == NULL && idata.exists) { 2171219089Spjd (void) fprintf(stderr, gettext("cannot import '%s': " 2172219089Spjd "a pool with that name is already created/imported,\n"), 2173219089Spjd argv[0]); 2174219089Spjd (void) fprintf(stderr, gettext("and no additional pools " 2175219089Spjd "with that name were found\n")); 2176219089Spjd err = 1; 2177219089Spjd } else if (pools == NULL) { 2178185029Spjd if (argc != 0) { 2179185029Spjd (void) fprintf(stderr, gettext("cannot import '%s': " 2180185029Spjd "no such pool available\n"), argv[0]); 2181185029Spjd } 2182219089Spjd err = 1; 2183219089Spjd } 2184219089Spjd 2185219089Spjd if (err == 1) { 2186185029Spjd free(searchdirs); 2187219089Spjd nvlist_free(policy); 2188185029Spjd return (1); 2189185029Spjd } 2190185029Spjd 2191185029Spjd /* 2192185029Spjd * At this point we have a list of import candidate configs. Even if 2193185029Spjd * we were searching by pool name or guid, we still need to 2194185029Spjd * post-process the list to deal with pool state and possible 2195185029Spjd * duplicate names. 2196185029Spjd */ 2197168404Spjd err = 0; 2198168404Spjd elem = NULL; 2199168404Spjd first = B_TRUE; 2200168404Spjd while ((elem = nvlist_next_nvpair(pools, elem)) != NULL) { 2201168404Spjd 2202168404Spjd verify(nvpair_value_nvlist(elem, &config) == 0); 2203168404Spjd 2204168404Spjd verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE, 2205168404Spjd &pool_state) == 0); 2206168404Spjd if (!do_destroyed && pool_state == POOL_STATE_DESTROYED) 2207168404Spjd continue; 2208168404Spjd if (do_destroyed && pool_state != POOL_STATE_DESTROYED) 2209168404Spjd continue; 2210168404Spjd 2211219089Spjd verify(nvlist_add_nvlist(config, ZPOOL_REWIND_POLICY, 2212219089Spjd policy) == 0); 2213219089Spjd 2214168404Spjd if (argc == 0) { 2215168404Spjd if (first) 2216168404Spjd first = B_FALSE; 2217168404Spjd else if (!do_all) 2218168404Spjd (void) printf("\n"); 2219168404Spjd 2220219089Spjd if (do_all) { 2221168404Spjd err |= do_import(config, NULL, mntopts, 2222219089Spjd props, flags); 2223219089Spjd } else { 2224168404Spjd show_import(config); 2225219089Spjd } 2226168404Spjd } else if (searchname != NULL) { 2227168404Spjd char *name; 2228168404Spjd 2229168404Spjd /* 2230168404Spjd * We are searching for a pool based on name. 2231168404Spjd */ 2232168404Spjd verify(nvlist_lookup_string(config, 2233168404Spjd ZPOOL_CONFIG_POOL_NAME, &name) == 0); 2234168404Spjd 2235168404Spjd if (strcmp(name, searchname) == 0) { 2236168404Spjd if (found_config != NULL) { 2237168404Spjd (void) fprintf(stderr, gettext( 2238168404Spjd "cannot import '%s': more than " 2239168404Spjd "one matching pool\n"), searchname); 2240168404Spjd (void) fprintf(stderr, gettext( 2241168404Spjd "import by numeric ID instead\n")); 2242168404Spjd err = B_TRUE; 2243168404Spjd } 2244168404Spjd found_config = config; 2245168404Spjd } 2246168404Spjd } else { 2247168404Spjd uint64_t guid; 2248168404Spjd 2249168404Spjd /* 2250168404Spjd * Search for a pool by guid. 2251168404Spjd */ 2252168404Spjd verify(nvlist_lookup_uint64(config, 2253168404Spjd ZPOOL_CONFIG_POOL_GUID, &guid) == 0); 2254168404Spjd 2255168404Spjd if (guid == searchguid) 2256168404Spjd found_config = config; 2257168404Spjd } 2258168404Spjd } 2259168404Spjd 2260168404Spjd /* 2261168404Spjd * If we were searching for a specific pool, verify that we found a 2262168404Spjd * pool, and then do the import. 2263168404Spjd */ 2264168404Spjd if (argc != 0 && err == 0) { 2265168404Spjd if (found_config == NULL) { 2266168404Spjd (void) fprintf(stderr, gettext("cannot import '%s': " 2267168404Spjd "no such pool available\n"), argv[0]); 2268168404Spjd err = B_TRUE; 2269168404Spjd } else { 2270168404Spjd err |= do_import(found_config, argc == 1 ? NULL : 2271219089Spjd argv[1], mntopts, props, flags); 2272168404Spjd } 2273168404Spjd } 2274168404Spjd 2275168404Spjd /* 2276168404Spjd * If we were just looking for pools, report an error if none were 2277168404Spjd * found. 2278168404Spjd */ 2279168404Spjd if (argc == 0 && first) 2280168404Spjd (void) fprintf(stderr, 2281168404Spjd gettext("no pools available to import\n")); 2282168404Spjd 2283185029Spjderror: 2284185029Spjd nvlist_free(props); 2285168404Spjd nvlist_free(pools); 2286219089Spjd nvlist_free(policy); 2287168404Spjd free(searchdirs); 2288168404Spjd 2289168404Spjd return (err ? 1 : 0); 2290168404Spjd} 2291168404Spjd 2292168404Spjdtypedef struct iostat_cbdata { 2293236155Smm boolean_t cb_verbose; 2294236155Smm int cb_namewidth; 2295236155Smm int cb_iteration; 2296168404Spjd zpool_list_t *cb_list; 2297168404Spjd} iostat_cbdata_t; 2298168404Spjd 2299168404Spjdstatic void 2300168404Spjdprint_iostat_separator(iostat_cbdata_t *cb) 2301168404Spjd{ 2302168404Spjd int i = 0; 2303168404Spjd 2304168404Spjd for (i = 0; i < cb->cb_namewidth; i++) 2305168404Spjd (void) printf("-"); 2306168404Spjd (void) printf(" ----- ----- ----- ----- ----- -----\n"); 2307168404Spjd} 2308168404Spjd 2309168404Spjdstatic void 2310168404Spjdprint_iostat_header(iostat_cbdata_t *cb) 2311168404Spjd{ 2312168404Spjd (void) printf("%*s capacity operations bandwidth\n", 2313168404Spjd cb->cb_namewidth, ""); 2314219089Spjd (void) printf("%-*s alloc free read write read write\n", 2315168404Spjd cb->cb_namewidth, "pool"); 2316168404Spjd print_iostat_separator(cb); 2317168404Spjd} 2318168404Spjd 2319168404Spjd/* 2320168404Spjd * Display a single statistic. 2321168404Spjd */ 2322185029Spjdstatic void 2323168404Spjdprint_one_stat(uint64_t value) 2324168404Spjd{ 2325168404Spjd char buf[64]; 2326168404Spjd 2327168404Spjd zfs_nicenum(value, buf, sizeof (buf)); 2328168404Spjd (void) printf(" %5s", buf); 2329168404Spjd} 2330168404Spjd 2331168404Spjd/* 2332168404Spjd * Print out all the statistics for the given vdev. This can either be the 2333168404Spjd * toplevel configuration, or called recursively. If 'name' is NULL, then this 2334168404Spjd * is a verbose output, and we don't want to display the toplevel pool stats. 2335168404Spjd */ 2336168404Spjdvoid 2337168404Spjdprint_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv, 2338168404Spjd nvlist_t *newnv, iostat_cbdata_t *cb, int depth) 2339168404Spjd{ 2340168404Spjd nvlist_t **oldchild, **newchild; 2341168404Spjd uint_t c, children; 2342168404Spjd vdev_stat_t *oldvs, *newvs; 2343168404Spjd vdev_stat_t zerovs = { 0 }; 2344168404Spjd uint64_t tdelta; 2345168404Spjd double scale; 2346168404Spjd char *vname; 2347168404Spjd 2348168404Spjd if (oldnv != NULL) { 2349219089Spjd verify(nvlist_lookup_uint64_array(oldnv, 2350219089Spjd ZPOOL_CONFIG_VDEV_STATS, (uint64_t **)&oldvs, &c) == 0); 2351168404Spjd } else { 2352168404Spjd oldvs = &zerovs; 2353168404Spjd } 2354168404Spjd 2355219089Spjd verify(nvlist_lookup_uint64_array(newnv, ZPOOL_CONFIG_VDEV_STATS, 2356168404Spjd (uint64_t **)&newvs, &c) == 0); 2357168404Spjd 2358168404Spjd if (strlen(name) + depth > cb->cb_namewidth) 2359168404Spjd (void) printf("%*s%s", depth, "", name); 2360168404Spjd else 2361168404Spjd (void) printf("%*s%s%*s", depth, "", name, 2362168404Spjd (int)(cb->cb_namewidth - strlen(name) - depth), ""); 2363168404Spjd 2364168404Spjd tdelta = newvs->vs_timestamp - oldvs->vs_timestamp; 2365168404Spjd 2366168404Spjd if (tdelta == 0) 2367168404Spjd scale = 1.0; 2368168404Spjd else 2369168404Spjd scale = (double)NANOSEC / tdelta; 2370168404Spjd 2371168404Spjd /* only toplevel vdevs have capacity stats */ 2372168404Spjd if (newvs->vs_space == 0) { 2373168404Spjd (void) printf(" - -"); 2374168404Spjd } else { 2375168404Spjd print_one_stat(newvs->vs_alloc); 2376168404Spjd print_one_stat(newvs->vs_space - newvs->vs_alloc); 2377168404Spjd } 2378168404Spjd 2379168404Spjd print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_READ] - 2380168404Spjd oldvs->vs_ops[ZIO_TYPE_READ]))); 2381168404Spjd 2382168404Spjd print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_WRITE] - 2383168404Spjd oldvs->vs_ops[ZIO_TYPE_WRITE]))); 2384168404Spjd 2385168404Spjd print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_READ] - 2386168404Spjd oldvs->vs_bytes[ZIO_TYPE_READ]))); 2387168404Spjd 2388168404Spjd print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_WRITE] - 2389168404Spjd oldvs->vs_bytes[ZIO_TYPE_WRITE]))); 2390168404Spjd 2391168404Spjd (void) printf("\n"); 2392168404Spjd 2393168404Spjd if (!cb->cb_verbose) 2394168404Spjd return; 2395168404Spjd 2396168404Spjd if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_CHILDREN, 2397168404Spjd &newchild, &children) != 0) 2398168404Spjd return; 2399168404Spjd 2400168404Spjd if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_CHILDREN, 2401168404Spjd &oldchild, &c) != 0) 2402168404Spjd return; 2403168404Spjd 2404168404Spjd for (c = 0; c < children; c++) { 2405227497Smm uint64_t ishole = B_FALSE, islog = B_FALSE; 2406219089Spjd 2407227497Smm (void) nvlist_lookup_uint64(newchild[c], ZPOOL_CONFIG_IS_HOLE, 2408227497Smm &ishole); 2409227497Smm 2410227497Smm (void) nvlist_lookup_uint64(newchild[c], ZPOOL_CONFIG_IS_LOG, 2411227497Smm &islog); 2412227497Smm 2413227497Smm if (ishole || islog) 2414219089Spjd continue; 2415219089Spjd 2416219089Spjd vname = zpool_vdev_name(g_zfs, zhp, newchild[c], B_FALSE); 2417168404Spjd print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL, 2418168404Spjd newchild[c], cb, depth + 2); 2419168404Spjd free(vname); 2420168404Spjd } 2421185029Spjd 2422185029Spjd /* 2423227497Smm * Log device section 2424227497Smm */ 2425227497Smm 2426227497Smm if (num_logs(newnv) > 0) { 2427227497Smm (void) printf("%-*s - - - - - " 2428227497Smm "-\n", cb->cb_namewidth, "logs"); 2429227497Smm 2430227497Smm for (c = 0; c < children; c++) { 2431227497Smm uint64_t islog = B_FALSE; 2432227497Smm (void) nvlist_lookup_uint64(newchild[c], 2433227497Smm ZPOOL_CONFIG_IS_LOG, &islog); 2434227497Smm 2435227497Smm if (islog) { 2436227497Smm vname = zpool_vdev_name(g_zfs, zhp, newchild[c], 2437227497Smm B_FALSE); 2438227497Smm print_vdev_stats(zhp, vname, oldnv ? 2439227497Smm oldchild[c] : NULL, newchild[c], 2440227497Smm cb, depth + 2); 2441227497Smm free(vname); 2442227497Smm } 2443227497Smm } 2444227497Smm 2445227497Smm } 2446227497Smm 2447227497Smm /* 2448185029Spjd * Include level 2 ARC devices in iostat output 2449185029Spjd */ 2450185029Spjd if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_L2CACHE, 2451185029Spjd &newchild, &children) != 0) 2452185029Spjd return; 2453185029Spjd 2454185029Spjd if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_L2CACHE, 2455185029Spjd &oldchild, &c) != 0) 2456185029Spjd return; 2457185029Spjd 2458185029Spjd if (children > 0) { 2459185029Spjd (void) printf("%-*s - - - - - " 2460185029Spjd "-\n", cb->cb_namewidth, "cache"); 2461185029Spjd for (c = 0; c < children; c++) { 2462219089Spjd vname = zpool_vdev_name(g_zfs, zhp, newchild[c], 2463219089Spjd B_FALSE); 2464185029Spjd print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL, 2465185029Spjd newchild[c], cb, depth + 2); 2466185029Spjd free(vname); 2467185029Spjd } 2468185029Spjd } 2469168404Spjd} 2470168404Spjd 2471168404Spjdstatic int 2472168404Spjdrefresh_iostat(zpool_handle_t *zhp, void *data) 2473168404Spjd{ 2474168404Spjd iostat_cbdata_t *cb = data; 2475168404Spjd boolean_t missing; 2476168404Spjd 2477168404Spjd /* 2478168404Spjd * If the pool has disappeared, remove it from the list and continue. 2479168404Spjd */ 2480168404Spjd if (zpool_refresh_stats(zhp, &missing) != 0) 2481168404Spjd return (-1); 2482168404Spjd 2483168404Spjd if (missing) 2484168404Spjd pool_list_remove(cb->cb_list, zhp); 2485168404Spjd 2486168404Spjd return (0); 2487168404Spjd} 2488168404Spjd 2489168404Spjd/* 2490168404Spjd * Callback to print out the iostats for the given pool. 2491168404Spjd */ 2492168404Spjdint 2493168404Spjdprint_iostat(zpool_handle_t *zhp, void *data) 2494168404Spjd{ 2495168404Spjd iostat_cbdata_t *cb = data; 2496168404Spjd nvlist_t *oldconfig, *newconfig; 2497168404Spjd nvlist_t *oldnvroot, *newnvroot; 2498168404Spjd 2499168404Spjd newconfig = zpool_get_config(zhp, &oldconfig); 2500168404Spjd 2501168404Spjd if (cb->cb_iteration == 1) 2502168404Spjd oldconfig = NULL; 2503168404Spjd 2504168404Spjd verify(nvlist_lookup_nvlist(newconfig, ZPOOL_CONFIG_VDEV_TREE, 2505168404Spjd &newnvroot) == 0); 2506168404Spjd 2507168404Spjd if (oldconfig == NULL) 2508168404Spjd oldnvroot = NULL; 2509168404Spjd else 2510168404Spjd verify(nvlist_lookup_nvlist(oldconfig, ZPOOL_CONFIG_VDEV_TREE, 2511168404Spjd &oldnvroot) == 0); 2512168404Spjd 2513168404Spjd /* 2514168404Spjd * Print out the statistics for the pool. 2515168404Spjd */ 2516168404Spjd print_vdev_stats(zhp, zpool_get_name(zhp), oldnvroot, newnvroot, cb, 0); 2517168404Spjd 2518168404Spjd if (cb->cb_verbose) 2519168404Spjd print_iostat_separator(cb); 2520168404Spjd 2521168404Spjd return (0); 2522168404Spjd} 2523168404Spjd 2524168404Spjdint 2525168404Spjdget_namewidth(zpool_handle_t *zhp, void *data) 2526168404Spjd{ 2527168404Spjd iostat_cbdata_t *cb = data; 2528168404Spjd nvlist_t *config, *nvroot; 2529168404Spjd 2530168404Spjd if ((config = zpool_get_config(zhp, NULL)) != NULL) { 2531168404Spjd verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 2532168404Spjd &nvroot) == 0); 2533168404Spjd if (!cb->cb_verbose) 2534168404Spjd cb->cb_namewidth = strlen(zpool_get_name(zhp)); 2535168404Spjd else 2536236145Smm cb->cb_namewidth = max_width(zhp, nvroot, 0, 2537236145Smm cb->cb_namewidth); 2538168404Spjd } 2539168404Spjd 2540168404Spjd /* 2541168404Spjd * The width must fall into the range [10,38]. The upper limit is the 2542168404Spjd * maximum we can have and still fit in 80 columns. 2543168404Spjd */ 2544168404Spjd if (cb->cb_namewidth < 10) 2545168404Spjd cb->cb_namewidth = 10; 2546168404Spjd if (cb->cb_namewidth > 38) 2547168404Spjd cb->cb_namewidth = 38; 2548168404Spjd 2549168404Spjd return (0); 2550168404Spjd} 2551168404Spjd 2552168404Spjd/* 2553219089Spjd * Parse the input string, get the 'interval' and 'count' value if there is one. 2554168404Spjd */ 2555219089Spjdstatic void 2556219089Spjdget_interval_count(int *argcp, char **argv, unsigned long *iv, 2557219089Spjd unsigned long *cnt) 2558168404Spjd{ 2559168404Spjd unsigned long interval = 0, count = 0; 2560219089Spjd int argc = *argcp, errno; 2561168404Spjd 2562168404Spjd /* 2563168404Spjd * Determine if the last argument is an integer or a pool name 2564168404Spjd */ 2565168404Spjd if (argc > 0 && isdigit(argv[argc - 1][0])) { 2566168404Spjd char *end; 2567168404Spjd 2568168404Spjd errno = 0; 2569168404Spjd interval = strtoul(argv[argc - 1], &end, 10); 2570168404Spjd 2571168404Spjd if (*end == '\0' && errno == 0) { 2572168404Spjd if (interval == 0) { 2573168404Spjd (void) fprintf(stderr, gettext("interval " 2574168404Spjd "cannot be zero\n")); 2575168404Spjd usage(B_FALSE); 2576168404Spjd } 2577168404Spjd /* 2578168404Spjd * Ignore the last parameter 2579168404Spjd */ 2580168404Spjd argc--; 2581168404Spjd } else { 2582168404Spjd /* 2583168404Spjd * If this is not a valid number, just plow on. The 2584168404Spjd * user will get a more informative error message later 2585168404Spjd * on. 2586168404Spjd */ 2587168404Spjd interval = 0; 2588168404Spjd } 2589168404Spjd } 2590168404Spjd 2591168404Spjd /* 2592168404Spjd * If the last argument is also an integer, then we have both a count 2593219089Spjd * and an interval. 2594168404Spjd */ 2595168404Spjd if (argc > 0 && isdigit(argv[argc - 1][0])) { 2596168404Spjd char *end; 2597168404Spjd 2598168404Spjd errno = 0; 2599168404Spjd count = interval; 2600168404Spjd interval = strtoul(argv[argc - 1], &end, 10); 2601168404Spjd 2602168404Spjd if (*end == '\0' && errno == 0) { 2603168404Spjd if (interval == 0) { 2604168404Spjd (void) fprintf(stderr, gettext("interval " 2605168404Spjd "cannot be zero\n")); 2606168404Spjd usage(B_FALSE); 2607168404Spjd } 2608168404Spjd 2609168404Spjd /* 2610168404Spjd * Ignore the last parameter 2611168404Spjd */ 2612168404Spjd argc--; 2613168404Spjd } else { 2614168404Spjd interval = 0; 2615168404Spjd } 2616168404Spjd } 2617168404Spjd 2618219089Spjd *iv = interval; 2619219089Spjd *cnt = count; 2620219089Spjd *argcp = argc; 2621219089Spjd} 2622219089Spjd 2623219089Spjdstatic void 2624219089Spjdget_timestamp_arg(char c) 2625219089Spjd{ 2626219089Spjd if (c == 'u') 2627219089Spjd timestamp_fmt = UDATE; 2628219089Spjd else if (c == 'd') 2629219089Spjd timestamp_fmt = DDATE; 2630219089Spjd else 2631219089Spjd usage(B_FALSE); 2632219089Spjd} 2633219089Spjd 2634219089Spjd/* 2635219089Spjd * zpool iostat [-v] [-T d|u] [pool] ... [interval [count]] 2636219089Spjd * 2637219089Spjd * -v Display statistics for individual vdevs 2638219089Spjd * -T Display a timestamp in date(1) or Unix format 2639219089Spjd * 2640219089Spjd * This command can be tricky because we want to be able to deal with pool 2641219089Spjd * creation/destruction as well as vdev configuration changes. The bulk of this 2642219089Spjd * processing is handled by the pool_list_* routines in zpool_iter.c. We rely 2643219089Spjd * on pool_list_update() to detect the addition of new pools. Configuration 2644219089Spjd * changes are all handled within libzfs. 2645219089Spjd */ 2646219089Spjdint 2647219089Spjdzpool_do_iostat(int argc, char **argv) 2648219089Spjd{ 2649219089Spjd int c; 2650219089Spjd int ret; 2651219089Spjd int npools; 2652219089Spjd unsigned long interval = 0, count = 0; 2653219089Spjd zpool_list_t *list; 2654219089Spjd boolean_t verbose = B_FALSE; 2655219089Spjd iostat_cbdata_t cb; 2656219089Spjd 2657219089Spjd /* check options */ 2658219089Spjd while ((c = getopt(argc, argv, "T:v")) != -1) { 2659219089Spjd switch (c) { 2660219089Spjd case 'T': 2661219089Spjd get_timestamp_arg(*optarg); 2662219089Spjd break; 2663219089Spjd case 'v': 2664219089Spjd verbose = B_TRUE; 2665219089Spjd break; 2666219089Spjd case '?': 2667219089Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2668219089Spjd optopt); 2669219089Spjd usage(B_FALSE); 2670219089Spjd } 2671219089Spjd } 2672219089Spjd 2673219089Spjd argc -= optind; 2674219089Spjd argv += optind; 2675219089Spjd 2676219089Spjd get_interval_count(&argc, argv, &interval, &count); 2677219089Spjd 2678168404Spjd /* 2679168404Spjd * Construct the list of all interesting pools. 2680168404Spjd */ 2681168404Spjd ret = 0; 2682168404Spjd if ((list = pool_list_get(argc, argv, NULL, &ret)) == NULL) 2683168404Spjd return (1); 2684168404Spjd 2685168404Spjd if (pool_list_count(list) == 0 && argc != 0) { 2686168404Spjd pool_list_free(list); 2687168404Spjd return (1); 2688168404Spjd } 2689168404Spjd 2690168404Spjd if (pool_list_count(list) == 0 && interval == 0) { 2691168404Spjd pool_list_free(list); 2692168404Spjd (void) fprintf(stderr, gettext("no pools available\n")); 2693168404Spjd return (1); 2694168404Spjd } 2695168404Spjd 2696168404Spjd /* 2697168404Spjd * Enter the main iostat loop. 2698168404Spjd */ 2699168404Spjd cb.cb_list = list; 2700168404Spjd cb.cb_verbose = verbose; 2701168404Spjd cb.cb_iteration = 0; 2702168404Spjd cb.cb_namewidth = 0; 2703168404Spjd 2704168404Spjd for (;;) { 2705168404Spjd pool_list_update(list); 2706168404Spjd 2707168404Spjd if ((npools = pool_list_count(list)) == 0) 2708168404Spjd break; 2709168404Spjd 2710168404Spjd /* 2711168404Spjd * Refresh all statistics. This is done as an explicit step 2712168404Spjd * before calculating the maximum name width, so that any 2713168404Spjd * configuration changes are properly accounted for. 2714168404Spjd */ 2715168404Spjd (void) pool_list_iter(list, B_FALSE, refresh_iostat, &cb); 2716168404Spjd 2717168404Spjd /* 2718168404Spjd * Iterate over all pools to determine the maximum width 2719168404Spjd * for the pool / device name column across all pools. 2720168404Spjd */ 2721168404Spjd cb.cb_namewidth = 0; 2722168404Spjd (void) pool_list_iter(list, B_FALSE, get_namewidth, &cb); 2723168404Spjd 2724219089Spjd if (timestamp_fmt != NODATE) 2725219089Spjd print_timestamp(timestamp_fmt); 2726219089Spjd 2727168404Spjd /* 2728168404Spjd * If it's the first time, or verbose mode, print the header. 2729168404Spjd */ 2730168404Spjd if (++cb.cb_iteration == 1 || verbose) 2731168404Spjd print_iostat_header(&cb); 2732168404Spjd 2733168404Spjd (void) pool_list_iter(list, B_FALSE, print_iostat, &cb); 2734168404Spjd 2735168404Spjd /* 2736168404Spjd * If there's more than one pool, and we're not in verbose mode 2737168404Spjd * (which prints a separator for us), then print a separator. 2738168404Spjd */ 2739168404Spjd if (npools > 1 && !verbose) 2740168404Spjd print_iostat_separator(&cb); 2741168404Spjd 2742168404Spjd if (verbose) 2743168404Spjd (void) printf("\n"); 2744168404Spjd 2745168404Spjd /* 2746168404Spjd * Flush the output so that redirection to a file isn't buffered 2747168404Spjd * indefinitely. 2748168404Spjd */ 2749168404Spjd (void) fflush(stdout); 2750168404Spjd 2751168404Spjd if (interval == 0) 2752168404Spjd break; 2753168404Spjd 2754168404Spjd if (count != 0 && --count == 0) 2755168404Spjd break; 2756168404Spjd 2757168404Spjd (void) sleep(interval); 2758168404Spjd } 2759168404Spjd 2760168404Spjd pool_list_free(list); 2761168404Spjd 2762168404Spjd return (ret); 2763168404Spjd} 2764168404Spjd 2765168404Spjdtypedef struct list_cbdata { 2766236155Smm boolean_t cb_verbose; 2767236155Smm int cb_namewidth; 2768168404Spjd boolean_t cb_scripted; 2769185029Spjd zprop_list_t *cb_proplist; 2770263889Sdelphij boolean_t cb_literal; 2771168404Spjd} list_cbdata_t; 2772168404Spjd 2773168404Spjd/* 2774168404Spjd * Given a list of columns to display, output appropriate headers for each one. 2775168404Spjd */ 2776185029Spjdstatic void 2777236155Smmprint_header(list_cbdata_t *cb) 2778168404Spjd{ 2779236155Smm zprop_list_t *pl = cb->cb_proplist; 2780236884Smm char headerbuf[ZPOOL_MAXPROPLEN]; 2781185029Spjd const char *header; 2782185029Spjd boolean_t first = B_TRUE; 2783185029Spjd boolean_t right_justify; 2784236155Smm size_t width = 0; 2785168404Spjd 2786185029Spjd for (; pl != NULL; pl = pl->pl_next) { 2787236155Smm width = pl->pl_width; 2788236155Smm if (first && cb->cb_verbose) { 2789236155Smm /* 2790236155Smm * Reset the width to accommodate the verbose listing 2791236155Smm * of devices. 2792236155Smm */ 2793236155Smm width = cb->cb_namewidth; 2794236155Smm } 2795236155Smm 2796185029Spjd if (!first) 2797168404Spjd (void) printf(" "); 2798168404Spjd else 2799185029Spjd first = B_FALSE; 2800168404Spjd 2801236884Smm right_justify = B_FALSE; 2802236884Smm if (pl->pl_prop != ZPROP_INVAL) { 2803236884Smm header = zpool_prop_column_name(pl->pl_prop); 2804236884Smm right_justify = zpool_prop_align_right(pl->pl_prop); 2805236884Smm } else { 2806236884Smm int i; 2807185029Spjd 2808236884Smm for (i = 0; pl->pl_user_prop[i] != '\0'; i++) 2809236884Smm headerbuf[i] = toupper(pl->pl_user_prop[i]); 2810236884Smm headerbuf[i] = '\0'; 2811236884Smm header = headerbuf; 2812236884Smm } 2813236884Smm 2814185029Spjd if (pl->pl_next == NULL && !right_justify) 2815185029Spjd (void) printf("%s", header); 2816185029Spjd else if (right_justify) 2817236155Smm (void) printf("%*s", width, header); 2818185029Spjd else 2819236155Smm (void) printf("%-*s", width, header); 2820236155Smm 2821168404Spjd } 2822168404Spjd 2823168404Spjd (void) printf("\n"); 2824168404Spjd} 2825168404Spjd 2826185029Spjd/* 2827185029Spjd * Given a pool and a list of properties, print out all the properties according 2828185029Spjd * to the described layout. 2829185029Spjd */ 2830185029Spjdstatic void 2831236155Smmprint_pool(zpool_handle_t *zhp, list_cbdata_t *cb) 2832168404Spjd{ 2833236155Smm zprop_list_t *pl = cb->cb_proplist; 2834185029Spjd boolean_t first = B_TRUE; 2835185029Spjd char property[ZPOOL_MAXPROPLEN]; 2836185029Spjd char *propstr; 2837185029Spjd boolean_t right_justify; 2838236155Smm size_t width; 2839168404Spjd 2840185029Spjd for (; pl != NULL; pl = pl->pl_next) { 2841236155Smm 2842236155Smm width = pl->pl_width; 2843236155Smm if (first && cb->cb_verbose) { 2844236155Smm /* 2845236155Smm * Reset the width to accommodate the verbose listing 2846236155Smm * of devices. 2847236155Smm */ 2848236155Smm width = cb->cb_namewidth; 2849236155Smm } 2850236155Smm 2851185029Spjd if (!first) { 2852236155Smm if (cb->cb_scripted) 2853168404Spjd (void) printf("\t"); 2854168404Spjd else 2855168404Spjd (void) printf(" "); 2856185029Spjd } else { 2857185029Spjd first = B_FALSE; 2858168404Spjd } 2859168404Spjd 2860185029Spjd right_justify = B_FALSE; 2861185029Spjd if (pl->pl_prop != ZPROP_INVAL) { 2862272502Sdelphij if (zpool_get_prop(zhp, pl->pl_prop, property, 2863263889Sdelphij sizeof (property), NULL, cb->cb_literal) != 0) 2864185029Spjd propstr = "-"; 2865168404Spjd else 2866185029Spjd propstr = property; 2867168404Spjd 2868185029Spjd right_justify = zpool_prop_align_right(pl->pl_prop); 2869236884Smm } else if ((zpool_prop_feature(pl->pl_user_prop) || 2870236884Smm zpool_prop_unsupported(pl->pl_user_prop)) && 2871236884Smm zpool_prop_get_feature(zhp, pl->pl_user_prop, property, 2872236884Smm sizeof (property)) == 0) { 2873236884Smm propstr = property; 2874185029Spjd } else { 2875185029Spjd propstr = "-"; 2876185029Spjd } 2877168404Spjd 2878168404Spjd 2879185029Spjd /* 2880185029Spjd * If this is being called in scripted mode, or if this is the 2881185029Spjd * last column and it is left-justified, don't include a width 2882185029Spjd * format specifier. 2883185029Spjd */ 2884236155Smm if (cb->cb_scripted || (pl->pl_next == NULL && !right_justify)) 2885185029Spjd (void) printf("%s", propstr); 2886185029Spjd else if (right_justify) 2887185029Spjd (void) printf("%*s", width, propstr); 2888185029Spjd else 2889185029Spjd (void) printf("%-*s", width, propstr); 2890185029Spjd } 2891168404Spjd 2892185029Spjd (void) printf("\n"); 2893185029Spjd} 2894168404Spjd 2895236155Smmstatic void 2896272502Sdelphijprint_one_column(zpool_prop_t prop, uint64_t value, boolean_t scripted, 2897272502Sdelphij boolean_t valid) 2898236155Smm{ 2899236155Smm char propval[64]; 2900236155Smm boolean_t fixed; 2901236155Smm size_t width = zprop_width(prop, &fixed, ZFS_TYPE_POOL); 2902236155Smm 2903272502Sdelphij switch (prop) { 2904272502Sdelphij case ZPOOL_PROP_EXPANDSZ: 2905272502Sdelphij if (value == 0) 2906272502Sdelphij (void) strlcpy(propval, "-", sizeof (propval)); 2907272502Sdelphij else 2908272502Sdelphij zfs_nicenum(value, propval, sizeof (propval)); 2909272502Sdelphij break; 2910272502Sdelphij case ZPOOL_PROP_FRAGMENTATION: 2911272502Sdelphij if (value == ZFS_FRAG_INVALID) { 2912272502Sdelphij (void) strlcpy(propval, "-", sizeof (propval)); 2913272502Sdelphij } else { 2914272502Sdelphij (void) snprintf(propval, sizeof (propval), "%llu%%", 2915272502Sdelphij value); 2916272502Sdelphij } 2917272502Sdelphij break; 2918272502Sdelphij case ZPOOL_PROP_CAPACITY: 2919269118Sdelphij (void) snprintf(propval, sizeof (propval), "%llu%%", value); 2920272502Sdelphij break; 2921272502Sdelphij default: 2922269118Sdelphij zfs_nicenum(value, propval, sizeof (propval)); 2923272502Sdelphij } 2924236155Smm 2925272502Sdelphij if (!valid) 2926272502Sdelphij (void) strlcpy(propval, "-", sizeof (propval)); 2927272502Sdelphij 2928236155Smm if (scripted) 2929236155Smm (void) printf("\t%s", propval); 2930236155Smm else 2931236155Smm (void) printf(" %*s", width, propval); 2932236155Smm} 2933236155Smm 2934236155Smmvoid 2935236155Smmprint_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv, 2936236155Smm list_cbdata_t *cb, int depth) 2937236155Smm{ 2938236155Smm nvlist_t **child; 2939236155Smm vdev_stat_t *vs; 2940236155Smm uint_t c, children; 2941236155Smm char *vname; 2942236155Smm boolean_t scripted = cb->cb_scripted; 2943289536Smav uint64_t islog = B_FALSE; 2944289536Smav boolean_t haslog = B_FALSE; 2945289536Smav char *dashes = "%-*s - - - - - -\n"; 2946236155Smm 2947236155Smm verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS, 2948236155Smm (uint64_t **)&vs, &c) == 0); 2949236155Smm 2950236155Smm if (name != NULL) { 2951272502Sdelphij boolean_t toplevel = (vs->vs_space != 0); 2952272502Sdelphij uint64_t cap; 2953272502Sdelphij 2954236155Smm if (scripted) 2955236155Smm (void) printf("\t%s", name); 2956236155Smm else if (strlen(name) + depth > cb->cb_namewidth) 2957236155Smm (void) printf("%*s%s", depth, "", name); 2958236155Smm else 2959236155Smm (void) printf("%*s%s%*s", depth, "", name, 2960236155Smm (int)(cb->cb_namewidth - strlen(name) - depth), ""); 2961236155Smm 2962272502Sdelphij /* 2963272502Sdelphij * Print the properties for the individual vdevs. Some 2964272502Sdelphij * properties are only applicable to toplevel vdevs. The 2965272502Sdelphij * 'toplevel' boolean value is passed to the print_one_column() 2966272502Sdelphij * to indicate that the value is valid. 2967272502Sdelphij */ 2968272502Sdelphij print_one_column(ZPOOL_PROP_SIZE, vs->vs_space, scripted, 2969272502Sdelphij toplevel); 2970272502Sdelphij print_one_column(ZPOOL_PROP_ALLOCATED, vs->vs_alloc, scripted, 2971272502Sdelphij toplevel); 2972272502Sdelphij print_one_column(ZPOOL_PROP_FREE, vs->vs_space - vs->vs_alloc, 2973272502Sdelphij scripted, toplevel); 2974272502Sdelphij print_one_column(ZPOOL_PROP_EXPANDSZ, vs->vs_esize, scripted, 2975272502Sdelphij B_TRUE); 2976272502Sdelphij print_one_column(ZPOOL_PROP_FRAGMENTATION, 2977272502Sdelphij vs->vs_fragmentation, scripted, 2978272502Sdelphij (vs->vs_fragmentation != ZFS_FRAG_INVALID && toplevel)); 2979272502Sdelphij cap = (vs->vs_space == 0) ? 0 : 2980272502Sdelphij (vs->vs_alloc * 100 / vs->vs_space); 2981272502Sdelphij print_one_column(ZPOOL_PROP_CAPACITY, cap, scripted, toplevel); 2982236155Smm (void) printf("\n"); 2983236155Smm } 2984236155Smm 2985236155Smm if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 2986236155Smm &child, &children) != 0) 2987236155Smm return; 2988236155Smm 2989236155Smm for (c = 0; c < children; c++) { 2990236155Smm uint64_t ishole = B_FALSE; 2991236155Smm 2992236155Smm if (nvlist_lookup_uint64(child[c], 2993236155Smm ZPOOL_CONFIG_IS_HOLE, &ishole) == 0 && ishole) 2994236155Smm continue; 2995236155Smm 2996289536Smav if (nvlist_lookup_uint64(child[c], 2997289536Smav ZPOOL_CONFIG_IS_LOG, &islog) == 0 && islog) { 2998289536Smav haslog = B_TRUE; 2999289536Smav continue; 3000289536Smav } 3001289536Smav 3002236155Smm vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE); 3003236155Smm print_list_stats(zhp, vname, child[c], cb, depth + 2); 3004236155Smm free(vname); 3005236155Smm } 3006236155Smm 3007289536Smav if (haslog == B_TRUE) { 3008289536Smav /* LINTED E_SEC_PRINTF_VAR_FMT */ 3009289536Smav (void) printf(dashes, cb->cb_namewidth, "log"); 3010289536Smav for (c = 0; c < children; c++) { 3011289536Smav if (nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 3012289536Smav &islog) != 0 || !islog) 3013289536Smav continue; 3014289536Smav vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE); 3015289536Smav print_list_stats(zhp, vname, child[c], cb, depth + 2); 3016289536Smav free(vname); 3017289536Smav } 3018289536Smav } 3019289536Smav 3020236155Smm if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE, 3021289536Smav &child, &children) == 0 && children > 0) { 3022289536Smav /* LINTED E_SEC_PRINTF_VAR_FMT */ 3023289536Smav (void) printf(dashes, cb->cb_namewidth, "cache"); 3024289536Smav for (c = 0; c < children; c++) { 3025289536Smav vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE); 3026289536Smav print_list_stats(zhp, vname, child[c], cb, depth + 2); 3027289536Smav free(vname); 3028289536Smav } 3029289536Smav } 3030236155Smm 3031289536Smav if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, &child, 3032289536Smav &children) == 0 && children > 0) { 3033289536Smav /* LINTED E_SEC_PRINTF_VAR_FMT */ 3034289536Smav (void) printf(dashes, cb->cb_namewidth, "spare"); 3035236155Smm for (c = 0; c < children; c++) { 3036289536Smav vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE); 3037236155Smm print_list_stats(zhp, vname, child[c], cb, depth + 2); 3038236155Smm free(vname); 3039236155Smm } 3040236155Smm } 3041236155Smm} 3042236155Smm 3043236155Smm 3044185029Spjd/* 3045185029Spjd * Generic callback function to list a pool. 3046185029Spjd */ 3047185029Spjdint 3048185029Spjdlist_callback(zpool_handle_t *zhp, void *data) 3049185029Spjd{ 3050185029Spjd list_cbdata_t *cbp = data; 3051236155Smm nvlist_t *config; 3052236155Smm nvlist_t *nvroot; 3053168404Spjd 3054236155Smm config = zpool_get_config(zhp, NULL); 3055168404Spjd 3056236155Smm print_pool(zhp, cbp); 3057236155Smm if (!cbp->cb_verbose) 3058236155Smm return (0); 3059168404Spjd 3060236155Smm verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 3061236155Smm &nvroot) == 0); 3062236155Smm print_list_stats(zhp, NULL, nvroot, cbp, 0); 3063236155Smm 3064168404Spjd return (0); 3065168404Spjd} 3066168404Spjd 3067168404Spjd/* 3068263889Sdelphij * zpool list [-Hp] [-o prop[,prop]*] [-T d|u] [pool] ... [interval [count]] 3069168404Spjd * 3070185029Spjd * -H Scripted mode. Don't display headers, and separate properties 3071185029Spjd * by a single tab. 3072185029Spjd * -o List of properties to display. Defaults to 3073272502Sdelphij * "name,size,allocated,free,expandsize,fragmentation,capacity," 3074272502Sdelphij * "dedupratio,health,altroot" 3075263889Sdelphij * -p Diplay values in parsable (exact) format. 3076219089Spjd * -T Display a timestamp in date(1) or Unix format 3077168404Spjd * 3078168404Spjd * List all pools in the system, whether or not they're healthy. Output space 3079168404Spjd * statistics for each one, as well as health status summary. 3080168404Spjd */ 3081168404Spjdint 3082168404Spjdzpool_do_list(int argc, char **argv) 3083168404Spjd{ 3084168404Spjd int c; 3085168404Spjd int ret; 3086168404Spjd list_cbdata_t cb = { 0 }; 3087185029Spjd static char default_props[] = 3088272502Sdelphij "name,size,allocated,free,expandsize,fragmentation,capacity," 3089269118Sdelphij "dedupratio,health,altroot"; 3090185029Spjd char *props = default_props; 3091219089Spjd unsigned long interval = 0, count = 0; 3092236155Smm zpool_list_t *list; 3093236155Smm boolean_t first = B_TRUE; 3094168404Spjd 3095168404Spjd /* check options */ 3096263889Sdelphij while ((c = getopt(argc, argv, ":Ho:pT:v")) != -1) { 3097168404Spjd switch (c) { 3098168404Spjd case 'H': 3099168404Spjd cb.cb_scripted = B_TRUE; 3100168404Spjd break; 3101168404Spjd case 'o': 3102185029Spjd props = optarg; 3103168404Spjd break; 3104263889Sdelphij case 'p': 3105263889Sdelphij cb.cb_literal = B_TRUE; 3106263889Sdelphij break; 3107219089Spjd case 'T': 3108219089Spjd get_timestamp_arg(*optarg); 3109219089Spjd break; 3110236155Smm case 'v': 3111236155Smm cb.cb_verbose = B_TRUE; 3112236155Smm break; 3113168404Spjd case ':': 3114168404Spjd (void) fprintf(stderr, gettext("missing argument for " 3115168404Spjd "'%c' option\n"), optopt); 3116168404Spjd usage(B_FALSE); 3117168404Spjd break; 3118168404Spjd case '?': 3119168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3120168404Spjd optopt); 3121168404Spjd usage(B_FALSE); 3122168404Spjd } 3123168404Spjd } 3124168404Spjd 3125168404Spjd argc -= optind; 3126168404Spjd argv += optind; 3127168404Spjd 3128219089Spjd get_interval_count(&argc, argv, &interval, &count); 3129219089Spjd 3130185029Spjd if (zprop_get_list(g_zfs, props, &cb.cb_proplist, ZFS_TYPE_POOL) != 0) 3131185029Spjd usage(B_FALSE); 3132168404Spjd 3133219089Spjd for (;;) { 3134268470Sdelphij if ((list = pool_list_get(argc, argv, &cb.cb_proplist, 3135268470Sdelphij &ret)) == NULL) 3136268470Sdelphij return (1); 3137168404Spjd 3138236155Smm if (pool_list_count(list) == 0) 3139236155Smm break; 3140236155Smm 3141236155Smm cb.cb_namewidth = 0; 3142236155Smm (void) pool_list_iter(list, B_FALSE, get_namewidth, &cb); 3143236155Smm 3144219089Spjd if (timestamp_fmt != NODATE) 3145219089Spjd print_timestamp(timestamp_fmt); 3146168404Spjd 3147236155Smm if (!cb.cb_scripted && (first || cb.cb_verbose)) { 3148236155Smm print_header(&cb); 3149236155Smm first = B_FALSE; 3150219089Spjd } 3151236155Smm ret = pool_list_iter(list, B_TRUE, list_callback, &cb); 3152219089Spjd 3153219089Spjd if (interval == 0) 3154219089Spjd break; 3155219089Spjd 3156219089Spjd if (count != 0 && --count == 0) 3157219089Spjd break; 3158219089Spjd 3159268470Sdelphij pool_list_free(list); 3160219089Spjd (void) sleep(interval); 3161168404Spjd } 3162168404Spjd 3163268470Sdelphij if (argc == 0 && !cb.cb_scripted && pool_list_count(list) == 0) { 3164268470Sdelphij (void) printf(gettext("no pools available\n")); 3165268470Sdelphij ret = 0; 3166268470Sdelphij } 3167268470Sdelphij 3168268470Sdelphij pool_list_free(list); 3169219089Spjd zprop_free_list(cb.cb_proplist); 3170168404Spjd return (ret); 3171168404Spjd} 3172168404Spjd 3173168404Spjdstatic nvlist_t * 3174168404Spjdzpool_get_vdev_by_name(nvlist_t *nv, char *name) 3175168404Spjd{ 3176168404Spjd nvlist_t **child; 3177168404Spjd uint_t c, children; 3178168404Spjd nvlist_t *match; 3179168404Spjd char *path; 3180168404Spjd 3181168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 3182168404Spjd &child, &children) != 0) { 3183168404Spjd verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0); 3184219089Spjd if (strncmp(name, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) 3185219089Spjd name += sizeof(_PATH_DEV) - 1; 3186219089Spjd if (strncmp(path, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) 3187219089Spjd path += sizeof(_PATH_DEV) - 1; 3188168404Spjd if (strcmp(name, path) == 0) 3189168404Spjd return (nv); 3190168404Spjd return (NULL); 3191168404Spjd } 3192168404Spjd 3193168404Spjd for (c = 0; c < children; c++) 3194168404Spjd if ((match = zpool_get_vdev_by_name(child[c], name)) != NULL) 3195168404Spjd return (match); 3196168404Spjd 3197168404Spjd return (NULL); 3198168404Spjd} 3199168404Spjd 3200168404Spjdstatic int 3201168404Spjdzpool_do_attach_or_replace(int argc, char **argv, int replacing) 3202168404Spjd{ 3203168404Spjd boolean_t force = B_FALSE; 3204168404Spjd int c; 3205168404Spjd nvlist_t *nvroot; 3206168404Spjd char *poolname, *old_disk, *new_disk; 3207168404Spjd zpool_handle_t *zhp; 3208168404Spjd int ret; 3209168404Spjd 3210168404Spjd /* check options */ 3211168404Spjd while ((c = getopt(argc, argv, "f")) != -1) { 3212168404Spjd switch (c) { 3213168404Spjd case 'f': 3214168404Spjd force = B_TRUE; 3215168404Spjd break; 3216168404Spjd case '?': 3217168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3218168404Spjd optopt); 3219168404Spjd usage(B_FALSE); 3220168404Spjd } 3221168404Spjd } 3222168404Spjd 3223168404Spjd argc -= optind; 3224168404Spjd argv += optind; 3225168404Spjd 3226168404Spjd /* get pool name and check number of arguments */ 3227168404Spjd if (argc < 1) { 3228168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 3229168404Spjd usage(B_FALSE); 3230168404Spjd } 3231168404Spjd 3232168404Spjd poolname = argv[0]; 3233168404Spjd 3234168404Spjd if (argc < 2) { 3235168404Spjd (void) fprintf(stderr, 3236168404Spjd gettext("missing <device> specification\n")); 3237168404Spjd usage(B_FALSE); 3238168404Spjd } 3239168404Spjd 3240168404Spjd old_disk = argv[1]; 3241168404Spjd 3242168404Spjd if (argc < 3) { 3243168404Spjd if (!replacing) { 3244168404Spjd (void) fprintf(stderr, 3245168404Spjd gettext("missing <new_device> specification\n")); 3246168404Spjd usage(B_FALSE); 3247168404Spjd } 3248168404Spjd new_disk = old_disk; 3249168404Spjd argc -= 1; 3250168404Spjd argv += 1; 3251168404Spjd } else { 3252168404Spjd new_disk = argv[2]; 3253168404Spjd argc -= 2; 3254168404Spjd argv += 2; 3255168404Spjd } 3256168404Spjd 3257168404Spjd if (argc > 1) { 3258168404Spjd (void) fprintf(stderr, gettext("too many arguments\n")); 3259168404Spjd usage(B_FALSE); 3260168404Spjd } 3261168404Spjd 3262168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 3263168404Spjd return (1); 3264168404Spjd 3265185029Spjd if (zpool_get_config(zhp, NULL) == NULL) { 3266168404Spjd (void) fprintf(stderr, gettext("pool '%s' is unavailable\n"), 3267168404Spjd poolname); 3268168404Spjd zpool_close(zhp); 3269168404Spjd return (1); 3270168404Spjd } 3271168404Spjd 3272185029Spjd nvroot = make_root_vdev(zhp, force, B_FALSE, replacing, B_FALSE, 3273185029Spjd argc, argv); 3274168404Spjd if (nvroot == NULL) { 3275168404Spjd zpool_close(zhp); 3276168404Spjd return (1); 3277168404Spjd } 3278168404Spjd 3279168404Spjd ret = zpool_vdev_attach(zhp, old_disk, new_disk, nvroot, replacing); 3280168404Spjd 3281168404Spjd nvlist_free(nvroot); 3282168404Spjd zpool_close(zhp); 3283168404Spjd 3284168404Spjd return (ret); 3285168404Spjd} 3286168404Spjd 3287168404Spjd/* 3288168404Spjd * zpool replace [-f] <pool> <device> <new_device> 3289168404Spjd * 3290168404Spjd * -f Force attach, even if <new_device> appears to be in use. 3291168404Spjd * 3292168404Spjd * Replace <device> with <new_device>. 3293168404Spjd */ 3294168404Spjd/* ARGSUSED */ 3295168404Spjdint 3296168404Spjdzpool_do_replace(int argc, char **argv) 3297168404Spjd{ 3298168404Spjd return (zpool_do_attach_or_replace(argc, argv, B_TRUE)); 3299168404Spjd} 3300168404Spjd 3301168404Spjd/* 3302168404Spjd * zpool attach [-f] <pool> <device> <new_device> 3303168404Spjd * 3304168404Spjd * -f Force attach, even if <new_device> appears to be in use. 3305168404Spjd * 3306168404Spjd * Attach <new_device> to the mirror containing <device>. If <device> is not 3307168404Spjd * part of a mirror, then <device> will be transformed into a mirror of 3308168404Spjd * <device> and <new_device>. In either case, <new_device> will begin life 3309168404Spjd * with a DTL of [0, now], and will immediately begin to resilver itself. 3310168404Spjd */ 3311168404Spjdint 3312168404Spjdzpool_do_attach(int argc, char **argv) 3313168404Spjd{ 3314168404Spjd return (zpool_do_attach_or_replace(argc, argv, B_FALSE)); 3315168404Spjd} 3316168404Spjd 3317168404Spjd/* 3318168404Spjd * zpool detach [-f] <pool> <device> 3319168404Spjd * 3320168404Spjd * -f Force detach of <device>, even if DTLs argue against it 3321168404Spjd * (not supported yet) 3322168404Spjd * 3323168404Spjd * Detach a device from a mirror. The operation will be refused if <device> 3324168404Spjd * is the last device in the mirror, or if the DTLs indicate that this device 3325168404Spjd * has the only valid copy of some data. 3326168404Spjd */ 3327168404Spjd/* ARGSUSED */ 3328168404Spjdint 3329168404Spjdzpool_do_detach(int argc, char **argv) 3330168404Spjd{ 3331168404Spjd int c; 3332168404Spjd char *poolname, *path; 3333168404Spjd zpool_handle_t *zhp; 3334168404Spjd int ret; 3335168404Spjd 3336168404Spjd /* check options */ 3337168404Spjd while ((c = getopt(argc, argv, "f")) != -1) { 3338168404Spjd switch (c) { 3339168404Spjd case 'f': 3340168404Spjd case '?': 3341168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3342168404Spjd optopt); 3343168404Spjd usage(B_FALSE); 3344168404Spjd } 3345168404Spjd } 3346168404Spjd 3347168404Spjd argc -= optind; 3348168404Spjd argv += optind; 3349168404Spjd 3350168404Spjd /* get pool name and check number of arguments */ 3351168404Spjd if (argc < 1) { 3352168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 3353168404Spjd usage(B_FALSE); 3354168404Spjd } 3355168404Spjd 3356168404Spjd if (argc < 2) { 3357168404Spjd (void) fprintf(stderr, 3358168404Spjd gettext("missing <device> specification\n")); 3359168404Spjd usage(B_FALSE); 3360168404Spjd } 3361168404Spjd 3362168404Spjd poolname = argv[0]; 3363168404Spjd path = argv[1]; 3364168404Spjd 3365168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 3366168404Spjd return (1); 3367168404Spjd 3368168404Spjd ret = zpool_vdev_detach(zhp, path); 3369168404Spjd 3370168404Spjd zpool_close(zhp); 3371168404Spjd 3372168404Spjd return (ret); 3373168404Spjd} 3374168404Spjd 3375168404Spjd/* 3376219089Spjd * zpool split [-n] [-o prop=val] ... 3377219089Spjd * [-o mntopt] ... 3378219089Spjd * [-R altroot] <pool> <newpool> [<device> ...] 3379219089Spjd * 3380219089Spjd * -n Do not split the pool, but display the resulting layout if 3381219089Spjd * it were to be split. 3382219089Spjd * -o Set property=value, or set mount options. 3383219089Spjd * -R Mount the split-off pool under an alternate root. 3384219089Spjd * 3385219089Spjd * Splits the named pool and gives it the new pool name. Devices to be split 3386219089Spjd * off may be listed, provided that no more than one device is specified 3387219089Spjd * per top-level vdev mirror. The newly split pool is left in an exported 3388219089Spjd * state unless -R is specified. 3389219089Spjd * 3390219089Spjd * Restrictions: the top-level of the pool pool must only be made up of 3391219089Spjd * mirrors; all devices in the pool must be healthy; no device may be 3392219089Spjd * undergoing a resilvering operation. 3393219089Spjd */ 3394219089Spjdint 3395219089Spjdzpool_do_split(int argc, char **argv) 3396219089Spjd{ 3397219089Spjd char *srcpool, *newpool, *propval; 3398219089Spjd char *mntopts = NULL; 3399219089Spjd splitflags_t flags; 3400219089Spjd int c, ret = 0; 3401219089Spjd zpool_handle_t *zhp; 3402219089Spjd nvlist_t *config, *props = NULL; 3403219089Spjd 3404219089Spjd flags.dryrun = B_FALSE; 3405219089Spjd flags.import = B_FALSE; 3406219089Spjd 3407219089Spjd /* check options */ 3408219089Spjd while ((c = getopt(argc, argv, ":R:no:")) != -1) { 3409219089Spjd switch (c) { 3410219089Spjd case 'R': 3411219089Spjd flags.import = B_TRUE; 3412219089Spjd if (add_prop_list( 3413219089Spjd zpool_prop_to_name(ZPOOL_PROP_ALTROOT), optarg, 3414219089Spjd &props, B_TRUE) != 0) { 3415219089Spjd if (props) 3416219089Spjd nvlist_free(props); 3417219089Spjd usage(B_FALSE); 3418219089Spjd } 3419219089Spjd break; 3420219089Spjd case 'n': 3421219089Spjd flags.dryrun = B_TRUE; 3422219089Spjd break; 3423219089Spjd case 'o': 3424219089Spjd if ((propval = strchr(optarg, '=')) != NULL) { 3425219089Spjd *propval = '\0'; 3426219089Spjd propval++; 3427219089Spjd if (add_prop_list(optarg, propval, 3428219089Spjd &props, B_TRUE) != 0) { 3429219089Spjd if (props) 3430219089Spjd nvlist_free(props); 3431219089Spjd usage(B_FALSE); 3432219089Spjd } 3433219089Spjd } else { 3434219089Spjd mntopts = optarg; 3435219089Spjd } 3436219089Spjd break; 3437219089Spjd case ':': 3438219089Spjd (void) fprintf(stderr, gettext("missing argument for " 3439219089Spjd "'%c' option\n"), optopt); 3440219089Spjd usage(B_FALSE); 3441219089Spjd break; 3442219089Spjd case '?': 3443219089Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3444219089Spjd optopt); 3445219089Spjd usage(B_FALSE); 3446219089Spjd break; 3447219089Spjd } 3448219089Spjd } 3449219089Spjd 3450219089Spjd if (!flags.import && mntopts != NULL) { 3451219089Spjd (void) fprintf(stderr, gettext("setting mntopts is only " 3452219089Spjd "valid when importing the pool\n")); 3453219089Spjd usage(B_FALSE); 3454219089Spjd } 3455219089Spjd 3456219089Spjd argc -= optind; 3457219089Spjd argv += optind; 3458219089Spjd 3459219089Spjd if (argc < 1) { 3460219089Spjd (void) fprintf(stderr, gettext("Missing pool name\n")); 3461219089Spjd usage(B_FALSE); 3462219089Spjd } 3463219089Spjd if (argc < 2) { 3464219089Spjd (void) fprintf(stderr, gettext("Missing new pool name\n")); 3465219089Spjd usage(B_FALSE); 3466219089Spjd } 3467219089Spjd 3468219089Spjd srcpool = argv[0]; 3469219089Spjd newpool = argv[1]; 3470219089Spjd 3471219089Spjd argc -= 2; 3472219089Spjd argv += 2; 3473219089Spjd 3474219089Spjd if ((zhp = zpool_open(g_zfs, srcpool)) == NULL) 3475219089Spjd return (1); 3476219089Spjd 3477219089Spjd config = split_mirror_vdev(zhp, newpool, props, flags, argc, argv); 3478219089Spjd if (config == NULL) { 3479219089Spjd ret = 1; 3480219089Spjd } else { 3481219089Spjd if (flags.dryrun) { 3482219089Spjd (void) printf(gettext("would create '%s' with the " 3483219089Spjd "following layout:\n\n"), newpool); 3484219089Spjd print_vdev_tree(NULL, newpool, config, 0, B_FALSE); 3485219089Spjd } 3486219089Spjd nvlist_free(config); 3487219089Spjd } 3488219089Spjd 3489219089Spjd zpool_close(zhp); 3490219089Spjd 3491219089Spjd if (ret != 0 || flags.dryrun || !flags.import) 3492219089Spjd return (ret); 3493219089Spjd 3494219089Spjd /* 3495219089Spjd * The split was successful. Now we need to open the new 3496219089Spjd * pool and import it. 3497219089Spjd */ 3498219089Spjd if ((zhp = zpool_open_canfail(g_zfs, newpool)) == NULL) 3499219089Spjd return (1); 3500219089Spjd if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL && 3501219089Spjd zpool_enable_datasets(zhp, mntopts, 0) != 0) { 3502219089Spjd ret = 1; 3503240415Smm (void) fprintf(stderr, gettext("Split was successful, but " 3504219089Spjd "the datasets could not all be mounted\n")); 3505219089Spjd (void) fprintf(stderr, gettext("Try doing '%s' with a " 3506219089Spjd "different altroot\n"), "zpool import"); 3507219089Spjd } 3508219089Spjd zpool_close(zhp); 3509219089Spjd 3510219089Spjd return (ret); 3511219089Spjd} 3512219089Spjd 3513219089Spjd 3514219089Spjd 3515219089Spjd/* 3516168404Spjd * zpool online <pool> <device> ... 3517168404Spjd */ 3518168404Spjdint 3519168404Spjdzpool_do_online(int argc, char **argv) 3520168404Spjd{ 3521168404Spjd int c, i; 3522168404Spjd char *poolname; 3523168404Spjd zpool_handle_t *zhp; 3524168404Spjd int ret = 0; 3525185029Spjd vdev_state_t newstate; 3526219089Spjd int flags = 0; 3527168404Spjd 3528168404Spjd /* check options */ 3529219089Spjd while ((c = getopt(argc, argv, "et")) != -1) { 3530168404Spjd switch (c) { 3531219089Spjd case 'e': 3532219089Spjd flags |= ZFS_ONLINE_EXPAND; 3533219089Spjd break; 3534168404Spjd case 't': 3535168404Spjd case '?': 3536168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3537168404Spjd optopt); 3538168404Spjd usage(B_FALSE); 3539168404Spjd } 3540168404Spjd } 3541168404Spjd 3542168404Spjd argc -= optind; 3543168404Spjd argv += optind; 3544168404Spjd 3545168404Spjd /* get pool name and check number of arguments */ 3546168404Spjd if (argc < 1) { 3547168404Spjd (void) fprintf(stderr, gettext("missing pool name\n")); 3548168404Spjd usage(B_FALSE); 3549168404Spjd } 3550168404Spjd if (argc < 2) { 3551168404Spjd (void) fprintf(stderr, gettext("missing device name\n")); 3552168404Spjd usage(B_FALSE); 3553168404Spjd } 3554168404Spjd 3555168404Spjd poolname = argv[0]; 3556168404Spjd 3557168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 3558168404Spjd return (1); 3559168404Spjd 3560185029Spjd for (i = 1; i < argc; i++) { 3561219089Spjd if (zpool_vdev_online(zhp, argv[i], flags, &newstate) == 0) { 3562185029Spjd if (newstate != VDEV_STATE_HEALTHY) { 3563185029Spjd (void) printf(gettext("warning: device '%s' " 3564185029Spjd "onlined, but remains in faulted state\n"), 3565185029Spjd argv[i]); 3566185029Spjd if (newstate == VDEV_STATE_FAULTED) 3567185029Spjd (void) printf(gettext("use 'zpool " 3568185029Spjd "clear' to restore a faulted " 3569185029Spjd "device\n")); 3570185029Spjd else 3571185029Spjd (void) printf(gettext("use 'zpool " 3572185029Spjd "replace' to replace devices " 3573185029Spjd "that are no longer present\n")); 3574185029Spjd } 3575185029Spjd } else { 3576168404Spjd ret = 1; 3577185029Spjd } 3578185029Spjd } 3579168404Spjd 3580168404Spjd zpool_close(zhp); 3581168404Spjd 3582168404Spjd return (ret); 3583168404Spjd} 3584168404Spjd 3585168404Spjd/* 3586168404Spjd * zpool offline [-ft] <pool> <device> ... 3587168404Spjd * 3588168404Spjd * -f Force the device into the offline state, even if doing 3589168404Spjd * so would appear to compromise pool availability. 3590168404Spjd * (not supported yet) 3591168404Spjd * 3592168404Spjd * -t Only take the device off-line temporarily. The offline 3593168404Spjd * state will not be persistent across reboots. 3594168404Spjd */ 3595168404Spjd/* ARGSUSED */ 3596168404Spjdint 3597168404Spjdzpool_do_offline(int argc, char **argv) 3598168404Spjd{ 3599168404Spjd int c, i; 3600168404Spjd char *poolname; 3601168404Spjd zpool_handle_t *zhp; 3602168404Spjd int ret = 0; 3603168404Spjd boolean_t istmp = B_FALSE; 3604168404Spjd 3605168404Spjd /* check options */ 3606168404Spjd while ((c = getopt(argc, argv, "ft")) != -1) { 3607168404Spjd switch (c) { 3608168404Spjd case 't': 3609168404Spjd istmp = B_TRUE; 3610168404Spjd break; 3611168404Spjd case 'f': 3612168404Spjd case '?': 3613168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3614168404Spjd optopt); 3615168404Spjd usage(B_FALSE); 3616168404Spjd } 3617168404Spjd } 3618168404Spjd 3619168404Spjd argc -= optind; 3620168404Spjd argv += optind; 3621168404Spjd 3622168404Spjd /* get pool name and check number of arguments */ 3623168404Spjd if (argc < 1) { 3624168404Spjd (void) fprintf(stderr, gettext("missing pool name\n")); 3625168404Spjd usage(B_FALSE); 3626168404Spjd } 3627168404Spjd if (argc < 2) { 3628168404Spjd (void) fprintf(stderr, gettext("missing device name\n")); 3629168404Spjd usage(B_FALSE); 3630168404Spjd } 3631168404Spjd 3632168404Spjd poolname = argv[0]; 3633168404Spjd 3634168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 3635168404Spjd return (1); 3636168404Spjd 3637185029Spjd for (i = 1; i < argc; i++) { 3638185029Spjd if (zpool_vdev_offline(zhp, argv[i], istmp) != 0) 3639168404Spjd ret = 1; 3640185029Spjd } 3641168404Spjd 3642168404Spjd zpool_close(zhp); 3643168404Spjd 3644168404Spjd return (ret); 3645168404Spjd} 3646168404Spjd 3647168404Spjd/* 3648168404Spjd * zpool clear <pool> [device] 3649168404Spjd * 3650168404Spjd * Clear all errors associated with a pool or a particular device. 3651168404Spjd */ 3652168404Spjdint 3653168404Spjdzpool_do_clear(int argc, char **argv) 3654168404Spjd{ 3655219089Spjd int c; 3656168404Spjd int ret = 0; 3657219089Spjd boolean_t dryrun = B_FALSE; 3658219089Spjd boolean_t do_rewind = B_FALSE; 3659219089Spjd boolean_t xtreme_rewind = B_FALSE; 3660219089Spjd uint32_t rewind_policy = ZPOOL_NO_REWIND; 3661219089Spjd nvlist_t *policy = NULL; 3662168404Spjd zpool_handle_t *zhp; 3663168404Spjd char *pool, *device; 3664168404Spjd 3665219089Spjd /* check options */ 3666219089Spjd while ((c = getopt(argc, argv, "FnX")) != -1) { 3667219089Spjd switch (c) { 3668219089Spjd case 'F': 3669219089Spjd do_rewind = B_TRUE; 3670219089Spjd break; 3671219089Spjd case 'n': 3672219089Spjd dryrun = B_TRUE; 3673219089Spjd break; 3674219089Spjd case 'X': 3675219089Spjd xtreme_rewind = B_TRUE; 3676219089Spjd break; 3677219089Spjd case '?': 3678219089Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3679219089Spjd optopt); 3680219089Spjd usage(B_FALSE); 3681219089Spjd } 3682219089Spjd } 3683219089Spjd 3684219089Spjd argc -= optind; 3685219089Spjd argv += optind; 3686219089Spjd 3687219089Spjd if (argc < 1) { 3688168404Spjd (void) fprintf(stderr, gettext("missing pool name\n")); 3689168404Spjd usage(B_FALSE); 3690168404Spjd } 3691168404Spjd 3692219089Spjd if (argc > 2) { 3693168404Spjd (void) fprintf(stderr, gettext("too many arguments\n")); 3694168404Spjd usage(B_FALSE); 3695168404Spjd } 3696168404Spjd 3697219089Spjd if ((dryrun || xtreme_rewind) && !do_rewind) { 3698219089Spjd (void) fprintf(stderr, 3699219089Spjd gettext("-n or -X only meaningful with -F\n")); 3700219089Spjd usage(B_FALSE); 3701219089Spjd } 3702219089Spjd if (dryrun) 3703219089Spjd rewind_policy = ZPOOL_TRY_REWIND; 3704219089Spjd else if (do_rewind) 3705219089Spjd rewind_policy = ZPOOL_DO_REWIND; 3706219089Spjd if (xtreme_rewind) 3707219089Spjd rewind_policy |= ZPOOL_EXTREME_REWIND; 3708168404Spjd 3709219089Spjd /* In future, further rewind policy choices can be passed along here */ 3710219089Spjd if (nvlist_alloc(&policy, NV_UNIQUE_NAME, 0) != 0 || 3711219089Spjd nvlist_add_uint32(policy, ZPOOL_REWIND_REQUEST, rewind_policy) != 0) 3712168404Spjd return (1); 3713168404Spjd 3714219089Spjd pool = argv[0]; 3715219089Spjd device = argc == 2 ? argv[1] : NULL; 3716219089Spjd 3717219089Spjd if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) { 3718219089Spjd nvlist_free(policy); 3719219089Spjd return (1); 3720219089Spjd } 3721219089Spjd 3722219089Spjd if (zpool_clear(zhp, device, policy) != 0) 3723168404Spjd ret = 1; 3724168404Spjd 3725168404Spjd zpool_close(zhp); 3726168404Spjd 3727219089Spjd nvlist_free(policy); 3728219089Spjd 3729168404Spjd return (ret); 3730168404Spjd} 3731168404Spjd 3732228103Smm/* 3733228103Smm * zpool reguid <pool> 3734228103Smm */ 3735228103Smmint 3736228103Smmzpool_do_reguid(int argc, char **argv) 3737228103Smm{ 3738228103Smm int c; 3739228103Smm char *poolname; 3740228103Smm zpool_handle_t *zhp; 3741228103Smm int ret = 0; 3742228103Smm 3743228103Smm /* check options */ 3744228103Smm while ((c = getopt(argc, argv, "")) != -1) { 3745228103Smm switch (c) { 3746228103Smm case '?': 3747228103Smm (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3748228103Smm optopt); 3749228103Smm usage(B_FALSE); 3750228103Smm } 3751228103Smm } 3752228103Smm 3753228103Smm argc -= optind; 3754228103Smm argv += optind; 3755228103Smm 3756228103Smm /* get pool name and check number of arguments */ 3757228103Smm if (argc < 1) { 3758228103Smm (void) fprintf(stderr, gettext("missing pool name\n")); 3759228103Smm usage(B_FALSE); 3760228103Smm } 3761228103Smm 3762228103Smm if (argc > 1) { 3763228103Smm (void) fprintf(stderr, gettext("too many arguments\n")); 3764228103Smm usage(B_FALSE); 3765228103Smm } 3766228103Smm 3767228103Smm poolname = argv[0]; 3768228103Smm if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 3769228103Smm return (1); 3770228103Smm 3771228103Smm ret = zpool_reguid(zhp); 3772228103Smm 3773228103Smm zpool_close(zhp); 3774228103Smm return (ret); 3775228103Smm} 3776228103Smm 3777228103Smm 3778236155Smm/* 3779236155Smm * zpool reopen <pool> 3780236155Smm * 3781236155Smm * Reopen the pool so that the kernel can update the sizes of all vdevs. 3782236155Smm */ 3783236155Smmint 3784236155Smmzpool_do_reopen(int argc, char **argv) 3785236155Smm{ 3786260138Sdelphij int c; 3787236155Smm int ret = 0; 3788236155Smm zpool_handle_t *zhp; 3789236155Smm char *pool; 3790236155Smm 3791260138Sdelphij /* check options */ 3792260138Sdelphij while ((c = getopt(argc, argv, "")) != -1) { 3793260138Sdelphij switch (c) { 3794260138Sdelphij case '?': 3795260138Sdelphij (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3796260138Sdelphij optopt); 3797260138Sdelphij usage(B_FALSE); 3798260138Sdelphij } 3799260138Sdelphij } 3800260138Sdelphij 3801236155Smm argc--; 3802236155Smm argv++; 3803236155Smm 3804260138Sdelphij if (argc < 1) { 3805260138Sdelphij (void) fprintf(stderr, gettext("missing pool name\n")); 3806260138Sdelphij usage(B_FALSE); 3807260138Sdelphij } 3808236155Smm 3809260138Sdelphij if (argc > 1) { 3810260138Sdelphij (void) fprintf(stderr, gettext("too many arguments\n")); 3811260138Sdelphij usage(B_FALSE); 3812260138Sdelphij } 3813260138Sdelphij 3814236155Smm pool = argv[0]; 3815236155Smm if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) 3816236155Smm return (1); 3817236155Smm 3818236155Smm ret = zpool_reopen(zhp); 3819236155Smm zpool_close(zhp); 3820236155Smm return (ret); 3821236155Smm} 3822236155Smm 3823168404Spjdtypedef struct scrub_cbdata { 3824168404Spjd int cb_type; 3825168404Spjd int cb_argc; 3826168404Spjd char **cb_argv; 3827168404Spjd} scrub_cbdata_t; 3828168404Spjd 3829168404Spjdint 3830168404Spjdscrub_callback(zpool_handle_t *zhp, void *data) 3831168404Spjd{ 3832168404Spjd scrub_cbdata_t *cb = data; 3833168404Spjd int err; 3834168404Spjd 3835168404Spjd /* 3836168404Spjd * Ignore faulted pools. 3837168404Spjd */ 3838168404Spjd if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) { 3839168404Spjd (void) fprintf(stderr, gettext("cannot scrub '%s': pool is " 3840168404Spjd "currently unavailable\n"), zpool_get_name(zhp)); 3841168404Spjd return (1); 3842168404Spjd } 3843168404Spjd 3844219089Spjd err = zpool_scan(zhp, cb->cb_type); 3845168404Spjd 3846168404Spjd return (err != 0); 3847168404Spjd} 3848168404Spjd 3849168404Spjd/* 3850168404Spjd * zpool scrub [-s] <pool> ... 3851168404Spjd * 3852168404Spjd * -s Stop. Stops any in-progress scrub. 3853168404Spjd */ 3854168404Spjdint 3855168404Spjdzpool_do_scrub(int argc, char **argv) 3856168404Spjd{ 3857168404Spjd int c; 3858168404Spjd scrub_cbdata_t cb; 3859168404Spjd 3860219089Spjd cb.cb_type = POOL_SCAN_SCRUB; 3861168404Spjd 3862168404Spjd /* check options */ 3863168404Spjd while ((c = getopt(argc, argv, "s")) != -1) { 3864168404Spjd switch (c) { 3865168404Spjd case 's': 3866219089Spjd cb.cb_type = POOL_SCAN_NONE; 3867168404Spjd break; 3868168404Spjd case '?': 3869168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3870168404Spjd optopt); 3871168404Spjd usage(B_FALSE); 3872168404Spjd } 3873168404Spjd } 3874168404Spjd 3875168404Spjd cb.cb_argc = argc; 3876168404Spjd cb.cb_argv = argv; 3877168404Spjd argc -= optind; 3878168404Spjd argv += optind; 3879168404Spjd 3880168404Spjd if (argc < 1) { 3881168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 3882168404Spjd usage(B_FALSE); 3883168404Spjd } 3884168404Spjd 3885168404Spjd return (for_each_pool(argc, argv, B_TRUE, NULL, scrub_callback, &cb)); 3886168404Spjd} 3887168404Spjd 3888168404Spjdtypedef struct status_cbdata { 3889168404Spjd int cb_count; 3890168404Spjd boolean_t cb_allpools; 3891168404Spjd boolean_t cb_verbose; 3892168404Spjd boolean_t cb_explain; 3893168404Spjd boolean_t cb_first; 3894219089Spjd boolean_t cb_dedup_stats; 3895168404Spjd} status_cbdata_t; 3896168404Spjd 3897168404Spjd/* 3898168404Spjd * Print out detailed scrub status. 3899168404Spjd */ 3900168404Spjdvoid 3901219089Spjdprint_scan_status(pool_scan_stat_t *ps) 3902168404Spjd{ 3903219089Spjd time_t start, end; 3904219089Spjd uint64_t elapsed, mins_left, hours_left; 3905219089Spjd uint64_t pass_exam, examined, total; 3906219089Spjd uint_t rate; 3907168404Spjd double fraction_done; 3908219089Spjd char processed_buf[7], examined_buf[7], total_buf[7], rate_buf[7]; 3909168404Spjd 3910226583Spjd (void) printf(gettext(" scan: ")); 3911168404Spjd 3912219089Spjd /* If there's never been a scan, there's not much to say. */ 3913219089Spjd if (ps == NULL || ps->pss_func == POOL_SCAN_NONE || 3914219089Spjd ps->pss_func >= POOL_SCAN_FUNCS) { 3915168404Spjd (void) printf(gettext("none requested\n")); 3916168404Spjd return; 3917168404Spjd } 3918168404Spjd 3919219089Spjd start = ps->pss_start_time; 3920219089Spjd end = ps->pss_end_time; 3921219089Spjd zfs_nicenum(ps->pss_processed, processed_buf, sizeof (processed_buf)); 3922168404Spjd 3923219089Spjd assert(ps->pss_func == POOL_SCAN_SCRUB || 3924219089Spjd ps->pss_func == POOL_SCAN_RESILVER); 3925219089Spjd /* 3926219089Spjd * Scan is finished or canceled. 3927219089Spjd */ 3928219089Spjd if (ps->pss_state == DSS_FINISHED) { 3929219089Spjd uint64_t minutes_taken = (end - start) / 60; 3930219089Spjd char *fmt; 3931168404Spjd 3932219089Spjd if (ps->pss_func == POOL_SCAN_SCRUB) { 3933219089Spjd fmt = gettext("scrub repaired %s in %lluh%um with " 3934219089Spjd "%llu errors on %s"); 3935219089Spjd } else if (ps->pss_func == POOL_SCAN_RESILVER) { 3936219089Spjd fmt = gettext("resilvered %s in %lluh%um with " 3937219089Spjd "%llu errors on %s"); 3938219089Spjd } 3939219089Spjd /* LINTED */ 3940219089Spjd (void) printf(fmt, processed_buf, 3941185029Spjd (u_longlong_t)(minutes_taken / 60), 3942185029Spjd (uint_t)(minutes_taken % 60), 3943219089Spjd (u_longlong_t)ps->pss_errors, 3944219089Spjd ctime((time_t *)&end)); 3945168404Spjd return; 3946219089Spjd } else if (ps->pss_state == DSS_CANCELED) { 3947219089Spjd if (ps->pss_func == POOL_SCAN_SCRUB) { 3948219089Spjd (void) printf(gettext("scrub canceled on %s"), 3949219089Spjd ctime(&end)); 3950219089Spjd } else if (ps->pss_func == POOL_SCAN_RESILVER) { 3951219089Spjd (void) printf(gettext("resilver canceled on %s"), 3952219089Spjd ctime(&end)); 3953219089Spjd } 3954219089Spjd return; 3955168404Spjd } 3956168404Spjd 3957219089Spjd assert(ps->pss_state == DSS_SCANNING); 3958168404Spjd 3959219089Spjd /* 3960219089Spjd * Scan is in progress. 3961219089Spjd */ 3962219089Spjd if (ps->pss_func == POOL_SCAN_SCRUB) { 3963219089Spjd (void) printf(gettext("scrub in progress since %s"), 3964219089Spjd ctime(&start)); 3965219089Spjd } else if (ps->pss_func == POOL_SCAN_RESILVER) { 3966219089Spjd (void) printf(gettext("resilver in progress since %s"), 3967219089Spjd ctime(&start)); 3968219089Spjd } 3969219089Spjd 3970219089Spjd examined = ps->pss_examined ? ps->pss_examined : 1; 3971219089Spjd total = ps->pss_to_examine; 3972168404Spjd fraction_done = (double)examined / total; 3973168404Spjd 3974219089Spjd /* elapsed time for this pass */ 3975219089Spjd elapsed = time(NULL) - ps->pss_pass_start; 3976219089Spjd elapsed = elapsed ? elapsed : 1; 3977219089Spjd pass_exam = ps->pss_pass_exam ? ps->pss_pass_exam : 1; 3978219089Spjd rate = pass_exam / elapsed; 3979219089Spjd rate = rate ? rate : 1; 3980219089Spjd mins_left = ((total - examined) / rate) / 60; 3981219089Spjd hours_left = mins_left / 60; 3982219089Spjd 3983219089Spjd zfs_nicenum(examined, examined_buf, sizeof (examined_buf)); 3984219089Spjd zfs_nicenum(total, total_buf, sizeof (total_buf)); 3985219089Spjd zfs_nicenum(rate, rate_buf, sizeof (rate_buf)); 3986219089Spjd 3987219089Spjd /* 3988219089Spjd * do not print estimated time if hours_left is more than 30 days 3989219089Spjd */ 3990226583Spjd (void) printf(gettext(" %s scanned out of %s at %s/s"), 3991219089Spjd examined_buf, total_buf, rate_buf); 3992219089Spjd if (hours_left < (30 * 24)) { 3993219089Spjd (void) printf(gettext(", %lluh%um to go\n"), 3994219089Spjd (u_longlong_t)hours_left, (uint_t)(mins_left % 60)); 3995219089Spjd } else { 3996219089Spjd (void) printf(gettext( 3997219089Spjd ", (scan is slow, no estimated time)\n")); 3998219089Spjd } 3999219089Spjd 4000219089Spjd if (ps->pss_func == POOL_SCAN_RESILVER) { 4001226583Spjd (void) printf(gettext(" %s resilvered, %.2f%% done\n"), 4002219089Spjd processed_buf, 100 * fraction_done); 4003219089Spjd } else if (ps->pss_func == POOL_SCAN_SCRUB) { 4004226583Spjd (void) printf(gettext(" %s repaired, %.2f%% done\n"), 4005219089Spjd processed_buf, 100 * fraction_done); 4006219089Spjd } 4007168404Spjd} 4008168404Spjd 4009168404Spjdstatic void 4010168404Spjdprint_error_log(zpool_handle_t *zhp) 4011168404Spjd{ 4012185029Spjd nvlist_t *nverrlist = NULL; 4013168404Spjd nvpair_t *elem; 4014168404Spjd char *pathname; 4015168404Spjd size_t len = MAXPATHLEN * 2; 4016168404Spjd 4017168404Spjd if (zpool_get_errlog(zhp, &nverrlist) != 0) { 4018168404Spjd (void) printf("errors: List of errors unavailable " 4019168404Spjd "(insufficient privileges)\n"); 4020168404Spjd return; 4021168404Spjd } 4022168404Spjd 4023168404Spjd (void) printf("errors: Permanent errors have been " 4024168404Spjd "detected in the following files:\n\n"); 4025168404Spjd 4026168404Spjd pathname = safe_malloc(len); 4027168404Spjd elem = NULL; 4028168404Spjd while ((elem = nvlist_next_nvpair(nverrlist, elem)) != NULL) { 4029168404Spjd nvlist_t *nv; 4030168404Spjd uint64_t dsobj, obj; 4031168404Spjd 4032168404Spjd verify(nvpair_value_nvlist(elem, &nv) == 0); 4033168404Spjd verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_DATASET, 4034168404Spjd &dsobj) == 0); 4035168404Spjd verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_OBJECT, 4036168404Spjd &obj) == 0); 4037168404Spjd zpool_obj_to_path(zhp, dsobj, obj, pathname, len); 4038168404Spjd (void) printf("%7s %s\n", "", pathname); 4039168404Spjd } 4040168404Spjd free(pathname); 4041168404Spjd nvlist_free(nverrlist); 4042168404Spjd} 4043168404Spjd 4044168404Spjdstatic void 4045168404Spjdprint_spares(zpool_handle_t *zhp, nvlist_t **spares, uint_t nspares, 4046168404Spjd int namewidth) 4047168404Spjd{ 4048168404Spjd uint_t i; 4049168404Spjd char *name; 4050168404Spjd 4051168404Spjd if (nspares == 0) 4052168404Spjd return; 4053168404Spjd 4054168404Spjd (void) printf(gettext("\tspares\n")); 4055168404Spjd 4056168404Spjd for (i = 0; i < nspares; i++) { 4057219089Spjd name = zpool_vdev_name(g_zfs, zhp, spares[i], B_FALSE); 4058168404Spjd print_status_config(zhp, name, spares[i], 4059209962Smm namewidth, 2, B_TRUE); 4060168404Spjd free(name); 4061168404Spjd } 4062168404Spjd} 4063168404Spjd 4064185029Spjdstatic void 4065185029Spjdprint_l2cache(zpool_handle_t *zhp, nvlist_t **l2cache, uint_t nl2cache, 4066185029Spjd int namewidth) 4067185029Spjd{ 4068185029Spjd uint_t i; 4069185029Spjd char *name; 4070185029Spjd 4071185029Spjd if (nl2cache == 0) 4072185029Spjd return; 4073185029Spjd 4074185029Spjd (void) printf(gettext("\tcache\n")); 4075185029Spjd 4076185029Spjd for (i = 0; i < nl2cache; i++) { 4077219089Spjd name = zpool_vdev_name(g_zfs, zhp, l2cache[i], B_FALSE); 4078185029Spjd print_status_config(zhp, name, l2cache[i], 4079209962Smm namewidth, 2, B_FALSE); 4080185029Spjd free(name); 4081185029Spjd } 4082185029Spjd} 4083185029Spjd 4084219089Spjdstatic void 4085219089Spjdprint_dedup_stats(nvlist_t *config) 4086219089Spjd{ 4087219089Spjd ddt_histogram_t *ddh; 4088219089Spjd ddt_stat_t *dds; 4089219089Spjd ddt_object_t *ddo; 4090219089Spjd uint_t c; 4091219089Spjd 4092219089Spjd /* 4093219089Spjd * If the pool was faulted then we may not have been able to 4094253441Sdelphij * obtain the config. Otherwise, if we have anything in the dedup 4095219089Spjd * table continue processing the stats. 4096219089Spjd */ 4097219089Spjd if (nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_OBJ_STATS, 4098227497Smm (uint64_t **)&ddo, &c) != 0) 4099219089Spjd return; 4100219089Spjd 4101219089Spjd (void) printf("\n"); 4102227497Smm (void) printf(gettext(" dedup: ")); 4103227497Smm if (ddo->ddo_count == 0) { 4104227497Smm (void) printf(gettext("no DDT entries\n")); 4105227497Smm return; 4106227497Smm } 4107227497Smm 4108219089Spjd (void) printf("DDT entries %llu, size %llu on disk, %llu in core\n", 4109219089Spjd (u_longlong_t)ddo->ddo_count, 4110219089Spjd (u_longlong_t)ddo->ddo_dspace, 4111219089Spjd (u_longlong_t)ddo->ddo_mspace); 4112219089Spjd 4113219089Spjd verify(nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_STATS, 4114219089Spjd (uint64_t **)&dds, &c) == 0); 4115219089Spjd verify(nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_HISTOGRAM, 4116219089Spjd (uint64_t **)&ddh, &c) == 0); 4117219089Spjd zpool_dump_ddt(dds, ddh); 4118219089Spjd} 4119219089Spjd 4120168404Spjd/* 4121168404Spjd * Display a summary of pool status. Displays a summary such as: 4122168404Spjd * 4123168404Spjd * pool: tank 4124168404Spjd * status: DEGRADED 4125168404Spjd * reason: One or more devices ... 4126236146Smm * see: http://illumos.org/msg/ZFS-xxxx-01 4127168404Spjd * config: 4128168404Spjd * mirror DEGRADED 4129168404Spjd * c1t0d0 OK 4130168404Spjd * c2t0d0 UNAVAIL 4131168404Spjd * 4132168404Spjd * When given the '-v' option, we print out the complete config. If the '-e' 4133168404Spjd * option is specified, then we print out error rate information as well. 4134168404Spjd */ 4135168404Spjdint 4136168404Spjdstatus_callback(zpool_handle_t *zhp, void *data) 4137168404Spjd{ 4138168404Spjd status_cbdata_t *cbp = data; 4139168404Spjd nvlist_t *config, *nvroot; 4140168404Spjd char *msgid; 4141168404Spjd int reason; 4142168404Spjd const char *health; 4143168404Spjd uint_t c; 4144168404Spjd vdev_stat_t *vs; 4145168404Spjd 4146168404Spjd config = zpool_get_config(zhp, NULL); 4147168404Spjd reason = zpool_get_status(zhp, &msgid); 4148168404Spjd 4149168404Spjd cbp->cb_count++; 4150168404Spjd 4151168404Spjd /* 4152168404Spjd * If we were given 'zpool status -x', only report those pools with 4153168404Spjd * problems. 4154168404Spjd */ 4155248267Smm if (cbp->cb_explain && 4156248267Smm (reason == ZPOOL_STATUS_OK || 4157248267Smm reason == ZPOOL_STATUS_VERSION_OLDER || 4158268621Ssmh reason == ZPOOL_STATUS_NON_NATIVE_ASHIFT || 4159248267Smm reason == ZPOOL_STATUS_FEAT_DISABLED)) { 4160168404Spjd if (!cbp->cb_allpools) { 4161168404Spjd (void) printf(gettext("pool '%s' is healthy\n"), 4162168404Spjd zpool_get_name(zhp)); 4163168404Spjd if (cbp->cb_first) 4164168404Spjd cbp->cb_first = B_FALSE; 4165168404Spjd } 4166168404Spjd return (0); 4167168404Spjd } 4168168404Spjd 4169168404Spjd if (cbp->cb_first) 4170168404Spjd cbp->cb_first = B_FALSE; 4171168404Spjd else 4172168404Spjd (void) printf("\n"); 4173168404Spjd 4174168404Spjd verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 4175168404Spjd &nvroot) == 0); 4176219089Spjd verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS, 4177168404Spjd (uint64_t **)&vs, &c) == 0); 4178185029Spjd health = zpool_state_to_name(vs->vs_state, vs->vs_aux); 4179168404Spjd 4180168404Spjd (void) printf(gettext(" pool: %s\n"), zpool_get_name(zhp)); 4181168404Spjd (void) printf(gettext(" state: %s\n"), health); 4182168404Spjd 4183168404Spjd switch (reason) { 4184168404Spjd case ZPOOL_STATUS_MISSING_DEV_R: 4185168404Spjd (void) printf(gettext("status: One or more devices could not " 4186168404Spjd "be opened. Sufficient replicas exist for\n\tthe pool to " 4187168404Spjd "continue functioning in a degraded state.\n")); 4188168404Spjd (void) printf(gettext("action: Attach the missing device and " 4189168404Spjd "online it using 'zpool online'.\n")); 4190168404Spjd break; 4191168404Spjd 4192168404Spjd case ZPOOL_STATUS_MISSING_DEV_NR: 4193168404Spjd (void) printf(gettext("status: One or more devices could not " 4194168404Spjd "be opened. There are insufficient\n\treplicas for the " 4195168404Spjd "pool to continue functioning.\n")); 4196168404Spjd (void) printf(gettext("action: Attach the missing device and " 4197168404Spjd "online it using 'zpool online'.\n")); 4198168404Spjd break; 4199168404Spjd 4200168404Spjd case ZPOOL_STATUS_CORRUPT_LABEL_R: 4201168404Spjd (void) printf(gettext("status: One or more devices could not " 4202168404Spjd "be used because the label is missing or\n\tinvalid. " 4203168404Spjd "Sufficient replicas exist for the pool to continue\n\t" 4204168404Spjd "functioning in a degraded state.\n")); 4205168404Spjd (void) printf(gettext("action: Replace the device using " 4206168404Spjd "'zpool replace'.\n")); 4207168404Spjd break; 4208168404Spjd 4209168404Spjd case ZPOOL_STATUS_CORRUPT_LABEL_NR: 4210168404Spjd (void) printf(gettext("status: One or more devices could not " 4211168404Spjd "be used because the label is missing \n\tor invalid. " 4212168404Spjd "There are insufficient replicas for the pool to " 4213168404Spjd "continue\n\tfunctioning.\n")); 4214219089Spjd zpool_explain_recover(zpool_get_handle(zhp), 4215219089Spjd zpool_get_name(zhp), reason, config); 4216168404Spjd break; 4217168404Spjd 4218168404Spjd case ZPOOL_STATUS_FAILING_DEV: 4219168404Spjd (void) printf(gettext("status: One or more devices has " 4220168404Spjd "experienced an unrecoverable error. An\n\tattempt was " 4221168404Spjd "made to correct the error. Applications are " 4222168404Spjd "unaffected.\n")); 4223168404Spjd (void) printf(gettext("action: Determine if the device needs " 4224168404Spjd "to be replaced, and clear the errors\n\tusing " 4225168404Spjd "'zpool clear' or replace the device with 'zpool " 4226168404Spjd "replace'.\n")); 4227168404Spjd break; 4228168404Spjd 4229168404Spjd case ZPOOL_STATUS_OFFLINE_DEV: 4230168404Spjd (void) printf(gettext("status: One or more devices has " 4231168404Spjd "been taken offline by the administrator.\n\tSufficient " 4232168404Spjd "replicas exist for the pool to continue functioning in " 4233168404Spjd "a\n\tdegraded state.\n")); 4234168404Spjd (void) printf(gettext("action: Online the device using " 4235168404Spjd "'zpool online' or replace the device with\n\t'zpool " 4236168404Spjd "replace'.\n")); 4237168404Spjd break; 4238168404Spjd 4239219089Spjd case ZPOOL_STATUS_REMOVED_DEV: 4240219089Spjd (void) printf(gettext("status: One or more devices has " 4241219089Spjd "been removed by the administrator.\n\tSufficient " 4242219089Spjd "replicas exist for the pool to continue functioning in " 4243219089Spjd "a\n\tdegraded state.\n")); 4244219089Spjd (void) printf(gettext("action: Online the device using " 4245219089Spjd "'zpool online' or replace the device with\n\t'zpool " 4246219089Spjd "replace'.\n")); 4247219089Spjd break; 4248219089Spjd 4249168404Spjd case ZPOOL_STATUS_RESILVERING: 4250168404Spjd (void) printf(gettext("status: One or more devices is " 4251168404Spjd "currently being resilvered. The pool will\n\tcontinue " 4252168404Spjd "to function, possibly in a degraded state.\n")); 4253168404Spjd (void) printf(gettext("action: Wait for the resilver to " 4254168404Spjd "complete.\n")); 4255168404Spjd break; 4256168404Spjd 4257168404Spjd case ZPOOL_STATUS_CORRUPT_DATA: 4258168404Spjd (void) printf(gettext("status: One or more devices has " 4259168404Spjd "experienced an error resulting in data\n\tcorruption. " 4260168404Spjd "Applications may be affected.\n")); 4261168404Spjd (void) printf(gettext("action: Restore the file in question " 4262168404Spjd "if possible. Otherwise restore the\n\tentire pool from " 4263168404Spjd "backup.\n")); 4264168404Spjd break; 4265168404Spjd 4266168404Spjd case ZPOOL_STATUS_CORRUPT_POOL: 4267168404Spjd (void) printf(gettext("status: The pool metadata is corrupted " 4268168404Spjd "and the pool cannot be opened.\n")); 4269219089Spjd zpool_explain_recover(zpool_get_handle(zhp), 4270219089Spjd zpool_get_name(zhp), reason, config); 4271168404Spjd break; 4272168404Spjd 4273168404Spjd case ZPOOL_STATUS_VERSION_OLDER: 4274238926Smm (void) printf(gettext("status: The pool is formatted using a " 4275238926Smm "legacy on-disk format. The pool can\n\tstill be used, " 4276238926Smm "but some features are unavailable.\n")); 4277168404Spjd (void) printf(gettext("action: Upgrade the pool using 'zpool " 4278168404Spjd "upgrade'. Once this is done, the\n\tpool will no longer " 4279238926Smm "be accessible on software that does not support feature\n" 4280238926Smm "\tflags.\n")); 4281168404Spjd break; 4282168404Spjd 4283168404Spjd case ZPOOL_STATUS_VERSION_NEWER: 4284168404Spjd (void) printf(gettext("status: The pool has been upgraded to a " 4285168404Spjd "newer, incompatible on-disk version.\n\tThe pool cannot " 4286168404Spjd "be accessed on this system.\n")); 4287168404Spjd (void) printf(gettext("action: Access the pool from a system " 4288168404Spjd "running more recent software, or\n\trestore the pool from " 4289168404Spjd "backup.\n")); 4290168404Spjd break; 4291168404Spjd 4292238926Smm case ZPOOL_STATUS_FEAT_DISABLED: 4293238926Smm (void) printf(gettext("status: Some supported features are not " 4294238926Smm "enabled on the pool. The pool can\n\tstill be used, but " 4295238926Smm "some features are unavailable.\n")); 4296238926Smm (void) printf(gettext("action: Enable all features using " 4297238926Smm "'zpool upgrade'. Once this is done,\n\tthe pool may no " 4298238926Smm "longer be accessible by software that does not support\n\t" 4299243014Smm "the features. See zpool-features(7) for details.\n")); 4300238926Smm break; 4301238926Smm 4302236884Smm case ZPOOL_STATUS_UNSUP_FEAT_READ: 4303236884Smm (void) printf(gettext("status: The pool cannot be accessed on " 4304236884Smm "this system because it uses the\n\tfollowing feature(s) " 4305236884Smm "not supported on this system:\n")); 4306236884Smm zpool_print_unsup_feat(config); 4307236884Smm (void) printf("\n"); 4308236884Smm (void) printf(gettext("action: Access the pool from a system " 4309236884Smm "that supports the required feature(s),\n\tor restore the " 4310236884Smm "pool from backup.\n")); 4311236884Smm break; 4312236884Smm 4313236884Smm case ZPOOL_STATUS_UNSUP_FEAT_WRITE: 4314236884Smm (void) printf(gettext("status: The pool can only be accessed " 4315236884Smm "in read-only mode on this system. It\n\tcannot be " 4316236884Smm "accessed in read-write mode because it uses the " 4317236884Smm "following\n\tfeature(s) not supported on this system:\n")); 4318236884Smm zpool_print_unsup_feat(config); 4319236884Smm (void) printf("\n"); 4320236884Smm (void) printf(gettext("action: The pool cannot be accessed in " 4321236884Smm "read-write mode. Import the pool with\n" 4322236884Smm "\t\"-o readonly=on\", access the pool from a system that " 4323236884Smm "supports the\n\trequired feature(s), or restore the " 4324236884Smm "pool from backup.\n")); 4325236884Smm break; 4326236884Smm 4327185029Spjd case ZPOOL_STATUS_FAULTED_DEV_R: 4328185029Spjd (void) printf(gettext("status: One or more devices are " 4329185029Spjd "faulted in response to persistent errors.\n\tSufficient " 4330185029Spjd "replicas exist for the pool to continue functioning " 4331185029Spjd "in a\n\tdegraded state.\n")); 4332185029Spjd (void) printf(gettext("action: Replace the faulted device, " 4333185029Spjd "or use 'zpool clear' to mark the device\n\trepaired.\n")); 4334185029Spjd break; 4335185029Spjd 4336185029Spjd case ZPOOL_STATUS_FAULTED_DEV_NR: 4337185029Spjd (void) printf(gettext("status: One or more devices are " 4338185029Spjd "faulted in response to persistent errors. There are " 4339185029Spjd "insufficient replicas for the pool to\n\tcontinue " 4340185029Spjd "functioning.\n")); 4341185029Spjd (void) printf(gettext("action: Destroy and re-create the pool " 4342185029Spjd "from a backup source. Manually marking the device\n" 4343185029Spjd "\trepaired using 'zpool clear' may allow some data " 4344185029Spjd "to be recovered.\n")); 4345185029Spjd break; 4346185029Spjd 4347185029Spjd case ZPOOL_STATUS_IO_FAILURE_WAIT: 4348185029Spjd case ZPOOL_STATUS_IO_FAILURE_CONTINUE: 4349185029Spjd (void) printf(gettext("status: One or more devices are " 4350185029Spjd "faulted in response to IO failures.\n")); 4351185029Spjd (void) printf(gettext("action: Make sure the affected devices " 4352185029Spjd "are connected, then run 'zpool clear'.\n")); 4353185029Spjd break; 4354185029Spjd 4355185029Spjd case ZPOOL_STATUS_BAD_LOG: 4356185029Spjd (void) printf(gettext("status: An intent log record " 4357185029Spjd "could not be read.\n" 4358185029Spjd "\tWaiting for adminstrator intervention to fix the " 4359185029Spjd "faulted pool.\n")); 4360185029Spjd (void) printf(gettext("action: Either restore the affected " 4361185029Spjd "device(s) and run 'zpool online',\n" 4362185029Spjd "\tor ignore the intent log records by running " 4363185029Spjd "'zpool clear'.\n")); 4364185029Spjd break; 4365185029Spjd 4366254591Sgibbs case ZPOOL_STATUS_NON_NATIVE_ASHIFT: 4367254591Sgibbs (void) printf(gettext("status: One or more devices are " 4368254591Sgibbs "configured to use a non-native block size.\n" 4369254591Sgibbs "\tExpect reduced performance.\n")); 4370254591Sgibbs (void) printf(gettext("action: Replace affected devices with " 4371254591Sgibbs "devices that support the\n\tconfigured block size, or " 4372254591Sgibbs "migrate data to a properly configured\n\tpool.\n")); 4373254591Sgibbs break; 4374254591Sgibbs 4375168404Spjd default: 4376168404Spjd /* 4377168404Spjd * The remaining errors can't actually be generated, yet. 4378168404Spjd */ 4379168404Spjd assert(reason == ZPOOL_STATUS_OK); 4380168404Spjd } 4381168404Spjd 4382168404Spjd if (msgid != NULL) 4383236146Smm (void) printf(gettext(" see: http://illumos.org/msg/%s\n"), 4384168404Spjd msgid); 4385168404Spjd 4386168404Spjd if (config != NULL) { 4387168404Spjd int namewidth; 4388168404Spjd uint64_t nerr; 4389185029Spjd nvlist_t **spares, **l2cache; 4390185029Spjd uint_t nspares, nl2cache; 4391219089Spjd pool_scan_stat_t *ps = NULL; 4392168404Spjd 4393219089Spjd (void) nvlist_lookup_uint64_array(nvroot, 4394219089Spjd ZPOOL_CONFIG_SCAN_STATS, (uint64_t **)&ps, &c); 4395219089Spjd print_scan_status(ps); 4396168404Spjd 4397168404Spjd namewidth = max_width(zhp, nvroot, 0, 0); 4398168404Spjd if (namewidth < 10) 4399168404Spjd namewidth = 10; 4400168404Spjd 4401168404Spjd (void) printf(gettext("config:\n\n")); 4402168404Spjd (void) printf(gettext("\t%-*s %-8s %5s %5s %5s\n"), namewidth, 4403168404Spjd "NAME", "STATE", "READ", "WRITE", "CKSUM"); 4404168404Spjd print_status_config(zhp, zpool_get_name(zhp), nvroot, 4405209962Smm namewidth, 0, B_FALSE); 4406209962Smm 4407185029Spjd if (num_logs(nvroot) > 0) 4408213197Smm print_logs(zhp, nvroot, namewidth, B_TRUE); 4409185029Spjd if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE, 4410185029Spjd &l2cache, &nl2cache) == 0) 4411185029Spjd print_l2cache(zhp, l2cache, nl2cache, namewidth); 4412185029Spjd 4413168404Spjd if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES, 4414168404Spjd &spares, &nspares) == 0) 4415168404Spjd print_spares(zhp, spares, nspares, namewidth); 4416168404Spjd 4417168404Spjd if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRCOUNT, 4418168404Spjd &nerr) == 0) { 4419168404Spjd nvlist_t *nverrlist = NULL; 4420168404Spjd 4421168404Spjd /* 4422168404Spjd * If the approximate error count is small, get a 4423168404Spjd * precise count by fetching the entire log and 4424168404Spjd * uniquifying the results. 4425168404Spjd */ 4426185029Spjd if (nerr > 0 && nerr < 100 && !cbp->cb_verbose && 4427168404Spjd zpool_get_errlog(zhp, &nverrlist) == 0) { 4428168404Spjd nvpair_t *elem; 4429168404Spjd 4430168404Spjd elem = NULL; 4431168404Spjd nerr = 0; 4432168404Spjd while ((elem = nvlist_next_nvpair(nverrlist, 4433168404Spjd elem)) != NULL) { 4434168404Spjd nerr++; 4435168404Spjd } 4436168404Spjd } 4437168404Spjd nvlist_free(nverrlist); 4438168404Spjd 4439168404Spjd (void) printf("\n"); 4440168404Spjd 4441168404Spjd if (nerr == 0) 4442168404Spjd (void) printf(gettext("errors: No known data " 4443168404Spjd "errors\n")); 4444168404Spjd else if (!cbp->cb_verbose) 4445168404Spjd (void) printf(gettext("errors: %llu data " 4446168404Spjd "errors, use '-v' for a list\n"), 4447168404Spjd (u_longlong_t)nerr); 4448168404Spjd else 4449168404Spjd print_error_log(zhp); 4450168404Spjd } 4451219089Spjd 4452219089Spjd if (cbp->cb_dedup_stats) 4453219089Spjd print_dedup_stats(config); 4454168404Spjd } else { 4455168404Spjd (void) printf(gettext("config: The configuration cannot be " 4456168404Spjd "determined.\n")); 4457168404Spjd } 4458168404Spjd 4459168404Spjd return (0); 4460168404Spjd} 4461168404Spjd 4462168404Spjd/* 4463219089Spjd * zpool status [-vx] [-T d|u] [pool] ... [interval [count]] 4464168404Spjd * 4465168404Spjd * -v Display complete error logs 4466168404Spjd * -x Display only pools with potential problems 4467219089Spjd * -D Display dedup status (undocumented) 4468219089Spjd * -T Display a timestamp in date(1) or Unix format 4469168404Spjd * 4470168404Spjd * Describes the health status of all pools or some subset. 4471168404Spjd */ 4472168404Spjdint 4473168404Spjdzpool_do_status(int argc, char **argv) 4474168404Spjd{ 4475168404Spjd int c; 4476168404Spjd int ret; 4477219089Spjd unsigned long interval = 0, count = 0; 4478168404Spjd status_cbdata_t cb = { 0 }; 4479168404Spjd 4480168404Spjd /* check options */ 4481219089Spjd while ((c = getopt(argc, argv, "vxDT:")) != -1) { 4482168404Spjd switch (c) { 4483168404Spjd case 'v': 4484168404Spjd cb.cb_verbose = B_TRUE; 4485168404Spjd break; 4486168404Spjd case 'x': 4487168404Spjd cb.cb_explain = B_TRUE; 4488168404Spjd break; 4489219089Spjd case 'D': 4490219089Spjd cb.cb_dedup_stats = B_TRUE; 4491219089Spjd break; 4492219089Spjd case 'T': 4493219089Spjd get_timestamp_arg(*optarg); 4494219089Spjd break; 4495168404Spjd case '?': 4496168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 4497168404Spjd optopt); 4498168404Spjd usage(B_FALSE); 4499168404Spjd } 4500168404Spjd } 4501168404Spjd 4502168404Spjd argc -= optind; 4503168404Spjd argv += optind; 4504168404Spjd 4505219089Spjd get_interval_count(&argc, argv, &interval, &count); 4506168404Spjd 4507168404Spjd if (argc == 0) 4508168404Spjd cb.cb_allpools = B_TRUE; 4509168404Spjd 4510219089Spjd cb.cb_first = B_TRUE; 4511168404Spjd 4512219089Spjd for (;;) { 4513219089Spjd if (timestamp_fmt != NODATE) 4514219089Spjd print_timestamp(timestamp_fmt); 4515168404Spjd 4516219089Spjd ret = for_each_pool(argc, argv, B_TRUE, NULL, 4517219089Spjd status_callback, &cb); 4518219089Spjd 4519219089Spjd if (argc == 0 && cb.cb_count == 0) 4520219089Spjd (void) printf(gettext("no pools available\n")); 4521219089Spjd else if (cb.cb_explain && cb.cb_first && cb.cb_allpools) 4522219089Spjd (void) printf(gettext("all pools are healthy\n")); 4523219089Spjd 4524219089Spjd if (ret != 0) 4525219089Spjd return (ret); 4526219089Spjd 4527219089Spjd if (interval == 0) 4528219089Spjd break; 4529219089Spjd 4530219089Spjd if (count != 0 && --count == 0) 4531219089Spjd break; 4532219089Spjd 4533219089Spjd (void) sleep(interval); 4534219089Spjd } 4535219089Spjd 4536219089Spjd return (0); 4537168404Spjd} 4538168404Spjd 4539168404Spjdtypedef struct upgrade_cbdata { 4540276226Ssmh boolean_t cb_first; 4541276226Ssmh boolean_t cb_unavail; 4542276226Ssmh char cb_poolname[ZPOOL_MAXNAMELEN]; 4543276226Ssmh int cb_argc; 4544276226Ssmh uint64_t cb_version; 4545276226Ssmh char **cb_argv; 4546168404Spjd} upgrade_cbdata_t; 4547168404Spjd 4548238950Smm#ifdef __FreeBSD__ 4549168404Spjdstatic int 4550212050Spjdis_root_pool(zpool_handle_t *zhp) 4551212050Spjd{ 4552212050Spjd static struct statfs sfs; 4553212050Spjd static char *poolname = NULL; 4554212050Spjd static boolean_t stated = B_FALSE; 4555212050Spjd char *slash; 4556212050Spjd 4557212067Spjd if (!stated) { 4558212050Spjd stated = B_TRUE; 4559212050Spjd if (statfs("/", &sfs) == -1) { 4560212050Spjd (void) fprintf(stderr, 4561212050Spjd "Unable to stat root file system: %s.\n", 4562212050Spjd strerror(errno)); 4563212067Spjd return (0); 4564212050Spjd } 4565212050Spjd if (strcmp(sfs.f_fstypename, "zfs") != 0) 4566212067Spjd return (0); 4567212050Spjd poolname = sfs.f_mntfromname; 4568212050Spjd if ((slash = strchr(poolname, '/')) != NULL) 4569212050Spjd *slash = '\0'; 4570212050Spjd } 4571212050Spjd return (poolname != NULL && strcmp(poolname, zpool_get_name(zhp)) == 0); 4572212050Spjd} 4573212050Spjd 4574238950Smmstatic void 4575271934Ssmhroot_pool_upgrade_check(zpool_handle_t *zhp, char *poolname, int size) 4576271934Ssmh{ 4577238950Smm 4578238950Smm if (poolname[0] == '\0' && is_root_pool(zhp)) 4579238950Smm (void) strlcpy(poolname, zpool_get_name(zhp), size); 4580238950Smm} 4581238950Smm#endif /* FreeBSD */ 4582238950Smm 4583212050Spjdstatic int 4584238926Smmupgrade_version(zpool_handle_t *zhp, uint64_t version) 4585238926Smm{ 4586238926Smm int ret; 4587238926Smm nvlist_t *config; 4588238926Smm uint64_t oldversion; 4589238926Smm 4590238926Smm config = zpool_get_config(zhp, NULL); 4591238926Smm verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, 4592238926Smm &oldversion) == 0); 4593238926Smm 4594238926Smm assert(SPA_VERSION_IS_SUPPORTED(oldversion)); 4595238926Smm assert(oldversion < version); 4596238926Smm 4597238926Smm ret = zpool_upgrade(zhp, version); 4598238926Smm if (ret != 0) 4599238926Smm return (ret); 4600238926Smm 4601238926Smm if (version >= SPA_VERSION_FEATURES) { 4602238926Smm (void) printf(gettext("Successfully upgraded " 4603238926Smm "'%s' from version %llu to feature flags.\n"), 4604238926Smm zpool_get_name(zhp), oldversion); 4605238926Smm } else { 4606238926Smm (void) printf(gettext("Successfully upgraded " 4607238926Smm "'%s' from version %llu to version %llu.\n"), 4608238926Smm zpool_get_name(zhp), oldversion, version); 4609238926Smm } 4610238926Smm 4611238926Smm return (0); 4612238926Smm} 4613238926Smm 4614238926Smmstatic int 4615238926Smmupgrade_enable_all(zpool_handle_t *zhp, int *countp) 4616238926Smm{ 4617238926Smm int i, ret, count; 4618238926Smm boolean_t firstff = B_TRUE; 4619238926Smm nvlist_t *enabled = zpool_get_features(zhp); 4620238926Smm 4621238926Smm count = 0; 4622238926Smm for (i = 0; i < SPA_FEATURES; i++) { 4623238926Smm const char *fname = spa_feature_table[i].fi_uname; 4624238926Smm const char *fguid = spa_feature_table[i].fi_guid; 4625238926Smm if (!nvlist_exists(enabled, fguid)) { 4626238926Smm char *propname; 4627238926Smm verify(-1 != asprintf(&propname, "feature@%s", fname)); 4628238926Smm ret = zpool_set_prop(zhp, propname, 4629238926Smm ZFS_FEATURE_ENABLED); 4630238926Smm if (ret != 0) { 4631238926Smm free(propname); 4632238926Smm return (ret); 4633238926Smm } 4634238926Smm count++; 4635238926Smm 4636238926Smm if (firstff) { 4637238926Smm (void) printf(gettext("Enabled the " 4638238926Smm "following features on '%s':\n"), 4639238926Smm zpool_get_name(zhp)); 4640238926Smm firstff = B_FALSE; 4641238926Smm } 4642238926Smm (void) printf(gettext(" %s\n"), fname); 4643238926Smm free(propname); 4644238926Smm } 4645238926Smm } 4646238926Smm 4647238926Smm if (countp != NULL) 4648238926Smm *countp = count; 4649238926Smm return (0); 4650238926Smm} 4651238926Smm 4652238926Smmstatic int 4653168404Spjdupgrade_cb(zpool_handle_t *zhp, void *arg) 4654168404Spjd{ 4655168404Spjd upgrade_cbdata_t *cbp = arg; 4656168404Spjd nvlist_t *config; 4657168404Spjd uint64_t version; 4658238926Smm boolean_t printnl = B_FALSE; 4659238926Smm int ret; 4660168404Spjd 4661276194Ssmh if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) { 4662276194Ssmh (void) fprintf(stderr, gettext("cannot upgrade '%s': pool is " 4663276226Ssmh "currently unavailable.\n\n"), zpool_get_name(zhp)); 4664276226Ssmh cbp->cb_unavail = B_TRUE; 4665276194Ssmh /* Allow iteration to continue. */ 4666276194Ssmh return (0); 4667276194Ssmh } 4668276194Ssmh 4669168404Spjd config = zpool_get_config(zhp, NULL); 4670168404Spjd verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, 4671168404Spjd &version) == 0); 4672168404Spjd 4673238926Smm assert(SPA_VERSION_IS_SUPPORTED(version)); 4674168404Spjd 4675238926Smm if (version < cbp->cb_version) { 4676238926Smm cbp->cb_first = B_FALSE; 4677238926Smm ret = upgrade_version(zhp, cbp->cb_version); 4678238926Smm if (ret != 0) 4679238926Smm return (ret); 4680238926Smm#ifdef __FreeBSD__ 4681238950Smm root_pool_upgrade_check(zhp, cbp->cb_poolname, 4682238950Smm sizeof(cbp->cb_poolname)); 4683271934Ssmh#endif /* __FreeBSD__ */ 4684238926Smm printnl = B_TRUE; 4685238926Smm 4686238926Smm#ifdef illumos 4687238926Smm /* 4688238926Smm * If they did "zpool upgrade -a", then we could 4689238926Smm * be doing ioctls to different pools. We need 4690238926Smm * to log this history once to each pool, and bypass 4691238926Smm * the normal history logging that happens in main(). 4692238926Smm */ 4693238926Smm (void) zpool_log_history(g_zfs, history_str); 4694238926Smm log_history = B_FALSE; 4695238926Smm#endif 4696238926Smm } 4697238926Smm 4698238926Smm if (cbp->cb_version >= SPA_VERSION_FEATURES) { 4699238926Smm int count; 4700238926Smm ret = upgrade_enable_all(zhp, &count); 4701238926Smm if (ret != 0) 4702238926Smm return (ret); 4703238926Smm 4704238926Smm if (count > 0) { 4705168404Spjd cbp->cb_first = B_FALSE; 4706238926Smm printnl = B_TRUE; 4707271934Ssmh#ifdef __FreeBSD__ 4708271934Ssmh root_pool_upgrade_check(zhp, cbp->cb_poolname, 4709271934Ssmh sizeof(cbp->cb_poolname)); 4710271934Ssmh#endif /* __FreeBSD__ */ 4711248571Smm /* 4712248571Smm * If they did "zpool upgrade -a", then we could 4713248571Smm * be doing ioctls to different pools. We need 4714248571Smm * to log this history once to each pool, and bypass 4715248571Smm * the normal history logging that happens in main(). 4716248571Smm */ 4717248571Smm (void) zpool_log_history(g_zfs, history_str); 4718248571Smm log_history = B_FALSE; 4719168404Spjd } 4720238926Smm } 4721168404Spjd 4722238926Smm if (printnl) { 4723238926Smm (void) printf(gettext("\n")); 4724238926Smm } 4725238926Smm 4726238926Smm return (0); 4727238926Smm} 4728238926Smm 4729238926Smmstatic int 4730276226Ssmhupgrade_list_unavail(zpool_handle_t *zhp, void *arg) 4731276226Ssmh{ 4732276226Ssmh upgrade_cbdata_t *cbp = arg; 4733276226Ssmh 4734276226Ssmh if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) { 4735276226Ssmh if (cbp->cb_first) { 4736276226Ssmh (void) fprintf(stderr, gettext("The following pools " 4737276226Ssmh "are unavailable and cannot be upgraded as this " 4738276226Ssmh "time.\n\n")); 4739276226Ssmh (void) fprintf(stderr, gettext("POOL\n")); 4740276226Ssmh (void) fprintf(stderr, gettext("------------\n")); 4741276226Ssmh cbp->cb_first = B_FALSE; 4742276226Ssmh } 4743276226Ssmh (void) printf(gettext("%s\n"), zpool_get_name(zhp)); 4744276226Ssmh cbp->cb_unavail = B_TRUE; 4745276226Ssmh } 4746276226Ssmh return (0); 4747276226Ssmh} 4748276226Ssmh 4749276226Ssmhstatic int 4750238926Smmupgrade_list_older_cb(zpool_handle_t *zhp, void *arg) 4751238926Smm{ 4752238926Smm upgrade_cbdata_t *cbp = arg; 4753238926Smm nvlist_t *config; 4754238926Smm uint64_t version; 4755238926Smm 4756276226Ssmh if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) { 4757276226Ssmh /* 4758276226Ssmh * This will have been reported by upgrade_list_unavail so 4759276226Ssmh * just allow iteration to continue. 4760276226Ssmh */ 4761276226Ssmh cbp->cb_unavail = B_TRUE; 4762276226Ssmh return (0); 4763276226Ssmh } 4764276226Ssmh 4765238926Smm config = zpool_get_config(zhp, NULL); 4766238926Smm verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, 4767238926Smm &version) == 0); 4768238926Smm 4769238926Smm assert(SPA_VERSION_IS_SUPPORTED(version)); 4770238926Smm 4771238926Smm if (version < SPA_VERSION_FEATURES) { 4772168404Spjd if (cbp->cb_first) { 4773168404Spjd (void) printf(gettext("The following pools are " 4774238926Smm "formatted with legacy version numbers and can\n" 4775238926Smm "be upgraded to use feature flags. After " 4776238926Smm "being upgraded, these pools\nwill no " 4777238926Smm "longer be accessible by software that does not " 4778238926Smm "support feature\nflags.\n\n")); 4779168404Spjd (void) printf(gettext("VER POOL\n")); 4780168404Spjd (void) printf(gettext("--- ------------\n")); 4781168404Spjd cbp->cb_first = B_FALSE; 4782168404Spjd } 4783168404Spjd 4784168404Spjd (void) printf("%2llu %s\n", (u_longlong_t)version, 4785168404Spjd zpool_get_name(zhp)); 4786168404Spjd } 4787168404Spjd 4788238926Smm return (0); 4789168404Spjd} 4790168404Spjd 4791238926Smmstatic int 4792238926Smmupgrade_list_disabled_cb(zpool_handle_t *zhp, void *arg) 4793238926Smm{ 4794238926Smm upgrade_cbdata_t *cbp = arg; 4795238926Smm nvlist_t *config; 4796238926Smm uint64_t version; 4797238926Smm 4798276194Ssmh if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) { 4799276226Ssmh /* 4800276226Ssmh * This will have been reported by upgrade_list_unavail so 4801276226Ssmh * just allow iteration to continue. 4802276226Ssmh */ 4803276226Ssmh cbp->cb_unavail = B_TRUE; 4804276194Ssmh return (0); 4805276194Ssmh } 4806276194Ssmh 4807238926Smm config = zpool_get_config(zhp, NULL); 4808238926Smm verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, 4809238926Smm &version) == 0); 4810238926Smm 4811238926Smm if (version >= SPA_VERSION_FEATURES) { 4812238926Smm int i; 4813238926Smm boolean_t poolfirst = B_TRUE; 4814238926Smm nvlist_t *enabled = zpool_get_features(zhp); 4815238926Smm 4816238926Smm for (i = 0; i < SPA_FEATURES; i++) { 4817238926Smm const char *fguid = spa_feature_table[i].fi_guid; 4818238926Smm const char *fname = spa_feature_table[i].fi_uname; 4819238926Smm if (!nvlist_exists(enabled, fguid)) { 4820238926Smm if (cbp->cb_first) { 4821238926Smm (void) printf(gettext("\nSome " 4822238926Smm "supported features are not " 4823238926Smm "enabled on the following pools. " 4824238926Smm "Once a\nfeature is enabled the " 4825238926Smm "pool may become incompatible with " 4826238926Smm "software\nthat does not support " 4827238926Smm "the feature. See " 4828243014Smm "zpool-features(7) for " 4829238926Smm "details.\n\n")); 4830238926Smm (void) printf(gettext("POOL " 4831238926Smm "FEATURE\n")); 4832238926Smm (void) printf(gettext("------" 4833238926Smm "---------\n")); 4834238926Smm cbp->cb_first = B_FALSE; 4835238926Smm } 4836238926Smm 4837238926Smm if (poolfirst) { 4838238926Smm (void) printf(gettext("%s\n"), 4839238926Smm zpool_get_name(zhp)); 4840238926Smm poolfirst = B_FALSE; 4841238926Smm } 4842238926Smm 4843238926Smm (void) printf(gettext(" %s\n"), fname); 4844238926Smm } 4845238926Smm } 4846238926Smm } 4847238926Smm 4848238926Smm return (0); 4849238926Smm} 4850238926Smm 4851168404Spjd/* ARGSUSED */ 4852168404Spjdstatic int 4853168404Spjdupgrade_one(zpool_handle_t *zhp, void *data) 4854168404Spjd{ 4855238926Smm boolean_t printnl = B_FALSE; 4856185029Spjd upgrade_cbdata_t *cbp = data; 4857185029Spjd uint64_t cur_version; 4858168404Spjd int ret; 4859168404Spjd 4860276226Ssmh if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) { 4861276226Ssmh (void) fprintf(stderr, gettext("cannot upgrade '%s': pool is " 4862276226Ssmh "is currently unavailable.\n\n"), zpool_get_name(zhp)); 4863276226Ssmh cbp->cb_unavail = B_TRUE; 4864276226Ssmh return (1); 4865276226Ssmh } 4866276226Ssmh 4867185029Spjd if (strcmp("log", zpool_get_name(zhp)) == 0) { 4868185029Spjd (void) printf(gettext("'log' is now a reserved word\n" 4869185029Spjd "Pool 'log' must be renamed using export and import" 4870276226Ssmh " to upgrade.\n\n")); 4871185029Spjd return (1); 4872185029Spjd } 4873168404Spjd 4874185029Spjd cur_version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL); 4875185029Spjd if (cur_version > cbp->cb_version) { 4876168404Spjd (void) printf(gettext("Pool '%s' is already formatted " 4877238926Smm "using more current version '%llu'.\n\n"), 4878185029Spjd zpool_get_name(zhp), cur_version); 4879185029Spjd return (0); 4880185029Spjd } 4881238926Smm 4882238926Smm if (cbp->cb_version != SPA_VERSION && cur_version == cbp->cb_version) { 4883185029Spjd (void) printf(gettext("Pool '%s' is already formatted " 4884238926Smm "using version %llu.\n\n"), zpool_get_name(zhp), 4885238926Smm cbp->cb_version); 4886168404Spjd return (0); 4887168404Spjd } 4888168404Spjd 4889238926Smm if (cur_version != cbp->cb_version) { 4890238926Smm printnl = B_TRUE; 4891238926Smm ret = upgrade_version(zhp, cbp->cb_version); 4892238950Smm if (ret != 0) 4893238950Smm return (ret); 4894238926Smm#ifdef __FreeBSD__ 4895238950Smm root_pool_upgrade_check(zhp, cbp->cb_poolname, 4896238950Smm sizeof(cbp->cb_poolname)); 4897271934Ssmh#endif /* __FreeBSD__ */ 4898238926Smm } 4899168404Spjd 4900238926Smm if (cbp->cb_version >= SPA_VERSION_FEATURES) { 4901238926Smm int count = 0; 4902238926Smm ret = upgrade_enable_all(zhp, &count); 4903238926Smm if (ret != 0) 4904238926Smm return (ret); 4905238926Smm 4906238926Smm if (count != 0) { 4907238926Smm printnl = B_TRUE; 4908238950Smm#ifdef __FreeBSD__ 4909238951Smm root_pool_upgrade_check(zhp, cbp->cb_poolname, 4910238951Smm sizeof(cbp->cb_poolname)); 4911238950Smm#endif /* __FreeBSD __*/ 4912238926Smm } else if (cur_version == SPA_VERSION) { 4913238926Smm (void) printf(gettext("Pool '%s' already has all " 4914276226Ssmh "supported features enabled.\n\n"), 4915238926Smm zpool_get_name(zhp)); 4916238926Smm } 4917168404Spjd } 4918168404Spjd 4919238926Smm if (printnl) { 4920238926Smm (void) printf(gettext("\n")); 4921238926Smm } 4922238926Smm 4923238926Smm return (0); 4924168404Spjd} 4925168404Spjd 4926168404Spjd/* 4927168404Spjd * zpool upgrade 4928168404Spjd * zpool upgrade -v 4929185029Spjd * zpool upgrade [-V version] <-a | pool ...> 4930168404Spjd * 4931168404Spjd * With no arguments, display downrev'd ZFS pool available for upgrade. 4932168404Spjd * Individual pools can be upgraded by specifying the pool, and '-a' will 4933168404Spjd * upgrade all pools. 4934168404Spjd */ 4935168404Spjdint 4936168404Spjdzpool_do_upgrade(int argc, char **argv) 4937168404Spjd{ 4938168404Spjd int c; 4939168404Spjd upgrade_cbdata_t cb = { 0 }; 4940168404Spjd int ret = 0; 4941168404Spjd boolean_t showversions = B_FALSE; 4942238926Smm boolean_t upgradeall = B_FALSE; 4943185029Spjd char *end; 4944168404Spjd 4945185029Spjd 4946168404Spjd /* check options */ 4947219089Spjd while ((c = getopt(argc, argv, ":avV:")) != -1) { 4948168404Spjd switch (c) { 4949168404Spjd case 'a': 4950238926Smm upgradeall = B_TRUE; 4951168404Spjd break; 4952168404Spjd case 'v': 4953168404Spjd showversions = B_TRUE; 4954168404Spjd break; 4955185029Spjd case 'V': 4956185029Spjd cb.cb_version = strtoll(optarg, &end, 10); 4957236884Smm if (*end != '\0' || 4958236884Smm !SPA_VERSION_IS_SUPPORTED(cb.cb_version)) { 4959185029Spjd (void) fprintf(stderr, 4960185029Spjd gettext("invalid version '%s'\n"), optarg); 4961185029Spjd usage(B_FALSE); 4962185029Spjd } 4963185029Spjd break; 4964219089Spjd case ':': 4965219089Spjd (void) fprintf(stderr, gettext("missing argument for " 4966219089Spjd "'%c' option\n"), optopt); 4967219089Spjd usage(B_FALSE); 4968219089Spjd break; 4969168404Spjd case '?': 4970168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 4971168404Spjd optopt); 4972168404Spjd usage(B_FALSE); 4973168404Spjd } 4974168404Spjd } 4975168404Spjd 4976168404Spjd cb.cb_argc = argc; 4977168404Spjd cb.cb_argv = argv; 4978168404Spjd argc -= optind; 4979168404Spjd argv += optind; 4980168404Spjd 4981185029Spjd if (cb.cb_version == 0) { 4982185029Spjd cb.cb_version = SPA_VERSION; 4983238926Smm } else if (!upgradeall && argc == 0) { 4984185029Spjd (void) fprintf(stderr, gettext("-V option is " 4985185029Spjd "incompatible with other arguments\n")); 4986185029Spjd usage(B_FALSE); 4987185029Spjd } 4988185029Spjd 4989168404Spjd if (showversions) { 4990238926Smm if (upgradeall || argc != 0) { 4991168404Spjd (void) fprintf(stderr, gettext("-v option is " 4992168404Spjd "incompatible with other arguments\n")); 4993168404Spjd usage(B_FALSE); 4994168404Spjd } 4995238926Smm } else if (upgradeall) { 4996168404Spjd if (argc != 0) { 4997185029Spjd (void) fprintf(stderr, gettext("-a option should not " 4998185029Spjd "be used along with a pool name\n")); 4999168404Spjd usage(B_FALSE); 5000168404Spjd } 5001168404Spjd } 5002168404Spjd 5003236884Smm (void) printf(gettext("This system supports ZFS pool feature " 5004236884Smm "flags.\n\n")); 5005168404Spjd if (showversions) { 5006238926Smm int i; 5007238926Smm 5008238926Smm (void) printf(gettext("The following features are " 5009168404Spjd "supported:\n\n")); 5010238926Smm (void) printf(gettext("FEAT DESCRIPTION\n")); 5011238926Smm (void) printf("----------------------------------------------" 5012238926Smm "---------------\n"); 5013238926Smm for (i = 0; i < SPA_FEATURES; i++) { 5014238926Smm zfeature_info_t *fi = &spa_feature_table[i]; 5015286708Smav const char *ro = 5016286708Smav (fi->fi_flags & ZFEATURE_FLAG_READONLY_COMPAT) ? 5017238926Smm " (read-only compatible)" : ""; 5018238926Smm 5019238926Smm (void) printf("%-37s%s\n", fi->fi_uname, ro); 5020238926Smm (void) printf(" %s\n", fi->fi_desc); 5021238926Smm } 5022238926Smm (void) printf("\n"); 5023238926Smm 5024238926Smm (void) printf(gettext("The following legacy versions are also " 5025238926Smm "supported:\n\n")); 5026168404Spjd (void) printf(gettext("VER DESCRIPTION\n")); 5027168404Spjd (void) printf("--- -----------------------------------------" 5028168404Spjd "---------------\n"); 5029168404Spjd (void) printf(gettext(" 1 Initial ZFS version\n")); 5030168404Spjd (void) printf(gettext(" 2 Ditto blocks " 5031168404Spjd "(replicated metadata)\n")); 5032168404Spjd (void) printf(gettext(" 3 Hot spares and double parity " 5033168404Spjd "RAID-Z\n")); 5034168404Spjd (void) printf(gettext(" 4 zpool history\n")); 5035168404Spjd (void) printf(gettext(" 5 Compression using the gzip " 5036168404Spjd "algorithm\n")); 5037185029Spjd (void) printf(gettext(" 6 bootfs pool property\n")); 5038185029Spjd (void) printf(gettext(" 7 Separate intent log devices\n")); 5039185029Spjd (void) printf(gettext(" 8 Delegated administration\n")); 5040185029Spjd (void) printf(gettext(" 9 refquota and refreservation " 5041185029Spjd "properties\n")); 5042185029Spjd (void) printf(gettext(" 10 Cache devices\n")); 5043185029Spjd (void) printf(gettext(" 11 Improved scrub performance\n")); 5044185029Spjd (void) printf(gettext(" 12 Snapshot properties\n")); 5045185029Spjd (void) printf(gettext(" 13 snapused property\n")); 5046209962Smm (void) printf(gettext(" 14 passthrough-x aclinherit\n")); 5047209962Smm (void) printf(gettext(" 15 user/group space accounting\n")); 5048219089Spjd (void) printf(gettext(" 16 stmf property support\n")); 5049219089Spjd (void) printf(gettext(" 17 Triple-parity RAID-Z\n")); 5050219089Spjd (void) printf(gettext(" 18 Snapshot user holds\n")); 5051219089Spjd (void) printf(gettext(" 19 Log device removal\n")); 5052219089Spjd (void) printf(gettext(" 20 Compression using zle " 5053219089Spjd "(zero-length encoding)\n")); 5054219089Spjd (void) printf(gettext(" 21 Deduplication\n")); 5055219089Spjd (void) printf(gettext(" 22 Received properties\n")); 5056219089Spjd (void) printf(gettext(" 23 Slim ZIL\n")); 5057219089Spjd (void) printf(gettext(" 24 System attributes\n")); 5058219089Spjd (void) printf(gettext(" 25 Improved scrub stats\n")); 5059219089Spjd (void) printf(gettext(" 26 Improved snapshot deletion " 5060219089Spjd "performance\n")); 5061219089Spjd (void) printf(gettext(" 27 Improved snapshot creation " 5062219089Spjd "performance\n")); 5063219089Spjd (void) printf(gettext(" 28 Multiple vdev replacements\n")); 5064219089Spjd (void) printf(gettext("\nFor more information on a particular " 5065219089Spjd "version, including supported releases,\n")); 5066219089Spjd (void) printf(gettext("see the ZFS Administration Guide.\n\n")); 5067238926Smm } else if (argc == 0 && upgradeall) { 5068238926Smm cb.cb_first = B_TRUE; 5069168404Spjd ret = zpool_iter(g_zfs, upgrade_cb, &cb); 5070238926Smm if (ret == 0 && cb.cb_first) { 5071238926Smm if (cb.cb_version == SPA_VERSION) { 5072276226Ssmh (void) printf(gettext("All %spools are already " 5073276226Ssmh "formatted using feature flags.\n\n"), 5074276226Ssmh cb.cb_unavail ? gettext("available ") : ""); 5075276226Ssmh (void) printf(gettext("Every %sfeature flags " 5076238926Smm "pool already has all supported features " 5077276226Ssmh "enabled.\n"), 5078276226Ssmh cb.cb_unavail ? gettext("available ") : ""); 5079238926Smm } else { 5080238926Smm (void) printf(gettext("All pools are already " 5081238926Smm "formatted with version %llu or higher.\n"), 5082238926Smm cb.cb_version); 5083168404Spjd } 5084168404Spjd } 5085238926Smm } else if (argc == 0) { 5086238926Smm cb.cb_first = B_TRUE; 5087276226Ssmh ret = zpool_iter(g_zfs, upgrade_list_unavail, &cb); 5088276226Ssmh assert(ret == 0); 5089276226Ssmh 5090276226Ssmh if (!cb.cb_first) { 5091276226Ssmh (void) fprintf(stderr, "\n"); 5092276226Ssmh } 5093276226Ssmh 5094276226Ssmh cb.cb_first = B_TRUE; 5095238926Smm ret = zpool_iter(g_zfs, upgrade_list_older_cb, &cb); 5096238926Smm assert(ret == 0); 5097168404Spjd 5098238926Smm if (cb.cb_first) { 5099276226Ssmh (void) printf(gettext("All %spools are formatted using " 5100276226Ssmh "feature flags.\n\n"), cb.cb_unavail ? 5101276226Ssmh gettext("available ") : ""); 5102238926Smm } else { 5103238926Smm (void) printf(gettext("\nUse 'zpool upgrade -v' " 5104238926Smm "for a list of available legacy versions.\n")); 5105168404Spjd } 5106238926Smm 5107238926Smm cb.cb_first = B_TRUE; 5108238926Smm ret = zpool_iter(g_zfs, upgrade_list_disabled_cb, &cb); 5109238926Smm assert(ret == 0); 5110238926Smm 5111238926Smm if (cb.cb_first) { 5112276226Ssmh (void) printf(gettext("Every %sfeature flags pool has " 5113276226Ssmh "all supported features enabled.\n"), 5114276226Ssmh cb.cb_unavail ? gettext("available ") : ""); 5115238926Smm } else { 5116238926Smm (void) printf(gettext("\n")); 5117238926Smm } 5118168404Spjd } else { 5119276226Ssmh ret = for_each_pool(argc, argv, B_TRUE, NULL, 5120168404Spjd upgrade_one, &cb); 5121168404Spjd } 5122168404Spjd 5123212050Spjd if (cb.cb_poolname[0] != '\0') { 5124212050Spjd (void) printf( 5125212050Spjd "If you boot from pool '%s', don't forget to update boot code.\n" 5126212050Spjd "Assuming you use GPT partitioning and da0 is your boot disk\n" 5127212050Spjd "the following command will do it:\n" 5128212050Spjd "\n" 5129212050Spjd "\tgpart bootcode -b /boot/pmbr -p /boot/gptzfsboot -i 1 da0\n\n", 5130212050Spjd cb.cb_poolname); 5131212050Spjd } 5132212050Spjd 5133168404Spjd return (ret); 5134168404Spjd} 5135168404Spjd 5136185029Spjdtypedef struct hist_cbdata { 5137185029Spjd boolean_t first; 5138248571Smm boolean_t longfmt; 5139248571Smm boolean_t internal; 5140185029Spjd} hist_cbdata_t; 5141185029Spjd 5142168404Spjd/* 5143168404Spjd * Print out the command history for a specific pool. 5144168404Spjd */ 5145168404Spjdstatic int 5146168404Spjdget_history_one(zpool_handle_t *zhp, void *data) 5147168404Spjd{ 5148168404Spjd nvlist_t *nvhis; 5149168404Spjd nvlist_t **records; 5150168404Spjd uint_t numrecords; 5151168404Spjd int ret, i; 5152185029Spjd hist_cbdata_t *cb = (hist_cbdata_t *)data; 5153168404Spjd 5154185029Spjd cb->first = B_FALSE; 5155168404Spjd 5156168404Spjd (void) printf(gettext("History for '%s':\n"), zpool_get_name(zhp)); 5157168404Spjd 5158168404Spjd if ((ret = zpool_get_history(zhp, &nvhis)) != 0) 5159168404Spjd return (ret); 5160168404Spjd 5161168404Spjd verify(nvlist_lookup_nvlist_array(nvhis, ZPOOL_HIST_RECORD, 5162168404Spjd &records, &numrecords) == 0); 5163168404Spjd for (i = 0; i < numrecords; i++) { 5164248571Smm nvlist_t *rec = records[i]; 5165248571Smm char tbuf[30] = ""; 5166185029Spjd 5167248571Smm if (nvlist_exists(rec, ZPOOL_HIST_TIME)) { 5168248571Smm time_t tsec; 5169248571Smm struct tm t; 5170185029Spjd 5171248571Smm tsec = fnvlist_lookup_uint64(records[i], 5172248571Smm ZPOOL_HIST_TIME); 5173248571Smm (void) localtime_r(&tsec, &t); 5174248571Smm (void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t); 5175248571Smm } 5176248571Smm 5177248571Smm if (nvlist_exists(rec, ZPOOL_HIST_CMD)) { 5178248571Smm (void) printf("%s %s", tbuf, 5179248571Smm fnvlist_lookup_string(rec, ZPOOL_HIST_CMD)); 5180248571Smm } else if (nvlist_exists(rec, ZPOOL_HIST_INT_EVENT)) { 5181248571Smm int ievent = 5182248571Smm fnvlist_lookup_uint64(rec, ZPOOL_HIST_INT_EVENT); 5183248571Smm if (!cb->internal) 5184185029Spjd continue; 5185248571Smm if (ievent >= ZFS_NUM_LEGACY_HISTORY_EVENTS) { 5186248571Smm (void) printf("%s unrecognized record:\n", 5187248571Smm tbuf); 5188248571Smm dump_nvlist(rec, 4); 5189185029Spjd continue; 5190248571Smm } 5191248571Smm (void) printf("%s [internal %s txg:%lld] %s", tbuf, 5192248571Smm zfs_history_event_names[ievent], 5193248571Smm fnvlist_lookup_uint64(rec, ZPOOL_HIST_TXG), 5194248571Smm fnvlist_lookup_string(rec, ZPOOL_HIST_INT_STR)); 5195248571Smm } else if (nvlist_exists(rec, ZPOOL_HIST_INT_NAME)) { 5196248571Smm if (!cb->internal) 5197248571Smm continue; 5198248571Smm (void) printf("%s [txg:%lld] %s", tbuf, 5199248571Smm fnvlist_lookup_uint64(rec, ZPOOL_HIST_TXG), 5200248571Smm fnvlist_lookup_string(rec, ZPOOL_HIST_INT_NAME)); 5201248571Smm if (nvlist_exists(rec, ZPOOL_HIST_DSNAME)) { 5202248571Smm (void) printf(" %s (%llu)", 5203248571Smm fnvlist_lookup_string(rec, 5204248571Smm ZPOOL_HIST_DSNAME), 5205248571Smm fnvlist_lookup_uint64(rec, 5206248571Smm ZPOOL_HIST_DSID)); 5207248571Smm } 5208248571Smm (void) printf(" %s", fnvlist_lookup_string(rec, 5209248571Smm ZPOOL_HIST_INT_STR)); 5210248571Smm } else if (nvlist_exists(rec, ZPOOL_HIST_IOCTL)) { 5211248571Smm if (!cb->internal) 5212248571Smm continue; 5213248571Smm (void) printf("%s ioctl %s\n", tbuf, 5214248571Smm fnvlist_lookup_string(rec, ZPOOL_HIST_IOCTL)); 5215248571Smm if (nvlist_exists(rec, ZPOOL_HIST_INPUT_NVL)) { 5216248571Smm (void) printf(" input:\n"); 5217248571Smm dump_nvlist(fnvlist_lookup_nvlist(rec, 5218248571Smm ZPOOL_HIST_INPUT_NVL), 8); 5219248571Smm } 5220248571Smm if (nvlist_exists(rec, ZPOOL_HIST_OUTPUT_NVL)) { 5221248571Smm (void) printf(" output:\n"); 5222248571Smm dump_nvlist(fnvlist_lookup_nvlist(rec, 5223248571Smm ZPOOL_HIST_OUTPUT_NVL), 8); 5224248571Smm } 5225248571Smm } else { 5226248571Smm if (!cb->internal) 5227248571Smm continue; 5228248571Smm (void) printf("%s unrecognized record:\n", tbuf); 5229248571Smm dump_nvlist(rec, 4); 5230168404Spjd } 5231185029Spjd 5232185029Spjd if (!cb->longfmt) { 5233185029Spjd (void) printf("\n"); 5234185029Spjd continue; 5235185029Spjd } 5236185029Spjd (void) printf(" ["); 5237248571Smm if (nvlist_exists(rec, ZPOOL_HIST_WHO)) { 5238248571Smm uid_t who = fnvlist_lookup_uint64(rec, ZPOOL_HIST_WHO); 5239248571Smm struct passwd *pwd = getpwuid(who); 5240248571Smm (void) printf("user %d ", (int)who); 5241248571Smm if (pwd != NULL) 5242248571Smm (void) printf("(%s) ", pwd->pw_name); 5243185029Spjd } 5244248571Smm if (nvlist_exists(rec, ZPOOL_HIST_HOST)) { 5245248571Smm (void) printf("on %s", 5246248571Smm fnvlist_lookup_string(rec, ZPOOL_HIST_HOST)); 5247185029Spjd } 5248248571Smm if (nvlist_exists(rec, ZPOOL_HIST_ZONE)) { 5249248571Smm (void) printf(":%s", 5250248571Smm fnvlist_lookup_string(rec, ZPOOL_HIST_ZONE)); 5251185029Spjd } 5252185029Spjd (void) printf("]"); 5253185029Spjd (void) printf("\n"); 5254168404Spjd } 5255168404Spjd (void) printf("\n"); 5256168404Spjd nvlist_free(nvhis); 5257168404Spjd 5258168404Spjd return (ret); 5259168404Spjd} 5260168404Spjd 5261168404Spjd/* 5262168404Spjd * zpool history <pool> 5263168404Spjd * 5264168404Spjd * Displays the history of commands that modified pools. 5265168404Spjd */ 5266168404Spjdint 5267168404Spjdzpool_do_history(int argc, char **argv) 5268168404Spjd{ 5269185029Spjd hist_cbdata_t cbdata = { 0 }; 5270168404Spjd int ret; 5271185029Spjd int c; 5272168404Spjd 5273185029Spjd cbdata.first = B_TRUE; 5274185029Spjd /* check options */ 5275185029Spjd while ((c = getopt(argc, argv, "li")) != -1) { 5276185029Spjd switch (c) { 5277185029Spjd case 'l': 5278248571Smm cbdata.longfmt = B_TRUE; 5279185029Spjd break; 5280185029Spjd case 'i': 5281248571Smm cbdata.internal = B_TRUE; 5282185029Spjd break; 5283185029Spjd case '?': 5284185029Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 5285185029Spjd optopt); 5286185029Spjd usage(B_FALSE); 5287185029Spjd } 5288185029Spjd } 5289168404Spjd argc -= optind; 5290168404Spjd argv += optind; 5291168404Spjd 5292168404Spjd ret = for_each_pool(argc, argv, B_FALSE, NULL, get_history_one, 5293185029Spjd &cbdata); 5294168404Spjd 5295185029Spjd if (argc == 0 && cbdata.first == B_TRUE) { 5296168404Spjd (void) printf(gettext("no pools available\n")); 5297168404Spjd return (0); 5298168404Spjd } 5299168404Spjd 5300168404Spjd return (ret); 5301168404Spjd} 5302168404Spjd 5303168404Spjdstatic int 5304168404Spjdget_callback(zpool_handle_t *zhp, void *data) 5305168404Spjd{ 5306185029Spjd zprop_get_cbdata_t *cbp = (zprop_get_cbdata_t *)data; 5307168404Spjd char value[MAXNAMELEN]; 5308185029Spjd zprop_source_t srctype; 5309185029Spjd zprop_list_t *pl; 5310168404Spjd 5311168404Spjd for (pl = cbp->cb_proplist; pl != NULL; pl = pl->pl_next) { 5312168404Spjd 5313168404Spjd /* 5314185029Spjd * Skip the special fake placeholder. This will also skip 5315185029Spjd * over the name property when 'all' is specified. 5316168404Spjd */ 5317185029Spjd if (pl->pl_prop == ZPOOL_PROP_NAME && 5318168404Spjd pl == cbp->cb_proplist) 5319168404Spjd continue; 5320168404Spjd 5321236884Smm if (pl->pl_prop == ZPROP_INVAL && 5322236884Smm (zpool_prop_feature(pl->pl_user_prop) || 5323236884Smm zpool_prop_unsupported(pl->pl_user_prop))) { 5324236884Smm srctype = ZPROP_SRC_LOCAL; 5325168404Spjd 5326236884Smm if (zpool_prop_get_feature(zhp, pl->pl_user_prop, 5327236884Smm value, sizeof (value)) == 0) { 5328236884Smm zprop_print_one_property(zpool_get_name(zhp), 5329236884Smm cbp, pl->pl_user_prop, value, srctype, 5330236884Smm NULL, NULL); 5331236884Smm } 5332236884Smm } else { 5333236884Smm if (zpool_get_prop(zhp, pl->pl_prop, value, 5334263889Sdelphij sizeof (value), &srctype, cbp->cb_literal) != 0) 5335236884Smm continue; 5336236884Smm 5337236884Smm zprop_print_one_property(zpool_get_name(zhp), cbp, 5338236884Smm zpool_prop_to_name(pl->pl_prop), value, srctype, 5339236884Smm NULL, NULL); 5340236884Smm } 5341168404Spjd } 5342168404Spjd return (0); 5343168404Spjd} 5344168404Spjd 5345263889Sdelphij/* 5346263889Sdelphij * zpool get [-Hp] [-o "all" | field[,...]] <"all" | property[,...]> <pool> ... 5347263889Sdelphij * 5348263889Sdelphij * -H Scripted mode. Don't display headers, and separate properties 5349263889Sdelphij * by a single tab. 5350263889Sdelphij * -o List of columns to display. Defaults to 5351263889Sdelphij * "name,property,value,source". 5352263889Sdelphij * -p Diplay values in parsable (exact) format. 5353263889Sdelphij * 5354263889Sdelphij * Get properties of pools in the system. Output space statistics 5355263889Sdelphij * for each one as well as other attributes. 5356263889Sdelphij */ 5357168404Spjdint 5358168404Spjdzpool_do_get(int argc, char **argv) 5359168404Spjd{ 5360185029Spjd zprop_get_cbdata_t cb = { 0 }; 5361185029Spjd zprop_list_t fake_name = { 0 }; 5362168404Spjd int ret; 5363263889Sdelphij int c, i; 5364263889Sdelphij char *value; 5365168404Spjd 5366263889Sdelphij cb.cb_first = B_TRUE; 5367168404Spjd 5368263889Sdelphij /* 5369263889Sdelphij * Set up default columns and sources. 5370263889Sdelphij */ 5371185029Spjd cb.cb_sources = ZPROP_SRC_ALL; 5372168404Spjd cb.cb_columns[0] = GET_COL_NAME; 5373168404Spjd cb.cb_columns[1] = GET_COL_PROPERTY; 5374168404Spjd cb.cb_columns[2] = GET_COL_VALUE; 5375168404Spjd cb.cb_columns[3] = GET_COL_SOURCE; 5376185029Spjd cb.cb_type = ZFS_TYPE_POOL; 5377168404Spjd 5378263889Sdelphij /* check options */ 5379263889Sdelphij while ((c = getopt(argc, argv, ":Hpo:")) != -1) { 5380263889Sdelphij switch (c) { 5381263889Sdelphij case 'p': 5382263889Sdelphij cb.cb_literal = B_TRUE; 5383263889Sdelphij break; 5384263889Sdelphij case 'H': 5385263889Sdelphij cb.cb_scripted = B_TRUE; 5386263889Sdelphij break; 5387263889Sdelphij case 'o': 5388263889Sdelphij bzero(&cb.cb_columns, sizeof (cb.cb_columns)); 5389263889Sdelphij i = 0; 5390263889Sdelphij while (*optarg != '\0') { 5391263889Sdelphij static char *col_subopts[] = 5392263889Sdelphij { "name", "property", "value", "source", 5393263889Sdelphij "all", NULL }; 5394263889Sdelphij 5395263889Sdelphij if (i == ZFS_GET_NCOLS) { 5396263889Sdelphij (void) fprintf(stderr, gettext("too " 5397263889Sdelphij "many fields given to -o " 5398263889Sdelphij "option\n")); 5399263889Sdelphij usage(B_FALSE); 5400263889Sdelphij } 5401263889Sdelphij 5402263889Sdelphij switch (getsubopt(&optarg, col_subopts, 5403263889Sdelphij &value)) { 5404263889Sdelphij case 0: 5405263889Sdelphij cb.cb_columns[i++] = GET_COL_NAME; 5406263889Sdelphij break; 5407263889Sdelphij case 1: 5408263889Sdelphij cb.cb_columns[i++] = GET_COL_PROPERTY; 5409263889Sdelphij break; 5410263889Sdelphij case 2: 5411263889Sdelphij cb.cb_columns[i++] = GET_COL_VALUE; 5412263889Sdelphij break; 5413263889Sdelphij case 3: 5414263889Sdelphij cb.cb_columns[i++] = GET_COL_SOURCE; 5415263889Sdelphij break; 5416263889Sdelphij case 4: 5417263889Sdelphij if (i > 0) { 5418263889Sdelphij (void) fprintf(stderr, 5419263889Sdelphij gettext("\"all\" conflicts " 5420263889Sdelphij "with specific fields " 5421263889Sdelphij "given to -o option\n")); 5422263889Sdelphij usage(B_FALSE); 5423263889Sdelphij } 5424263889Sdelphij cb.cb_columns[0] = GET_COL_NAME; 5425263889Sdelphij cb.cb_columns[1] = GET_COL_PROPERTY; 5426263889Sdelphij cb.cb_columns[2] = GET_COL_VALUE; 5427263889Sdelphij cb.cb_columns[3] = GET_COL_SOURCE; 5428263889Sdelphij i = ZFS_GET_NCOLS; 5429263889Sdelphij break; 5430263889Sdelphij default: 5431263889Sdelphij (void) fprintf(stderr, 5432263889Sdelphij gettext("invalid column name " 5433263889Sdelphij "'%s'\n"), value); 5434263889Sdelphij usage(B_FALSE); 5435263889Sdelphij } 5436263889Sdelphij } 5437263889Sdelphij break; 5438263889Sdelphij case '?': 5439263889Sdelphij (void) fprintf(stderr, gettext("invalid option '%c'\n"), 5440263889Sdelphij optopt); 5441263889Sdelphij usage(B_FALSE); 5442263889Sdelphij } 5443263889Sdelphij } 5444263889Sdelphij 5445263889Sdelphij argc -= optind; 5446263889Sdelphij argv += optind; 5447263889Sdelphij 5448263889Sdelphij if (argc < 1) { 5449263889Sdelphij (void) fprintf(stderr, gettext("missing property " 5450263889Sdelphij "argument\n")); 5451263889Sdelphij usage(B_FALSE); 5452263889Sdelphij } 5453263889Sdelphij 5454263889Sdelphij if (zprop_get_list(g_zfs, argv[0], &cb.cb_proplist, 5455185029Spjd ZFS_TYPE_POOL) != 0) 5456168404Spjd usage(B_FALSE); 5457168404Spjd 5458263889Sdelphij argc--; 5459263889Sdelphij argv++; 5460263889Sdelphij 5461168404Spjd if (cb.cb_proplist != NULL) { 5462185029Spjd fake_name.pl_prop = ZPOOL_PROP_NAME; 5463168404Spjd fake_name.pl_width = strlen(gettext("NAME")); 5464168404Spjd fake_name.pl_next = cb.cb_proplist; 5465168404Spjd cb.cb_proplist = &fake_name; 5466168404Spjd } 5467168404Spjd 5468263889Sdelphij ret = for_each_pool(argc, argv, B_TRUE, &cb.cb_proplist, 5469168404Spjd get_callback, &cb); 5470168404Spjd 5471168404Spjd if (cb.cb_proplist == &fake_name) 5472185029Spjd zprop_free_list(fake_name.pl_next); 5473168404Spjd else 5474185029Spjd zprop_free_list(cb.cb_proplist); 5475168404Spjd 5476168404Spjd return (ret); 5477168404Spjd} 5478168404Spjd 5479168404Spjdtypedef struct set_cbdata { 5480168404Spjd char *cb_propname; 5481168404Spjd char *cb_value; 5482168404Spjd boolean_t cb_any_successful; 5483168404Spjd} set_cbdata_t; 5484168404Spjd 5485168404Spjdint 5486168404Spjdset_callback(zpool_handle_t *zhp, void *data) 5487168404Spjd{ 5488168404Spjd int error; 5489168404Spjd set_cbdata_t *cb = (set_cbdata_t *)data; 5490168404Spjd 5491168404Spjd error = zpool_set_prop(zhp, cb->cb_propname, cb->cb_value); 5492168404Spjd 5493168404Spjd if (!error) 5494168404Spjd cb->cb_any_successful = B_TRUE; 5495168404Spjd 5496168404Spjd return (error); 5497168404Spjd} 5498168404Spjd 5499168404Spjdint 5500168404Spjdzpool_do_set(int argc, char **argv) 5501168404Spjd{ 5502168404Spjd set_cbdata_t cb = { 0 }; 5503168404Spjd int error; 5504168404Spjd 5505168404Spjd if (argc > 1 && argv[1][0] == '-') { 5506168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 5507168404Spjd argv[1][1]); 5508168404Spjd usage(B_FALSE); 5509168404Spjd } 5510168404Spjd 5511168404Spjd if (argc < 2) { 5512168404Spjd (void) fprintf(stderr, gettext("missing property=value " 5513168404Spjd "argument\n")); 5514168404Spjd usage(B_FALSE); 5515168404Spjd } 5516168404Spjd 5517168404Spjd if (argc < 3) { 5518168404Spjd (void) fprintf(stderr, gettext("missing pool name\n")); 5519168404Spjd usage(B_FALSE); 5520168404Spjd } 5521168404Spjd 5522168404Spjd if (argc > 3) { 5523168404Spjd (void) fprintf(stderr, gettext("too many pool names\n")); 5524168404Spjd usage(B_FALSE); 5525168404Spjd } 5526168404Spjd 5527168404Spjd cb.cb_propname = argv[1]; 5528168404Spjd cb.cb_value = strchr(cb.cb_propname, '='); 5529168404Spjd if (cb.cb_value == NULL) { 5530168404Spjd (void) fprintf(stderr, gettext("missing value in " 5531168404Spjd "property=value argument\n")); 5532168404Spjd usage(B_FALSE); 5533168404Spjd } 5534168404Spjd 5535168404Spjd *(cb.cb_value) = '\0'; 5536168404Spjd cb.cb_value++; 5537168404Spjd 5538168404Spjd error = for_each_pool(argc - 2, argv + 2, B_TRUE, NULL, 5539168404Spjd set_callback, &cb); 5540168404Spjd 5541168404Spjd return (error); 5542168404Spjd} 5543168404Spjd 5544168404Spjdstatic int 5545168404Spjdfind_command_idx(char *command, int *idx) 5546168404Spjd{ 5547168404Spjd int i; 5548168404Spjd 5549168404Spjd for (i = 0; i < NCOMMAND; i++) { 5550168404Spjd if (command_table[i].name == NULL) 5551168404Spjd continue; 5552168404Spjd 5553168404Spjd if (strcmp(command, command_table[i].name) == 0) { 5554168404Spjd *idx = i; 5555168404Spjd return (0); 5556168404Spjd } 5557168404Spjd } 5558168404Spjd return (1); 5559168404Spjd} 5560168404Spjd 5561168404Spjdint 5562168404Spjdmain(int argc, char **argv) 5563168404Spjd{ 5564168404Spjd int ret; 5565168404Spjd int i; 5566168404Spjd char *cmdname; 5567168404Spjd 5568168404Spjd (void) setlocale(LC_ALL, ""); 5569168404Spjd (void) textdomain(TEXT_DOMAIN); 5570168404Spjd 5571168404Spjd if ((g_zfs = libzfs_init()) == NULL) { 5572168404Spjd (void) fprintf(stderr, gettext("internal error: failed to " 5573168404Spjd "initialize ZFS library\n")); 5574168404Spjd return (1); 5575168404Spjd } 5576168404Spjd 5577168404Spjd libzfs_print_on_error(g_zfs, B_TRUE); 5578168404Spjd 5579168404Spjd opterr = 0; 5580168404Spjd 5581168404Spjd /* 5582168404Spjd * Make sure the user has specified some command. 5583168404Spjd */ 5584168404Spjd if (argc < 2) { 5585168404Spjd (void) fprintf(stderr, gettext("missing command\n")); 5586168404Spjd usage(B_FALSE); 5587168404Spjd } 5588168404Spjd 5589168404Spjd cmdname = argv[1]; 5590168404Spjd 5591168404Spjd /* 5592168404Spjd * Special case '-?' 5593168404Spjd */ 5594168404Spjd if (strcmp(cmdname, "-?") == 0) 5595168404Spjd usage(B_TRUE); 5596168404Spjd 5597248571Smm zfs_save_arguments(argc, argv, history_str, sizeof (history_str)); 5598185029Spjd 5599168404Spjd /* 5600168404Spjd * Run the appropriate command. 5601168404Spjd */ 5602168404Spjd if (find_command_idx(cmdname, &i) == 0) { 5603168404Spjd current_command = &command_table[i]; 5604168404Spjd ret = command_table[i].func(argc - 1, argv + 1); 5605185029Spjd } else if (strchr(cmdname, '=')) { 5606185029Spjd verify(find_command_idx("set", &i) == 0); 5607185029Spjd current_command = &command_table[i]; 5608185029Spjd ret = command_table[i].func(argc, argv); 5609185029Spjd } else if (strcmp(cmdname, "freeze") == 0 && argc == 3) { 5610185029Spjd /* 5611185029Spjd * 'freeze' is a vile debugging abomination, so we treat 5612185029Spjd * it as such. 5613185029Spjd */ 5614252059Ssmh zfs_cmd_t zc = { 0 }; 5615252059Ssmh (void) strlcpy(zc.zc_name, argv[2], sizeof (zc.zc_name)); 5616252059Ssmh return (!!zfs_ioctl(g_zfs, ZFS_IOC_POOL_FREEZE, &zc)); 5617185029Spjd } else { 5618168404Spjd (void) fprintf(stderr, gettext("unrecognized " 5619168404Spjd "command '%s'\n"), cmdname); 5620168404Spjd usage(B_FALSE); 5621168404Spjd } 5622168404Spjd 5623248571Smm if (ret == 0 && log_history) 5624248571Smm (void) zpool_log_history(g_zfs, history_str); 5625248571Smm 5626168404Spjd libzfs_fini(g_zfs); 5627168404Spjd 5628168404Spjd /* 5629168404Spjd * The 'ZFS_ABORT' environment variable causes us to dump core on exit 5630168404Spjd * for the purposes of running ::findleaks. 5631168404Spjd */ 5632168404Spjd if (getenv("ZFS_ABORT") != NULL) { 5633168404Spjd (void) printf("dumping core by request\n"); 5634168404Spjd abort(); 5635168404Spjd } 5636168404Spjd 5637168404Spjd return (ret); 5638168404Spjd} 5639