zpool_main.c revision 324255
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. 24286708Smav * Copyright (c) 2011, 2015 by Delphix. All rights reserved. 25236145Smm * Copyright (c) 2012 by Frederik Wessels. All rights reserved. 26236155Smm * Copyright (c) 2012 Martin Matuska <mm@FreeBSD.org>. All rights reserved. 27254758Sdelphij * Copyright (c) 2013 by Prasad Joshi (sTec). All rights reserved. 28296537Smav * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>. 29297763Smav * Copyright 2016 Nexenta Systems, Inc. 30324010Savg * Copyright (c) 2017 Datto Inc. 31168404Spjd */ 32168404Spjd 33168404Spjd#include <solaris.h> 34168404Spjd#include <assert.h> 35168404Spjd#include <ctype.h> 36168404Spjd#include <dirent.h> 37168404Spjd#include <errno.h> 38168404Spjd#include <fcntl.h> 39168404Spjd#include <libgen.h> 40168404Spjd#include <libintl.h> 41168404Spjd#include <libuutil.h> 42168404Spjd#include <locale.h> 43168404Spjd#include <stdio.h> 44168404Spjd#include <stdlib.h> 45168404Spjd#include <string.h> 46168404Spjd#include <strings.h> 47168404Spjd#include <unistd.h> 48168404Spjd#include <priv.h> 49185029Spjd#include <pwd.h> 50185029Spjd#include <zone.h> 51168404Spjd#include <sys/time.h> 52236155Smm#include <zfs_prop.h> 53168404Spjd#include <sys/fs/zfs.h> 54168404Spjd#include <sys/stat.h> 55168404Spjd 56168404Spjd#include <libzfs.h> 57168404Spjd 58168404Spjd#include "zpool_util.h" 59185029Spjd#include "zfs_comutil.h" 60236884Smm#include "zfeature_common.h" 61168404Spjd 62219089Spjd#include "statcommon.h" 63219089Spjd 64168404Spjdstatic int zpool_do_create(int, char **); 65168404Spjdstatic int zpool_do_destroy(int, char **); 66168404Spjd 67168404Spjdstatic int zpool_do_add(int, char **); 68168404Spjdstatic int zpool_do_remove(int, char **); 69224171Sgibbsstatic int zpool_do_labelclear(int, char **); 70168404Spjd 71168404Spjdstatic int zpool_do_list(int, char **); 72168404Spjdstatic int zpool_do_iostat(int, char **); 73168404Spjdstatic int zpool_do_status(int, char **); 74168404Spjd 75168404Spjdstatic int zpool_do_online(int, char **); 76168404Spjdstatic int zpool_do_offline(int, char **); 77168404Spjdstatic int zpool_do_clear(int, char **); 78236155Smmstatic int zpool_do_reopen(int, char **); 79168404Spjd 80228103Smmstatic int zpool_do_reguid(int, char **); 81228103Smm 82168404Spjdstatic int zpool_do_attach(int, char **); 83168404Spjdstatic int zpool_do_detach(int, char **); 84168404Spjdstatic int zpool_do_replace(int, char **); 85219089Spjdstatic int zpool_do_split(int, char **); 86168404Spjd 87168404Spjdstatic int zpool_do_scrub(int, char **); 88168404Spjd 89168404Spjdstatic int zpool_do_import(int, char **); 90168404Spjdstatic int zpool_do_export(int, char **); 91168404Spjd 92168404Spjdstatic int zpool_do_upgrade(int, char **); 93168404Spjd 94168404Spjdstatic int zpool_do_history(int, char **); 95168404Spjd 96168404Spjdstatic int zpool_do_get(int, char **); 97168404Spjdstatic int zpool_do_set(int, char **); 98168404Spjd 99168404Spjd/* 100168404Spjd * These libumem hooks provide a reasonable set of defaults for the allocator's 101168404Spjd * debugging facilities. 102168404Spjd */ 103185029Spjd 104185029Spjd#ifdef DEBUG 105168404Spjdconst char * 106168404Spjd_umem_debug_init(void) 107168404Spjd{ 108168404Spjd return ("default,verbose"); /* $UMEM_DEBUG setting */ 109168404Spjd} 110168404Spjd 111168404Spjdconst char * 112168404Spjd_umem_logging_init(void) 113168404Spjd{ 114168404Spjd return ("fail,contents"); /* $UMEM_LOGGING setting */ 115168404Spjd} 116185029Spjd#endif 117168404Spjd 118168404Spjdtypedef enum { 119168404Spjd HELP_ADD, 120168404Spjd HELP_ATTACH, 121168404Spjd HELP_CLEAR, 122168404Spjd HELP_CREATE, 123168404Spjd HELP_DESTROY, 124168404Spjd HELP_DETACH, 125168404Spjd HELP_EXPORT, 126168404Spjd HELP_HISTORY, 127168404Spjd HELP_IMPORT, 128168404Spjd HELP_IOSTAT, 129224171Sgibbs HELP_LABELCLEAR, 130168404Spjd HELP_LIST, 131168404Spjd HELP_OFFLINE, 132168404Spjd HELP_ONLINE, 133168404Spjd HELP_REPLACE, 134168404Spjd HELP_REMOVE, 135168404Spjd HELP_SCRUB, 136168404Spjd HELP_STATUS, 137168404Spjd HELP_UPGRADE, 138168404Spjd HELP_GET, 139219089Spjd HELP_SET, 140228103Smm HELP_SPLIT, 141236155Smm HELP_REGUID, 142236155Smm HELP_REOPEN 143168404Spjd} zpool_help_t; 144168404Spjd 145168404Spjd 146168404Spjdtypedef struct zpool_command { 147168404Spjd const char *name; 148168404Spjd int (*func)(int, char **); 149168404Spjd zpool_help_t usage; 150168404Spjd} zpool_command_t; 151168404Spjd 152168404Spjd/* 153168404Spjd * Master command table. Each ZFS command has a name, associated function, and 154168404Spjd * usage message. The usage messages need to be internationalized, so we have 155168404Spjd * to have a function to return the usage message based on a command index. 156168404Spjd * 157168404Spjd * These commands are organized according to how they are displayed in the usage 158168404Spjd * message. An empty command (one with a NULL name) indicates an empty line in 159168404Spjd * the generic usage message. 160168404Spjd */ 161168404Spjdstatic zpool_command_t command_table[] = { 162168404Spjd { "create", zpool_do_create, HELP_CREATE }, 163168404Spjd { "destroy", zpool_do_destroy, HELP_DESTROY }, 164168404Spjd { NULL }, 165168404Spjd { "add", zpool_do_add, HELP_ADD }, 166168404Spjd { "remove", zpool_do_remove, HELP_REMOVE }, 167168404Spjd { NULL }, 168224171Sgibbs { "labelclear", zpool_do_labelclear, HELP_LABELCLEAR }, 169224171Sgibbs { NULL }, 170168404Spjd { "list", zpool_do_list, HELP_LIST }, 171168404Spjd { "iostat", zpool_do_iostat, HELP_IOSTAT }, 172168404Spjd { "status", zpool_do_status, HELP_STATUS }, 173168404Spjd { NULL }, 174168404Spjd { "online", zpool_do_online, HELP_ONLINE }, 175168404Spjd { "offline", zpool_do_offline, HELP_OFFLINE }, 176168404Spjd { "clear", zpool_do_clear, HELP_CLEAR }, 177236155Smm { "reopen", zpool_do_reopen, HELP_REOPEN }, 178168404Spjd { NULL }, 179168404Spjd { "attach", zpool_do_attach, HELP_ATTACH }, 180168404Spjd { "detach", zpool_do_detach, HELP_DETACH }, 181168404Spjd { "replace", zpool_do_replace, HELP_REPLACE }, 182219089Spjd { "split", zpool_do_split, HELP_SPLIT }, 183168404Spjd { NULL }, 184168404Spjd { "scrub", zpool_do_scrub, HELP_SCRUB }, 185168404Spjd { NULL }, 186168404Spjd { "import", zpool_do_import, HELP_IMPORT }, 187168404Spjd { "export", zpool_do_export, HELP_EXPORT }, 188168404Spjd { "upgrade", zpool_do_upgrade, HELP_UPGRADE }, 189228103Smm { "reguid", zpool_do_reguid, HELP_REGUID }, 190168404Spjd { NULL }, 191168404Spjd { "history", zpool_do_history, HELP_HISTORY }, 192168404Spjd { "get", zpool_do_get, HELP_GET }, 193168404Spjd { "set", zpool_do_set, HELP_SET }, 194168404Spjd}; 195168404Spjd 196168404Spjd#define NCOMMAND (sizeof (command_table) / sizeof (command_table[0])) 197168404Spjd 198248571Smmstatic zpool_command_t *current_command; 199185029Spjdstatic char history_str[HIS_MAX_RECORD_LEN]; 200248571Smmstatic boolean_t log_history = B_TRUE; 201219089Spjdstatic uint_t timestamp_fmt = NODATE; 202219089Spjd 203168404Spjdstatic const char * 204289562Smavget_usage(zpool_help_t idx) 205289562Smav{ 206168404Spjd switch (idx) { 207168404Spjd case HELP_ADD: 208168404Spjd return (gettext("\tadd [-fn] <pool> <vdev> ...\n")); 209168404Spjd case HELP_ATTACH: 210168404Spjd return (gettext("\tattach [-f] <pool> <device> " 211185029Spjd "<new-device>\n")); 212168404Spjd case HELP_CLEAR: 213219089Spjd return (gettext("\tclear [-nF] <pool> [device]\n")); 214168404Spjd case HELP_CREATE: 215236884Smm return (gettext("\tcreate [-fnd] [-o property=value] ... \n" 216185029Spjd "\t [-O file-system-property=value] ... \n" 217185029Spjd "\t [-m mountpoint] [-R root] <pool> <vdev> ...\n")); 218168404Spjd case HELP_DESTROY: 219168404Spjd return (gettext("\tdestroy [-f] <pool>\n")); 220168404Spjd case HELP_DETACH: 221168404Spjd return (gettext("\tdetach <pool> <device>\n")); 222168404Spjd case HELP_EXPORT: 223168404Spjd return (gettext("\texport [-f] <pool> ...\n")); 224168404Spjd case HELP_HISTORY: 225185029Spjd return (gettext("\thistory [-il] [<pool>] ...\n")); 226168404Spjd case HELP_IMPORT: 227168404Spjd return (gettext("\timport [-d dir] [-D]\n" 228219089Spjd "\timport [-d dir | -c cachefile] [-F [-n]] <pool | id>\n" 229185029Spjd "\timport [-o mntopts] [-o property=value] ... \n" 230219089Spjd "\t [-d dir | -c cachefile] [-D] [-f] [-m] [-N] " 231219089Spjd "[-R root] [-F [-n]] -a\n" 232185029Spjd "\timport [-o mntopts] [-o property=value] ... \n" 233219089Spjd "\t [-d dir | -c cachefile] [-D] [-f] [-m] [-N] " 234219089Spjd "[-R root] [-F [-n]]\n" 235219089Spjd "\t <pool | id> [newpool]\n")); 236168404Spjd case HELP_IOSTAT: 237219089Spjd return (gettext("\tiostat [-v] [-T d|u] [pool] ... [interval " 238168404Spjd "[count]]\n")); 239224171Sgibbs case HELP_LABELCLEAR: 240224171Sgibbs return (gettext("\tlabelclear [-f] <vdev>\n")); 241168404Spjd case HELP_LIST: 242263889Sdelphij return (gettext("\tlist [-Hpv] [-o property[,...]] " 243219089Spjd "[-T d|u] [pool] ... [interval [count]]\n")); 244168404Spjd case HELP_OFFLINE: 245168404Spjd return (gettext("\toffline [-t] <pool> <device> ...\n")); 246168404Spjd case HELP_ONLINE: 247228020Smm return (gettext("\tonline [-e] <pool> <device> ...\n")); 248168404Spjd case HELP_REPLACE: 249168404Spjd return (gettext("\treplace [-f] <pool> <device> " 250185029Spjd "[new-device]\n")); 251168404Spjd case HELP_REMOVE: 252185029Spjd return (gettext("\tremove <pool> <device> ...\n")); 253236155Smm case HELP_REOPEN: 254260138Sdelphij return (gettext("\treopen <pool>\n")); 255168404Spjd case HELP_SCRUB: 256324010Savg return (gettext("\tscrub [-s | -p] <pool> ...\n")); 257168404Spjd case HELP_STATUS: 258219089Spjd return (gettext("\tstatus [-vx] [-T d|u] [pool] ... [interval " 259219089Spjd "[count]]\n")); 260168404Spjd case HELP_UPGRADE: 261228020Smm return (gettext("\tupgrade [-v]\n" 262185029Spjd "\tupgrade [-V version] <-a | pool ...>\n")); 263168404Spjd case HELP_GET: 264263889Sdelphij return (gettext("\tget [-Hp] [-o \"all\" | field[,...]] " 265263889Sdelphij "<\"all\" | property[,...]> <pool> ...\n")); 266168404Spjd case HELP_SET: 267168404Spjd return (gettext("\tset <property=value> <pool> \n")); 268219089Spjd case HELP_SPLIT: 269219089Spjd return (gettext("\tsplit [-n] [-R altroot] [-o mntopts]\n" 270219089Spjd "\t [-o property=value] <pool> <newpool> " 271219089Spjd "[<device> ...]\n")); 272228103Smm case HELP_REGUID: 273228103Smm return (gettext("\treguid <pool>\n")); 274168404Spjd } 275168404Spjd 276168404Spjd abort(); 277168404Spjd /* NOTREACHED */ 278168404Spjd} 279168404Spjd 280168404Spjd 281168404Spjd/* 282168404Spjd * Callback routine that will print out a pool property value. 283168404Spjd */ 284185029Spjdstatic int 285185029Spjdprint_prop_cb(int prop, void *cb) 286168404Spjd{ 287168404Spjd FILE *fp = cb; 288168404Spjd 289219089Spjd (void) fprintf(fp, "\t%-15s ", zpool_prop_to_name(prop)); 290168404Spjd 291185029Spjd if (zpool_prop_readonly(prop)) 292185029Spjd (void) fprintf(fp, " NO "); 293185029Spjd else 294219089Spjd (void) fprintf(fp, " YES "); 295185029Spjd 296168404Spjd if (zpool_prop_values(prop) == NULL) 297168404Spjd (void) fprintf(fp, "-\n"); 298168404Spjd else 299168404Spjd (void) fprintf(fp, "%s\n", zpool_prop_values(prop)); 300168404Spjd 301185029Spjd return (ZPROP_CONT); 302168404Spjd} 303168404Spjd 304168404Spjd/* 305168404Spjd * Display usage message. If we're inside a command, display only the usage for 306168404Spjd * that command. Otherwise, iterate over the entire command table and display 307168404Spjd * a complete usage message. 308168404Spjd */ 309168404Spjdvoid 310168404Spjdusage(boolean_t requested) 311168404Spjd{ 312168404Spjd FILE *fp = requested ? stdout : stderr; 313168404Spjd 314168404Spjd if (current_command == NULL) { 315168404Spjd int i; 316168404Spjd 317168404Spjd (void) fprintf(fp, gettext("usage: zpool command args ...\n")); 318168404Spjd (void) fprintf(fp, 319168404Spjd gettext("where 'command' is one of the following:\n\n")); 320168404Spjd 321168404Spjd for (i = 0; i < NCOMMAND; i++) { 322168404Spjd if (command_table[i].name == NULL) 323168404Spjd (void) fprintf(fp, "\n"); 324168404Spjd else 325168404Spjd (void) fprintf(fp, "%s", 326168404Spjd get_usage(command_table[i].usage)); 327168404Spjd } 328168404Spjd } else { 329168404Spjd (void) fprintf(fp, gettext("usage:\n")); 330168404Spjd (void) fprintf(fp, "%s", get_usage(current_command->usage)); 331168404Spjd } 332168404Spjd 333168404Spjd if (current_command != NULL && 334168404Spjd ((strcmp(current_command->name, "set") == 0) || 335185029Spjd (strcmp(current_command->name, "get") == 0) || 336185029Spjd (strcmp(current_command->name, "list") == 0))) { 337168404Spjd 338168404Spjd (void) fprintf(fp, 339168404Spjd gettext("\nthe following properties are supported:\n")); 340168404Spjd 341219089Spjd (void) fprintf(fp, "\n\t%-15s %s %s\n\n", 342185029Spjd "PROPERTY", "EDIT", "VALUES"); 343168404Spjd 344168404Spjd /* Iterate over all properties */ 345185029Spjd (void) zprop_iter(print_prop_cb, fp, B_FALSE, B_TRUE, 346185029Spjd ZFS_TYPE_POOL); 347236884Smm 348236884Smm (void) fprintf(fp, "\t%-15s ", "feature@..."); 349236884Smm (void) fprintf(fp, "YES disabled | enabled | active\n"); 350236884Smm 351236884Smm (void) fprintf(fp, gettext("\nThe feature@ properties must be " 352243014Smm "appended with a feature name.\nSee zpool-features(7).\n")); 353168404Spjd } 354168404Spjd 355168404Spjd /* 356168404Spjd * See comments at end of main(). 357168404Spjd */ 358168404Spjd if (getenv("ZFS_ABORT") != NULL) { 359168404Spjd (void) printf("dumping core by request\n"); 360168404Spjd abort(); 361168404Spjd } 362168404Spjd 363168404Spjd exit(requested ? 0 : 2); 364168404Spjd} 365168404Spjd 366168404Spjdvoid 367185029Spjdprint_vdev_tree(zpool_handle_t *zhp, const char *name, nvlist_t *nv, int indent, 368185029Spjd boolean_t print_logs) 369168404Spjd{ 370168404Spjd nvlist_t **child; 371168404Spjd uint_t c, children; 372168404Spjd char *vname; 373168404Spjd 374168404Spjd if (name != NULL) 375168404Spjd (void) printf("\t%*s%s\n", indent, "", name); 376168404Spjd 377168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 378168404Spjd &child, &children) != 0) 379168404Spjd return; 380168404Spjd 381168404Spjd for (c = 0; c < children; c++) { 382185029Spjd uint64_t is_log = B_FALSE; 383185029Spjd 384185029Spjd (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 385185029Spjd &is_log); 386185029Spjd if ((is_log && !print_logs) || (!is_log && print_logs)) 387185029Spjd continue; 388185029Spjd 389219089Spjd vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE); 390185029Spjd print_vdev_tree(zhp, vname, child[c], indent + 2, 391185029Spjd B_FALSE); 392168404Spjd free(vname); 393168404Spjd } 394168404Spjd} 395168404Spjd 396238926Smmstatic boolean_t 397238926Smmprop_list_contains_feature(nvlist_t *proplist) 398238926Smm{ 399238926Smm nvpair_t *nvp; 400238926Smm for (nvp = nvlist_next_nvpair(proplist, NULL); NULL != nvp; 401238926Smm nvp = nvlist_next_nvpair(proplist, nvp)) { 402238926Smm if (zpool_prop_feature(nvpair_name(nvp))) 403238926Smm return (B_TRUE); 404238926Smm } 405238926Smm return (B_FALSE); 406238926Smm} 407238926Smm 408168404Spjd/* 409185029Spjd * Add a property pair (name, string-value) into a property nvlist. 410185029Spjd */ 411185029Spjdstatic int 412185029Spjdadd_prop_list(const char *propname, char *propval, nvlist_t **props, 413185029Spjd boolean_t poolprop) 414185029Spjd{ 415185029Spjd zpool_prop_t prop = ZPROP_INVAL; 416185029Spjd zfs_prop_t fprop; 417185029Spjd nvlist_t *proplist; 418185029Spjd const char *normnm; 419185029Spjd char *strval; 420185029Spjd 421185029Spjd if (*props == NULL && 422185029Spjd nvlist_alloc(props, NV_UNIQUE_NAME, 0) != 0) { 423185029Spjd (void) fprintf(stderr, 424185029Spjd gettext("internal error: out of memory\n")); 425185029Spjd return (1); 426185029Spjd } 427185029Spjd 428185029Spjd proplist = *props; 429185029Spjd 430185029Spjd if (poolprop) { 431238926Smm const char *vname = zpool_prop_to_name(ZPOOL_PROP_VERSION); 432238926Smm 433236884Smm if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL && 434236884Smm !zpool_prop_feature(propname)) { 435185029Spjd (void) fprintf(stderr, gettext("property '%s' is " 436185029Spjd "not a valid pool property\n"), propname); 437185029Spjd return (2); 438185029Spjd } 439238926Smm 440238926Smm /* 441238926Smm * feature@ properties and version should not be specified 442238926Smm * at the same time. 443238926Smm */ 444238926Smm if ((prop == ZPROP_INVAL && zpool_prop_feature(propname) && 445238926Smm nvlist_exists(proplist, vname)) || 446238926Smm (prop == ZPOOL_PROP_VERSION && 447238926Smm prop_list_contains_feature(proplist))) { 448238926Smm (void) fprintf(stderr, gettext("'feature@' and " 449238926Smm "'version' properties cannot be specified " 450238926Smm "together\n")); 451238926Smm return (2); 452238926Smm } 453238926Smm 454238926Smm 455236884Smm if (zpool_prop_feature(propname)) 456236884Smm normnm = propname; 457236884Smm else 458236884Smm normnm = zpool_prop_to_name(prop); 459185029Spjd } else { 460209962Smm if ((fprop = zfs_name_to_prop(propname)) != ZPROP_INVAL) { 461209962Smm normnm = zfs_prop_to_name(fprop); 462209962Smm } else { 463209962Smm normnm = propname; 464185029Spjd } 465185029Spjd } 466185029Spjd 467185029Spjd if (nvlist_lookup_string(proplist, normnm, &strval) == 0 && 468185029Spjd prop != ZPOOL_PROP_CACHEFILE) { 469185029Spjd (void) fprintf(stderr, gettext("property '%s' " 470185029Spjd "specified multiple times\n"), propname); 471185029Spjd return (2); 472185029Spjd } 473185029Spjd 474185029Spjd if (nvlist_add_string(proplist, normnm, propval) != 0) { 475185029Spjd (void) fprintf(stderr, gettext("internal " 476185029Spjd "error: out of memory\n")); 477185029Spjd return (1); 478185029Spjd } 479185029Spjd 480185029Spjd return (0); 481185029Spjd} 482185029Spjd 483185029Spjd/* 484168404Spjd * zpool add [-fn] <pool> <vdev> ... 485168404Spjd * 486168404Spjd * -f Force addition of devices, even if they appear in use 487168404Spjd * -n Do not add the devices, but display the resulting layout if 488168404Spjd * they were to be added. 489168404Spjd * 490168404Spjd * Adds the given vdevs to 'pool'. As with create, the bulk of this work is 491168404Spjd * handled by get_vdev_spec(), which constructs the nvlist needed to pass to 492168404Spjd * libzfs. 493168404Spjd */ 494168404Spjdint 495168404Spjdzpool_do_add(int argc, char **argv) 496168404Spjd{ 497168404Spjd boolean_t force = B_FALSE; 498168404Spjd boolean_t dryrun = B_FALSE; 499168404Spjd int c; 500168404Spjd nvlist_t *nvroot; 501168404Spjd char *poolname; 502168404Spjd int ret; 503168404Spjd zpool_handle_t *zhp; 504168404Spjd nvlist_t *config; 505168404Spjd 506168404Spjd /* check options */ 507168404Spjd while ((c = getopt(argc, argv, "fn")) != -1) { 508168404Spjd switch (c) { 509168404Spjd case 'f': 510168404Spjd force = B_TRUE; 511168404Spjd break; 512168404Spjd case 'n': 513168404Spjd dryrun = B_TRUE; 514168404Spjd break; 515168404Spjd case '?': 516168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 517168404Spjd optopt); 518168404Spjd usage(B_FALSE); 519168404Spjd } 520168404Spjd } 521168404Spjd 522168404Spjd argc -= optind; 523168404Spjd argv += optind; 524168404Spjd 525168404Spjd /* get pool name and check number of arguments */ 526168404Spjd if (argc < 1) { 527168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 528168404Spjd usage(B_FALSE); 529168404Spjd } 530168404Spjd if (argc < 2) { 531168404Spjd (void) fprintf(stderr, gettext("missing vdev specification\n")); 532168404Spjd usage(B_FALSE); 533168404Spjd } 534168404Spjd 535168404Spjd poolname = argv[0]; 536168404Spjd 537168404Spjd argc--; 538168404Spjd argv++; 539168404Spjd 540168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 541168404Spjd return (1); 542168404Spjd 543168404Spjd if ((config = zpool_get_config(zhp, NULL)) == NULL) { 544168404Spjd (void) fprintf(stderr, gettext("pool '%s' is unavailable\n"), 545168404Spjd poolname); 546168404Spjd zpool_close(zhp); 547168404Spjd return (1); 548168404Spjd } 549168404Spjd 550168404Spjd /* pass off to get_vdev_spec for processing */ 551185029Spjd nvroot = make_root_vdev(zhp, force, !force, B_FALSE, dryrun, 552185029Spjd argc, argv); 553168404Spjd if (nvroot == NULL) { 554168404Spjd zpool_close(zhp); 555168404Spjd return (1); 556168404Spjd } 557168404Spjd 558168404Spjd if (dryrun) { 559168404Spjd nvlist_t *poolnvroot; 560168404Spjd 561168404Spjd verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 562168404Spjd &poolnvroot) == 0); 563168404Spjd 564168404Spjd (void) printf(gettext("would update '%s' to the following " 565168404Spjd "configuration:\n"), zpool_get_name(zhp)); 566168404Spjd 567185029Spjd /* print original main pool and new tree */ 568185029Spjd print_vdev_tree(zhp, poolname, poolnvroot, 0, B_FALSE); 569185029Spjd print_vdev_tree(zhp, NULL, nvroot, 0, B_FALSE); 570168404Spjd 571185029Spjd /* Do the same for the logs */ 572185029Spjd if (num_logs(poolnvroot) > 0) { 573185029Spjd print_vdev_tree(zhp, "logs", poolnvroot, 0, B_TRUE); 574185029Spjd print_vdev_tree(zhp, NULL, nvroot, 0, B_TRUE); 575185029Spjd } else if (num_logs(nvroot) > 0) { 576185029Spjd print_vdev_tree(zhp, "logs", nvroot, 0, B_TRUE); 577185029Spjd } 578185029Spjd 579168404Spjd ret = 0; 580168404Spjd } else { 581168404Spjd ret = (zpool_add(zhp, nvroot) != 0); 582168404Spjd } 583168404Spjd 584168404Spjd nvlist_free(nvroot); 585168404Spjd zpool_close(zhp); 586168404Spjd 587168404Spjd return (ret); 588168404Spjd} 589168404Spjd 590168404Spjd/* 591219089Spjd * zpool remove <pool> <vdev> ... 592168404Spjd * 593219089Spjd * Removes the given vdev from the pool. Currently, this supports removing 594219089Spjd * spares, cache, and log devices from the pool. 595168404Spjd */ 596168404Spjdint 597168404Spjdzpool_do_remove(int argc, char **argv) 598168404Spjd{ 599168404Spjd char *poolname; 600185029Spjd int i, ret = 0; 601168404Spjd zpool_handle_t *zhp; 602168404Spjd 603168404Spjd argc--; 604168404Spjd argv++; 605168404Spjd 606168404Spjd /* get pool name and check number of arguments */ 607168404Spjd if (argc < 1) { 608168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 609168404Spjd usage(B_FALSE); 610168404Spjd } 611168404Spjd if (argc < 2) { 612168404Spjd (void) fprintf(stderr, gettext("missing device\n")); 613168404Spjd usage(B_FALSE); 614168404Spjd } 615168404Spjd 616168404Spjd poolname = argv[0]; 617168404Spjd 618168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 619168404Spjd return (1); 620168404Spjd 621185029Spjd for (i = 1; i < argc; i++) { 622185029Spjd if (zpool_vdev_remove(zhp, argv[i]) != 0) 623185029Spjd ret = 1; 624168404Spjd } 625168404Spjd 626168404Spjd return (ret); 627168404Spjd} 628168404Spjd 629168404Spjd/* 630297763Smav * zpool labelclear [-f] <vdev> 631224171Sgibbs * 632297763Smav * -f Force clearing the label for the vdevs which are members of 633297763Smav * the exported or foreign pools. 634297763Smav * 635224171Sgibbs * Verifies that the vdev is not active and zeros out the label information 636224171Sgibbs * on the device. 637224171Sgibbs */ 638224171Sgibbsint 639224171Sgibbszpool_do_labelclear(int argc, char **argv) 640224171Sgibbs{ 641297763Smav char vdev[MAXPATHLEN]; 642297763Smav char *name = NULL; 643297763Smav struct stat st; 644297763Smav int c, fd, ret = 0; 645297763Smav nvlist_t *config; 646224171Sgibbs pool_state_t state; 647224171Sgibbs boolean_t inuse = B_FALSE; 648224171Sgibbs boolean_t force = B_FALSE; 649224171Sgibbs 650224171Sgibbs /* check options */ 651224171Sgibbs while ((c = getopt(argc, argv, "f")) != -1) { 652224171Sgibbs switch (c) { 653224171Sgibbs case 'f': 654224171Sgibbs force = B_TRUE; 655224171Sgibbs break; 656224171Sgibbs default: 657224171Sgibbs (void) fprintf(stderr, gettext("invalid option '%c'\n"), 658224171Sgibbs optopt); 659224171Sgibbs usage(B_FALSE); 660224171Sgibbs } 661224171Sgibbs } 662224171Sgibbs 663224171Sgibbs argc -= optind; 664224171Sgibbs argv += optind; 665224171Sgibbs 666224171Sgibbs /* get vdev name */ 667224171Sgibbs if (argc < 1) { 668297763Smav (void) fprintf(stderr, gettext("missing vdev name\n")); 669224171Sgibbs usage(B_FALSE); 670224171Sgibbs } 671297763Smav if (argc > 1) { 672297763Smav (void) fprintf(stderr, gettext("too many arguments\n")); 673297763Smav usage(B_FALSE); 674297763Smav } 675224171Sgibbs 676297763Smav /* 677297763Smav * Check if we were given absolute path and use it as is. 678297763Smav * Otherwise if the provided vdev name doesn't point to a file, 679297763Smav * try prepending dsk path and appending s0. 680297763Smav */ 681297763Smav (void) strlcpy(vdev, argv[0], sizeof (vdev)); 682297763Smav if (vdev[0] != '/' && stat(vdev, &st) != 0) { 683297763Smav char *s; 684297763Smav 685297763Smav (void) snprintf(vdev, sizeof (vdev), "%s/%s", 686297763Smav#ifdef illumos 687297763Smav ZFS_DISK_ROOT, argv[0]); 688297763Smav if ((s = strrchr(argv[0], 's')) == NULL || 689297763Smav !isdigit(*(s + 1))) 690297763Smav (void) strlcat(vdev, "s0", sizeof (vdev)); 691297763Smav#else 692297763Smav "/dev", argv[0]); 693297763Smav#endif 694297763Smav if (stat(vdev, &st) != 0) { 695297763Smav (void) fprintf(stderr, gettext( 696297763Smav "failed to find device %s, try specifying absolute " 697297763Smav "path instead\n"), argv[0]); 698297763Smav return (1); 699297763Smav } 700297763Smav } 701297763Smav 702224171Sgibbs if ((fd = open(vdev, O_RDWR)) < 0) { 703297763Smav (void) fprintf(stderr, gettext("failed to open %s: %s\n"), 704297763Smav vdev, strerror(errno)); 705297763Smav return (1); 706224171Sgibbs } 707224171Sgibbs 708324255Savg if (zpool_read_label(fd, &config) != 0) { 709224171Sgibbs (void) fprintf(stderr, 710297763Smav gettext("failed to read label from %s\n"), vdev); 711297763Smav return (1); 712297763Smav } 713297763Smav nvlist_free(config); 714224171Sgibbs 715297763Smav ret = zpool_in_use(g_zfs, fd, &state, &name, &inuse); 716297763Smav if (ret != 0) { 717297763Smav (void) fprintf(stderr, 718297763Smav gettext("failed to check state for %s\n"), vdev); 719224171Sgibbs return (1); 720224171Sgibbs } 721224171Sgibbs 722297763Smav if (!inuse) 723297763Smav goto wipe_label; 724224171Sgibbs 725297763Smav switch (state) { 726297763Smav default: 727297763Smav case POOL_STATE_ACTIVE: 728297763Smav case POOL_STATE_SPARE: 729297763Smav case POOL_STATE_L2CACHE: 730297763Smav (void) fprintf(stderr, gettext( 731297763Smav "%s is a member (%s) of pool \"%s\"\n"), 732297763Smav vdev, zpool_pool_state_to_name(state), name); 733297763Smav ret = 1; 734297763Smav goto errout; 735224171Sgibbs 736297763Smav case POOL_STATE_EXPORTED: 737297763Smav if (force) 738297763Smav break; 739297763Smav (void) fprintf(stderr, gettext( 740297763Smav "use '-f' to override the following error:\n" 741297763Smav "%s is a member of exported pool \"%s\"\n"), 742297763Smav vdev, name); 743297763Smav ret = 1; 744297763Smav goto errout; 745224171Sgibbs 746297763Smav case POOL_STATE_POTENTIALLY_ACTIVE: 747297763Smav if (force) 748297763Smav break; 749297763Smav (void) fprintf(stderr, gettext( 750297763Smav "use '-f' to override the following error:\n" 751297763Smav "%s is a member of potentially active pool \"%s\"\n"), 752297763Smav vdev, name); 753297763Smav ret = 1; 754297763Smav goto errout; 755224171Sgibbs 756297763Smav case POOL_STATE_DESTROYED: 757297763Smav /* inuse should never be set for a destroyed pool */ 758297763Smav assert(0); 759297763Smav break; 760224171Sgibbs } 761224171Sgibbs 762224171Sgibbswipe_label: 763297763Smav ret = zpool_clear_label(fd); 764297763Smav if (ret != 0) { 765224171Sgibbs (void) fprintf(stderr, 766297763Smav gettext("failed to clear label for %s\n"), vdev); 767224171Sgibbs } 768224171Sgibbs 769224171Sgibbserrout: 770297763Smav free(name); 771297763Smav (void) close(fd); 772224171Sgibbs 773224171Sgibbs return (ret); 774224171Sgibbs} 775224171Sgibbs 776224171Sgibbs/* 777236884Smm * zpool create [-fnd] [-o property=value] ... 778185029Spjd * [-O file-system-property=value] ... 779185029Spjd * [-R root] [-m mountpoint] <pool> <dev> ... 780168404Spjd * 781168404Spjd * -f Force creation, even if devices appear in use 782168404Spjd * -n Do not create the pool, but display the resulting layout if it 783168404Spjd * were to be created. 784168404Spjd * -R Create a pool under an alternate root 785168404Spjd * -m Set default mountpoint for the root dataset. By default it's 786236884Smm * '/<pool>' 787185029Spjd * -o Set property=value. 788236884Smm * -d Don't automatically enable all supported pool features 789236884Smm * (individual features can be enabled with -o). 790185029Spjd * -O Set fsproperty=value in the pool's root file system 791168404Spjd * 792168404Spjd * Creates the named pool according to the given vdev specification. The 793168404Spjd * bulk of the vdev processing is done in get_vdev_spec() in zpool_vdev.c. Once 794168404Spjd * we get the nvlist back from get_vdev_spec(), we either print out the contents 795168404Spjd * (if '-n' was specified), or pass it to libzfs to do the creation. 796168404Spjd */ 797168404Spjdint 798168404Spjdzpool_do_create(int argc, char **argv) 799168404Spjd{ 800168404Spjd boolean_t force = B_FALSE; 801168404Spjd boolean_t dryrun = B_FALSE; 802236884Smm boolean_t enable_all_pool_feat = B_TRUE; 803168404Spjd int c; 804185029Spjd nvlist_t *nvroot = NULL; 805168404Spjd char *poolname; 806185029Spjd int ret = 1; 807168404Spjd char *altroot = NULL; 808168404Spjd char *mountpoint = NULL; 809185029Spjd nvlist_t *fsprops = NULL; 810185029Spjd nvlist_t *props = NULL; 811185029Spjd char *propval; 812168404Spjd 813168404Spjd /* check options */ 814236884Smm while ((c = getopt(argc, argv, ":fndR:m:o:O:")) != -1) { 815168404Spjd switch (c) { 816168404Spjd case 'f': 817168404Spjd force = B_TRUE; 818168404Spjd break; 819168404Spjd case 'n': 820168404Spjd dryrun = B_TRUE; 821168404Spjd break; 822236884Smm case 'd': 823236884Smm enable_all_pool_feat = B_FALSE; 824236884Smm break; 825168404Spjd case 'R': 826168404Spjd altroot = optarg; 827185029Spjd if (add_prop_list(zpool_prop_to_name( 828185029Spjd ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE)) 829185029Spjd goto errout; 830185029Spjd if (nvlist_lookup_string(props, 831185029Spjd zpool_prop_to_name(ZPOOL_PROP_CACHEFILE), 832185029Spjd &propval) == 0) 833185029Spjd break; 834185029Spjd if (add_prop_list(zpool_prop_to_name( 835185029Spjd ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE)) 836185029Spjd goto errout; 837168404Spjd break; 838168404Spjd case 'm': 839251634Sdelphij /* Equivalent to -O mountpoint=optarg */ 840168404Spjd mountpoint = optarg; 841168404Spjd break; 842185029Spjd case 'o': 843185029Spjd if ((propval = strchr(optarg, '=')) == NULL) { 844185029Spjd (void) fprintf(stderr, gettext("missing " 845185029Spjd "'=' for -o option\n")); 846185029Spjd goto errout; 847185029Spjd } 848185029Spjd *propval = '\0'; 849185029Spjd propval++; 850185029Spjd 851185029Spjd if (add_prop_list(optarg, propval, &props, B_TRUE)) 852185029Spjd goto errout; 853236884Smm 854236884Smm /* 855236884Smm * If the user is creating a pool that doesn't support 856236884Smm * feature flags, don't enable any features. 857236884Smm */ 858236884Smm if (zpool_name_to_prop(optarg) == ZPOOL_PROP_VERSION) { 859236884Smm char *end; 860236884Smm u_longlong_t ver; 861236884Smm 862236884Smm ver = strtoull(propval, &end, 10); 863236884Smm if (*end == '\0' && 864236884Smm ver < SPA_VERSION_FEATURES) { 865236884Smm enable_all_pool_feat = B_FALSE; 866236884Smm } 867236884Smm } 868279366Sdelphij if (zpool_name_to_prop(optarg) == ZPOOL_PROP_ALTROOT) 869279366Sdelphij altroot = propval; 870185029Spjd break; 871185029Spjd case 'O': 872185029Spjd if ((propval = strchr(optarg, '=')) == NULL) { 873185029Spjd (void) fprintf(stderr, gettext("missing " 874185029Spjd "'=' for -O option\n")); 875185029Spjd goto errout; 876185029Spjd } 877185029Spjd *propval = '\0'; 878185029Spjd propval++; 879185029Spjd 880251634Sdelphij /* 881251634Sdelphij * Mountpoints are checked and then added later. 882251634Sdelphij * Uniquely among properties, they can be specified 883251634Sdelphij * more than once, to avoid conflict with -m. 884251634Sdelphij */ 885251634Sdelphij if (0 == strcmp(optarg, 886251634Sdelphij zfs_prop_to_name(ZFS_PROP_MOUNTPOINT))) { 887251634Sdelphij mountpoint = propval; 888251634Sdelphij } else if (add_prop_list(optarg, propval, &fsprops, 889251634Sdelphij B_FALSE)) { 890185029Spjd goto errout; 891251634Sdelphij } 892185029Spjd break; 893168404Spjd case ':': 894168404Spjd (void) fprintf(stderr, gettext("missing argument for " 895168404Spjd "'%c' option\n"), optopt); 896185029Spjd goto badusage; 897168404Spjd case '?': 898168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 899168404Spjd optopt); 900185029Spjd goto badusage; 901168404Spjd } 902168404Spjd } 903168404Spjd 904168404Spjd argc -= optind; 905168404Spjd argv += optind; 906168404Spjd 907168404Spjd /* get pool name and check number of arguments */ 908168404Spjd if (argc < 1) { 909168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 910185029Spjd goto badusage; 911168404Spjd } 912168404Spjd if (argc < 2) { 913168404Spjd (void) fprintf(stderr, gettext("missing vdev specification\n")); 914185029Spjd goto badusage; 915168404Spjd } 916168404Spjd 917168404Spjd poolname = argv[0]; 918168404Spjd 919168404Spjd /* 920168404Spjd * As a special case, check for use of '/' in the name, and direct the 921168404Spjd * user to use 'zfs create' instead. 922168404Spjd */ 923168404Spjd if (strchr(poolname, '/') != NULL) { 924168404Spjd (void) fprintf(stderr, gettext("cannot create '%s': invalid " 925168404Spjd "character '/' in pool name\n"), poolname); 926168404Spjd (void) fprintf(stderr, gettext("use 'zfs create' to " 927168404Spjd "create a dataset\n")); 928185029Spjd goto errout; 929168404Spjd } 930168404Spjd 931168404Spjd /* pass off to get_vdev_spec for bulk processing */ 932185029Spjd nvroot = make_root_vdev(NULL, force, !force, B_FALSE, dryrun, 933185029Spjd argc - 1, argv + 1); 934168404Spjd if (nvroot == NULL) 935185029Spjd goto errout; 936168404Spjd 937168404Spjd /* make_root_vdev() allows 0 toplevel children if there are spares */ 938185029Spjd if (!zfs_allocatable_devs(nvroot)) { 939168404Spjd (void) fprintf(stderr, gettext("invalid vdev " 940168404Spjd "specification: at least one toplevel vdev must be " 941168404Spjd "specified\n")); 942185029Spjd goto errout; 943168404Spjd } 944168404Spjd 945168404Spjd if (altroot != NULL && altroot[0] != '/') { 946168404Spjd (void) fprintf(stderr, gettext("invalid alternate root '%s': " 947168404Spjd "must be an absolute path\n"), altroot); 948185029Spjd goto errout; 949168404Spjd } 950168404Spjd 951168404Spjd /* 952168404Spjd * Check the validity of the mountpoint and direct the user to use the 953168404Spjd * '-m' mountpoint option if it looks like its in use. 954244857Spjd * Ignore the checks if the '-f' option is given. 955168404Spjd */ 956244857Spjd if (!force && (mountpoint == NULL || 957168404Spjd (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0 && 958244857Spjd strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) != 0))) { 959168404Spjd char buf[MAXPATHLEN]; 960185029Spjd DIR *dirp; 961168404Spjd 962168404Spjd if (mountpoint && mountpoint[0] != '/') { 963168404Spjd (void) fprintf(stderr, gettext("invalid mountpoint " 964168404Spjd "'%s': must be an absolute path, 'legacy', or " 965168404Spjd "'none'\n"), mountpoint); 966185029Spjd goto errout; 967168404Spjd } 968168404Spjd 969168404Spjd if (mountpoint == NULL) { 970168404Spjd if (altroot != NULL) 971168404Spjd (void) snprintf(buf, sizeof (buf), "%s/%s", 972168404Spjd altroot, poolname); 973168404Spjd else 974168404Spjd (void) snprintf(buf, sizeof (buf), "/%s", 975168404Spjd poolname); 976168404Spjd } else { 977168404Spjd if (altroot != NULL) 978168404Spjd (void) snprintf(buf, sizeof (buf), "%s%s", 979168404Spjd altroot, mountpoint); 980168404Spjd else 981168404Spjd (void) snprintf(buf, sizeof (buf), "%s", 982168404Spjd mountpoint); 983168404Spjd } 984168404Spjd 985185029Spjd if ((dirp = opendir(buf)) == NULL && errno != ENOENT) { 986185029Spjd (void) fprintf(stderr, gettext("mountpoint '%s' : " 987185029Spjd "%s\n"), buf, strerror(errno)); 988185029Spjd (void) fprintf(stderr, gettext("use '-m' " 989185029Spjd "option to provide a different default\n")); 990185029Spjd goto errout; 991185029Spjd } else if (dirp) { 992185029Spjd int count = 0; 993185029Spjd 994185029Spjd while (count < 3 && readdir(dirp) != NULL) 995185029Spjd count++; 996185029Spjd (void) closedir(dirp); 997185029Spjd 998185029Spjd if (count > 2) { 999168404Spjd (void) fprintf(stderr, gettext("mountpoint " 1000168404Spjd "'%s' exists and is not empty\n"), buf); 1001185029Spjd (void) fprintf(stderr, gettext("use '-m' " 1002185029Spjd "option to provide a " 1003185029Spjd "different default\n")); 1004185029Spjd goto errout; 1005185029Spjd } 1006168404Spjd } 1007168404Spjd } 1008168404Spjd 1009251634Sdelphij /* 1010251634Sdelphij * Now that the mountpoint's validity has been checked, ensure that 1011251634Sdelphij * the property is set appropriately prior to creating the pool. 1012251634Sdelphij */ 1013251634Sdelphij if (mountpoint != NULL) { 1014251634Sdelphij ret = add_prop_list(zfs_prop_to_name(ZFS_PROP_MOUNTPOINT), 1015251634Sdelphij mountpoint, &fsprops, B_FALSE); 1016251634Sdelphij if (ret != 0) 1017251634Sdelphij goto errout; 1018251634Sdelphij } 1019251634Sdelphij 1020251634Sdelphij ret = 1; 1021168404Spjd if (dryrun) { 1022168404Spjd /* 1023168404Spjd * For a dry run invocation, print out a basic message and run 1024168404Spjd * through all the vdevs in the list and print out in an 1025168404Spjd * appropriate hierarchy. 1026168404Spjd */ 1027168404Spjd (void) printf(gettext("would create '%s' with the " 1028168404Spjd "following layout:\n\n"), poolname); 1029168404Spjd 1030185029Spjd print_vdev_tree(NULL, poolname, nvroot, 0, B_FALSE); 1031185029Spjd if (num_logs(nvroot) > 0) 1032185029Spjd print_vdev_tree(NULL, "logs", nvroot, 0, B_TRUE); 1033168404Spjd 1034168404Spjd ret = 0; 1035168404Spjd } else { 1036168404Spjd /* 1037168404Spjd * Hand off to libzfs. 1038168404Spjd */ 1039236884Smm if (enable_all_pool_feat) { 1040259813Sdelphij spa_feature_t i; 1041236884Smm for (i = 0; i < SPA_FEATURES; i++) { 1042236884Smm char propname[MAXPATHLEN]; 1043236884Smm zfeature_info_t *feat = &spa_feature_table[i]; 1044236884Smm 1045236884Smm (void) snprintf(propname, sizeof (propname), 1046236884Smm "feature@%s", feat->fi_uname); 1047236884Smm 1048236884Smm /* 1049236884Smm * Skip feature if user specified it manually 1050236884Smm * on the command line. 1051236884Smm */ 1052236884Smm if (nvlist_exists(props, propname)) 1053236884Smm continue; 1054236884Smm 1055251634Sdelphij ret = add_prop_list(propname, 1056251634Sdelphij ZFS_FEATURE_ENABLED, &props, B_TRUE); 1057251634Sdelphij if (ret != 0) 1058236884Smm goto errout; 1059236884Smm } 1060236884Smm } 1061251634Sdelphij 1062251634Sdelphij ret = 1; 1063185029Spjd if (zpool_create(g_zfs, poolname, 1064185029Spjd nvroot, props, fsprops) == 0) { 1065168404Spjd zfs_handle_t *pool = zfs_open(g_zfs, poolname, 1066168404Spjd ZFS_TYPE_FILESYSTEM); 1067168404Spjd if (pool != NULL) { 1068168404Spjd if (zfs_mount(pool, NULL, 0) == 0) 1069185029Spjd ret = zfs_shareall(pool); 1070168404Spjd zfs_close(pool); 1071168404Spjd } 1072168404Spjd } else if (libzfs_errno(g_zfs) == EZFS_INVALIDNAME) { 1073168404Spjd (void) fprintf(stderr, gettext("pool name may have " 1074168404Spjd "been omitted\n")); 1075168404Spjd } 1076168404Spjd } 1077168404Spjd 1078185029Spjderrout: 1079168404Spjd nvlist_free(nvroot); 1080185029Spjd nvlist_free(fsprops); 1081185029Spjd nvlist_free(props); 1082168404Spjd return (ret); 1083185029Spjdbadusage: 1084185029Spjd nvlist_free(fsprops); 1085185029Spjd nvlist_free(props); 1086185029Spjd usage(B_FALSE); 1087185029Spjd return (2); 1088168404Spjd} 1089168404Spjd 1090168404Spjd/* 1091168404Spjd * zpool destroy <pool> 1092168404Spjd * 1093168404Spjd * -f Forcefully unmount any datasets 1094168404Spjd * 1095168404Spjd * Destroy the given pool. Automatically unmounts any datasets in the pool. 1096168404Spjd */ 1097168404Spjdint 1098168404Spjdzpool_do_destroy(int argc, char **argv) 1099168404Spjd{ 1100168404Spjd boolean_t force = B_FALSE; 1101168404Spjd int c; 1102168404Spjd char *pool; 1103168404Spjd zpool_handle_t *zhp; 1104168404Spjd int ret; 1105168404Spjd 1106168404Spjd /* check options */ 1107168404Spjd while ((c = getopt(argc, argv, "f")) != -1) { 1108168404Spjd switch (c) { 1109168404Spjd case 'f': 1110168404Spjd force = B_TRUE; 1111168404Spjd break; 1112168404Spjd case '?': 1113168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1114168404Spjd optopt); 1115168404Spjd usage(B_FALSE); 1116168404Spjd } 1117168404Spjd } 1118168404Spjd 1119168404Spjd argc -= optind; 1120168404Spjd argv += optind; 1121168404Spjd 1122168404Spjd /* check arguments */ 1123168404Spjd if (argc < 1) { 1124168404Spjd (void) fprintf(stderr, gettext("missing pool argument\n")); 1125168404Spjd usage(B_FALSE); 1126168404Spjd } 1127168404Spjd if (argc > 1) { 1128168404Spjd (void) fprintf(stderr, gettext("too many arguments\n")); 1129168404Spjd usage(B_FALSE); 1130168404Spjd } 1131168404Spjd 1132168404Spjd pool = argv[0]; 1133168404Spjd 1134168404Spjd if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) { 1135168404Spjd /* 1136168404Spjd * As a special case, check for use of '/' in the name, and 1137168404Spjd * direct the user to use 'zfs destroy' instead. 1138168404Spjd */ 1139168404Spjd if (strchr(pool, '/') != NULL) 1140168404Spjd (void) fprintf(stderr, gettext("use 'zfs destroy' to " 1141168404Spjd "destroy a dataset\n")); 1142168404Spjd return (1); 1143168404Spjd } 1144168404Spjd 1145168404Spjd if (zpool_disable_datasets(zhp, force) != 0) { 1146168404Spjd (void) fprintf(stderr, gettext("could not destroy '%s': " 1147168404Spjd "could not unmount datasets\n"), zpool_get_name(zhp)); 1148168404Spjd return (1); 1149168404Spjd } 1150168404Spjd 1151248571Smm /* The history must be logged as part of the export */ 1152248571Smm log_history = B_FALSE; 1153168404Spjd 1154248571Smm ret = (zpool_destroy(zhp, history_str) != 0); 1155248571Smm 1156168404Spjd zpool_close(zhp); 1157168404Spjd 1158168404Spjd return (ret); 1159168404Spjd} 1160168404Spjd 1161168404Spjd/* 1162168404Spjd * zpool export [-f] <pool> ... 1163168404Spjd * 1164168404Spjd * -f Forcefully unmount datasets 1165168404Spjd * 1166168404Spjd * Export the given pools. By default, the command will attempt to cleanly 1167168404Spjd * unmount any active datasets within the pool. If the '-f' flag is specified, 1168168404Spjd * then the datasets will be forcefully unmounted. 1169168404Spjd */ 1170168404Spjdint 1171168404Spjdzpool_do_export(int argc, char **argv) 1172168404Spjd{ 1173168404Spjd boolean_t force = B_FALSE; 1174207670Smm boolean_t hardforce = B_FALSE; 1175168404Spjd int c; 1176168404Spjd zpool_handle_t *zhp; 1177168404Spjd int ret; 1178168404Spjd int i; 1179168404Spjd 1180168404Spjd /* check options */ 1181207670Smm while ((c = getopt(argc, argv, "fF")) != -1) { 1182168404Spjd switch (c) { 1183168404Spjd case 'f': 1184168404Spjd force = B_TRUE; 1185168404Spjd break; 1186207670Smm case 'F': 1187207670Smm hardforce = B_TRUE; 1188207670Smm break; 1189168404Spjd case '?': 1190168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1191168404Spjd optopt); 1192168404Spjd usage(B_FALSE); 1193168404Spjd } 1194168404Spjd } 1195168404Spjd 1196168404Spjd argc -= optind; 1197168404Spjd argv += optind; 1198168404Spjd 1199168404Spjd /* check arguments */ 1200168404Spjd if (argc < 1) { 1201168404Spjd (void) fprintf(stderr, gettext("missing pool argument\n")); 1202168404Spjd usage(B_FALSE); 1203168404Spjd } 1204168404Spjd 1205168404Spjd ret = 0; 1206168404Spjd for (i = 0; i < argc; i++) { 1207168404Spjd if ((zhp = zpool_open_canfail(g_zfs, argv[i])) == NULL) { 1208168404Spjd ret = 1; 1209168404Spjd continue; 1210168404Spjd } 1211168404Spjd 1212168404Spjd if (zpool_disable_datasets(zhp, force) != 0) { 1213168404Spjd ret = 1; 1214168404Spjd zpool_close(zhp); 1215168404Spjd continue; 1216168404Spjd } 1217168404Spjd 1218248571Smm /* The history must be logged as part of the export */ 1219248571Smm log_history = B_FALSE; 1220248571Smm 1221207670Smm if (hardforce) { 1222248571Smm if (zpool_export_force(zhp, history_str) != 0) 1223207670Smm ret = 1; 1224248571Smm } else if (zpool_export(zhp, force, history_str) != 0) { 1225168404Spjd ret = 1; 1226207670Smm } 1227168404Spjd 1228168404Spjd zpool_close(zhp); 1229168404Spjd } 1230168404Spjd 1231168404Spjd return (ret); 1232168404Spjd} 1233168404Spjd 1234168404Spjd/* 1235168404Spjd * Given a vdev configuration, determine the maximum width needed for the device 1236168404Spjd * name column. 1237168404Spjd */ 1238168404Spjdstatic int 1239168404Spjdmax_width(zpool_handle_t *zhp, nvlist_t *nv, int depth, int max) 1240168404Spjd{ 1241219089Spjd char *name = zpool_vdev_name(g_zfs, zhp, nv, B_TRUE); 1242168404Spjd nvlist_t **child; 1243168404Spjd uint_t c, children; 1244168404Spjd int ret; 1245168404Spjd 1246168404Spjd if (strlen(name) + depth > max) 1247168404Spjd max = strlen(name) + depth; 1248168404Spjd 1249168404Spjd free(name); 1250168404Spjd 1251168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, 1252168404Spjd &child, &children) == 0) { 1253168404Spjd for (c = 0; c < children; c++) 1254168404Spjd if ((ret = max_width(zhp, child[c], depth + 2, 1255168404Spjd max)) > max) 1256168404Spjd max = ret; 1257168404Spjd } 1258168404Spjd 1259185029Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE, 1260185029Spjd &child, &children) == 0) { 1261185029Spjd for (c = 0; c < children; c++) 1262185029Spjd if ((ret = max_width(zhp, child[c], depth + 2, 1263185029Spjd max)) > max) 1264185029Spjd max = ret; 1265185029Spjd } 1266185029Spjd 1267168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 1268168404Spjd &child, &children) == 0) { 1269168404Spjd for (c = 0; c < children; c++) 1270168404Spjd if ((ret = max_width(zhp, child[c], depth + 2, 1271168404Spjd max)) > max) 1272168404Spjd max = ret; 1273168404Spjd } 1274168404Spjd 1275168404Spjd 1276168404Spjd return (max); 1277168404Spjd} 1278168404Spjd 1279213197Smmtypedef struct spare_cbdata { 1280213197Smm uint64_t cb_guid; 1281213197Smm zpool_handle_t *cb_zhp; 1282213197Smm} spare_cbdata_t; 1283168404Spjd 1284213197Smmstatic boolean_t 1285213197Smmfind_vdev(nvlist_t *nv, uint64_t search) 1286213197Smm{ 1287213197Smm uint64_t guid; 1288213197Smm nvlist_t **child; 1289213197Smm uint_t c, children; 1290213197Smm 1291213197Smm if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &guid) == 0 && 1292213197Smm search == guid) 1293213197Smm return (B_TRUE); 1294213197Smm 1295213197Smm if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 1296213197Smm &child, &children) == 0) { 1297213197Smm for (c = 0; c < children; c++) 1298213197Smm if (find_vdev(child[c], search)) 1299213197Smm return (B_TRUE); 1300213197Smm } 1301213197Smm 1302213197Smm return (B_FALSE); 1303213197Smm} 1304213197Smm 1305213197Smmstatic int 1306213197Smmfind_spare(zpool_handle_t *zhp, void *data) 1307213197Smm{ 1308213197Smm spare_cbdata_t *cbp = data; 1309213197Smm nvlist_t *config, *nvroot; 1310213197Smm 1311213197Smm config = zpool_get_config(zhp, NULL); 1312213197Smm verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 1313213197Smm &nvroot) == 0); 1314213197Smm 1315213197Smm if (find_vdev(nvroot, cbp->cb_guid)) { 1316213197Smm cbp->cb_zhp = zhp; 1317213197Smm return (1); 1318213197Smm } 1319213197Smm 1320213197Smm zpool_close(zhp); 1321213197Smm return (0); 1322213197Smm} 1323213197Smm 1324168404Spjd/* 1325213197Smm * Print out configuration state as requested by status_callback. 1326213197Smm */ 1327213197Smmvoid 1328213197Smmprint_status_config(zpool_handle_t *zhp, const char *name, nvlist_t *nv, 1329213197Smm int namewidth, int depth, boolean_t isspare) 1330213197Smm{ 1331213197Smm nvlist_t **child; 1332254591Sgibbs uint_t c, vsc, children; 1333219089Spjd pool_scan_stat_t *ps = NULL; 1334213197Smm vdev_stat_t *vs; 1335219089Spjd char rbuf[6], wbuf[6], cbuf[6]; 1336213197Smm char *vname; 1337213197Smm uint64_t notpresent; 1338254591Sgibbs uint64_t ashift; 1339213197Smm spare_cbdata_t cb; 1340224169Sgibbs const char *state; 1341213197Smm 1342213197Smm if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 1343213197Smm &child, &children) != 0) 1344213197Smm children = 0; 1345213197Smm 1346219089Spjd verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS, 1347254591Sgibbs (uint64_t **)&vs, &vsc) == 0); 1348219089Spjd 1349213197Smm state = zpool_state_to_name(vs->vs_state, vs->vs_aux); 1350213197Smm if (isspare) { 1351213197Smm /* 1352213197Smm * For hot spares, we use the terms 'INUSE' and 'AVAILABLE' for 1353213197Smm * online drives. 1354213197Smm */ 1355213197Smm if (vs->vs_aux == VDEV_AUX_SPARED) 1356213197Smm state = "INUSE"; 1357213197Smm else if (vs->vs_state == VDEV_STATE_HEALTHY) 1358213197Smm state = "AVAIL"; 1359213197Smm } 1360213197Smm 1361213197Smm (void) printf("\t%*s%-*s %-8s", depth, "", namewidth - depth, 1362213197Smm name, state); 1363213197Smm 1364213197Smm if (!isspare) { 1365213197Smm zfs_nicenum(vs->vs_read_errors, rbuf, sizeof (rbuf)); 1366213197Smm zfs_nicenum(vs->vs_write_errors, wbuf, sizeof (wbuf)); 1367213197Smm zfs_nicenum(vs->vs_checksum_errors, cbuf, sizeof (cbuf)); 1368213197Smm (void) printf(" %5s %5s %5s", rbuf, wbuf, cbuf); 1369213197Smm } 1370213197Smm 1371213197Smm if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT, 1372224170Sgibbs ¬present) == 0 || 1373224170Sgibbs vs->vs_state <= VDEV_STATE_CANT_OPEN) { 1374213197Smm char *path; 1375224170Sgibbs if (nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0) 1376224170Sgibbs (void) printf(" was %s", path); 1377213197Smm } else if (vs->vs_aux != 0) { 1378213197Smm (void) printf(" "); 1379213197Smm 1380213197Smm switch (vs->vs_aux) { 1381213197Smm case VDEV_AUX_OPEN_FAILED: 1382213197Smm (void) printf(gettext("cannot open")); 1383213197Smm break; 1384213197Smm 1385213197Smm case VDEV_AUX_BAD_GUID_SUM: 1386213197Smm (void) printf(gettext("missing device")); 1387213197Smm break; 1388213197Smm 1389213197Smm case VDEV_AUX_NO_REPLICAS: 1390213197Smm (void) printf(gettext("insufficient replicas")); 1391213197Smm break; 1392213197Smm 1393213197Smm case VDEV_AUX_VERSION_NEWER: 1394213197Smm (void) printf(gettext("newer version")); 1395213197Smm break; 1396213197Smm 1397236884Smm case VDEV_AUX_UNSUP_FEAT: 1398236884Smm (void) printf(gettext("unsupported feature(s)")); 1399236884Smm break; 1400236884Smm 1401254591Sgibbs case VDEV_AUX_ASHIFT_TOO_BIG: 1402254591Sgibbs (void) printf(gettext("unsupported minimum blocksize")); 1403254591Sgibbs break; 1404254591Sgibbs 1405213197Smm case VDEV_AUX_SPARED: 1406213197Smm verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, 1407213197Smm &cb.cb_guid) == 0); 1408213197Smm if (zpool_iter(g_zfs, find_spare, &cb) == 1) { 1409213197Smm if (strcmp(zpool_get_name(cb.cb_zhp), 1410213197Smm zpool_get_name(zhp)) == 0) 1411213197Smm (void) printf(gettext("currently in " 1412213197Smm "use")); 1413213197Smm else 1414213197Smm (void) printf(gettext("in use by " 1415213197Smm "pool '%s'"), 1416213197Smm zpool_get_name(cb.cb_zhp)); 1417213197Smm zpool_close(cb.cb_zhp); 1418213197Smm } else { 1419213197Smm (void) printf(gettext("currently in use")); 1420213197Smm } 1421213197Smm break; 1422213197Smm 1423213197Smm case VDEV_AUX_ERR_EXCEEDED: 1424213197Smm (void) printf(gettext("too many errors")); 1425213197Smm break; 1426213197Smm 1427213197Smm case VDEV_AUX_IO_FAILURE: 1428213197Smm (void) printf(gettext("experienced I/O failures")); 1429213197Smm break; 1430213197Smm 1431213197Smm case VDEV_AUX_BAD_LOG: 1432213197Smm (void) printf(gettext("bad intent log")); 1433213197Smm break; 1434213197Smm 1435219089Spjd case VDEV_AUX_EXTERNAL: 1436219089Spjd (void) printf(gettext("external device fault")); 1437219089Spjd break; 1438219089Spjd 1439219089Spjd case VDEV_AUX_SPLIT_POOL: 1440219089Spjd (void) printf(gettext("split into new pool")); 1441219089Spjd break; 1442219089Spjd 1443213197Smm default: 1444213197Smm (void) printf(gettext("corrupted data")); 1445213197Smm break; 1446213197Smm } 1447254591Sgibbs } else if (children == 0 && !isspare && 1448254591Sgibbs VDEV_STAT_VALID(vs_physical_ashift, vsc) && 1449254591Sgibbs vs->vs_configured_ashift < vs->vs_physical_ashift) { 1450254591Sgibbs (void) printf( 1451254591Sgibbs gettext(" block size: %dB configured, %dB native"), 1452254591Sgibbs 1 << vs->vs_configured_ashift, 1 << vs->vs_physical_ashift); 1453213197Smm } 1454213197Smm 1455219089Spjd (void) nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_SCAN_STATS, 1456219089Spjd (uint64_t **)&ps, &c); 1457219089Spjd 1458219089Spjd if (ps && ps->pss_state == DSS_SCANNING && 1459219089Spjd vs->vs_scan_processed != 0 && children == 0) { 1460219089Spjd (void) printf(gettext(" (%s)"), 1461219089Spjd (ps->pss_func == POOL_SCAN_RESILVER) ? 1462219089Spjd "resilvering" : "repairing"); 1463219089Spjd } 1464219089Spjd 1465213197Smm (void) printf("\n"); 1466213197Smm 1467213197Smm for (c = 0; c < children; c++) { 1468219089Spjd uint64_t islog = B_FALSE, ishole = B_FALSE; 1469213197Smm 1470219089Spjd /* Don't print logs or holes here */ 1471213197Smm (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 1472219089Spjd &islog); 1473219089Spjd (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_HOLE, 1474219089Spjd &ishole); 1475219089Spjd if (islog || ishole) 1476213197Smm continue; 1477219089Spjd vname = zpool_vdev_name(g_zfs, zhp, child[c], B_TRUE); 1478213197Smm print_status_config(zhp, vname, child[c], 1479213197Smm namewidth, depth + 2, isspare); 1480213197Smm free(vname); 1481213197Smm } 1482213197Smm} 1483213197Smm 1484213197Smm 1485213197Smm/* 1486168404Spjd * Print the configuration of an exported pool. Iterate over all vdevs in the 1487168404Spjd * pool, printing out the name and status for each one. 1488168404Spjd */ 1489168404Spjdvoid 1490213197Smmprint_import_config(const char *name, nvlist_t *nv, int namewidth, int depth) 1491168404Spjd{ 1492168404Spjd nvlist_t **child; 1493168404Spjd uint_t c, children; 1494168404Spjd vdev_stat_t *vs; 1495168404Spjd char *type, *vname; 1496168404Spjd 1497168404Spjd verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0); 1498219089Spjd if (strcmp(type, VDEV_TYPE_MISSING) == 0 || 1499219089Spjd strcmp(type, VDEV_TYPE_HOLE) == 0) 1500168404Spjd return; 1501168404Spjd 1502219089Spjd verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS, 1503168404Spjd (uint64_t **)&vs, &c) == 0); 1504168404Spjd 1505168404Spjd (void) printf("\t%*s%-*s", depth, "", namewidth - depth, name); 1506185029Spjd (void) printf(" %s", zpool_state_to_name(vs->vs_state, vs->vs_aux)); 1507168404Spjd 1508168404Spjd if (vs->vs_aux != 0) { 1509185029Spjd (void) printf(" "); 1510168404Spjd 1511168404Spjd switch (vs->vs_aux) { 1512168404Spjd case VDEV_AUX_OPEN_FAILED: 1513168404Spjd (void) printf(gettext("cannot open")); 1514168404Spjd break; 1515168404Spjd 1516168404Spjd case VDEV_AUX_BAD_GUID_SUM: 1517168404Spjd (void) printf(gettext("missing device")); 1518168404Spjd break; 1519168404Spjd 1520168404Spjd case VDEV_AUX_NO_REPLICAS: 1521168404Spjd (void) printf(gettext("insufficient replicas")); 1522168404Spjd break; 1523168404Spjd 1524168404Spjd case VDEV_AUX_VERSION_NEWER: 1525168404Spjd (void) printf(gettext("newer version")); 1526168404Spjd break; 1527168404Spjd 1528236884Smm case VDEV_AUX_UNSUP_FEAT: 1529236884Smm (void) printf(gettext("unsupported feature(s)")); 1530236884Smm break; 1531236884Smm 1532185029Spjd case VDEV_AUX_ERR_EXCEEDED: 1533185029Spjd (void) printf(gettext("too many errors")); 1534185029Spjd break; 1535185029Spjd 1536168404Spjd default: 1537168404Spjd (void) printf(gettext("corrupted data")); 1538168404Spjd break; 1539168404Spjd } 1540168404Spjd } 1541168404Spjd (void) printf("\n"); 1542168404Spjd 1543168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 1544168404Spjd &child, &children) != 0) 1545168404Spjd return; 1546168404Spjd 1547168404Spjd for (c = 0; c < children; c++) { 1548185029Spjd uint64_t is_log = B_FALSE; 1549185029Spjd 1550185029Spjd (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 1551185029Spjd &is_log); 1552213197Smm if (is_log) 1553185029Spjd continue; 1554185029Spjd 1555219089Spjd vname = zpool_vdev_name(g_zfs, NULL, child[c], B_TRUE); 1556213197Smm print_import_config(vname, child[c], namewidth, depth + 2); 1557168404Spjd free(vname); 1558168404Spjd } 1559168404Spjd 1560185029Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE, 1561185029Spjd &child, &children) == 0) { 1562185029Spjd (void) printf(gettext("\tcache\n")); 1563185029Spjd for (c = 0; c < children; c++) { 1564219089Spjd vname = zpool_vdev_name(g_zfs, NULL, child[c], B_FALSE); 1565185029Spjd (void) printf("\t %s\n", vname); 1566185029Spjd free(vname); 1567185029Spjd } 1568185029Spjd } 1569185029Spjd 1570168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, 1571185029Spjd &child, &children) == 0) { 1572185029Spjd (void) printf(gettext("\tspares\n")); 1573185029Spjd for (c = 0; c < children; c++) { 1574219089Spjd vname = zpool_vdev_name(g_zfs, NULL, child[c], B_FALSE); 1575185029Spjd (void) printf("\t %s\n", vname); 1576185029Spjd free(vname); 1577185029Spjd } 1578168404Spjd } 1579168404Spjd} 1580168404Spjd 1581168404Spjd/* 1582213197Smm * Print log vdevs. 1583213197Smm * Logs are recorded as top level vdevs in the main pool child array 1584213197Smm * but with "is_log" set to 1. We use either print_status_config() or 1585213197Smm * print_import_config() to print the top level logs then any log 1586213197Smm * children (eg mirrored slogs) are printed recursively - which 1587213197Smm * works because only the top level vdev is marked "is_log" 1588213197Smm */ 1589213197Smmstatic void 1590213197Smmprint_logs(zpool_handle_t *zhp, nvlist_t *nv, int namewidth, boolean_t verbose) 1591213197Smm{ 1592213197Smm uint_t c, children; 1593213197Smm nvlist_t **child; 1594213197Smm 1595213197Smm if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, &child, 1596213197Smm &children) != 0) 1597213197Smm return; 1598213197Smm 1599213197Smm (void) printf(gettext("\tlogs\n")); 1600213197Smm 1601213197Smm for (c = 0; c < children; c++) { 1602213197Smm uint64_t is_log = B_FALSE; 1603213197Smm char *name; 1604213197Smm 1605213197Smm (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 1606213197Smm &is_log); 1607213197Smm if (!is_log) 1608213197Smm continue; 1609219089Spjd name = zpool_vdev_name(g_zfs, zhp, child[c], B_TRUE); 1610213197Smm if (verbose) 1611213197Smm print_status_config(zhp, name, child[c], namewidth, 1612213197Smm 2, B_FALSE); 1613213197Smm else 1614213197Smm print_import_config(name, child[c], namewidth, 2); 1615213197Smm free(name); 1616213197Smm } 1617213197Smm} 1618219089Spjd 1619213197Smm/* 1620168404Spjd * Display the status for the given pool. 1621168404Spjd */ 1622168404Spjdstatic void 1623168404Spjdshow_import(nvlist_t *config) 1624168404Spjd{ 1625168404Spjd uint64_t pool_state; 1626168404Spjd vdev_stat_t *vs; 1627168404Spjd char *name; 1628168404Spjd uint64_t guid; 1629168404Spjd char *msgid; 1630168404Spjd nvlist_t *nvroot; 1631168404Spjd int reason; 1632168404Spjd const char *health; 1633168404Spjd uint_t vsc; 1634168404Spjd int namewidth; 1635228103Smm char *comment; 1636168404Spjd 1637168404Spjd verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, 1638168404Spjd &name) == 0); 1639168404Spjd verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, 1640168404Spjd &guid) == 0); 1641168404Spjd verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE, 1642168404Spjd &pool_state) == 0); 1643168404Spjd verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 1644168404Spjd &nvroot) == 0); 1645168404Spjd 1646219089Spjd verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS, 1647168404Spjd (uint64_t **)&vs, &vsc) == 0); 1648185029Spjd health = zpool_state_to_name(vs->vs_state, vs->vs_aux); 1649168404Spjd 1650168404Spjd reason = zpool_import_status(config, &msgid); 1651168404Spjd 1652228103Smm (void) printf(gettext(" pool: %s\n"), name); 1653228103Smm (void) printf(gettext(" id: %llu\n"), (u_longlong_t)guid); 1654228103Smm (void) printf(gettext(" state: %s"), health); 1655168404Spjd if (pool_state == POOL_STATE_DESTROYED) 1656168404Spjd (void) printf(gettext(" (DESTROYED)")); 1657168404Spjd (void) printf("\n"); 1658168404Spjd 1659168404Spjd switch (reason) { 1660168404Spjd case ZPOOL_STATUS_MISSING_DEV_R: 1661168404Spjd case ZPOOL_STATUS_MISSING_DEV_NR: 1662168404Spjd case ZPOOL_STATUS_BAD_GUID_SUM: 1663228103Smm (void) printf(gettext(" status: One or more devices are " 1664228103Smm "missing from the system.\n")); 1665168404Spjd break; 1666168404Spjd 1667168404Spjd case ZPOOL_STATUS_CORRUPT_LABEL_R: 1668168404Spjd case ZPOOL_STATUS_CORRUPT_LABEL_NR: 1669228103Smm (void) printf(gettext(" status: One or more devices contains " 1670168404Spjd "corrupted data.\n")); 1671168404Spjd break; 1672168404Spjd 1673168404Spjd case ZPOOL_STATUS_CORRUPT_DATA: 1674228103Smm (void) printf( 1675228103Smm gettext(" status: The pool data is corrupted.\n")); 1676168404Spjd break; 1677168404Spjd 1678168404Spjd case ZPOOL_STATUS_OFFLINE_DEV: 1679228103Smm (void) printf(gettext(" status: One or more devices " 1680168404Spjd "are offlined.\n")); 1681168404Spjd break; 1682168404Spjd 1683168404Spjd case ZPOOL_STATUS_CORRUPT_POOL: 1684228103Smm (void) printf(gettext(" status: The pool metadata is " 1685168404Spjd "corrupted.\n")); 1686168404Spjd break; 1687168404Spjd 1688168404Spjd case ZPOOL_STATUS_VERSION_OLDER: 1689238926Smm (void) printf(gettext(" status: The pool is formatted using a " 1690238926Smm "legacy on-disk version.\n")); 1691168404Spjd break; 1692168404Spjd 1693168404Spjd case ZPOOL_STATUS_VERSION_NEWER: 1694228103Smm (void) printf(gettext(" status: The pool is formatted using an " 1695168404Spjd "incompatible version.\n")); 1696168404Spjd break; 1697168404Spjd 1698238926Smm case ZPOOL_STATUS_FEAT_DISABLED: 1699238926Smm (void) printf(gettext(" status: Some supported features are " 1700238926Smm "not enabled on the pool.\n")); 1701238926Smm break; 1702238926Smm 1703236884Smm case ZPOOL_STATUS_UNSUP_FEAT_READ: 1704236884Smm (void) printf(gettext("status: The pool uses the following " 1705236884Smm "feature(s) not supported on this sytem:\n")); 1706236884Smm zpool_print_unsup_feat(config); 1707236884Smm break; 1708236884Smm 1709236884Smm case ZPOOL_STATUS_UNSUP_FEAT_WRITE: 1710236884Smm (void) printf(gettext("status: The pool can only be accessed " 1711236884Smm "in read-only mode on this system. It\n\tcannot be " 1712236884Smm "accessed in read-write mode because it uses the " 1713236884Smm "following\n\tfeature(s) not supported on this system:\n")); 1714236884Smm zpool_print_unsup_feat(config); 1715236884Smm break; 1716236884Smm 1717168498Spjd case ZPOOL_STATUS_HOSTID_MISMATCH: 1718228103Smm (void) printf(gettext(" status: The pool was last accessed by " 1719168498Spjd "another system.\n")); 1720168498Spjd break; 1721185029Spjd 1722185029Spjd case ZPOOL_STATUS_FAULTED_DEV_R: 1723185029Spjd case ZPOOL_STATUS_FAULTED_DEV_NR: 1724228103Smm (void) printf(gettext(" status: One or more devices are " 1725185029Spjd "faulted.\n")); 1726185029Spjd break; 1727185029Spjd 1728185029Spjd case ZPOOL_STATUS_BAD_LOG: 1729228103Smm (void) printf(gettext(" status: An intent log record cannot be " 1730185029Spjd "read.\n")); 1731185029Spjd break; 1732185029Spjd 1733219089Spjd case ZPOOL_STATUS_RESILVERING: 1734228103Smm (void) printf(gettext(" status: One or more devices were being " 1735219089Spjd "resilvered.\n")); 1736219089Spjd break; 1737219089Spjd 1738259131Sdelphij case ZPOOL_STATUS_NON_NATIVE_ASHIFT: 1739259131Sdelphij (void) printf(gettext("status: One or more devices were " 1740259131Sdelphij "configured to use a non-native block size.\n" 1741259131Sdelphij "\tExpect reduced performance.\n")); 1742259131Sdelphij break; 1743259131Sdelphij 1744168404Spjd default: 1745168404Spjd /* 1746168404Spjd * No other status can be seen when importing pools. 1747168404Spjd */ 1748168404Spjd assert(reason == ZPOOL_STATUS_OK); 1749168404Spjd } 1750168404Spjd 1751168404Spjd /* 1752168404Spjd * Print out an action according to the overall state of the pool. 1753168404Spjd */ 1754168404Spjd if (vs->vs_state == VDEV_STATE_HEALTHY) { 1755238926Smm if (reason == ZPOOL_STATUS_VERSION_OLDER || 1756238926Smm reason == ZPOOL_STATUS_FEAT_DISABLED) { 1757228103Smm (void) printf(gettext(" action: The pool can be " 1758168404Spjd "imported using its name or numeric identifier, " 1759168404Spjd "though\n\tsome features will not be available " 1760168404Spjd "without an explicit 'zpool upgrade'.\n")); 1761238926Smm } else if (reason == ZPOOL_STATUS_HOSTID_MISMATCH) { 1762228103Smm (void) printf(gettext(" action: The pool can be " 1763168498Spjd "imported using its name or numeric " 1764168498Spjd "identifier and\n\tthe '-f' flag.\n")); 1765238926Smm } else { 1766228103Smm (void) printf(gettext(" action: The pool can be " 1767168404Spjd "imported using its name or numeric " 1768168404Spjd "identifier.\n")); 1769238926Smm } 1770168404Spjd } else if (vs->vs_state == VDEV_STATE_DEGRADED) { 1771228103Smm (void) printf(gettext(" action: The pool can be imported " 1772168404Spjd "despite missing or damaged devices. The\n\tfault " 1773168404Spjd "tolerance of the pool may be compromised if imported.\n")); 1774168404Spjd } else { 1775168404Spjd switch (reason) { 1776168404Spjd case ZPOOL_STATUS_VERSION_NEWER: 1777228103Smm (void) printf(gettext(" action: The pool cannot be " 1778168404Spjd "imported. Access the pool on a system running " 1779168404Spjd "newer\n\tsoftware, or recreate the pool from " 1780168404Spjd "backup.\n")); 1781168404Spjd break; 1782236884Smm case ZPOOL_STATUS_UNSUP_FEAT_READ: 1783236884Smm (void) printf(gettext("action: The pool cannot be " 1784236884Smm "imported. Access the pool on a system that " 1785236884Smm "supports\n\tthe required feature(s), or recreate " 1786236884Smm "the pool from backup.\n")); 1787236884Smm break; 1788236884Smm case ZPOOL_STATUS_UNSUP_FEAT_WRITE: 1789236884Smm (void) printf(gettext("action: The pool cannot be " 1790236884Smm "imported in read-write mode. Import the pool " 1791236884Smm "with\n" 1792236884Smm "\t\"-o readonly=on\", access the pool on a system " 1793236884Smm "that supports the\n\trequired feature(s), or " 1794236884Smm "recreate the pool from backup.\n")); 1795236884Smm break; 1796168404Spjd case ZPOOL_STATUS_MISSING_DEV_R: 1797168404Spjd case ZPOOL_STATUS_MISSING_DEV_NR: 1798168404Spjd case ZPOOL_STATUS_BAD_GUID_SUM: 1799228103Smm (void) printf(gettext(" action: The pool cannot be " 1800168404Spjd "imported. Attach the missing\n\tdevices and try " 1801168404Spjd "again.\n")); 1802168404Spjd break; 1803168404Spjd default: 1804228103Smm (void) printf(gettext(" action: The pool cannot be " 1805168404Spjd "imported due to damaged devices or data.\n")); 1806168404Spjd } 1807168404Spjd } 1808168404Spjd 1809228103Smm /* Print the comment attached to the pool. */ 1810228103Smm if (nvlist_lookup_string(config, ZPOOL_CONFIG_COMMENT, &comment) == 0) 1811228103Smm (void) printf(gettext("comment: %s\n"), comment); 1812228103Smm 1813168404Spjd /* 1814168404Spjd * If the state is "closed" or "can't open", and the aux state 1815168404Spjd * is "corrupt data": 1816168404Spjd */ 1817168404Spjd if (((vs->vs_state == VDEV_STATE_CLOSED) || 1818168404Spjd (vs->vs_state == VDEV_STATE_CANT_OPEN)) && 1819168404Spjd (vs->vs_aux == VDEV_AUX_CORRUPT_DATA)) { 1820168404Spjd if (pool_state == POOL_STATE_DESTROYED) 1821168404Spjd (void) printf(gettext("\tThe pool was destroyed, " 1822168404Spjd "but can be imported using the '-Df' flags.\n")); 1823168404Spjd else if (pool_state != POOL_STATE_EXPORTED) 1824168404Spjd (void) printf(gettext("\tThe pool may be active on " 1825185029Spjd "another system, but can be imported using\n\t" 1826168404Spjd "the '-f' flag.\n")); 1827168404Spjd } 1828168404Spjd 1829168404Spjd if (msgid != NULL) 1830236146Smm (void) printf(gettext(" see: http://illumos.org/msg/%s\n"), 1831168404Spjd msgid); 1832168404Spjd 1833228103Smm (void) printf(gettext(" config:\n\n")); 1834168404Spjd 1835168404Spjd namewidth = max_width(NULL, nvroot, 0, 0); 1836168404Spjd if (namewidth < 10) 1837168404Spjd namewidth = 10; 1838168404Spjd 1839213197Smm print_import_config(name, nvroot, namewidth, 0); 1840213197Smm if (num_logs(nvroot) > 0) 1841213197Smm print_logs(NULL, nvroot, namewidth, B_FALSE); 1842185029Spjd 1843168404Spjd if (reason == ZPOOL_STATUS_BAD_GUID_SUM) { 1844168404Spjd (void) printf(gettext("\n\tAdditional devices are known to " 1845168404Spjd "be part of this pool, though their\n\texact " 1846168404Spjd "configuration cannot be determined.\n")); 1847168404Spjd } 1848168404Spjd} 1849168404Spjd 1850168404Spjd/* 1851168404Spjd * Perform the import for the given configuration. This passes the heavy 1852185029Spjd * lifting off to zpool_import_props(), and then mounts the datasets contained 1853185029Spjd * within the pool. 1854168404Spjd */ 1855168404Spjdstatic int 1856168404Spjddo_import(nvlist_t *config, const char *newname, const char *mntopts, 1857219089Spjd nvlist_t *props, int flags) 1858168404Spjd{ 1859168404Spjd zpool_handle_t *zhp; 1860168404Spjd char *name; 1861168404Spjd uint64_t state; 1862168404Spjd uint64_t version; 1863168404Spjd 1864168404Spjd verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, 1865168404Spjd &name) == 0); 1866168404Spjd 1867168404Spjd verify(nvlist_lookup_uint64(config, 1868168404Spjd ZPOOL_CONFIG_POOL_STATE, &state) == 0); 1869168404Spjd verify(nvlist_lookup_uint64(config, 1870168404Spjd ZPOOL_CONFIG_VERSION, &version) == 0); 1871236884Smm if (!SPA_VERSION_IS_SUPPORTED(version)) { 1872168404Spjd (void) fprintf(stderr, gettext("cannot import '%s': pool " 1873236884Smm "is formatted using an unsupported ZFS version\n"), name); 1874168404Spjd return (1); 1875219089Spjd } else if (state != POOL_STATE_EXPORTED && 1876219089Spjd !(flags & ZFS_IMPORT_ANY_HOST)) { 1877168498Spjd uint64_t hostid; 1878168498Spjd 1879168498Spjd if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID, 1880168498Spjd &hostid) == 0) { 1881168498Spjd if ((unsigned long)hostid != gethostid()) { 1882168498Spjd char *hostname; 1883168498Spjd uint64_t timestamp; 1884168498Spjd time_t t; 1885168498Spjd 1886168498Spjd verify(nvlist_lookup_string(config, 1887168498Spjd ZPOOL_CONFIG_HOSTNAME, &hostname) == 0); 1888168498Spjd verify(nvlist_lookup_uint64(config, 1889168498Spjd ZPOOL_CONFIG_TIMESTAMP, ×tamp) == 0); 1890168498Spjd t = timestamp; 1891168498Spjd (void) fprintf(stderr, gettext("cannot import " 1892168498Spjd "'%s': pool may be in use from other " 1893168498Spjd "system, it was last accessed by %s " 1894168498Spjd "(hostid: 0x%lx) on %s"), name, hostname, 1895168498Spjd (unsigned long)hostid, 1896168498Spjd asctime(localtime(&t))); 1897168498Spjd (void) fprintf(stderr, gettext("use '-f' to " 1898168498Spjd "import anyway\n")); 1899168498Spjd return (1); 1900168498Spjd } 1901168498Spjd } else { 1902168498Spjd (void) fprintf(stderr, gettext("cannot import '%s': " 1903168498Spjd "pool may be in use from other system\n"), name); 1904168498Spjd (void) fprintf(stderr, gettext("use '-f' to import " 1905168498Spjd "anyway\n")); 1906168498Spjd return (1); 1907168498Spjd } 1908168404Spjd } 1909168404Spjd 1910219089Spjd if (zpool_import_props(g_zfs, config, newname, props, flags) != 0) 1911168404Spjd return (1); 1912168404Spjd 1913168404Spjd if (newname != NULL) 1914168404Spjd name = (char *)newname; 1915168404Spjd 1916209962Smm if ((zhp = zpool_open_canfail(g_zfs, name)) == NULL) 1917209962Smm return (1); 1918168404Spjd 1919209962Smm if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL && 1920219089Spjd !(flags & ZFS_IMPORT_ONLY) && 1921209962Smm zpool_enable_datasets(zhp, mntopts, 0) != 0) { 1922168404Spjd zpool_close(zhp); 1923168404Spjd return (1); 1924168404Spjd } 1925168404Spjd 1926168404Spjd zpool_close(zhp); 1927219089Spjd return (0); 1928168404Spjd} 1929168404Spjd 1930168404Spjd/* 1931168404Spjd * zpool import [-d dir] [-D] 1932185029Spjd * import [-o mntopts] [-o prop=value] ... [-R root] [-D] 1933185029Spjd * [-d dir | -c cachefile] [-f] -a 1934185029Spjd * import [-o mntopts] [-o prop=value] ... [-R root] [-D] 1935219089Spjd * [-d dir | -c cachefile] [-f] [-n] [-F] <pool | id> [newpool] 1936168404Spjd * 1937185029Spjd * -c Read pool information from a cachefile instead of searching 1938185029Spjd * devices. 1939185029Spjd * 1940168404Spjd * -d Scan in a specific directory, other than /dev/dsk. More than 1941168404Spjd * one directory can be specified using multiple '-d' options. 1942168404Spjd * 1943168404Spjd * -D Scan for previously destroyed pools or import all or only 1944168404Spjd * specified destroyed pools. 1945168404Spjd * 1946168404Spjd * -R Temporarily import the pool, with all mountpoints relative to 1947168404Spjd * the given root. The pool will remain exported when the machine 1948168404Spjd * is rebooted. 1949168404Spjd * 1950219089Spjd * -V Import even in the presence of faulted vdevs. This is an 1951185029Spjd * intentionally undocumented option for testing purposes, and 1952185029Spjd * treats the pool configuration as complete, leaving any bad 1953209962Smm * vdevs in the FAULTED state. In other words, it does verbatim 1954209962Smm * import. 1955185029Spjd * 1956219089Spjd * -f Force import, even if it appears that the pool is active. 1957219089Spjd * 1958219089Spjd * -F Attempt rewind if necessary. 1959219089Spjd * 1960219089Spjd * -n See if rewind would work, but don't actually rewind. 1961219089Spjd * 1962219089Spjd * -N Import the pool but don't mount datasets. 1963219089Spjd * 1964219089Spjd * -T Specify a starting txg to use for import. This option is 1965219089Spjd * intentionally undocumented option for testing purposes. 1966219089Spjd * 1967168404Spjd * -a Import all pools found. 1968168404Spjd * 1969185029Spjd * -o Set property=value and/or temporary mount options (without '='). 1970185029Spjd * 1971168404Spjd * The import command scans for pools to import, and import pools based on pool 1972168404Spjd * name and GUID. The pool can also be renamed as part of the import process. 1973168404Spjd */ 1974168404Spjdint 1975168404Spjdzpool_do_import(int argc, char **argv) 1976168404Spjd{ 1977168404Spjd char **searchdirs = NULL; 1978168404Spjd int nsearch = 0; 1979168404Spjd int c; 1980219089Spjd int err = 0; 1981185029Spjd nvlist_t *pools = NULL; 1982168404Spjd boolean_t do_all = B_FALSE; 1983168404Spjd boolean_t do_destroyed = B_FALSE; 1984168404Spjd char *mntopts = NULL; 1985168404Spjd nvpair_t *elem; 1986168404Spjd nvlist_t *config; 1987185029Spjd uint64_t searchguid = 0; 1988185029Spjd char *searchname = NULL; 1989185029Spjd char *propval; 1990168404Spjd nvlist_t *found_config; 1991219089Spjd nvlist_t *policy = NULL; 1992185029Spjd nvlist_t *props = NULL; 1993168404Spjd boolean_t first; 1994219089Spjd int flags = ZFS_IMPORT_NORMAL; 1995219089Spjd uint32_t rewind_policy = ZPOOL_NO_REWIND; 1996219089Spjd boolean_t dryrun = B_FALSE; 1997219089Spjd boolean_t do_rewind = B_FALSE; 1998219089Spjd boolean_t xtreme_rewind = B_FALSE; 1999219089Spjd uint64_t pool_state, txg = -1ULL; 2000185029Spjd char *cachefile = NULL; 2001219089Spjd importargs_t idata = { 0 }; 2002219089Spjd char *endptr; 2003168404Spjd 2004168404Spjd /* check options */ 2005263385Sdelphij while ((c = getopt(argc, argv, ":aCc:d:DEfFmnNo:R:T:VX")) != -1) { 2006168404Spjd switch (c) { 2007168404Spjd case 'a': 2008168404Spjd do_all = B_TRUE; 2009168404Spjd break; 2010185029Spjd case 'c': 2011185029Spjd cachefile = optarg; 2012185029Spjd break; 2013168404Spjd case 'd': 2014168404Spjd if (searchdirs == NULL) { 2015168404Spjd searchdirs = safe_malloc(sizeof (char *)); 2016168404Spjd } else { 2017168404Spjd char **tmp = safe_malloc((nsearch + 1) * 2018168404Spjd sizeof (char *)); 2019168404Spjd bcopy(searchdirs, tmp, nsearch * 2020168404Spjd sizeof (char *)); 2021168404Spjd free(searchdirs); 2022168404Spjd searchdirs = tmp; 2023168404Spjd } 2024168404Spjd searchdirs[nsearch++] = optarg; 2025168404Spjd break; 2026168404Spjd case 'D': 2027168404Spjd do_destroyed = B_TRUE; 2028168404Spjd break; 2029168404Spjd case 'f': 2030219089Spjd flags |= ZFS_IMPORT_ANY_HOST; 2031168404Spjd break; 2032185029Spjd case 'F': 2033219089Spjd do_rewind = B_TRUE; 2034185029Spjd break; 2035219089Spjd case 'm': 2036219089Spjd flags |= ZFS_IMPORT_MISSING_LOG; 2037219089Spjd break; 2038219089Spjd case 'n': 2039219089Spjd dryrun = B_TRUE; 2040219089Spjd break; 2041219089Spjd case 'N': 2042219089Spjd flags |= ZFS_IMPORT_ONLY; 2043219089Spjd break; 2044168404Spjd case 'o': 2045185029Spjd if ((propval = strchr(optarg, '=')) != NULL) { 2046185029Spjd *propval = '\0'; 2047185029Spjd propval++; 2048185029Spjd if (add_prop_list(optarg, propval, 2049185029Spjd &props, B_TRUE)) 2050185029Spjd goto error; 2051185029Spjd } else { 2052185029Spjd mntopts = optarg; 2053185029Spjd } 2054168404Spjd break; 2055168404Spjd case 'R': 2056185029Spjd if (add_prop_list(zpool_prop_to_name( 2057185029Spjd ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE)) 2058185029Spjd goto error; 2059185029Spjd if (nvlist_lookup_string(props, 2060185029Spjd zpool_prop_to_name(ZPOOL_PROP_CACHEFILE), 2061185029Spjd &propval) == 0) 2062185029Spjd break; 2063185029Spjd if (add_prop_list(zpool_prop_to_name( 2064185029Spjd ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE)) 2065185029Spjd goto error; 2066168404Spjd break; 2067219089Spjd case 'T': 2068219089Spjd errno = 0; 2069268720Sdelphij txg = strtoull(optarg, &endptr, 0); 2070219089Spjd if (errno != 0 || *endptr != '\0') { 2071219089Spjd (void) fprintf(stderr, 2072219089Spjd gettext("invalid txg value\n")); 2073219089Spjd usage(B_FALSE); 2074219089Spjd } 2075219089Spjd rewind_policy = ZPOOL_DO_REWIND | ZPOOL_EXTREME_REWIND; 2076219089Spjd break; 2077219089Spjd case 'V': 2078219089Spjd flags |= ZFS_IMPORT_VERBATIM; 2079219089Spjd break; 2080219089Spjd case 'X': 2081219089Spjd xtreme_rewind = B_TRUE; 2082219089Spjd break; 2083168404Spjd case ':': 2084168404Spjd (void) fprintf(stderr, gettext("missing argument for " 2085168404Spjd "'%c' option\n"), optopt); 2086168404Spjd usage(B_FALSE); 2087168404Spjd break; 2088168404Spjd case '?': 2089168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2090168404Spjd optopt); 2091168404Spjd usage(B_FALSE); 2092168404Spjd } 2093168404Spjd } 2094168404Spjd 2095168404Spjd argc -= optind; 2096168404Spjd argv += optind; 2097168404Spjd 2098185029Spjd if (cachefile && nsearch != 0) { 2099185029Spjd (void) fprintf(stderr, gettext("-c is incompatible with -d\n")); 2100185029Spjd usage(B_FALSE); 2101185029Spjd } 2102185029Spjd 2103219089Spjd if ((dryrun || xtreme_rewind) && !do_rewind) { 2104219089Spjd (void) fprintf(stderr, 2105219089Spjd gettext("-n or -X only meaningful with -F\n")); 2106219089Spjd usage(B_FALSE); 2107219089Spjd } 2108219089Spjd if (dryrun) 2109219089Spjd rewind_policy = ZPOOL_TRY_REWIND; 2110219089Spjd else if (do_rewind) 2111219089Spjd rewind_policy = ZPOOL_DO_REWIND; 2112219089Spjd if (xtreme_rewind) 2113219089Spjd rewind_policy |= ZPOOL_EXTREME_REWIND; 2114219089Spjd 2115219089Spjd /* In the future, we can capture further policy and include it here */ 2116219089Spjd if (nvlist_alloc(&policy, NV_UNIQUE_NAME, 0) != 0 || 2117219089Spjd nvlist_add_uint64(policy, ZPOOL_REWIND_REQUEST_TXG, txg) != 0 || 2118219089Spjd nvlist_add_uint32(policy, ZPOOL_REWIND_REQUEST, rewind_policy) != 0) 2119219089Spjd goto error; 2120219089Spjd 2121168404Spjd if (searchdirs == NULL) { 2122168404Spjd searchdirs = safe_malloc(sizeof (char *)); 2123235478Savg searchdirs[0] = "/dev"; 2124168404Spjd nsearch = 1; 2125168404Spjd } 2126168404Spjd 2127168404Spjd /* check argument count */ 2128168404Spjd if (do_all) { 2129168404Spjd if (argc != 0) { 2130168404Spjd (void) fprintf(stderr, gettext("too many arguments\n")); 2131168404Spjd usage(B_FALSE); 2132168404Spjd } 2133168404Spjd } else { 2134168404Spjd if (argc > 2) { 2135168404Spjd (void) fprintf(stderr, gettext("too many arguments\n")); 2136168404Spjd usage(B_FALSE); 2137168404Spjd } 2138168404Spjd 2139168404Spjd /* 2140168404Spjd * Check for the SYS_CONFIG privilege. We do this explicitly 2141168404Spjd * here because otherwise any attempt to discover pools will 2142168404Spjd * silently fail. 2143168404Spjd */ 2144168404Spjd if (argc == 0 && !priv_ineffect(PRIV_SYS_CONFIG)) { 2145168404Spjd (void) fprintf(stderr, gettext("cannot " 2146168404Spjd "discover pools: permission denied\n")); 2147168404Spjd free(searchdirs); 2148219089Spjd nvlist_free(policy); 2149168404Spjd return (1); 2150168404Spjd } 2151168404Spjd } 2152168404Spjd 2153168404Spjd /* 2154168404Spjd * Depending on the arguments given, we do one of the following: 2155168404Spjd * 2156168404Spjd * <none> Iterate through all pools and display information about 2157168404Spjd * each one. 2158168404Spjd * 2159168404Spjd * -a Iterate through all pools and try to import each one. 2160168404Spjd * 2161168404Spjd * <id> Find the pool that corresponds to the given GUID/pool 2162168404Spjd * name and import that one. 2163168404Spjd * 2164168404Spjd * -D Above options applies only to destroyed pools. 2165168404Spjd */ 2166168404Spjd if (argc != 0) { 2167168404Spjd char *endptr; 2168168404Spjd 2169168404Spjd errno = 0; 2170168404Spjd searchguid = strtoull(argv[0], &endptr, 10); 2171254758Sdelphij if (errno != 0 || *endptr != '\0') { 2172168404Spjd searchname = argv[0]; 2173254758Sdelphij searchguid = 0; 2174254758Sdelphij } 2175168404Spjd found_config = NULL; 2176168404Spjd 2177185029Spjd /* 2178219089Spjd * User specified a name or guid. Ensure it's unique. 2179185029Spjd */ 2180219089Spjd idata.unique = B_TRUE; 2181185029Spjd } 2182185029Spjd 2183219089Spjd 2184219089Spjd idata.path = searchdirs; 2185219089Spjd idata.paths = nsearch; 2186219089Spjd idata.poolname = searchname; 2187219089Spjd idata.guid = searchguid; 2188219089Spjd idata.cachefile = cachefile; 2189219089Spjd 2190219089Spjd pools = zpool_search_import(g_zfs, &idata); 2191219089Spjd 2192219089Spjd if (pools != NULL && idata.exists && 2193219089Spjd (argc == 1 || strcmp(argv[0], argv[1]) == 0)) { 2194219089Spjd (void) fprintf(stderr, gettext("cannot import '%s': " 2195219089Spjd "a pool with that name already exists\n"), 2196219089Spjd argv[0]); 2197219089Spjd (void) fprintf(stderr, gettext("use the form '%s " 2198219089Spjd "<pool | id> <newpool>' to give it a new name\n"), 2199219089Spjd "zpool import"); 2200219089Spjd err = 1; 2201219089Spjd } else if (pools == NULL && idata.exists) { 2202219089Spjd (void) fprintf(stderr, gettext("cannot import '%s': " 2203219089Spjd "a pool with that name is already created/imported,\n"), 2204219089Spjd argv[0]); 2205219089Spjd (void) fprintf(stderr, gettext("and no additional pools " 2206219089Spjd "with that name were found\n")); 2207219089Spjd err = 1; 2208219089Spjd } else if (pools == NULL) { 2209185029Spjd if (argc != 0) { 2210185029Spjd (void) fprintf(stderr, gettext("cannot import '%s': " 2211185029Spjd "no such pool available\n"), argv[0]); 2212185029Spjd } 2213219089Spjd err = 1; 2214219089Spjd } 2215219089Spjd 2216219089Spjd if (err == 1) { 2217185029Spjd free(searchdirs); 2218219089Spjd nvlist_free(policy); 2219185029Spjd return (1); 2220185029Spjd } 2221185029Spjd 2222185029Spjd /* 2223185029Spjd * At this point we have a list of import candidate configs. Even if 2224185029Spjd * we were searching by pool name or guid, we still need to 2225185029Spjd * post-process the list to deal with pool state and possible 2226185029Spjd * duplicate names. 2227185029Spjd */ 2228168404Spjd err = 0; 2229168404Spjd elem = NULL; 2230168404Spjd first = B_TRUE; 2231168404Spjd while ((elem = nvlist_next_nvpair(pools, elem)) != NULL) { 2232168404Spjd 2233168404Spjd verify(nvpair_value_nvlist(elem, &config) == 0); 2234168404Spjd 2235168404Spjd verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE, 2236168404Spjd &pool_state) == 0); 2237168404Spjd if (!do_destroyed && pool_state == POOL_STATE_DESTROYED) 2238168404Spjd continue; 2239168404Spjd if (do_destroyed && pool_state != POOL_STATE_DESTROYED) 2240168404Spjd continue; 2241168404Spjd 2242219089Spjd verify(nvlist_add_nvlist(config, ZPOOL_REWIND_POLICY, 2243219089Spjd policy) == 0); 2244219089Spjd 2245168404Spjd if (argc == 0) { 2246168404Spjd if (first) 2247168404Spjd first = B_FALSE; 2248168404Spjd else if (!do_all) 2249168404Spjd (void) printf("\n"); 2250168404Spjd 2251219089Spjd if (do_all) { 2252168404Spjd err |= do_import(config, NULL, mntopts, 2253219089Spjd props, flags); 2254219089Spjd } else { 2255168404Spjd show_import(config); 2256219089Spjd } 2257168404Spjd } else if (searchname != NULL) { 2258168404Spjd char *name; 2259168404Spjd 2260168404Spjd /* 2261168404Spjd * We are searching for a pool based on name. 2262168404Spjd */ 2263168404Spjd verify(nvlist_lookup_string(config, 2264168404Spjd ZPOOL_CONFIG_POOL_NAME, &name) == 0); 2265168404Spjd 2266168404Spjd if (strcmp(name, searchname) == 0) { 2267168404Spjd if (found_config != NULL) { 2268168404Spjd (void) fprintf(stderr, gettext( 2269168404Spjd "cannot import '%s': more than " 2270168404Spjd "one matching pool\n"), searchname); 2271168404Spjd (void) fprintf(stderr, gettext( 2272168404Spjd "import by numeric ID instead\n")); 2273168404Spjd err = B_TRUE; 2274168404Spjd } 2275168404Spjd found_config = config; 2276168404Spjd } 2277168404Spjd } else { 2278168404Spjd uint64_t guid; 2279168404Spjd 2280168404Spjd /* 2281168404Spjd * Search for a pool by guid. 2282168404Spjd */ 2283168404Spjd verify(nvlist_lookup_uint64(config, 2284168404Spjd ZPOOL_CONFIG_POOL_GUID, &guid) == 0); 2285168404Spjd 2286168404Spjd if (guid == searchguid) 2287168404Spjd found_config = config; 2288168404Spjd } 2289168404Spjd } 2290168404Spjd 2291168404Spjd /* 2292168404Spjd * If we were searching for a specific pool, verify that we found a 2293168404Spjd * pool, and then do the import. 2294168404Spjd */ 2295168404Spjd if (argc != 0 && err == 0) { 2296168404Spjd if (found_config == NULL) { 2297168404Spjd (void) fprintf(stderr, gettext("cannot import '%s': " 2298168404Spjd "no such pool available\n"), argv[0]); 2299168404Spjd err = B_TRUE; 2300168404Spjd } else { 2301168404Spjd err |= do_import(found_config, argc == 1 ? NULL : 2302219089Spjd argv[1], mntopts, props, flags); 2303168404Spjd } 2304168404Spjd } 2305168404Spjd 2306168404Spjd /* 2307168404Spjd * If we were just looking for pools, report an error if none were 2308168404Spjd * found. 2309168404Spjd */ 2310168404Spjd if (argc == 0 && first) 2311168404Spjd (void) fprintf(stderr, 2312168404Spjd gettext("no pools available to import\n")); 2313168404Spjd 2314185029Spjderror: 2315185029Spjd nvlist_free(props); 2316168404Spjd nvlist_free(pools); 2317219089Spjd nvlist_free(policy); 2318168404Spjd free(searchdirs); 2319168404Spjd 2320168404Spjd return (err ? 1 : 0); 2321168404Spjd} 2322168404Spjd 2323168404Spjdtypedef struct iostat_cbdata { 2324236155Smm boolean_t cb_verbose; 2325236155Smm int cb_namewidth; 2326236155Smm int cb_iteration; 2327168404Spjd zpool_list_t *cb_list; 2328168404Spjd} iostat_cbdata_t; 2329168404Spjd 2330168404Spjdstatic void 2331168404Spjdprint_iostat_separator(iostat_cbdata_t *cb) 2332168404Spjd{ 2333168404Spjd int i = 0; 2334168404Spjd 2335168404Spjd for (i = 0; i < cb->cb_namewidth; i++) 2336168404Spjd (void) printf("-"); 2337168404Spjd (void) printf(" ----- ----- ----- ----- ----- -----\n"); 2338168404Spjd} 2339168404Spjd 2340168404Spjdstatic void 2341168404Spjdprint_iostat_header(iostat_cbdata_t *cb) 2342168404Spjd{ 2343168404Spjd (void) printf("%*s capacity operations bandwidth\n", 2344168404Spjd cb->cb_namewidth, ""); 2345219089Spjd (void) printf("%-*s alloc free read write read write\n", 2346168404Spjd cb->cb_namewidth, "pool"); 2347168404Spjd print_iostat_separator(cb); 2348168404Spjd} 2349168404Spjd 2350168404Spjd/* 2351168404Spjd * Display a single statistic. 2352168404Spjd */ 2353185029Spjdstatic void 2354168404Spjdprint_one_stat(uint64_t value) 2355168404Spjd{ 2356168404Spjd char buf[64]; 2357168404Spjd 2358168404Spjd zfs_nicenum(value, buf, sizeof (buf)); 2359168404Spjd (void) printf(" %5s", buf); 2360168404Spjd} 2361168404Spjd 2362168404Spjd/* 2363168404Spjd * Print out all the statistics for the given vdev. This can either be the 2364168404Spjd * toplevel configuration, or called recursively. If 'name' is NULL, then this 2365168404Spjd * is a verbose output, and we don't want to display the toplevel pool stats. 2366168404Spjd */ 2367168404Spjdvoid 2368168404Spjdprint_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv, 2369168404Spjd nvlist_t *newnv, iostat_cbdata_t *cb, int depth) 2370168404Spjd{ 2371168404Spjd nvlist_t **oldchild, **newchild; 2372168404Spjd uint_t c, children; 2373168404Spjd vdev_stat_t *oldvs, *newvs; 2374168404Spjd vdev_stat_t zerovs = { 0 }; 2375168404Spjd uint64_t tdelta; 2376168404Spjd double scale; 2377168404Spjd char *vname; 2378168404Spjd 2379168404Spjd if (oldnv != NULL) { 2380219089Spjd verify(nvlist_lookup_uint64_array(oldnv, 2381219089Spjd ZPOOL_CONFIG_VDEV_STATS, (uint64_t **)&oldvs, &c) == 0); 2382168404Spjd } else { 2383168404Spjd oldvs = &zerovs; 2384168404Spjd } 2385168404Spjd 2386219089Spjd verify(nvlist_lookup_uint64_array(newnv, ZPOOL_CONFIG_VDEV_STATS, 2387168404Spjd (uint64_t **)&newvs, &c) == 0); 2388168404Spjd 2389168404Spjd if (strlen(name) + depth > cb->cb_namewidth) 2390168404Spjd (void) printf("%*s%s", depth, "", name); 2391168404Spjd else 2392168404Spjd (void) printf("%*s%s%*s", depth, "", name, 2393168404Spjd (int)(cb->cb_namewidth - strlen(name) - depth), ""); 2394168404Spjd 2395168404Spjd tdelta = newvs->vs_timestamp - oldvs->vs_timestamp; 2396168404Spjd 2397168404Spjd if (tdelta == 0) 2398168404Spjd scale = 1.0; 2399168404Spjd else 2400168404Spjd scale = (double)NANOSEC / tdelta; 2401168404Spjd 2402168404Spjd /* only toplevel vdevs have capacity stats */ 2403168404Spjd if (newvs->vs_space == 0) { 2404168404Spjd (void) printf(" - -"); 2405168404Spjd } else { 2406168404Spjd print_one_stat(newvs->vs_alloc); 2407168404Spjd print_one_stat(newvs->vs_space - newvs->vs_alloc); 2408168404Spjd } 2409168404Spjd 2410168404Spjd print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_READ] - 2411168404Spjd oldvs->vs_ops[ZIO_TYPE_READ]))); 2412168404Spjd 2413168404Spjd print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_WRITE] - 2414168404Spjd oldvs->vs_ops[ZIO_TYPE_WRITE]))); 2415168404Spjd 2416168404Spjd print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_READ] - 2417168404Spjd oldvs->vs_bytes[ZIO_TYPE_READ]))); 2418168404Spjd 2419168404Spjd print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_WRITE] - 2420168404Spjd oldvs->vs_bytes[ZIO_TYPE_WRITE]))); 2421168404Spjd 2422168404Spjd (void) printf("\n"); 2423168404Spjd 2424168404Spjd if (!cb->cb_verbose) 2425168404Spjd return; 2426168404Spjd 2427168404Spjd if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_CHILDREN, 2428168404Spjd &newchild, &children) != 0) 2429168404Spjd return; 2430168404Spjd 2431168404Spjd if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_CHILDREN, 2432168404Spjd &oldchild, &c) != 0) 2433168404Spjd return; 2434168404Spjd 2435168404Spjd for (c = 0; c < children; c++) { 2436227497Smm uint64_t ishole = B_FALSE, islog = B_FALSE; 2437219089Spjd 2438227497Smm (void) nvlist_lookup_uint64(newchild[c], ZPOOL_CONFIG_IS_HOLE, 2439227497Smm &ishole); 2440227497Smm 2441227497Smm (void) nvlist_lookup_uint64(newchild[c], ZPOOL_CONFIG_IS_LOG, 2442227497Smm &islog); 2443227497Smm 2444227497Smm if (ishole || islog) 2445219089Spjd continue; 2446219089Spjd 2447219089Spjd vname = zpool_vdev_name(g_zfs, zhp, newchild[c], B_FALSE); 2448168404Spjd print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL, 2449168404Spjd newchild[c], cb, depth + 2); 2450168404Spjd free(vname); 2451168404Spjd } 2452185029Spjd 2453185029Spjd /* 2454227497Smm * Log device section 2455227497Smm */ 2456227497Smm 2457227497Smm if (num_logs(newnv) > 0) { 2458227497Smm (void) printf("%-*s - - - - - " 2459227497Smm "-\n", cb->cb_namewidth, "logs"); 2460227497Smm 2461227497Smm for (c = 0; c < children; c++) { 2462227497Smm uint64_t islog = B_FALSE; 2463227497Smm (void) nvlist_lookup_uint64(newchild[c], 2464227497Smm ZPOOL_CONFIG_IS_LOG, &islog); 2465227497Smm 2466227497Smm if (islog) { 2467227497Smm vname = zpool_vdev_name(g_zfs, zhp, newchild[c], 2468227497Smm B_FALSE); 2469227497Smm print_vdev_stats(zhp, vname, oldnv ? 2470227497Smm oldchild[c] : NULL, newchild[c], 2471227497Smm cb, depth + 2); 2472227497Smm free(vname); 2473227497Smm } 2474227497Smm } 2475227497Smm 2476227497Smm } 2477227497Smm 2478227497Smm /* 2479185029Spjd * Include level 2 ARC devices in iostat output 2480185029Spjd */ 2481185029Spjd if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_L2CACHE, 2482185029Spjd &newchild, &children) != 0) 2483185029Spjd return; 2484185029Spjd 2485185029Spjd if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_L2CACHE, 2486185029Spjd &oldchild, &c) != 0) 2487185029Spjd return; 2488185029Spjd 2489185029Spjd if (children > 0) { 2490185029Spjd (void) printf("%-*s - - - - - " 2491185029Spjd "-\n", cb->cb_namewidth, "cache"); 2492185029Spjd for (c = 0; c < children; c++) { 2493219089Spjd vname = zpool_vdev_name(g_zfs, zhp, newchild[c], 2494219089Spjd B_FALSE); 2495185029Spjd print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL, 2496185029Spjd newchild[c], cb, depth + 2); 2497185029Spjd free(vname); 2498185029Spjd } 2499185029Spjd } 2500168404Spjd} 2501168404Spjd 2502168404Spjdstatic int 2503168404Spjdrefresh_iostat(zpool_handle_t *zhp, void *data) 2504168404Spjd{ 2505168404Spjd iostat_cbdata_t *cb = data; 2506168404Spjd boolean_t missing; 2507168404Spjd 2508168404Spjd /* 2509168404Spjd * If the pool has disappeared, remove it from the list and continue. 2510168404Spjd */ 2511168404Spjd if (zpool_refresh_stats(zhp, &missing) != 0) 2512168404Spjd return (-1); 2513168404Spjd 2514168404Spjd if (missing) 2515168404Spjd pool_list_remove(cb->cb_list, zhp); 2516168404Spjd 2517168404Spjd return (0); 2518168404Spjd} 2519168404Spjd 2520168404Spjd/* 2521168404Spjd * Callback to print out the iostats for the given pool. 2522168404Spjd */ 2523168404Spjdint 2524168404Spjdprint_iostat(zpool_handle_t *zhp, void *data) 2525168404Spjd{ 2526168404Spjd iostat_cbdata_t *cb = data; 2527168404Spjd nvlist_t *oldconfig, *newconfig; 2528168404Spjd nvlist_t *oldnvroot, *newnvroot; 2529168404Spjd 2530168404Spjd newconfig = zpool_get_config(zhp, &oldconfig); 2531168404Spjd 2532168404Spjd if (cb->cb_iteration == 1) 2533168404Spjd oldconfig = NULL; 2534168404Spjd 2535168404Spjd verify(nvlist_lookup_nvlist(newconfig, ZPOOL_CONFIG_VDEV_TREE, 2536168404Spjd &newnvroot) == 0); 2537168404Spjd 2538168404Spjd if (oldconfig == NULL) 2539168404Spjd oldnvroot = NULL; 2540168404Spjd else 2541168404Spjd verify(nvlist_lookup_nvlist(oldconfig, ZPOOL_CONFIG_VDEV_TREE, 2542168404Spjd &oldnvroot) == 0); 2543168404Spjd 2544168404Spjd /* 2545168404Spjd * Print out the statistics for the pool. 2546168404Spjd */ 2547168404Spjd print_vdev_stats(zhp, zpool_get_name(zhp), oldnvroot, newnvroot, cb, 0); 2548168404Spjd 2549168404Spjd if (cb->cb_verbose) 2550168404Spjd print_iostat_separator(cb); 2551168404Spjd 2552168404Spjd return (0); 2553168404Spjd} 2554168404Spjd 2555168404Spjdint 2556168404Spjdget_namewidth(zpool_handle_t *zhp, void *data) 2557168404Spjd{ 2558168404Spjd iostat_cbdata_t *cb = data; 2559168404Spjd nvlist_t *config, *nvroot; 2560168404Spjd 2561168404Spjd if ((config = zpool_get_config(zhp, NULL)) != NULL) { 2562168404Spjd verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 2563168404Spjd &nvroot) == 0); 2564168404Spjd if (!cb->cb_verbose) 2565168404Spjd cb->cb_namewidth = strlen(zpool_get_name(zhp)); 2566168404Spjd else 2567236145Smm cb->cb_namewidth = max_width(zhp, nvroot, 0, 2568236145Smm cb->cb_namewidth); 2569168404Spjd } 2570168404Spjd 2571168404Spjd /* 2572168404Spjd * The width must fall into the range [10,38]. The upper limit is the 2573168404Spjd * maximum we can have and still fit in 80 columns. 2574168404Spjd */ 2575168404Spjd if (cb->cb_namewidth < 10) 2576168404Spjd cb->cb_namewidth = 10; 2577168404Spjd if (cb->cb_namewidth > 38) 2578168404Spjd cb->cb_namewidth = 38; 2579168404Spjd 2580168404Spjd return (0); 2581168404Spjd} 2582168404Spjd 2583168404Spjd/* 2584219089Spjd * Parse the input string, get the 'interval' and 'count' value if there is one. 2585168404Spjd */ 2586219089Spjdstatic void 2587219089Spjdget_interval_count(int *argcp, char **argv, unsigned long *iv, 2588219089Spjd unsigned long *cnt) 2589168404Spjd{ 2590168404Spjd unsigned long interval = 0, count = 0; 2591219089Spjd int argc = *argcp, errno; 2592168404Spjd 2593168404Spjd /* 2594168404Spjd * Determine if the last argument is an integer or a pool name 2595168404Spjd */ 2596168404Spjd if (argc > 0 && isdigit(argv[argc - 1][0])) { 2597168404Spjd char *end; 2598168404Spjd 2599168404Spjd errno = 0; 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 * Ignore the last parameter 2610168404Spjd */ 2611168404Spjd argc--; 2612168404Spjd } else { 2613168404Spjd /* 2614168404Spjd * If this is not a valid number, just plow on. The 2615168404Spjd * user will get a more informative error message later 2616168404Spjd * on. 2617168404Spjd */ 2618168404Spjd interval = 0; 2619168404Spjd } 2620168404Spjd } 2621168404Spjd 2622168404Spjd /* 2623168404Spjd * If the last argument is also an integer, then we have both a count 2624219089Spjd * and an interval. 2625168404Spjd */ 2626168404Spjd if (argc > 0 && isdigit(argv[argc - 1][0])) { 2627168404Spjd char *end; 2628168404Spjd 2629168404Spjd errno = 0; 2630168404Spjd count = interval; 2631168404Spjd interval = strtoul(argv[argc - 1], &end, 10); 2632168404Spjd 2633168404Spjd if (*end == '\0' && errno == 0) { 2634168404Spjd if (interval == 0) { 2635168404Spjd (void) fprintf(stderr, gettext("interval " 2636168404Spjd "cannot be zero\n")); 2637168404Spjd usage(B_FALSE); 2638168404Spjd } 2639168404Spjd 2640168404Spjd /* 2641168404Spjd * Ignore the last parameter 2642168404Spjd */ 2643168404Spjd argc--; 2644168404Spjd } else { 2645168404Spjd interval = 0; 2646168404Spjd } 2647168404Spjd } 2648168404Spjd 2649219089Spjd *iv = interval; 2650219089Spjd *cnt = count; 2651219089Spjd *argcp = argc; 2652219089Spjd} 2653219089Spjd 2654219089Spjdstatic void 2655219089Spjdget_timestamp_arg(char c) 2656219089Spjd{ 2657219089Spjd if (c == 'u') 2658219089Spjd timestamp_fmt = UDATE; 2659219089Spjd else if (c == 'd') 2660219089Spjd timestamp_fmt = DDATE; 2661219089Spjd else 2662219089Spjd usage(B_FALSE); 2663219089Spjd} 2664219089Spjd 2665219089Spjd/* 2666219089Spjd * zpool iostat [-v] [-T d|u] [pool] ... [interval [count]] 2667219089Spjd * 2668219089Spjd * -v Display statistics for individual vdevs 2669219089Spjd * -T Display a timestamp in date(1) or Unix format 2670219089Spjd * 2671219089Spjd * This command can be tricky because we want to be able to deal with pool 2672219089Spjd * creation/destruction as well as vdev configuration changes. The bulk of this 2673219089Spjd * processing is handled by the pool_list_* routines in zpool_iter.c. We rely 2674219089Spjd * on pool_list_update() to detect the addition of new pools. Configuration 2675219089Spjd * changes are all handled within libzfs. 2676219089Spjd */ 2677219089Spjdint 2678219089Spjdzpool_do_iostat(int argc, char **argv) 2679219089Spjd{ 2680219089Spjd int c; 2681219089Spjd int ret; 2682219089Spjd int npools; 2683219089Spjd unsigned long interval = 0, count = 0; 2684219089Spjd zpool_list_t *list; 2685219089Spjd boolean_t verbose = B_FALSE; 2686219089Spjd iostat_cbdata_t cb; 2687219089Spjd 2688219089Spjd /* check options */ 2689219089Spjd while ((c = getopt(argc, argv, "T:v")) != -1) { 2690219089Spjd switch (c) { 2691219089Spjd case 'T': 2692219089Spjd get_timestamp_arg(*optarg); 2693219089Spjd break; 2694219089Spjd case 'v': 2695219089Spjd verbose = B_TRUE; 2696219089Spjd break; 2697219089Spjd case '?': 2698219089Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2699219089Spjd optopt); 2700219089Spjd usage(B_FALSE); 2701219089Spjd } 2702219089Spjd } 2703219089Spjd 2704219089Spjd argc -= optind; 2705219089Spjd argv += optind; 2706219089Spjd 2707219089Spjd get_interval_count(&argc, argv, &interval, &count); 2708219089Spjd 2709168404Spjd /* 2710168404Spjd * Construct the list of all interesting pools. 2711168404Spjd */ 2712168404Spjd ret = 0; 2713168404Spjd if ((list = pool_list_get(argc, argv, NULL, &ret)) == NULL) 2714168404Spjd return (1); 2715168404Spjd 2716168404Spjd if (pool_list_count(list) == 0 && argc != 0) { 2717168404Spjd pool_list_free(list); 2718168404Spjd return (1); 2719168404Spjd } 2720168404Spjd 2721168404Spjd if (pool_list_count(list) == 0 && interval == 0) { 2722168404Spjd pool_list_free(list); 2723168404Spjd (void) fprintf(stderr, gettext("no pools available\n")); 2724168404Spjd return (1); 2725168404Spjd } 2726168404Spjd 2727168404Spjd /* 2728168404Spjd * Enter the main iostat loop. 2729168404Spjd */ 2730168404Spjd cb.cb_list = list; 2731168404Spjd cb.cb_verbose = verbose; 2732168404Spjd cb.cb_iteration = 0; 2733168404Spjd cb.cb_namewidth = 0; 2734168404Spjd 2735168404Spjd for (;;) { 2736168404Spjd pool_list_update(list); 2737168404Spjd 2738168404Spjd if ((npools = pool_list_count(list)) == 0) 2739168404Spjd break; 2740168404Spjd 2741168404Spjd /* 2742168404Spjd * Refresh all statistics. This is done as an explicit step 2743168404Spjd * before calculating the maximum name width, so that any 2744168404Spjd * configuration changes are properly accounted for. 2745168404Spjd */ 2746168404Spjd (void) pool_list_iter(list, B_FALSE, refresh_iostat, &cb); 2747168404Spjd 2748168404Spjd /* 2749168404Spjd * Iterate over all pools to determine the maximum width 2750168404Spjd * for the pool / device name column across all pools. 2751168404Spjd */ 2752168404Spjd cb.cb_namewidth = 0; 2753168404Spjd (void) pool_list_iter(list, B_FALSE, get_namewidth, &cb); 2754168404Spjd 2755219089Spjd if (timestamp_fmt != NODATE) 2756219089Spjd print_timestamp(timestamp_fmt); 2757219089Spjd 2758168404Spjd /* 2759168404Spjd * If it's the first time, or verbose mode, print the header. 2760168404Spjd */ 2761168404Spjd if (++cb.cb_iteration == 1 || verbose) 2762168404Spjd print_iostat_header(&cb); 2763168404Spjd 2764168404Spjd (void) pool_list_iter(list, B_FALSE, print_iostat, &cb); 2765168404Spjd 2766168404Spjd /* 2767168404Spjd * If there's more than one pool, and we're not in verbose mode 2768168404Spjd * (which prints a separator for us), then print a separator. 2769168404Spjd */ 2770168404Spjd if (npools > 1 && !verbose) 2771168404Spjd print_iostat_separator(&cb); 2772168404Spjd 2773168404Spjd if (verbose) 2774168404Spjd (void) printf("\n"); 2775168404Spjd 2776168404Spjd /* 2777168404Spjd * Flush the output so that redirection to a file isn't buffered 2778168404Spjd * indefinitely. 2779168404Spjd */ 2780168404Spjd (void) fflush(stdout); 2781168404Spjd 2782168404Spjd if (interval == 0) 2783168404Spjd break; 2784168404Spjd 2785168404Spjd if (count != 0 && --count == 0) 2786168404Spjd break; 2787168404Spjd 2788168404Spjd (void) sleep(interval); 2789168404Spjd } 2790168404Spjd 2791168404Spjd pool_list_free(list); 2792168404Spjd 2793168404Spjd return (ret); 2794168404Spjd} 2795168404Spjd 2796168404Spjdtypedef struct list_cbdata { 2797236155Smm boolean_t cb_verbose; 2798236155Smm int cb_namewidth; 2799168404Spjd boolean_t cb_scripted; 2800185029Spjd zprop_list_t *cb_proplist; 2801263889Sdelphij boolean_t cb_literal; 2802168404Spjd} list_cbdata_t; 2803168404Spjd 2804168404Spjd/* 2805168404Spjd * Given a list of columns to display, output appropriate headers for each one. 2806168404Spjd */ 2807185029Spjdstatic void 2808236155Smmprint_header(list_cbdata_t *cb) 2809168404Spjd{ 2810236155Smm zprop_list_t *pl = cb->cb_proplist; 2811236884Smm char headerbuf[ZPOOL_MAXPROPLEN]; 2812185029Spjd const char *header; 2813185029Spjd boolean_t first = B_TRUE; 2814185029Spjd boolean_t right_justify; 2815236155Smm size_t width = 0; 2816168404Spjd 2817185029Spjd for (; pl != NULL; pl = pl->pl_next) { 2818236155Smm width = pl->pl_width; 2819236155Smm if (first && cb->cb_verbose) { 2820236155Smm /* 2821236155Smm * Reset the width to accommodate the verbose listing 2822236155Smm * of devices. 2823236155Smm */ 2824236155Smm width = cb->cb_namewidth; 2825236155Smm } 2826236155Smm 2827185029Spjd if (!first) 2828168404Spjd (void) printf(" "); 2829168404Spjd else 2830185029Spjd first = B_FALSE; 2831168404Spjd 2832236884Smm right_justify = B_FALSE; 2833236884Smm if (pl->pl_prop != ZPROP_INVAL) { 2834236884Smm header = zpool_prop_column_name(pl->pl_prop); 2835236884Smm right_justify = zpool_prop_align_right(pl->pl_prop); 2836236884Smm } else { 2837236884Smm int i; 2838185029Spjd 2839236884Smm for (i = 0; pl->pl_user_prop[i] != '\0'; i++) 2840236884Smm headerbuf[i] = toupper(pl->pl_user_prop[i]); 2841236884Smm headerbuf[i] = '\0'; 2842236884Smm header = headerbuf; 2843236884Smm } 2844236884Smm 2845185029Spjd if (pl->pl_next == NULL && !right_justify) 2846185029Spjd (void) printf("%s", header); 2847185029Spjd else if (right_justify) 2848236155Smm (void) printf("%*s", width, header); 2849185029Spjd else 2850236155Smm (void) printf("%-*s", width, header); 2851236155Smm 2852168404Spjd } 2853168404Spjd 2854168404Spjd (void) printf("\n"); 2855168404Spjd} 2856168404Spjd 2857185029Spjd/* 2858185029Spjd * Given a pool and a list of properties, print out all the properties according 2859185029Spjd * to the described layout. 2860185029Spjd */ 2861185029Spjdstatic void 2862236155Smmprint_pool(zpool_handle_t *zhp, list_cbdata_t *cb) 2863168404Spjd{ 2864236155Smm zprop_list_t *pl = cb->cb_proplist; 2865185029Spjd boolean_t first = B_TRUE; 2866185029Spjd char property[ZPOOL_MAXPROPLEN]; 2867185029Spjd char *propstr; 2868185029Spjd boolean_t right_justify; 2869236155Smm size_t width; 2870168404Spjd 2871185029Spjd for (; pl != NULL; pl = pl->pl_next) { 2872236155Smm 2873236155Smm width = pl->pl_width; 2874236155Smm if (first && cb->cb_verbose) { 2875236155Smm /* 2876236155Smm * Reset the width to accommodate the verbose listing 2877236155Smm * of devices. 2878236155Smm */ 2879236155Smm width = cb->cb_namewidth; 2880236155Smm } 2881236155Smm 2882185029Spjd if (!first) { 2883236155Smm if (cb->cb_scripted) 2884168404Spjd (void) printf("\t"); 2885168404Spjd else 2886168404Spjd (void) printf(" "); 2887185029Spjd } else { 2888185029Spjd first = B_FALSE; 2889168404Spjd } 2890168404Spjd 2891185029Spjd right_justify = B_FALSE; 2892185029Spjd if (pl->pl_prop != ZPROP_INVAL) { 2893272502Sdelphij if (zpool_get_prop(zhp, pl->pl_prop, property, 2894263889Sdelphij sizeof (property), NULL, cb->cb_literal) != 0) 2895185029Spjd propstr = "-"; 2896168404Spjd else 2897185029Spjd propstr = property; 2898168404Spjd 2899185029Spjd right_justify = zpool_prop_align_right(pl->pl_prop); 2900236884Smm } else if ((zpool_prop_feature(pl->pl_user_prop) || 2901236884Smm zpool_prop_unsupported(pl->pl_user_prop)) && 2902236884Smm zpool_prop_get_feature(zhp, pl->pl_user_prop, property, 2903236884Smm sizeof (property)) == 0) { 2904236884Smm propstr = property; 2905185029Spjd } else { 2906185029Spjd propstr = "-"; 2907185029Spjd } 2908168404Spjd 2909168404Spjd 2910185029Spjd /* 2911185029Spjd * If this is being called in scripted mode, or if this is the 2912185029Spjd * last column and it is left-justified, don't include a width 2913185029Spjd * format specifier. 2914185029Spjd */ 2915236155Smm if (cb->cb_scripted || (pl->pl_next == NULL && !right_justify)) 2916185029Spjd (void) printf("%s", propstr); 2917185029Spjd else if (right_justify) 2918185029Spjd (void) printf("%*s", width, propstr); 2919185029Spjd else 2920185029Spjd (void) printf("%-*s", width, propstr); 2921185029Spjd } 2922168404Spjd 2923185029Spjd (void) printf("\n"); 2924185029Spjd} 2925168404Spjd 2926236155Smmstatic void 2927272502Sdelphijprint_one_column(zpool_prop_t prop, uint64_t value, boolean_t scripted, 2928272502Sdelphij boolean_t valid) 2929236155Smm{ 2930236155Smm char propval[64]; 2931236155Smm boolean_t fixed; 2932236155Smm size_t width = zprop_width(prop, &fixed, ZFS_TYPE_POOL); 2933236155Smm 2934272502Sdelphij switch (prop) { 2935272502Sdelphij case ZPOOL_PROP_EXPANDSZ: 2936272502Sdelphij if (value == 0) 2937272502Sdelphij (void) strlcpy(propval, "-", sizeof (propval)); 2938272502Sdelphij else 2939272502Sdelphij zfs_nicenum(value, propval, sizeof (propval)); 2940272502Sdelphij break; 2941272502Sdelphij case ZPOOL_PROP_FRAGMENTATION: 2942272502Sdelphij if (value == ZFS_FRAG_INVALID) { 2943272502Sdelphij (void) strlcpy(propval, "-", sizeof (propval)); 2944272502Sdelphij } else { 2945272502Sdelphij (void) snprintf(propval, sizeof (propval), "%llu%%", 2946272502Sdelphij value); 2947272502Sdelphij } 2948272502Sdelphij break; 2949272502Sdelphij case ZPOOL_PROP_CAPACITY: 2950269118Sdelphij (void) snprintf(propval, sizeof (propval), "%llu%%", value); 2951272502Sdelphij break; 2952272502Sdelphij default: 2953269118Sdelphij zfs_nicenum(value, propval, sizeof (propval)); 2954272502Sdelphij } 2955236155Smm 2956272502Sdelphij if (!valid) 2957272502Sdelphij (void) strlcpy(propval, "-", sizeof (propval)); 2958272502Sdelphij 2959236155Smm if (scripted) 2960236155Smm (void) printf("\t%s", propval); 2961236155Smm else 2962236155Smm (void) printf(" %*s", width, propval); 2963236155Smm} 2964236155Smm 2965236155Smmvoid 2966236155Smmprint_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv, 2967236155Smm list_cbdata_t *cb, int depth) 2968236155Smm{ 2969236155Smm nvlist_t **child; 2970236155Smm vdev_stat_t *vs; 2971236155Smm uint_t c, children; 2972236155Smm char *vname; 2973236155Smm boolean_t scripted = cb->cb_scripted; 2974289536Smav uint64_t islog = B_FALSE; 2975289536Smav boolean_t haslog = B_FALSE; 2976289536Smav char *dashes = "%-*s - - - - - -\n"; 2977236155Smm 2978236155Smm verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS, 2979236155Smm (uint64_t **)&vs, &c) == 0); 2980236155Smm 2981236155Smm if (name != NULL) { 2982272502Sdelphij boolean_t toplevel = (vs->vs_space != 0); 2983272502Sdelphij uint64_t cap; 2984272502Sdelphij 2985236155Smm if (scripted) 2986236155Smm (void) printf("\t%s", name); 2987236155Smm else if (strlen(name) + depth > cb->cb_namewidth) 2988236155Smm (void) printf("%*s%s", depth, "", name); 2989236155Smm else 2990236155Smm (void) printf("%*s%s%*s", depth, "", name, 2991236155Smm (int)(cb->cb_namewidth - strlen(name) - depth), ""); 2992236155Smm 2993272502Sdelphij /* 2994272502Sdelphij * Print the properties for the individual vdevs. Some 2995272502Sdelphij * properties are only applicable to toplevel vdevs. The 2996272502Sdelphij * 'toplevel' boolean value is passed to the print_one_column() 2997272502Sdelphij * to indicate that the value is valid. 2998272502Sdelphij */ 2999272502Sdelphij print_one_column(ZPOOL_PROP_SIZE, vs->vs_space, scripted, 3000272502Sdelphij toplevel); 3001272502Sdelphij print_one_column(ZPOOL_PROP_ALLOCATED, vs->vs_alloc, scripted, 3002272502Sdelphij toplevel); 3003272502Sdelphij print_one_column(ZPOOL_PROP_FREE, vs->vs_space - vs->vs_alloc, 3004272502Sdelphij scripted, toplevel); 3005272502Sdelphij print_one_column(ZPOOL_PROP_EXPANDSZ, vs->vs_esize, scripted, 3006272502Sdelphij B_TRUE); 3007272502Sdelphij print_one_column(ZPOOL_PROP_FRAGMENTATION, 3008272502Sdelphij vs->vs_fragmentation, scripted, 3009272502Sdelphij (vs->vs_fragmentation != ZFS_FRAG_INVALID && toplevel)); 3010272502Sdelphij cap = (vs->vs_space == 0) ? 0 : 3011272502Sdelphij (vs->vs_alloc * 100 / vs->vs_space); 3012272502Sdelphij print_one_column(ZPOOL_PROP_CAPACITY, cap, scripted, toplevel); 3013236155Smm (void) printf("\n"); 3014236155Smm } 3015236155Smm 3016236155Smm if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 3017236155Smm &child, &children) != 0) 3018236155Smm return; 3019236155Smm 3020236155Smm for (c = 0; c < children; c++) { 3021236155Smm uint64_t ishole = B_FALSE; 3022236155Smm 3023236155Smm if (nvlist_lookup_uint64(child[c], 3024236155Smm ZPOOL_CONFIG_IS_HOLE, &ishole) == 0 && ishole) 3025236155Smm continue; 3026236155Smm 3027289536Smav if (nvlist_lookup_uint64(child[c], 3028289536Smav ZPOOL_CONFIG_IS_LOG, &islog) == 0 && islog) { 3029289536Smav haslog = B_TRUE; 3030289536Smav continue; 3031289536Smav } 3032289536Smav 3033236155Smm vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE); 3034236155Smm print_list_stats(zhp, vname, child[c], cb, depth + 2); 3035236155Smm free(vname); 3036236155Smm } 3037236155Smm 3038289536Smav if (haslog == B_TRUE) { 3039289536Smav /* LINTED E_SEC_PRINTF_VAR_FMT */ 3040289536Smav (void) printf(dashes, cb->cb_namewidth, "log"); 3041289536Smav for (c = 0; c < children; c++) { 3042289536Smav if (nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 3043289536Smav &islog) != 0 || !islog) 3044289536Smav continue; 3045289536Smav vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE); 3046289536Smav print_list_stats(zhp, vname, child[c], cb, depth + 2); 3047289536Smav free(vname); 3048289536Smav } 3049289536Smav } 3050289536Smav 3051236155Smm if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE, 3052289536Smav &child, &children) == 0 && children > 0) { 3053289536Smav /* LINTED E_SEC_PRINTF_VAR_FMT */ 3054289536Smav (void) printf(dashes, cb->cb_namewidth, "cache"); 3055289536Smav for (c = 0; c < children; c++) { 3056289536Smav vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE); 3057289536Smav print_list_stats(zhp, vname, child[c], cb, depth + 2); 3058289536Smav free(vname); 3059289536Smav } 3060289536Smav } 3061236155Smm 3062289536Smav if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, &child, 3063289536Smav &children) == 0 && children > 0) { 3064289536Smav /* LINTED E_SEC_PRINTF_VAR_FMT */ 3065289536Smav (void) printf(dashes, cb->cb_namewidth, "spare"); 3066236155Smm for (c = 0; c < children; c++) { 3067289536Smav vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE); 3068236155Smm print_list_stats(zhp, vname, child[c], cb, depth + 2); 3069236155Smm free(vname); 3070236155Smm } 3071236155Smm } 3072236155Smm} 3073236155Smm 3074236155Smm 3075185029Spjd/* 3076185029Spjd * Generic callback function to list a pool. 3077185029Spjd */ 3078185029Spjdint 3079185029Spjdlist_callback(zpool_handle_t *zhp, void *data) 3080185029Spjd{ 3081185029Spjd list_cbdata_t *cbp = data; 3082236155Smm nvlist_t *config; 3083236155Smm nvlist_t *nvroot; 3084168404Spjd 3085236155Smm config = zpool_get_config(zhp, NULL); 3086168404Spjd 3087236155Smm print_pool(zhp, cbp); 3088236155Smm if (!cbp->cb_verbose) 3089236155Smm return (0); 3090168404Spjd 3091236155Smm verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 3092236155Smm &nvroot) == 0); 3093236155Smm print_list_stats(zhp, NULL, nvroot, cbp, 0); 3094236155Smm 3095168404Spjd return (0); 3096168404Spjd} 3097168404Spjd 3098168404Spjd/* 3099263889Sdelphij * zpool list [-Hp] [-o prop[,prop]*] [-T d|u] [pool] ... [interval [count]] 3100168404Spjd * 3101185029Spjd * -H Scripted mode. Don't display headers, and separate properties 3102185029Spjd * by a single tab. 3103185029Spjd * -o List of properties to display. Defaults to 3104272502Sdelphij * "name,size,allocated,free,expandsize,fragmentation,capacity," 3105272502Sdelphij * "dedupratio,health,altroot" 3106263889Sdelphij * -p Diplay values in parsable (exact) format. 3107219089Spjd * -T Display a timestamp in date(1) or Unix format 3108168404Spjd * 3109168404Spjd * List all pools in the system, whether or not they're healthy. Output space 3110168404Spjd * statistics for each one, as well as health status summary. 3111168404Spjd */ 3112168404Spjdint 3113168404Spjdzpool_do_list(int argc, char **argv) 3114168404Spjd{ 3115168404Spjd int c; 3116168404Spjd int ret; 3117168404Spjd list_cbdata_t cb = { 0 }; 3118185029Spjd static char default_props[] = 3119272502Sdelphij "name,size,allocated,free,expandsize,fragmentation,capacity," 3120269118Sdelphij "dedupratio,health,altroot"; 3121185029Spjd char *props = default_props; 3122219089Spjd unsigned long interval = 0, count = 0; 3123236155Smm zpool_list_t *list; 3124236155Smm boolean_t first = B_TRUE; 3125168404Spjd 3126168404Spjd /* check options */ 3127263889Sdelphij while ((c = getopt(argc, argv, ":Ho:pT:v")) != -1) { 3128168404Spjd switch (c) { 3129168404Spjd case 'H': 3130168404Spjd cb.cb_scripted = B_TRUE; 3131168404Spjd break; 3132168404Spjd case 'o': 3133185029Spjd props = optarg; 3134168404Spjd break; 3135263889Sdelphij case 'p': 3136263889Sdelphij cb.cb_literal = B_TRUE; 3137263889Sdelphij break; 3138219089Spjd case 'T': 3139219089Spjd get_timestamp_arg(*optarg); 3140219089Spjd break; 3141236155Smm case 'v': 3142236155Smm cb.cb_verbose = B_TRUE; 3143236155Smm break; 3144168404Spjd case ':': 3145168404Spjd (void) fprintf(stderr, gettext("missing argument for " 3146168404Spjd "'%c' option\n"), optopt); 3147168404Spjd usage(B_FALSE); 3148168404Spjd break; 3149168404Spjd case '?': 3150168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3151168404Spjd optopt); 3152168404Spjd usage(B_FALSE); 3153168404Spjd } 3154168404Spjd } 3155168404Spjd 3156168404Spjd argc -= optind; 3157168404Spjd argv += optind; 3158168404Spjd 3159219089Spjd get_interval_count(&argc, argv, &interval, &count); 3160219089Spjd 3161185029Spjd if (zprop_get_list(g_zfs, props, &cb.cb_proplist, ZFS_TYPE_POOL) != 0) 3162185029Spjd usage(B_FALSE); 3163168404Spjd 3164219089Spjd for (;;) { 3165268470Sdelphij if ((list = pool_list_get(argc, argv, &cb.cb_proplist, 3166268470Sdelphij &ret)) == NULL) 3167268470Sdelphij return (1); 3168168404Spjd 3169236155Smm if (pool_list_count(list) == 0) 3170236155Smm break; 3171236155Smm 3172236155Smm cb.cb_namewidth = 0; 3173236155Smm (void) pool_list_iter(list, B_FALSE, get_namewidth, &cb); 3174236155Smm 3175219089Spjd if (timestamp_fmt != NODATE) 3176219089Spjd print_timestamp(timestamp_fmt); 3177168404Spjd 3178236155Smm if (!cb.cb_scripted && (first || cb.cb_verbose)) { 3179236155Smm print_header(&cb); 3180236155Smm first = B_FALSE; 3181219089Spjd } 3182236155Smm ret = pool_list_iter(list, B_TRUE, list_callback, &cb); 3183219089Spjd 3184219089Spjd if (interval == 0) 3185219089Spjd break; 3186219089Spjd 3187219089Spjd if (count != 0 && --count == 0) 3188219089Spjd break; 3189219089Spjd 3190268470Sdelphij pool_list_free(list); 3191219089Spjd (void) sleep(interval); 3192168404Spjd } 3193168404Spjd 3194268470Sdelphij if (argc == 0 && !cb.cb_scripted && pool_list_count(list) == 0) { 3195268470Sdelphij (void) printf(gettext("no pools available\n")); 3196268470Sdelphij ret = 0; 3197268470Sdelphij } 3198268470Sdelphij 3199268470Sdelphij pool_list_free(list); 3200219089Spjd zprop_free_list(cb.cb_proplist); 3201168404Spjd return (ret); 3202168404Spjd} 3203168404Spjd 3204168404Spjdstatic int 3205168404Spjdzpool_do_attach_or_replace(int argc, char **argv, int replacing) 3206168404Spjd{ 3207168404Spjd boolean_t force = B_FALSE; 3208168404Spjd int c; 3209168404Spjd nvlist_t *nvroot; 3210168404Spjd char *poolname, *old_disk, *new_disk; 3211168404Spjd zpool_handle_t *zhp; 3212168404Spjd int ret; 3213168404Spjd 3214168404Spjd /* check options */ 3215168404Spjd while ((c = getopt(argc, argv, "f")) != -1) { 3216168404Spjd switch (c) { 3217168404Spjd case 'f': 3218168404Spjd force = B_TRUE; 3219168404Spjd break; 3220168404Spjd case '?': 3221168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3222168404Spjd optopt); 3223168404Spjd usage(B_FALSE); 3224168404Spjd } 3225168404Spjd } 3226168404Spjd 3227168404Spjd argc -= optind; 3228168404Spjd argv += optind; 3229168404Spjd 3230168404Spjd /* get pool name and check number of arguments */ 3231168404Spjd if (argc < 1) { 3232168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 3233168404Spjd usage(B_FALSE); 3234168404Spjd } 3235168404Spjd 3236168404Spjd poolname = argv[0]; 3237168404Spjd 3238168404Spjd if (argc < 2) { 3239168404Spjd (void) fprintf(stderr, 3240168404Spjd gettext("missing <device> specification\n")); 3241168404Spjd usage(B_FALSE); 3242168404Spjd } 3243168404Spjd 3244168404Spjd old_disk = argv[1]; 3245168404Spjd 3246168404Spjd if (argc < 3) { 3247168404Spjd if (!replacing) { 3248168404Spjd (void) fprintf(stderr, 3249168404Spjd gettext("missing <new_device> specification\n")); 3250168404Spjd usage(B_FALSE); 3251168404Spjd } 3252168404Spjd new_disk = old_disk; 3253168404Spjd argc -= 1; 3254168404Spjd argv += 1; 3255168404Spjd } else { 3256168404Spjd new_disk = argv[2]; 3257168404Spjd argc -= 2; 3258168404Spjd argv += 2; 3259168404Spjd } 3260168404Spjd 3261168404Spjd if (argc > 1) { 3262168404Spjd (void) fprintf(stderr, gettext("too many arguments\n")); 3263168404Spjd usage(B_FALSE); 3264168404Spjd } 3265168404Spjd 3266168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 3267168404Spjd return (1); 3268168404Spjd 3269185029Spjd if (zpool_get_config(zhp, NULL) == NULL) { 3270168404Spjd (void) fprintf(stderr, gettext("pool '%s' is unavailable\n"), 3271168404Spjd poolname); 3272168404Spjd zpool_close(zhp); 3273168404Spjd return (1); 3274168404Spjd } 3275168404Spjd 3276185029Spjd nvroot = make_root_vdev(zhp, force, B_FALSE, replacing, B_FALSE, 3277185029Spjd argc, argv); 3278168404Spjd if (nvroot == NULL) { 3279168404Spjd zpool_close(zhp); 3280168404Spjd return (1); 3281168404Spjd } 3282168404Spjd 3283168404Spjd ret = zpool_vdev_attach(zhp, old_disk, new_disk, nvroot, replacing); 3284168404Spjd 3285168404Spjd nvlist_free(nvroot); 3286168404Spjd zpool_close(zhp); 3287168404Spjd 3288168404Spjd return (ret); 3289168404Spjd} 3290168404Spjd 3291168404Spjd/* 3292168404Spjd * zpool replace [-f] <pool> <device> <new_device> 3293168404Spjd * 3294168404Spjd * -f Force attach, even if <new_device> appears to be in use. 3295168404Spjd * 3296168404Spjd * Replace <device> with <new_device>. 3297168404Spjd */ 3298168404Spjd/* ARGSUSED */ 3299168404Spjdint 3300168404Spjdzpool_do_replace(int argc, char **argv) 3301168404Spjd{ 3302168404Spjd return (zpool_do_attach_or_replace(argc, argv, B_TRUE)); 3303168404Spjd} 3304168404Spjd 3305168404Spjd/* 3306168404Spjd * zpool attach [-f] <pool> <device> <new_device> 3307168404Spjd * 3308168404Spjd * -f Force attach, even if <new_device> appears to be in use. 3309168404Spjd * 3310168404Spjd * Attach <new_device> to the mirror containing <device>. If <device> is not 3311168404Spjd * part of a mirror, then <device> will be transformed into a mirror of 3312168404Spjd * <device> and <new_device>. In either case, <new_device> will begin life 3313168404Spjd * with a DTL of [0, now], and will immediately begin to resilver itself. 3314168404Spjd */ 3315168404Spjdint 3316168404Spjdzpool_do_attach(int argc, char **argv) 3317168404Spjd{ 3318168404Spjd return (zpool_do_attach_or_replace(argc, argv, B_FALSE)); 3319168404Spjd} 3320168404Spjd 3321168404Spjd/* 3322168404Spjd * zpool detach [-f] <pool> <device> 3323168404Spjd * 3324168404Spjd * -f Force detach of <device>, even if DTLs argue against it 3325168404Spjd * (not supported yet) 3326168404Spjd * 3327168404Spjd * Detach a device from a mirror. The operation will be refused if <device> 3328168404Spjd * is the last device in the mirror, or if the DTLs indicate that this device 3329168404Spjd * has the only valid copy of some data. 3330168404Spjd */ 3331168404Spjd/* ARGSUSED */ 3332168404Spjdint 3333168404Spjdzpool_do_detach(int argc, char **argv) 3334168404Spjd{ 3335168404Spjd int c; 3336168404Spjd char *poolname, *path; 3337168404Spjd zpool_handle_t *zhp; 3338168404Spjd int ret; 3339168404Spjd 3340168404Spjd /* check options */ 3341168404Spjd while ((c = getopt(argc, argv, "f")) != -1) { 3342168404Spjd switch (c) { 3343168404Spjd case 'f': 3344168404Spjd case '?': 3345168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3346168404Spjd optopt); 3347168404Spjd usage(B_FALSE); 3348168404Spjd } 3349168404Spjd } 3350168404Spjd 3351168404Spjd argc -= optind; 3352168404Spjd argv += optind; 3353168404Spjd 3354168404Spjd /* get pool name and check number of arguments */ 3355168404Spjd if (argc < 1) { 3356168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 3357168404Spjd usage(B_FALSE); 3358168404Spjd } 3359168404Spjd 3360168404Spjd if (argc < 2) { 3361168404Spjd (void) fprintf(stderr, 3362168404Spjd gettext("missing <device> specification\n")); 3363168404Spjd usage(B_FALSE); 3364168404Spjd } 3365168404Spjd 3366168404Spjd poolname = argv[0]; 3367168404Spjd path = argv[1]; 3368168404Spjd 3369168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 3370168404Spjd return (1); 3371168404Spjd 3372168404Spjd ret = zpool_vdev_detach(zhp, path); 3373168404Spjd 3374168404Spjd zpool_close(zhp); 3375168404Spjd 3376168404Spjd return (ret); 3377168404Spjd} 3378168404Spjd 3379168404Spjd/* 3380219089Spjd * zpool split [-n] [-o prop=val] ... 3381219089Spjd * [-o mntopt] ... 3382219089Spjd * [-R altroot] <pool> <newpool> [<device> ...] 3383219089Spjd * 3384219089Spjd * -n Do not split the pool, but display the resulting layout if 3385219089Spjd * it were to be split. 3386219089Spjd * -o Set property=value, or set mount options. 3387219089Spjd * -R Mount the split-off pool under an alternate root. 3388219089Spjd * 3389219089Spjd * Splits the named pool and gives it the new pool name. Devices to be split 3390219089Spjd * off may be listed, provided that no more than one device is specified 3391219089Spjd * per top-level vdev mirror. The newly split pool is left in an exported 3392219089Spjd * state unless -R is specified. 3393219089Spjd * 3394219089Spjd * Restrictions: the top-level of the pool pool must only be made up of 3395219089Spjd * mirrors; all devices in the pool must be healthy; no device may be 3396219089Spjd * undergoing a resilvering operation. 3397219089Spjd */ 3398219089Spjdint 3399219089Spjdzpool_do_split(int argc, char **argv) 3400219089Spjd{ 3401219089Spjd char *srcpool, *newpool, *propval; 3402219089Spjd char *mntopts = NULL; 3403219089Spjd splitflags_t flags; 3404219089Spjd int c, ret = 0; 3405219089Spjd zpool_handle_t *zhp; 3406219089Spjd nvlist_t *config, *props = NULL; 3407219089Spjd 3408219089Spjd flags.dryrun = B_FALSE; 3409219089Spjd flags.import = B_FALSE; 3410219089Spjd 3411219089Spjd /* check options */ 3412219089Spjd while ((c = getopt(argc, argv, ":R:no:")) != -1) { 3413219089Spjd switch (c) { 3414219089Spjd case 'R': 3415219089Spjd flags.import = B_TRUE; 3416219089Spjd if (add_prop_list( 3417219089Spjd zpool_prop_to_name(ZPOOL_PROP_ALTROOT), optarg, 3418219089Spjd &props, B_TRUE) != 0) { 3419296528Smav nvlist_free(props); 3420219089Spjd usage(B_FALSE); 3421219089Spjd } 3422219089Spjd break; 3423219089Spjd case 'n': 3424219089Spjd flags.dryrun = B_TRUE; 3425219089Spjd break; 3426219089Spjd case 'o': 3427219089Spjd if ((propval = strchr(optarg, '=')) != NULL) { 3428219089Spjd *propval = '\0'; 3429219089Spjd propval++; 3430219089Spjd if (add_prop_list(optarg, propval, 3431219089Spjd &props, B_TRUE) != 0) { 3432296528Smav nvlist_free(props); 3433219089Spjd usage(B_FALSE); 3434219089Spjd } 3435219089Spjd } else { 3436219089Spjd mntopts = optarg; 3437219089Spjd } 3438219089Spjd break; 3439219089Spjd case ':': 3440219089Spjd (void) fprintf(stderr, gettext("missing argument for " 3441219089Spjd "'%c' option\n"), optopt); 3442219089Spjd usage(B_FALSE); 3443219089Spjd break; 3444219089Spjd case '?': 3445219089Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3446219089Spjd optopt); 3447219089Spjd usage(B_FALSE); 3448219089Spjd break; 3449219089Spjd } 3450219089Spjd } 3451219089Spjd 3452219089Spjd if (!flags.import && mntopts != NULL) { 3453219089Spjd (void) fprintf(stderr, gettext("setting mntopts is only " 3454219089Spjd "valid when importing the pool\n")); 3455219089Spjd usage(B_FALSE); 3456219089Spjd } 3457219089Spjd 3458219089Spjd argc -= optind; 3459219089Spjd argv += optind; 3460219089Spjd 3461219089Spjd if (argc < 1) { 3462219089Spjd (void) fprintf(stderr, gettext("Missing pool name\n")); 3463219089Spjd usage(B_FALSE); 3464219089Spjd } 3465219089Spjd if (argc < 2) { 3466219089Spjd (void) fprintf(stderr, gettext("Missing new pool name\n")); 3467219089Spjd usage(B_FALSE); 3468219089Spjd } 3469219089Spjd 3470219089Spjd srcpool = argv[0]; 3471219089Spjd newpool = argv[1]; 3472219089Spjd 3473219089Spjd argc -= 2; 3474219089Spjd argv += 2; 3475219089Spjd 3476219089Spjd if ((zhp = zpool_open(g_zfs, srcpool)) == NULL) 3477219089Spjd return (1); 3478219089Spjd 3479219089Spjd config = split_mirror_vdev(zhp, newpool, props, flags, argc, argv); 3480219089Spjd if (config == NULL) { 3481219089Spjd ret = 1; 3482219089Spjd } else { 3483219089Spjd if (flags.dryrun) { 3484219089Spjd (void) printf(gettext("would create '%s' with the " 3485219089Spjd "following layout:\n\n"), newpool); 3486219089Spjd print_vdev_tree(NULL, newpool, config, 0, B_FALSE); 3487219089Spjd } 3488219089Spjd nvlist_free(config); 3489219089Spjd } 3490219089Spjd 3491219089Spjd zpool_close(zhp); 3492219089Spjd 3493219089Spjd if (ret != 0 || flags.dryrun || !flags.import) 3494219089Spjd return (ret); 3495219089Spjd 3496219089Spjd /* 3497219089Spjd * The split was successful. Now we need to open the new 3498219089Spjd * pool and import it. 3499219089Spjd */ 3500219089Spjd if ((zhp = zpool_open_canfail(g_zfs, newpool)) == NULL) 3501219089Spjd return (1); 3502219089Spjd if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL && 3503219089Spjd zpool_enable_datasets(zhp, mntopts, 0) != 0) { 3504219089Spjd ret = 1; 3505240415Smm (void) fprintf(stderr, gettext("Split was successful, but " 3506219089Spjd "the datasets could not all be mounted\n")); 3507219089Spjd (void) fprintf(stderr, gettext("Try doing '%s' with a " 3508219089Spjd "different altroot\n"), "zpool import"); 3509219089Spjd } 3510219089Spjd zpool_close(zhp); 3511219089Spjd 3512219089Spjd return (ret); 3513219089Spjd} 3514219089Spjd 3515219089Spjd 3516219089Spjd 3517219089Spjd/* 3518168404Spjd * zpool online <pool> <device> ... 3519168404Spjd */ 3520168404Spjdint 3521168404Spjdzpool_do_online(int argc, char **argv) 3522168404Spjd{ 3523168404Spjd int c, i; 3524168404Spjd char *poolname; 3525168404Spjd zpool_handle_t *zhp; 3526168404Spjd int ret = 0; 3527185029Spjd vdev_state_t newstate; 3528219089Spjd int flags = 0; 3529168404Spjd 3530168404Spjd /* check options */ 3531219089Spjd while ((c = getopt(argc, argv, "et")) != -1) { 3532168404Spjd switch (c) { 3533219089Spjd case 'e': 3534219089Spjd flags |= ZFS_ONLINE_EXPAND; 3535219089Spjd break; 3536168404Spjd case 't': 3537168404Spjd case '?': 3538168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3539168404Spjd optopt); 3540168404Spjd usage(B_FALSE); 3541168404Spjd } 3542168404Spjd } 3543168404Spjd 3544168404Spjd argc -= optind; 3545168404Spjd argv += optind; 3546168404Spjd 3547168404Spjd /* get pool name and check number of arguments */ 3548168404Spjd if (argc < 1) { 3549168404Spjd (void) fprintf(stderr, gettext("missing pool name\n")); 3550168404Spjd usage(B_FALSE); 3551168404Spjd } 3552168404Spjd if (argc < 2) { 3553168404Spjd (void) fprintf(stderr, gettext("missing device name\n")); 3554168404Spjd usage(B_FALSE); 3555168404Spjd } 3556168404Spjd 3557168404Spjd poolname = argv[0]; 3558168404Spjd 3559168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 3560168404Spjd return (1); 3561168404Spjd 3562185029Spjd for (i = 1; i < argc; i++) { 3563219089Spjd if (zpool_vdev_online(zhp, argv[i], flags, &newstate) == 0) { 3564185029Spjd if (newstate != VDEV_STATE_HEALTHY) { 3565185029Spjd (void) printf(gettext("warning: device '%s' " 3566185029Spjd "onlined, but remains in faulted state\n"), 3567185029Spjd argv[i]); 3568185029Spjd if (newstate == VDEV_STATE_FAULTED) 3569185029Spjd (void) printf(gettext("use 'zpool " 3570185029Spjd "clear' to restore a faulted " 3571185029Spjd "device\n")); 3572185029Spjd else 3573185029Spjd (void) printf(gettext("use 'zpool " 3574185029Spjd "replace' to replace devices " 3575185029Spjd "that are no longer present\n")); 3576185029Spjd } 3577185029Spjd } else { 3578168404Spjd ret = 1; 3579185029Spjd } 3580185029Spjd } 3581168404Spjd 3582168404Spjd zpool_close(zhp); 3583168404Spjd 3584168404Spjd return (ret); 3585168404Spjd} 3586168404Spjd 3587168404Spjd/* 3588168404Spjd * zpool offline [-ft] <pool> <device> ... 3589168404Spjd * 3590168404Spjd * -f Force the device into the offline state, even if doing 3591168404Spjd * so would appear to compromise pool availability. 3592168404Spjd * (not supported yet) 3593168404Spjd * 3594168404Spjd * -t Only take the device off-line temporarily. The offline 3595168404Spjd * state will not be persistent across reboots. 3596168404Spjd */ 3597168404Spjd/* ARGSUSED */ 3598168404Spjdint 3599168404Spjdzpool_do_offline(int argc, char **argv) 3600168404Spjd{ 3601168404Spjd int c, i; 3602168404Spjd char *poolname; 3603168404Spjd zpool_handle_t *zhp; 3604168404Spjd int ret = 0; 3605168404Spjd boolean_t istmp = B_FALSE; 3606168404Spjd 3607168404Spjd /* check options */ 3608168404Spjd while ((c = getopt(argc, argv, "ft")) != -1) { 3609168404Spjd switch (c) { 3610168404Spjd case 't': 3611168404Spjd istmp = B_TRUE; 3612168404Spjd break; 3613168404Spjd case 'f': 3614168404Spjd case '?': 3615168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3616168404Spjd optopt); 3617168404Spjd usage(B_FALSE); 3618168404Spjd } 3619168404Spjd } 3620168404Spjd 3621168404Spjd argc -= optind; 3622168404Spjd argv += optind; 3623168404Spjd 3624168404Spjd /* get pool name and check number of arguments */ 3625168404Spjd if (argc < 1) { 3626168404Spjd (void) fprintf(stderr, gettext("missing pool name\n")); 3627168404Spjd usage(B_FALSE); 3628168404Spjd } 3629168404Spjd if (argc < 2) { 3630168404Spjd (void) fprintf(stderr, gettext("missing device name\n")); 3631168404Spjd usage(B_FALSE); 3632168404Spjd } 3633168404Spjd 3634168404Spjd poolname = argv[0]; 3635168404Spjd 3636168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 3637168404Spjd return (1); 3638168404Spjd 3639185029Spjd for (i = 1; i < argc; i++) { 3640185029Spjd if (zpool_vdev_offline(zhp, argv[i], istmp) != 0) 3641168404Spjd ret = 1; 3642185029Spjd } 3643168404Spjd 3644168404Spjd zpool_close(zhp); 3645168404Spjd 3646168404Spjd return (ret); 3647168404Spjd} 3648168404Spjd 3649168404Spjd/* 3650168404Spjd * zpool clear <pool> [device] 3651168404Spjd * 3652168404Spjd * Clear all errors associated with a pool or a particular device. 3653168404Spjd */ 3654168404Spjdint 3655168404Spjdzpool_do_clear(int argc, char **argv) 3656168404Spjd{ 3657219089Spjd int c; 3658168404Spjd int ret = 0; 3659219089Spjd boolean_t dryrun = B_FALSE; 3660219089Spjd boolean_t do_rewind = B_FALSE; 3661219089Spjd boolean_t xtreme_rewind = B_FALSE; 3662219089Spjd uint32_t rewind_policy = ZPOOL_NO_REWIND; 3663219089Spjd nvlist_t *policy = NULL; 3664168404Spjd zpool_handle_t *zhp; 3665168404Spjd char *pool, *device; 3666168404Spjd 3667219089Spjd /* check options */ 3668219089Spjd while ((c = getopt(argc, argv, "FnX")) != -1) { 3669219089Spjd switch (c) { 3670219089Spjd case 'F': 3671219089Spjd do_rewind = B_TRUE; 3672219089Spjd break; 3673219089Spjd case 'n': 3674219089Spjd dryrun = B_TRUE; 3675219089Spjd break; 3676219089Spjd case 'X': 3677219089Spjd xtreme_rewind = B_TRUE; 3678219089Spjd break; 3679219089Spjd case '?': 3680219089Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3681219089Spjd optopt); 3682219089Spjd usage(B_FALSE); 3683219089Spjd } 3684219089Spjd } 3685219089Spjd 3686219089Spjd argc -= optind; 3687219089Spjd argv += optind; 3688219089Spjd 3689219089Spjd if (argc < 1) { 3690168404Spjd (void) fprintf(stderr, gettext("missing pool name\n")); 3691168404Spjd usage(B_FALSE); 3692168404Spjd } 3693168404Spjd 3694219089Spjd if (argc > 2) { 3695168404Spjd (void) fprintf(stderr, gettext("too many arguments\n")); 3696168404Spjd usage(B_FALSE); 3697168404Spjd } 3698168404Spjd 3699219089Spjd if ((dryrun || xtreme_rewind) && !do_rewind) { 3700219089Spjd (void) fprintf(stderr, 3701219089Spjd gettext("-n or -X only meaningful with -F\n")); 3702219089Spjd usage(B_FALSE); 3703219089Spjd } 3704219089Spjd if (dryrun) 3705219089Spjd rewind_policy = ZPOOL_TRY_REWIND; 3706219089Spjd else if (do_rewind) 3707219089Spjd rewind_policy = ZPOOL_DO_REWIND; 3708219089Spjd if (xtreme_rewind) 3709219089Spjd rewind_policy |= ZPOOL_EXTREME_REWIND; 3710168404Spjd 3711219089Spjd /* In future, further rewind policy choices can be passed along here */ 3712219089Spjd if (nvlist_alloc(&policy, NV_UNIQUE_NAME, 0) != 0 || 3713219089Spjd nvlist_add_uint32(policy, ZPOOL_REWIND_REQUEST, rewind_policy) != 0) 3714168404Spjd return (1); 3715168404Spjd 3716219089Spjd pool = argv[0]; 3717219089Spjd device = argc == 2 ? argv[1] : NULL; 3718219089Spjd 3719219089Spjd if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) { 3720219089Spjd nvlist_free(policy); 3721219089Spjd return (1); 3722219089Spjd } 3723219089Spjd 3724219089Spjd if (zpool_clear(zhp, device, policy) != 0) 3725168404Spjd ret = 1; 3726168404Spjd 3727168404Spjd zpool_close(zhp); 3728168404Spjd 3729219089Spjd nvlist_free(policy); 3730219089Spjd 3731168404Spjd return (ret); 3732168404Spjd} 3733168404Spjd 3734228103Smm/* 3735228103Smm * zpool reguid <pool> 3736228103Smm */ 3737228103Smmint 3738228103Smmzpool_do_reguid(int argc, char **argv) 3739228103Smm{ 3740228103Smm int c; 3741228103Smm char *poolname; 3742228103Smm zpool_handle_t *zhp; 3743228103Smm int ret = 0; 3744228103Smm 3745228103Smm /* check options */ 3746228103Smm while ((c = getopt(argc, argv, "")) != -1) { 3747228103Smm switch (c) { 3748228103Smm case '?': 3749228103Smm (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3750228103Smm optopt); 3751228103Smm usage(B_FALSE); 3752228103Smm } 3753228103Smm } 3754228103Smm 3755228103Smm argc -= optind; 3756228103Smm argv += optind; 3757228103Smm 3758228103Smm /* get pool name and check number of arguments */ 3759228103Smm if (argc < 1) { 3760228103Smm (void) fprintf(stderr, gettext("missing pool name\n")); 3761228103Smm usage(B_FALSE); 3762228103Smm } 3763228103Smm 3764228103Smm if (argc > 1) { 3765228103Smm (void) fprintf(stderr, gettext("too many arguments\n")); 3766228103Smm usage(B_FALSE); 3767228103Smm } 3768228103Smm 3769228103Smm poolname = argv[0]; 3770228103Smm if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 3771228103Smm return (1); 3772228103Smm 3773228103Smm ret = zpool_reguid(zhp); 3774228103Smm 3775228103Smm zpool_close(zhp); 3776228103Smm return (ret); 3777228103Smm} 3778228103Smm 3779228103Smm 3780236155Smm/* 3781236155Smm * zpool reopen <pool> 3782236155Smm * 3783236155Smm * Reopen the pool so that the kernel can update the sizes of all vdevs. 3784236155Smm */ 3785236155Smmint 3786236155Smmzpool_do_reopen(int argc, char **argv) 3787236155Smm{ 3788260138Sdelphij int c; 3789236155Smm int ret = 0; 3790236155Smm zpool_handle_t *zhp; 3791236155Smm char *pool; 3792236155Smm 3793260138Sdelphij /* check options */ 3794260138Sdelphij while ((c = getopt(argc, argv, "")) != -1) { 3795260138Sdelphij switch (c) { 3796260138Sdelphij case '?': 3797260138Sdelphij (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3798260138Sdelphij optopt); 3799260138Sdelphij usage(B_FALSE); 3800260138Sdelphij } 3801260138Sdelphij } 3802260138Sdelphij 3803236155Smm argc--; 3804236155Smm argv++; 3805236155Smm 3806260138Sdelphij if (argc < 1) { 3807260138Sdelphij (void) fprintf(stderr, gettext("missing pool name\n")); 3808260138Sdelphij usage(B_FALSE); 3809260138Sdelphij } 3810236155Smm 3811260138Sdelphij if (argc > 1) { 3812260138Sdelphij (void) fprintf(stderr, gettext("too many arguments\n")); 3813260138Sdelphij usage(B_FALSE); 3814260138Sdelphij } 3815260138Sdelphij 3816236155Smm pool = argv[0]; 3817236155Smm if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) 3818236155Smm return (1); 3819236155Smm 3820236155Smm ret = zpool_reopen(zhp); 3821236155Smm zpool_close(zhp); 3822236155Smm return (ret); 3823236155Smm} 3824236155Smm 3825168404Spjdtypedef struct scrub_cbdata { 3826168404Spjd int cb_type; 3827168404Spjd int cb_argc; 3828168404Spjd char **cb_argv; 3829324010Savg pool_scrub_cmd_t cb_scrub_cmd; 3830168404Spjd} scrub_cbdata_t; 3831168404Spjd 3832168404Spjdint 3833168404Spjdscrub_callback(zpool_handle_t *zhp, void *data) 3834168404Spjd{ 3835168404Spjd scrub_cbdata_t *cb = data; 3836168404Spjd int err; 3837168404Spjd 3838168404Spjd /* 3839168404Spjd * Ignore faulted pools. 3840168404Spjd */ 3841168404Spjd if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) { 3842168404Spjd (void) fprintf(stderr, gettext("cannot scrub '%s': pool is " 3843168404Spjd "currently unavailable\n"), zpool_get_name(zhp)); 3844168404Spjd return (1); 3845168404Spjd } 3846168404Spjd 3847324010Savg err = zpool_scan(zhp, cb->cb_type, cb->cb_scrub_cmd); 3848168404Spjd 3849168404Spjd return (err != 0); 3850168404Spjd} 3851168404Spjd 3852168404Spjd/* 3853324010Savg * zpool scrub [-s | -p] <pool> ... 3854168404Spjd * 3855168404Spjd * -s Stop. Stops any in-progress scrub. 3856324010Savg * -p Pause. Pause in-progress scrub. 3857168404Spjd */ 3858168404Spjdint 3859168404Spjdzpool_do_scrub(int argc, char **argv) 3860168404Spjd{ 3861168404Spjd int c; 3862168404Spjd scrub_cbdata_t cb; 3863168404Spjd 3864219089Spjd cb.cb_type = POOL_SCAN_SCRUB; 3865324010Savg cb.cb_scrub_cmd = POOL_SCRUB_NORMAL; 3866168404Spjd 3867168404Spjd /* check options */ 3868324010Savg while ((c = getopt(argc, argv, "sp")) != -1) { 3869168404Spjd switch (c) { 3870168404Spjd case 's': 3871219089Spjd cb.cb_type = POOL_SCAN_NONE; 3872168404Spjd break; 3873324010Savg case 'p': 3874324010Savg cb.cb_scrub_cmd = POOL_SCRUB_PAUSE; 3875324010Savg break; 3876168404Spjd case '?': 3877168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3878168404Spjd optopt); 3879168404Spjd usage(B_FALSE); 3880168404Spjd } 3881168404Spjd } 3882168404Spjd 3883324010Savg if (cb.cb_type == POOL_SCAN_NONE && 3884324010Savg cb.cb_scrub_cmd == POOL_SCRUB_PAUSE) { 3885324010Savg (void) fprintf(stderr, gettext("invalid option combination: " 3886324010Savg "-s and -p are mutually exclusive\n")); 3887324010Savg usage(B_FALSE); 3888324010Savg } 3889324010Savg 3890168404Spjd cb.cb_argc = argc; 3891168404Spjd cb.cb_argv = argv; 3892168404Spjd argc -= optind; 3893168404Spjd argv += optind; 3894168404Spjd 3895168404Spjd if (argc < 1) { 3896168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 3897168404Spjd usage(B_FALSE); 3898168404Spjd } 3899168404Spjd 3900168404Spjd return (for_each_pool(argc, argv, B_TRUE, NULL, scrub_callback, &cb)); 3901168404Spjd} 3902168404Spjd 3903168404Spjdtypedef struct status_cbdata { 3904168404Spjd int cb_count; 3905168404Spjd boolean_t cb_allpools; 3906168404Spjd boolean_t cb_verbose; 3907168404Spjd boolean_t cb_explain; 3908168404Spjd boolean_t cb_first; 3909219089Spjd boolean_t cb_dedup_stats; 3910168404Spjd} status_cbdata_t; 3911168404Spjd 3912168404Spjd/* 3913168404Spjd * Print out detailed scrub status. 3914168404Spjd */ 3915168404Spjdvoid 3916219089Spjdprint_scan_status(pool_scan_stat_t *ps) 3917168404Spjd{ 3918324010Savg time_t start, end, pause; 3919219089Spjd uint64_t elapsed, mins_left, hours_left; 3920219089Spjd uint64_t pass_exam, examined, total; 3921219089Spjd uint_t rate; 3922168404Spjd double fraction_done; 3923219089Spjd char processed_buf[7], examined_buf[7], total_buf[7], rate_buf[7]; 3924168404Spjd 3925226583Spjd (void) printf(gettext(" scan: ")); 3926168404Spjd 3927219089Spjd /* If there's never been a scan, there's not much to say. */ 3928219089Spjd if (ps == NULL || ps->pss_func == POOL_SCAN_NONE || 3929219089Spjd ps->pss_func >= POOL_SCAN_FUNCS) { 3930168404Spjd (void) printf(gettext("none requested\n")); 3931168404Spjd return; 3932168404Spjd } 3933168404Spjd 3934219089Spjd start = ps->pss_start_time; 3935219089Spjd end = ps->pss_end_time; 3936324010Savg pause = ps->pss_pass_scrub_pause; 3937219089Spjd zfs_nicenum(ps->pss_processed, processed_buf, sizeof (processed_buf)); 3938168404Spjd 3939219089Spjd assert(ps->pss_func == POOL_SCAN_SCRUB || 3940219089Spjd ps->pss_func == POOL_SCAN_RESILVER); 3941219089Spjd /* 3942219089Spjd * Scan is finished or canceled. 3943219089Spjd */ 3944219089Spjd if (ps->pss_state == DSS_FINISHED) { 3945219089Spjd uint64_t minutes_taken = (end - start) / 60; 3946296537Smav char *fmt = NULL; 3947168404Spjd 3948219089Spjd if (ps->pss_func == POOL_SCAN_SCRUB) { 3949219089Spjd fmt = gettext("scrub repaired %s in %lluh%um with " 3950219089Spjd "%llu errors on %s"); 3951219089Spjd } else if (ps->pss_func == POOL_SCAN_RESILVER) { 3952219089Spjd fmt = gettext("resilvered %s in %lluh%um with " 3953219089Spjd "%llu errors on %s"); 3954219089Spjd } 3955219089Spjd /* LINTED */ 3956219089Spjd (void) printf(fmt, processed_buf, 3957185029Spjd (u_longlong_t)(minutes_taken / 60), 3958185029Spjd (uint_t)(minutes_taken % 60), 3959219089Spjd (u_longlong_t)ps->pss_errors, 3960219089Spjd ctime((time_t *)&end)); 3961168404Spjd return; 3962219089Spjd } else if (ps->pss_state == DSS_CANCELED) { 3963219089Spjd if (ps->pss_func == POOL_SCAN_SCRUB) { 3964219089Spjd (void) printf(gettext("scrub canceled on %s"), 3965219089Spjd ctime(&end)); 3966219089Spjd } else if (ps->pss_func == POOL_SCAN_RESILVER) { 3967219089Spjd (void) printf(gettext("resilver canceled on %s"), 3968219089Spjd ctime(&end)); 3969219089Spjd } 3970219089Spjd return; 3971168404Spjd } 3972168404Spjd 3973219089Spjd assert(ps->pss_state == DSS_SCANNING); 3974168404Spjd 3975219089Spjd /* 3976219089Spjd * Scan is in progress. 3977219089Spjd */ 3978219089Spjd if (ps->pss_func == POOL_SCAN_SCRUB) { 3979324010Savg if (pause == 0) { 3980324010Savg (void) printf(gettext("scrub in progress since %s"), 3981324010Savg ctime(&start)); 3982324010Savg } else { 3983324010Savg char buf[32]; 3984324010Savg struct tm *p = localtime(&pause); 3985324010Savg (void) strftime(buf, sizeof (buf), "%a %b %e %T %Y", p); 3986324010Savg (void) printf(gettext("scrub paused since %s\n"), buf); 3987324010Savg (void) printf(gettext("\tscrub started on %s"), 3988324010Savg ctime(&start)); 3989324010Savg } 3990219089Spjd } else if (ps->pss_func == POOL_SCAN_RESILVER) { 3991219089Spjd (void) printf(gettext("resilver in progress since %s"), 3992219089Spjd ctime(&start)); 3993219089Spjd } 3994219089Spjd 3995219089Spjd examined = ps->pss_examined ? ps->pss_examined : 1; 3996219089Spjd total = ps->pss_to_examine; 3997168404Spjd fraction_done = (double)examined / total; 3998168404Spjd 3999219089Spjd /* elapsed time for this pass */ 4000219089Spjd elapsed = time(NULL) - ps->pss_pass_start; 4001324010Savg elapsed -= ps->pss_pass_scrub_spent_paused; 4002219089Spjd elapsed = elapsed ? elapsed : 1; 4003219089Spjd pass_exam = ps->pss_pass_exam ? ps->pss_pass_exam : 1; 4004219089Spjd rate = pass_exam / elapsed; 4005219089Spjd rate = rate ? rate : 1; 4006219089Spjd mins_left = ((total - examined) / rate) / 60; 4007219089Spjd hours_left = mins_left / 60; 4008219089Spjd 4009219089Spjd zfs_nicenum(examined, examined_buf, sizeof (examined_buf)); 4010219089Spjd zfs_nicenum(total, total_buf, sizeof (total_buf)); 4011219089Spjd 4012219089Spjd /* 4013219089Spjd * do not print estimated time if hours_left is more than 30 days 4014324010Savg * or we have a paused scrub 4015219089Spjd */ 4016324010Savg if (pause == 0) { 4017324010Savg zfs_nicenum(rate, rate_buf, sizeof (rate_buf)); 4018324010Savg (void) printf(gettext("\t%s scanned out of %s at %s/s"), 4019324010Savg examined_buf, total_buf, rate_buf); 4020324010Savg if (hours_left < (30 * 24)) { 4021324010Savg (void) printf(gettext(", %lluh%um to go\n"), 4022324010Savg (u_longlong_t)hours_left, (uint_t)(mins_left % 60)); 4023324010Savg } else { 4024324010Savg (void) printf(gettext( 4025324010Savg ", (scan is slow, no estimated time)\n")); 4026324010Savg } 4027219089Spjd } else { 4028324010Savg (void) printf(gettext("\t%s scanned out of %s\n"), 4029324010Savg examined_buf, total_buf); 4030219089Spjd } 4031219089Spjd 4032219089Spjd if (ps->pss_func == POOL_SCAN_RESILVER) { 4033226583Spjd (void) printf(gettext(" %s resilvered, %.2f%% done\n"), 4034219089Spjd processed_buf, 100 * fraction_done); 4035219089Spjd } else if (ps->pss_func == POOL_SCAN_SCRUB) { 4036226583Spjd (void) printf(gettext(" %s repaired, %.2f%% done\n"), 4037219089Spjd processed_buf, 100 * fraction_done); 4038219089Spjd } 4039168404Spjd} 4040168404Spjd 4041168404Spjdstatic void 4042168404Spjdprint_error_log(zpool_handle_t *zhp) 4043168404Spjd{ 4044185029Spjd nvlist_t *nverrlist = NULL; 4045168404Spjd nvpair_t *elem; 4046168404Spjd char *pathname; 4047168404Spjd size_t len = MAXPATHLEN * 2; 4048168404Spjd 4049168404Spjd if (zpool_get_errlog(zhp, &nverrlist) != 0) { 4050168404Spjd (void) printf("errors: List of errors unavailable " 4051168404Spjd "(insufficient privileges)\n"); 4052168404Spjd return; 4053168404Spjd } 4054168404Spjd 4055168404Spjd (void) printf("errors: Permanent errors have been " 4056168404Spjd "detected in the following files:\n\n"); 4057168404Spjd 4058168404Spjd pathname = safe_malloc(len); 4059168404Spjd elem = NULL; 4060168404Spjd while ((elem = nvlist_next_nvpair(nverrlist, elem)) != NULL) { 4061168404Spjd nvlist_t *nv; 4062168404Spjd uint64_t dsobj, obj; 4063168404Spjd 4064168404Spjd verify(nvpair_value_nvlist(elem, &nv) == 0); 4065168404Spjd verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_DATASET, 4066168404Spjd &dsobj) == 0); 4067168404Spjd verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_OBJECT, 4068168404Spjd &obj) == 0); 4069168404Spjd zpool_obj_to_path(zhp, dsobj, obj, pathname, len); 4070168404Spjd (void) printf("%7s %s\n", "", pathname); 4071168404Spjd } 4072168404Spjd free(pathname); 4073168404Spjd nvlist_free(nverrlist); 4074168404Spjd} 4075168404Spjd 4076168404Spjdstatic void 4077168404Spjdprint_spares(zpool_handle_t *zhp, nvlist_t **spares, uint_t nspares, 4078168404Spjd int namewidth) 4079168404Spjd{ 4080168404Spjd uint_t i; 4081168404Spjd char *name; 4082168404Spjd 4083168404Spjd if (nspares == 0) 4084168404Spjd return; 4085168404Spjd 4086168404Spjd (void) printf(gettext("\tspares\n")); 4087168404Spjd 4088168404Spjd for (i = 0; i < nspares; i++) { 4089219089Spjd name = zpool_vdev_name(g_zfs, zhp, spares[i], B_FALSE); 4090168404Spjd print_status_config(zhp, name, spares[i], 4091209962Smm namewidth, 2, B_TRUE); 4092168404Spjd free(name); 4093168404Spjd } 4094168404Spjd} 4095168404Spjd 4096185029Spjdstatic void 4097185029Spjdprint_l2cache(zpool_handle_t *zhp, nvlist_t **l2cache, uint_t nl2cache, 4098185029Spjd int namewidth) 4099185029Spjd{ 4100185029Spjd uint_t i; 4101185029Spjd char *name; 4102185029Spjd 4103185029Spjd if (nl2cache == 0) 4104185029Spjd return; 4105185029Spjd 4106185029Spjd (void) printf(gettext("\tcache\n")); 4107185029Spjd 4108185029Spjd for (i = 0; i < nl2cache; i++) { 4109219089Spjd name = zpool_vdev_name(g_zfs, zhp, l2cache[i], B_FALSE); 4110185029Spjd print_status_config(zhp, name, l2cache[i], 4111209962Smm namewidth, 2, B_FALSE); 4112185029Spjd free(name); 4113185029Spjd } 4114185029Spjd} 4115185029Spjd 4116219089Spjdstatic void 4117219089Spjdprint_dedup_stats(nvlist_t *config) 4118219089Spjd{ 4119219089Spjd ddt_histogram_t *ddh; 4120219089Spjd ddt_stat_t *dds; 4121219089Spjd ddt_object_t *ddo; 4122219089Spjd uint_t c; 4123219089Spjd 4124219089Spjd /* 4125219089Spjd * If the pool was faulted then we may not have been able to 4126253441Sdelphij * obtain the config. Otherwise, if we have anything in the dedup 4127219089Spjd * table continue processing the stats. 4128219089Spjd */ 4129219089Spjd if (nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_OBJ_STATS, 4130227497Smm (uint64_t **)&ddo, &c) != 0) 4131219089Spjd return; 4132219089Spjd 4133219089Spjd (void) printf("\n"); 4134227497Smm (void) printf(gettext(" dedup: ")); 4135227497Smm if (ddo->ddo_count == 0) { 4136227497Smm (void) printf(gettext("no DDT entries\n")); 4137227497Smm return; 4138227497Smm } 4139227497Smm 4140219089Spjd (void) printf("DDT entries %llu, size %llu on disk, %llu in core\n", 4141219089Spjd (u_longlong_t)ddo->ddo_count, 4142219089Spjd (u_longlong_t)ddo->ddo_dspace, 4143219089Spjd (u_longlong_t)ddo->ddo_mspace); 4144219089Spjd 4145219089Spjd verify(nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_STATS, 4146219089Spjd (uint64_t **)&dds, &c) == 0); 4147219089Spjd verify(nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_HISTOGRAM, 4148219089Spjd (uint64_t **)&ddh, &c) == 0); 4149219089Spjd zpool_dump_ddt(dds, ddh); 4150219089Spjd} 4151219089Spjd 4152168404Spjd/* 4153168404Spjd * Display a summary of pool status. Displays a summary such as: 4154168404Spjd * 4155168404Spjd * pool: tank 4156168404Spjd * status: DEGRADED 4157168404Spjd * reason: One or more devices ... 4158236146Smm * see: http://illumos.org/msg/ZFS-xxxx-01 4159168404Spjd * config: 4160168404Spjd * mirror DEGRADED 4161168404Spjd * c1t0d0 OK 4162168404Spjd * c2t0d0 UNAVAIL 4163168404Spjd * 4164168404Spjd * When given the '-v' option, we print out the complete config. If the '-e' 4165168404Spjd * option is specified, then we print out error rate information as well. 4166168404Spjd */ 4167168404Spjdint 4168168404Spjdstatus_callback(zpool_handle_t *zhp, void *data) 4169168404Spjd{ 4170168404Spjd status_cbdata_t *cbp = data; 4171168404Spjd nvlist_t *config, *nvroot; 4172168404Spjd char *msgid; 4173168404Spjd int reason; 4174168404Spjd const char *health; 4175168404Spjd uint_t c; 4176168404Spjd vdev_stat_t *vs; 4177168404Spjd 4178168404Spjd config = zpool_get_config(zhp, NULL); 4179168404Spjd reason = zpool_get_status(zhp, &msgid); 4180168404Spjd 4181168404Spjd cbp->cb_count++; 4182168404Spjd 4183168404Spjd /* 4184168404Spjd * If we were given 'zpool status -x', only report those pools with 4185168404Spjd * problems. 4186168404Spjd */ 4187248267Smm if (cbp->cb_explain && 4188248267Smm (reason == ZPOOL_STATUS_OK || 4189248267Smm reason == ZPOOL_STATUS_VERSION_OLDER || 4190268621Ssmh reason == ZPOOL_STATUS_NON_NATIVE_ASHIFT || 4191248267Smm reason == ZPOOL_STATUS_FEAT_DISABLED)) { 4192168404Spjd if (!cbp->cb_allpools) { 4193168404Spjd (void) printf(gettext("pool '%s' is healthy\n"), 4194168404Spjd zpool_get_name(zhp)); 4195168404Spjd if (cbp->cb_first) 4196168404Spjd cbp->cb_first = B_FALSE; 4197168404Spjd } 4198168404Spjd return (0); 4199168404Spjd } 4200168404Spjd 4201168404Spjd if (cbp->cb_first) 4202168404Spjd cbp->cb_first = B_FALSE; 4203168404Spjd else 4204168404Spjd (void) printf("\n"); 4205168404Spjd 4206168404Spjd verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 4207168404Spjd &nvroot) == 0); 4208219089Spjd verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS, 4209168404Spjd (uint64_t **)&vs, &c) == 0); 4210185029Spjd health = zpool_state_to_name(vs->vs_state, vs->vs_aux); 4211168404Spjd 4212168404Spjd (void) printf(gettext(" pool: %s\n"), zpool_get_name(zhp)); 4213168404Spjd (void) printf(gettext(" state: %s\n"), health); 4214168404Spjd 4215168404Spjd switch (reason) { 4216168404Spjd case ZPOOL_STATUS_MISSING_DEV_R: 4217168404Spjd (void) printf(gettext("status: One or more devices could not " 4218168404Spjd "be opened. Sufficient replicas exist for\n\tthe pool to " 4219168404Spjd "continue functioning in a degraded state.\n")); 4220168404Spjd (void) printf(gettext("action: Attach the missing device and " 4221168404Spjd "online it using 'zpool online'.\n")); 4222168404Spjd break; 4223168404Spjd 4224168404Spjd case ZPOOL_STATUS_MISSING_DEV_NR: 4225168404Spjd (void) printf(gettext("status: One or more devices could not " 4226168404Spjd "be opened. There are insufficient\n\treplicas for the " 4227168404Spjd "pool to continue functioning.\n")); 4228168404Spjd (void) printf(gettext("action: Attach the missing device and " 4229168404Spjd "online it using 'zpool online'.\n")); 4230168404Spjd break; 4231168404Spjd 4232168404Spjd case ZPOOL_STATUS_CORRUPT_LABEL_R: 4233168404Spjd (void) printf(gettext("status: One or more devices could not " 4234168404Spjd "be used because the label is missing or\n\tinvalid. " 4235168404Spjd "Sufficient replicas exist for the pool to continue\n\t" 4236168404Spjd "functioning in a degraded state.\n")); 4237168404Spjd (void) printf(gettext("action: Replace the device using " 4238168404Spjd "'zpool replace'.\n")); 4239168404Spjd break; 4240168404Spjd 4241168404Spjd case ZPOOL_STATUS_CORRUPT_LABEL_NR: 4242168404Spjd (void) printf(gettext("status: One or more devices could not " 4243168404Spjd "be used because the label is missing \n\tor invalid. " 4244168404Spjd "There are insufficient replicas for the pool to " 4245168404Spjd "continue\n\tfunctioning.\n")); 4246219089Spjd zpool_explain_recover(zpool_get_handle(zhp), 4247219089Spjd zpool_get_name(zhp), reason, config); 4248168404Spjd break; 4249168404Spjd 4250168404Spjd case ZPOOL_STATUS_FAILING_DEV: 4251168404Spjd (void) printf(gettext("status: One or more devices has " 4252168404Spjd "experienced an unrecoverable error. An\n\tattempt was " 4253168404Spjd "made to correct the error. Applications are " 4254168404Spjd "unaffected.\n")); 4255168404Spjd (void) printf(gettext("action: Determine if the device needs " 4256168404Spjd "to be replaced, and clear the errors\n\tusing " 4257168404Spjd "'zpool clear' or replace the device with 'zpool " 4258168404Spjd "replace'.\n")); 4259168404Spjd break; 4260168404Spjd 4261168404Spjd case ZPOOL_STATUS_OFFLINE_DEV: 4262168404Spjd (void) printf(gettext("status: One or more devices has " 4263168404Spjd "been taken offline by the administrator.\n\tSufficient " 4264168404Spjd "replicas exist for the pool to continue functioning in " 4265168404Spjd "a\n\tdegraded state.\n")); 4266168404Spjd (void) printf(gettext("action: Online the device using " 4267168404Spjd "'zpool online' or replace the device with\n\t'zpool " 4268168404Spjd "replace'.\n")); 4269168404Spjd break; 4270168404Spjd 4271219089Spjd case ZPOOL_STATUS_REMOVED_DEV: 4272219089Spjd (void) printf(gettext("status: One or more devices has " 4273219089Spjd "been removed by the administrator.\n\tSufficient " 4274219089Spjd "replicas exist for the pool to continue functioning in " 4275219089Spjd "a\n\tdegraded state.\n")); 4276219089Spjd (void) printf(gettext("action: Online the device using " 4277219089Spjd "'zpool online' or replace the device with\n\t'zpool " 4278219089Spjd "replace'.\n")); 4279219089Spjd break; 4280219089Spjd 4281168404Spjd case ZPOOL_STATUS_RESILVERING: 4282168404Spjd (void) printf(gettext("status: One or more devices is " 4283168404Spjd "currently being resilvered. The pool will\n\tcontinue " 4284168404Spjd "to function, possibly in a degraded state.\n")); 4285168404Spjd (void) printf(gettext("action: Wait for the resilver to " 4286168404Spjd "complete.\n")); 4287168404Spjd break; 4288168404Spjd 4289168404Spjd case ZPOOL_STATUS_CORRUPT_DATA: 4290168404Spjd (void) printf(gettext("status: One or more devices has " 4291168404Spjd "experienced an error resulting in data\n\tcorruption. " 4292168404Spjd "Applications may be affected.\n")); 4293168404Spjd (void) printf(gettext("action: Restore the file in question " 4294168404Spjd "if possible. Otherwise restore the\n\tentire pool from " 4295168404Spjd "backup.\n")); 4296168404Spjd break; 4297168404Spjd 4298168404Spjd case ZPOOL_STATUS_CORRUPT_POOL: 4299168404Spjd (void) printf(gettext("status: The pool metadata is corrupted " 4300168404Spjd "and the pool cannot be opened.\n")); 4301219089Spjd zpool_explain_recover(zpool_get_handle(zhp), 4302219089Spjd zpool_get_name(zhp), reason, config); 4303168404Spjd break; 4304168404Spjd 4305168404Spjd case ZPOOL_STATUS_VERSION_OLDER: 4306238926Smm (void) printf(gettext("status: The pool is formatted using a " 4307238926Smm "legacy on-disk format. The pool can\n\tstill be used, " 4308238926Smm "but some features are unavailable.\n")); 4309168404Spjd (void) printf(gettext("action: Upgrade the pool using 'zpool " 4310168404Spjd "upgrade'. Once this is done, the\n\tpool will no longer " 4311238926Smm "be accessible on software that does not support feature\n" 4312238926Smm "\tflags.\n")); 4313168404Spjd break; 4314168404Spjd 4315168404Spjd case ZPOOL_STATUS_VERSION_NEWER: 4316168404Spjd (void) printf(gettext("status: The pool has been upgraded to a " 4317168404Spjd "newer, incompatible on-disk version.\n\tThe pool cannot " 4318168404Spjd "be accessed on this system.\n")); 4319168404Spjd (void) printf(gettext("action: Access the pool from a system " 4320168404Spjd "running more recent software, or\n\trestore the pool from " 4321168404Spjd "backup.\n")); 4322168404Spjd break; 4323168404Spjd 4324238926Smm case ZPOOL_STATUS_FEAT_DISABLED: 4325238926Smm (void) printf(gettext("status: Some supported features are not " 4326238926Smm "enabled on the pool. The pool can\n\tstill be used, but " 4327238926Smm "some features are unavailable.\n")); 4328238926Smm (void) printf(gettext("action: Enable all features using " 4329238926Smm "'zpool upgrade'. Once this is done,\n\tthe pool may no " 4330238926Smm "longer be accessible by software that does not support\n\t" 4331243014Smm "the features. See zpool-features(7) for details.\n")); 4332238926Smm break; 4333238926Smm 4334236884Smm case ZPOOL_STATUS_UNSUP_FEAT_READ: 4335236884Smm (void) printf(gettext("status: The pool cannot be accessed on " 4336236884Smm "this system because it uses the\n\tfollowing feature(s) " 4337236884Smm "not supported on this system:\n")); 4338236884Smm zpool_print_unsup_feat(config); 4339236884Smm (void) printf("\n"); 4340236884Smm (void) printf(gettext("action: Access the pool from a system " 4341236884Smm "that supports the required feature(s),\n\tor restore the " 4342236884Smm "pool from backup.\n")); 4343236884Smm break; 4344236884Smm 4345236884Smm case ZPOOL_STATUS_UNSUP_FEAT_WRITE: 4346236884Smm (void) printf(gettext("status: The pool can only be accessed " 4347236884Smm "in read-only mode on this system. It\n\tcannot be " 4348236884Smm "accessed in read-write mode because it uses the " 4349236884Smm "following\n\tfeature(s) not supported on this system:\n")); 4350236884Smm zpool_print_unsup_feat(config); 4351236884Smm (void) printf("\n"); 4352236884Smm (void) printf(gettext("action: The pool cannot be accessed in " 4353236884Smm "read-write mode. Import the pool with\n" 4354236884Smm "\t\"-o readonly=on\", access the pool from a system that " 4355236884Smm "supports the\n\trequired feature(s), or restore the " 4356236884Smm "pool from backup.\n")); 4357236884Smm break; 4358236884Smm 4359185029Spjd case ZPOOL_STATUS_FAULTED_DEV_R: 4360185029Spjd (void) printf(gettext("status: One or more devices are " 4361185029Spjd "faulted in response to persistent errors.\n\tSufficient " 4362185029Spjd "replicas exist for the pool to continue functioning " 4363185029Spjd "in a\n\tdegraded state.\n")); 4364185029Spjd (void) printf(gettext("action: Replace the faulted device, " 4365185029Spjd "or use 'zpool clear' to mark the device\n\trepaired.\n")); 4366185029Spjd break; 4367185029Spjd 4368185029Spjd case ZPOOL_STATUS_FAULTED_DEV_NR: 4369185029Spjd (void) printf(gettext("status: One or more devices are " 4370185029Spjd "faulted in response to persistent errors. There are " 4371185029Spjd "insufficient replicas for the pool to\n\tcontinue " 4372185029Spjd "functioning.\n")); 4373185029Spjd (void) printf(gettext("action: Destroy and re-create the pool " 4374185029Spjd "from a backup source. Manually marking the device\n" 4375185029Spjd "\trepaired using 'zpool clear' may allow some data " 4376185029Spjd "to be recovered.\n")); 4377185029Spjd break; 4378185029Spjd 4379185029Spjd case ZPOOL_STATUS_IO_FAILURE_WAIT: 4380185029Spjd case ZPOOL_STATUS_IO_FAILURE_CONTINUE: 4381185029Spjd (void) printf(gettext("status: One or more devices are " 4382185029Spjd "faulted in response to IO failures.\n")); 4383185029Spjd (void) printf(gettext("action: Make sure the affected devices " 4384185029Spjd "are connected, then run 'zpool clear'.\n")); 4385185029Spjd break; 4386185029Spjd 4387185029Spjd case ZPOOL_STATUS_BAD_LOG: 4388185029Spjd (void) printf(gettext("status: An intent log record " 4389185029Spjd "could not be read.\n" 4390185029Spjd "\tWaiting for adminstrator intervention to fix the " 4391185029Spjd "faulted pool.\n")); 4392185029Spjd (void) printf(gettext("action: Either restore the affected " 4393185029Spjd "device(s) and run 'zpool online',\n" 4394185029Spjd "\tor ignore the intent log records by running " 4395185029Spjd "'zpool clear'.\n")); 4396185029Spjd break; 4397185029Spjd 4398254591Sgibbs case ZPOOL_STATUS_NON_NATIVE_ASHIFT: 4399254591Sgibbs (void) printf(gettext("status: One or more devices are " 4400254591Sgibbs "configured to use a non-native block size.\n" 4401254591Sgibbs "\tExpect reduced performance.\n")); 4402254591Sgibbs (void) printf(gettext("action: Replace affected devices with " 4403254591Sgibbs "devices that support the\n\tconfigured block size, or " 4404254591Sgibbs "migrate data to a properly configured\n\tpool.\n")); 4405254591Sgibbs break; 4406254591Sgibbs 4407168404Spjd default: 4408168404Spjd /* 4409168404Spjd * The remaining errors can't actually be generated, yet. 4410168404Spjd */ 4411168404Spjd assert(reason == ZPOOL_STATUS_OK); 4412168404Spjd } 4413168404Spjd 4414168404Spjd if (msgid != NULL) 4415236146Smm (void) printf(gettext(" see: http://illumos.org/msg/%s\n"), 4416168404Spjd msgid); 4417168404Spjd 4418168404Spjd if (config != NULL) { 4419168404Spjd int namewidth; 4420168404Spjd uint64_t nerr; 4421185029Spjd nvlist_t **spares, **l2cache; 4422185029Spjd uint_t nspares, nl2cache; 4423219089Spjd pool_scan_stat_t *ps = NULL; 4424168404Spjd 4425219089Spjd (void) nvlist_lookup_uint64_array(nvroot, 4426219089Spjd ZPOOL_CONFIG_SCAN_STATS, (uint64_t **)&ps, &c); 4427219089Spjd print_scan_status(ps); 4428168404Spjd 4429168404Spjd namewidth = max_width(zhp, nvroot, 0, 0); 4430168404Spjd if (namewidth < 10) 4431168404Spjd namewidth = 10; 4432168404Spjd 4433168404Spjd (void) printf(gettext("config:\n\n")); 4434168404Spjd (void) printf(gettext("\t%-*s %-8s %5s %5s %5s\n"), namewidth, 4435168404Spjd "NAME", "STATE", "READ", "WRITE", "CKSUM"); 4436168404Spjd print_status_config(zhp, zpool_get_name(zhp), nvroot, 4437209962Smm namewidth, 0, B_FALSE); 4438209962Smm 4439185029Spjd if (num_logs(nvroot) > 0) 4440213197Smm print_logs(zhp, nvroot, namewidth, B_TRUE); 4441185029Spjd if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE, 4442185029Spjd &l2cache, &nl2cache) == 0) 4443185029Spjd print_l2cache(zhp, l2cache, nl2cache, namewidth); 4444185029Spjd 4445168404Spjd if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES, 4446168404Spjd &spares, &nspares) == 0) 4447168404Spjd print_spares(zhp, spares, nspares, namewidth); 4448168404Spjd 4449168404Spjd if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRCOUNT, 4450168404Spjd &nerr) == 0) { 4451168404Spjd nvlist_t *nverrlist = NULL; 4452168404Spjd 4453168404Spjd /* 4454168404Spjd * If the approximate error count is small, get a 4455168404Spjd * precise count by fetching the entire log and 4456168404Spjd * uniquifying the results. 4457168404Spjd */ 4458185029Spjd if (nerr > 0 && nerr < 100 && !cbp->cb_verbose && 4459168404Spjd zpool_get_errlog(zhp, &nverrlist) == 0) { 4460168404Spjd nvpair_t *elem; 4461168404Spjd 4462168404Spjd elem = NULL; 4463168404Spjd nerr = 0; 4464168404Spjd while ((elem = nvlist_next_nvpair(nverrlist, 4465168404Spjd elem)) != NULL) { 4466168404Spjd nerr++; 4467168404Spjd } 4468168404Spjd } 4469168404Spjd nvlist_free(nverrlist); 4470168404Spjd 4471168404Spjd (void) printf("\n"); 4472168404Spjd 4473168404Spjd if (nerr == 0) 4474168404Spjd (void) printf(gettext("errors: No known data " 4475168404Spjd "errors\n")); 4476168404Spjd else if (!cbp->cb_verbose) 4477168404Spjd (void) printf(gettext("errors: %llu data " 4478168404Spjd "errors, use '-v' for a list\n"), 4479168404Spjd (u_longlong_t)nerr); 4480168404Spjd else 4481168404Spjd print_error_log(zhp); 4482168404Spjd } 4483219089Spjd 4484219089Spjd if (cbp->cb_dedup_stats) 4485219089Spjd print_dedup_stats(config); 4486168404Spjd } else { 4487168404Spjd (void) printf(gettext("config: The configuration cannot be " 4488168404Spjd "determined.\n")); 4489168404Spjd } 4490168404Spjd 4491168404Spjd return (0); 4492168404Spjd} 4493168404Spjd 4494168404Spjd/* 4495219089Spjd * zpool status [-vx] [-T d|u] [pool] ... [interval [count]] 4496168404Spjd * 4497168404Spjd * -v Display complete error logs 4498168404Spjd * -x Display only pools with potential problems 4499219089Spjd * -D Display dedup status (undocumented) 4500219089Spjd * -T Display a timestamp in date(1) or Unix format 4501168404Spjd * 4502168404Spjd * Describes the health status of all pools or some subset. 4503168404Spjd */ 4504168404Spjdint 4505168404Spjdzpool_do_status(int argc, char **argv) 4506168404Spjd{ 4507168404Spjd int c; 4508168404Spjd int ret; 4509219089Spjd unsigned long interval = 0, count = 0; 4510168404Spjd status_cbdata_t cb = { 0 }; 4511168404Spjd 4512168404Spjd /* check options */ 4513219089Spjd while ((c = getopt(argc, argv, "vxDT:")) != -1) { 4514168404Spjd switch (c) { 4515168404Spjd case 'v': 4516168404Spjd cb.cb_verbose = B_TRUE; 4517168404Spjd break; 4518168404Spjd case 'x': 4519168404Spjd cb.cb_explain = B_TRUE; 4520168404Spjd break; 4521219089Spjd case 'D': 4522219089Spjd cb.cb_dedup_stats = B_TRUE; 4523219089Spjd break; 4524219089Spjd case 'T': 4525219089Spjd get_timestamp_arg(*optarg); 4526219089Spjd break; 4527168404Spjd case '?': 4528168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 4529168404Spjd optopt); 4530168404Spjd usage(B_FALSE); 4531168404Spjd } 4532168404Spjd } 4533168404Spjd 4534168404Spjd argc -= optind; 4535168404Spjd argv += optind; 4536168404Spjd 4537219089Spjd get_interval_count(&argc, argv, &interval, &count); 4538168404Spjd 4539168404Spjd if (argc == 0) 4540168404Spjd cb.cb_allpools = B_TRUE; 4541168404Spjd 4542219089Spjd cb.cb_first = B_TRUE; 4543168404Spjd 4544219089Spjd for (;;) { 4545219089Spjd if (timestamp_fmt != NODATE) 4546219089Spjd print_timestamp(timestamp_fmt); 4547168404Spjd 4548219089Spjd ret = for_each_pool(argc, argv, B_TRUE, NULL, 4549219089Spjd status_callback, &cb); 4550219089Spjd 4551219089Spjd if (argc == 0 && cb.cb_count == 0) 4552219089Spjd (void) printf(gettext("no pools available\n")); 4553219089Spjd else if (cb.cb_explain && cb.cb_first && cb.cb_allpools) 4554219089Spjd (void) printf(gettext("all pools are healthy\n")); 4555219089Spjd 4556219089Spjd if (ret != 0) 4557219089Spjd return (ret); 4558219089Spjd 4559219089Spjd if (interval == 0) 4560219089Spjd break; 4561219089Spjd 4562219089Spjd if (count != 0 && --count == 0) 4563219089Spjd break; 4564219089Spjd 4565219089Spjd (void) sleep(interval); 4566219089Spjd } 4567219089Spjd 4568219089Spjd return (0); 4569168404Spjd} 4570168404Spjd 4571168404Spjdtypedef struct upgrade_cbdata { 4572276226Ssmh boolean_t cb_first; 4573276226Ssmh boolean_t cb_unavail; 4574307108Smav char cb_poolname[ZFS_MAX_DATASET_NAME_LEN]; 4575276226Ssmh int cb_argc; 4576276226Ssmh uint64_t cb_version; 4577276226Ssmh char **cb_argv; 4578168404Spjd} upgrade_cbdata_t; 4579168404Spjd 4580238950Smm#ifdef __FreeBSD__ 4581168404Spjdstatic int 4582212050Spjdis_root_pool(zpool_handle_t *zhp) 4583212050Spjd{ 4584212050Spjd static struct statfs sfs; 4585212050Spjd static char *poolname = NULL; 4586212050Spjd static boolean_t stated = B_FALSE; 4587212050Spjd char *slash; 4588212050Spjd 4589212067Spjd if (!stated) { 4590212050Spjd stated = B_TRUE; 4591212050Spjd if (statfs("/", &sfs) == -1) { 4592212050Spjd (void) fprintf(stderr, 4593212050Spjd "Unable to stat root file system: %s.\n", 4594212050Spjd strerror(errno)); 4595212067Spjd return (0); 4596212050Spjd } 4597212050Spjd if (strcmp(sfs.f_fstypename, "zfs") != 0) 4598212067Spjd return (0); 4599212050Spjd poolname = sfs.f_mntfromname; 4600212050Spjd if ((slash = strchr(poolname, '/')) != NULL) 4601212050Spjd *slash = '\0'; 4602212050Spjd } 4603212050Spjd return (poolname != NULL && strcmp(poolname, zpool_get_name(zhp)) == 0); 4604212050Spjd} 4605212050Spjd 4606238950Smmstatic void 4607271934Ssmhroot_pool_upgrade_check(zpool_handle_t *zhp, char *poolname, int size) 4608271934Ssmh{ 4609238950Smm 4610238950Smm if (poolname[0] == '\0' && is_root_pool(zhp)) 4611238950Smm (void) strlcpy(poolname, zpool_get_name(zhp), size); 4612238950Smm} 4613238950Smm#endif /* FreeBSD */ 4614238950Smm 4615212050Spjdstatic int 4616238926Smmupgrade_version(zpool_handle_t *zhp, uint64_t version) 4617238926Smm{ 4618238926Smm int ret; 4619238926Smm nvlist_t *config; 4620238926Smm uint64_t oldversion; 4621238926Smm 4622238926Smm config = zpool_get_config(zhp, NULL); 4623238926Smm verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, 4624238926Smm &oldversion) == 0); 4625238926Smm 4626238926Smm assert(SPA_VERSION_IS_SUPPORTED(oldversion)); 4627238926Smm assert(oldversion < version); 4628238926Smm 4629238926Smm ret = zpool_upgrade(zhp, version); 4630238926Smm if (ret != 0) 4631238926Smm return (ret); 4632238926Smm 4633238926Smm if (version >= SPA_VERSION_FEATURES) { 4634238926Smm (void) printf(gettext("Successfully upgraded " 4635238926Smm "'%s' from version %llu to feature flags.\n"), 4636238926Smm zpool_get_name(zhp), oldversion); 4637238926Smm } else { 4638238926Smm (void) printf(gettext("Successfully upgraded " 4639238926Smm "'%s' from version %llu to version %llu.\n"), 4640238926Smm zpool_get_name(zhp), oldversion, version); 4641238926Smm } 4642238926Smm 4643238926Smm return (0); 4644238926Smm} 4645238926Smm 4646238926Smmstatic int 4647238926Smmupgrade_enable_all(zpool_handle_t *zhp, int *countp) 4648238926Smm{ 4649238926Smm int i, ret, count; 4650238926Smm boolean_t firstff = B_TRUE; 4651238926Smm nvlist_t *enabled = zpool_get_features(zhp); 4652238926Smm 4653238926Smm count = 0; 4654238926Smm for (i = 0; i < SPA_FEATURES; i++) { 4655238926Smm const char *fname = spa_feature_table[i].fi_uname; 4656238926Smm const char *fguid = spa_feature_table[i].fi_guid; 4657238926Smm if (!nvlist_exists(enabled, fguid)) { 4658238926Smm char *propname; 4659238926Smm verify(-1 != asprintf(&propname, "feature@%s", fname)); 4660238926Smm ret = zpool_set_prop(zhp, propname, 4661238926Smm ZFS_FEATURE_ENABLED); 4662238926Smm if (ret != 0) { 4663238926Smm free(propname); 4664238926Smm return (ret); 4665238926Smm } 4666238926Smm count++; 4667238926Smm 4668238926Smm if (firstff) { 4669238926Smm (void) printf(gettext("Enabled the " 4670238926Smm "following features on '%s':\n"), 4671238926Smm zpool_get_name(zhp)); 4672238926Smm firstff = B_FALSE; 4673238926Smm } 4674238926Smm (void) printf(gettext(" %s\n"), fname); 4675238926Smm free(propname); 4676238926Smm } 4677238926Smm } 4678238926Smm 4679238926Smm if (countp != NULL) 4680238926Smm *countp = count; 4681238926Smm return (0); 4682238926Smm} 4683238926Smm 4684238926Smmstatic int 4685168404Spjdupgrade_cb(zpool_handle_t *zhp, void *arg) 4686168404Spjd{ 4687168404Spjd upgrade_cbdata_t *cbp = arg; 4688168404Spjd nvlist_t *config; 4689168404Spjd uint64_t version; 4690238926Smm boolean_t printnl = B_FALSE; 4691238926Smm int ret; 4692168404Spjd 4693276194Ssmh if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) { 4694276194Ssmh (void) fprintf(stderr, gettext("cannot upgrade '%s': pool is " 4695276226Ssmh "currently unavailable.\n\n"), zpool_get_name(zhp)); 4696276226Ssmh cbp->cb_unavail = B_TRUE; 4697276194Ssmh /* Allow iteration to continue. */ 4698276194Ssmh return (0); 4699276194Ssmh } 4700276194Ssmh 4701168404Spjd config = zpool_get_config(zhp, NULL); 4702168404Spjd verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, 4703168404Spjd &version) == 0); 4704168404Spjd 4705238926Smm assert(SPA_VERSION_IS_SUPPORTED(version)); 4706168404Spjd 4707238926Smm if (version < cbp->cb_version) { 4708238926Smm cbp->cb_first = B_FALSE; 4709238926Smm ret = upgrade_version(zhp, cbp->cb_version); 4710238926Smm if (ret != 0) 4711238926Smm return (ret); 4712238926Smm#ifdef __FreeBSD__ 4713238950Smm root_pool_upgrade_check(zhp, cbp->cb_poolname, 4714238950Smm sizeof(cbp->cb_poolname)); 4715271934Ssmh#endif /* __FreeBSD__ */ 4716238926Smm printnl = B_TRUE; 4717238926Smm 4718238926Smm#ifdef illumos 4719238926Smm /* 4720238926Smm * If they did "zpool upgrade -a", then we could 4721238926Smm * be doing ioctls to different pools. We need 4722238926Smm * to log this history once to each pool, and bypass 4723238926Smm * the normal history logging that happens in main(). 4724238926Smm */ 4725238926Smm (void) zpool_log_history(g_zfs, history_str); 4726238926Smm log_history = B_FALSE; 4727238926Smm#endif 4728238926Smm } 4729238926Smm 4730238926Smm if (cbp->cb_version >= SPA_VERSION_FEATURES) { 4731238926Smm int count; 4732238926Smm ret = upgrade_enable_all(zhp, &count); 4733238926Smm if (ret != 0) 4734238926Smm return (ret); 4735238926Smm 4736238926Smm if (count > 0) { 4737168404Spjd cbp->cb_first = B_FALSE; 4738238926Smm printnl = B_TRUE; 4739271934Ssmh#ifdef __FreeBSD__ 4740271934Ssmh root_pool_upgrade_check(zhp, cbp->cb_poolname, 4741271934Ssmh sizeof(cbp->cb_poolname)); 4742271934Ssmh#endif /* __FreeBSD__ */ 4743248571Smm /* 4744248571Smm * If they did "zpool upgrade -a", then we could 4745248571Smm * be doing ioctls to different pools. We need 4746248571Smm * to log this history once to each pool, and bypass 4747248571Smm * the normal history logging that happens in main(). 4748248571Smm */ 4749248571Smm (void) zpool_log_history(g_zfs, history_str); 4750248571Smm log_history = B_FALSE; 4751168404Spjd } 4752238926Smm } 4753168404Spjd 4754238926Smm if (printnl) { 4755238926Smm (void) printf(gettext("\n")); 4756238926Smm } 4757238926Smm 4758238926Smm return (0); 4759238926Smm} 4760238926Smm 4761238926Smmstatic int 4762276226Ssmhupgrade_list_unavail(zpool_handle_t *zhp, void *arg) 4763276226Ssmh{ 4764276226Ssmh upgrade_cbdata_t *cbp = arg; 4765276226Ssmh 4766276226Ssmh if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) { 4767276226Ssmh if (cbp->cb_first) { 4768276226Ssmh (void) fprintf(stderr, gettext("The following pools " 4769276226Ssmh "are unavailable and cannot be upgraded as this " 4770276226Ssmh "time.\n\n")); 4771276226Ssmh (void) fprintf(stderr, gettext("POOL\n")); 4772276226Ssmh (void) fprintf(stderr, gettext("------------\n")); 4773276226Ssmh cbp->cb_first = B_FALSE; 4774276226Ssmh } 4775276226Ssmh (void) printf(gettext("%s\n"), zpool_get_name(zhp)); 4776276226Ssmh cbp->cb_unavail = B_TRUE; 4777276226Ssmh } 4778276226Ssmh return (0); 4779276226Ssmh} 4780276226Ssmh 4781276226Ssmhstatic int 4782238926Smmupgrade_list_older_cb(zpool_handle_t *zhp, void *arg) 4783238926Smm{ 4784238926Smm upgrade_cbdata_t *cbp = arg; 4785238926Smm nvlist_t *config; 4786238926Smm uint64_t version; 4787238926Smm 4788276226Ssmh if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) { 4789276226Ssmh /* 4790276226Ssmh * This will have been reported by upgrade_list_unavail so 4791276226Ssmh * just allow iteration to continue. 4792276226Ssmh */ 4793276226Ssmh cbp->cb_unavail = B_TRUE; 4794276226Ssmh return (0); 4795276226Ssmh } 4796276226Ssmh 4797238926Smm config = zpool_get_config(zhp, NULL); 4798238926Smm verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, 4799238926Smm &version) == 0); 4800238926Smm 4801238926Smm assert(SPA_VERSION_IS_SUPPORTED(version)); 4802238926Smm 4803238926Smm if (version < SPA_VERSION_FEATURES) { 4804168404Spjd if (cbp->cb_first) { 4805168404Spjd (void) printf(gettext("The following pools are " 4806238926Smm "formatted with legacy version numbers and can\n" 4807238926Smm "be upgraded to use feature flags. After " 4808238926Smm "being upgraded, these pools\nwill no " 4809238926Smm "longer be accessible by software that does not " 4810238926Smm "support feature\nflags.\n\n")); 4811168404Spjd (void) printf(gettext("VER POOL\n")); 4812168404Spjd (void) printf(gettext("--- ------------\n")); 4813168404Spjd cbp->cb_first = B_FALSE; 4814168404Spjd } 4815168404Spjd 4816168404Spjd (void) printf("%2llu %s\n", (u_longlong_t)version, 4817168404Spjd zpool_get_name(zhp)); 4818168404Spjd } 4819168404Spjd 4820238926Smm return (0); 4821168404Spjd} 4822168404Spjd 4823238926Smmstatic int 4824238926Smmupgrade_list_disabled_cb(zpool_handle_t *zhp, void *arg) 4825238926Smm{ 4826238926Smm upgrade_cbdata_t *cbp = arg; 4827238926Smm nvlist_t *config; 4828238926Smm uint64_t version; 4829238926Smm 4830276194Ssmh if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) { 4831276226Ssmh /* 4832276226Ssmh * This will have been reported by upgrade_list_unavail so 4833276226Ssmh * just allow iteration to continue. 4834276226Ssmh */ 4835276226Ssmh cbp->cb_unavail = B_TRUE; 4836276194Ssmh return (0); 4837276194Ssmh } 4838276194Ssmh 4839238926Smm config = zpool_get_config(zhp, NULL); 4840238926Smm verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, 4841238926Smm &version) == 0); 4842238926Smm 4843238926Smm if (version >= SPA_VERSION_FEATURES) { 4844238926Smm int i; 4845238926Smm boolean_t poolfirst = B_TRUE; 4846238926Smm nvlist_t *enabled = zpool_get_features(zhp); 4847238926Smm 4848238926Smm for (i = 0; i < SPA_FEATURES; i++) { 4849238926Smm const char *fguid = spa_feature_table[i].fi_guid; 4850238926Smm const char *fname = spa_feature_table[i].fi_uname; 4851238926Smm if (!nvlist_exists(enabled, fguid)) { 4852238926Smm if (cbp->cb_first) { 4853238926Smm (void) printf(gettext("\nSome " 4854238926Smm "supported features are not " 4855238926Smm "enabled on the following pools. " 4856238926Smm "Once a\nfeature is enabled the " 4857238926Smm "pool may become incompatible with " 4858238926Smm "software\nthat does not support " 4859238926Smm "the feature. See " 4860243014Smm "zpool-features(7) for " 4861238926Smm "details.\n\n")); 4862238926Smm (void) printf(gettext("POOL " 4863238926Smm "FEATURE\n")); 4864238926Smm (void) printf(gettext("------" 4865238926Smm "---------\n")); 4866238926Smm cbp->cb_first = B_FALSE; 4867238926Smm } 4868238926Smm 4869238926Smm if (poolfirst) { 4870238926Smm (void) printf(gettext("%s\n"), 4871238926Smm zpool_get_name(zhp)); 4872238926Smm poolfirst = B_FALSE; 4873238926Smm } 4874238926Smm 4875238926Smm (void) printf(gettext(" %s\n"), fname); 4876238926Smm } 4877238926Smm } 4878238926Smm } 4879238926Smm 4880238926Smm return (0); 4881238926Smm} 4882238926Smm 4883168404Spjd/* ARGSUSED */ 4884168404Spjdstatic int 4885168404Spjdupgrade_one(zpool_handle_t *zhp, void *data) 4886168404Spjd{ 4887238926Smm boolean_t printnl = B_FALSE; 4888185029Spjd upgrade_cbdata_t *cbp = data; 4889185029Spjd uint64_t cur_version; 4890168404Spjd int ret; 4891168404Spjd 4892276226Ssmh if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) { 4893276226Ssmh (void) fprintf(stderr, gettext("cannot upgrade '%s': pool is " 4894276226Ssmh "is currently unavailable.\n\n"), zpool_get_name(zhp)); 4895276226Ssmh cbp->cb_unavail = B_TRUE; 4896276226Ssmh return (1); 4897276226Ssmh } 4898276226Ssmh 4899185029Spjd if (strcmp("log", zpool_get_name(zhp)) == 0) { 4900185029Spjd (void) printf(gettext("'log' is now a reserved word\n" 4901185029Spjd "Pool 'log' must be renamed using export and import" 4902276226Ssmh " to upgrade.\n\n")); 4903185029Spjd return (1); 4904185029Spjd } 4905168404Spjd 4906185029Spjd cur_version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL); 4907185029Spjd if (cur_version > cbp->cb_version) { 4908168404Spjd (void) printf(gettext("Pool '%s' is already formatted " 4909238926Smm "using more current version '%llu'.\n\n"), 4910185029Spjd zpool_get_name(zhp), cur_version); 4911185029Spjd return (0); 4912185029Spjd } 4913238926Smm 4914238926Smm if (cbp->cb_version != SPA_VERSION && cur_version == cbp->cb_version) { 4915185029Spjd (void) printf(gettext("Pool '%s' is already formatted " 4916238926Smm "using version %llu.\n\n"), zpool_get_name(zhp), 4917238926Smm cbp->cb_version); 4918168404Spjd return (0); 4919168404Spjd } 4920168404Spjd 4921238926Smm if (cur_version != cbp->cb_version) { 4922238926Smm printnl = B_TRUE; 4923238926Smm ret = upgrade_version(zhp, cbp->cb_version); 4924238950Smm if (ret != 0) 4925238950Smm return (ret); 4926238926Smm#ifdef __FreeBSD__ 4927238950Smm root_pool_upgrade_check(zhp, cbp->cb_poolname, 4928238950Smm sizeof(cbp->cb_poolname)); 4929271934Ssmh#endif /* __FreeBSD__ */ 4930238926Smm } 4931168404Spjd 4932238926Smm if (cbp->cb_version >= SPA_VERSION_FEATURES) { 4933238926Smm int count = 0; 4934238926Smm ret = upgrade_enable_all(zhp, &count); 4935238926Smm if (ret != 0) 4936238926Smm return (ret); 4937238926Smm 4938238926Smm if (count != 0) { 4939238926Smm printnl = B_TRUE; 4940238950Smm#ifdef __FreeBSD__ 4941238951Smm root_pool_upgrade_check(zhp, cbp->cb_poolname, 4942238951Smm sizeof(cbp->cb_poolname)); 4943238950Smm#endif /* __FreeBSD __*/ 4944238926Smm } else if (cur_version == SPA_VERSION) { 4945238926Smm (void) printf(gettext("Pool '%s' already has all " 4946276226Ssmh "supported features enabled.\n\n"), 4947238926Smm zpool_get_name(zhp)); 4948238926Smm } 4949168404Spjd } 4950168404Spjd 4951238926Smm if (printnl) { 4952238926Smm (void) printf(gettext("\n")); 4953238926Smm } 4954238926Smm 4955238926Smm return (0); 4956168404Spjd} 4957168404Spjd 4958168404Spjd/* 4959168404Spjd * zpool upgrade 4960168404Spjd * zpool upgrade -v 4961185029Spjd * zpool upgrade [-V version] <-a | pool ...> 4962168404Spjd * 4963168404Spjd * With no arguments, display downrev'd ZFS pool available for upgrade. 4964168404Spjd * Individual pools can be upgraded by specifying the pool, and '-a' will 4965168404Spjd * upgrade all pools. 4966168404Spjd */ 4967168404Spjdint 4968168404Spjdzpool_do_upgrade(int argc, char **argv) 4969168404Spjd{ 4970168404Spjd int c; 4971168404Spjd upgrade_cbdata_t cb = { 0 }; 4972168404Spjd int ret = 0; 4973168404Spjd boolean_t showversions = B_FALSE; 4974238926Smm boolean_t upgradeall = B_FALSE; 4975185029Spjd char *end; 4976168404Spjd 4977185029Spjd 4978168404Spjd /* check options */ 4979219089Spjd while ((c = getopt(argc, argv, ":avV:")) != -1) { 4980168404Spjd switch (c) { 4981168404Spjd case 'a': 4982238926Smm upgradeall = B_TRUE; 4983168404Spjd break; 4984168404Spjd case 'v': 4985168404Spjd showversions = B_TRUE; 4986168404Spjd break; 4987185029Spjd case 'V': 4988185029Spjd cb.cb_version = strtoll(optarg, &end, 10); 4989236884Smm if (*end != '\0' || 4990236884Smm !SPA_VERSION_IS_SUPPORTED(cb.cb_version)) { 4991185029Spjd (void) fprintf(stderr, 4992185029Spjd gettext("invalid version '%s'\n"), optarg); 4993185029Spjd usage(B_FALSE); 4994185029Spjd } 4995185029Spjd break; 4996219089Spjd case ':': 4997219089Spjd (void) fprintf(stderr, gettext("missing argument for " 4998219089Spjd "'%c' option\n"), optopt); 4999219089Spjd usage(B_FALSE); 5000219089Spjd break; 5001168404Spjd case '?': 5002168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 5003168404Spjd optopt); 5004168404Spjd usage(B_FALSE); 5005168404Spjd } 5006168404Spjd } 5007168404Spjd 5008168404Spjd cb.cb_argc = argc; 5009168404Spjd cb.cb_argv = argv; 5010168404Spjd argc -= optind; 5011168404Spjd argv += optind; 5012168404Spjd 5013185029Spjd if (cb.cb_version == 0) { 5014185029Spjd cb.cb_version = SPA_VERSION; 5015238926Smm } else if (!upgradeall && argc == 0) { 5016185029Spjd (void) fprintf(stderr, gettext("-V option is " 5017185029Spjd "incompatible with other arguments\n")); 5018185029Spjd usage(B_FALSE); 5019185029Spjd } 5020185029Spjd 5021168404Spjd if (showversions) { 5022238926Smm if (upgradeall || argc != 0) { 5023168404Spjd (void) fprintf(stderr, gettext("-v option is " 5024168404Spjd "incompatible with other arguments\n")); 5025168404Spjd usage(B_FALSE); 5026168404Spjd } 5027238926Smm } else if (upgradeall) { 5028168404Spjd if (argc != 0) { 5029185029Spjd (void) fprintf(stderr, gettext("-a option should not " 5030185029Spjd "be used along with a pool name\n")); 5031168404Spjd usage(B_FALSE); 5032168404Spjd } 5033168404Spjd } 5034168404Spjd 5035236884Smm (void) printf(gettext("This system supports ZFS pool feature " 5036236884Smm "flags.\n\n")); 5037168404Spjd if (showversions) { 5038238926Smm int i; 5039238926Smm 5040238926Smm (void) printf(gettext("The following features are " 5041168404Spjd "supported:\n\n")); 5042238926Smm (void) printf(gettext("FEAT DESCRIPTION\n")); 5043238926Smm (void) printf("----------------------------------------------" 5044238926Smm "---------------\n"); 5045238926Smm for (i = 0; i < SPA_FEATURES; i++) { 5046238926Smm zfeature_info_t *fi = &spa_feature_table[i]; 5047286708Smav const char *ro = 5048286708Smav (fi->fi_flags & ZFEATURE_FLAG_READONLY_COMPAT) ? 5049238926Smm " (read-only compatible)" : ""; 5050238926Smm 5051238926Smm (void) printf("%-37s%s\n", fi->fi_uname, ro); 5052238926Smm (void) printf(" %s\n", fi->fi_desc); 5053238926Smm } 5054238926Smm (void) printf("\n"); 5055238926Smm 5056238926Smm (void) printf(gettext("The following legacy versions are also " 5057238926Smm "supported:\n\n")); 5058168404Spjd (void) printf(gettext("VER DESCRIPTION\n")); 5059168404Spjd (void) printf("--- -----------------------------------------" 5060168404Spjd "---------------\n"); 5061168404Spjd (void) printf(gettext(" 1 Initial ZFS version\n")); 5062168404Spjd (void) printf(gettext(" 2 Ditto blocks " 5063168404Spjd "(replicated metadata)\n")); 5064168404Spjd (void) printf(gettext(" 3 Hot spares and double parity " 5065168404Spjd "RAID-Z\n")); 5066168404Spjd (void) printf(gettext(" 4 zpool history\n")); 5067168404Spjd (void) printf(gettext(" 5 Compression using the gzip " 5068168404Spjd "algorithm\n")); 5069185029Spjd (void) printf(gettext(" 6 bootfs pool property\n")); 5070185029Spjd (void) printf(gettext(" 7 Separate intent log devices\n")); 5071185029Spjd (void) printf(gettext(" 8 Delegated administration\n")); 5072185029Spjd (void) printf(gettext(" 9 refquota and refreservation " 5073185029Spjd "properties\n")); 5074185029Spjd (void) printf(gettext(" 10 Cache devices\n")); 5075185029Spjd (void) printf(gettext(" 11 Improved scrub performance\n")); 5076185029Spjd (void) printf(gettext(" 12 Snapshot properties\n")); 5077185029Spjd (void) printf(gettext(" 13 snapused property\n")); 5078209962Smm (void) printf(gettext(" 14 passthrough-x aclinherit\n")); 5079209962Smm (void) printf(gettext(" 15 user/group space accounting\n")); 5080219089Spjd (void) printf(gettext(" 16 stmf property support\n")); 5081219089Spjd (void) printf(gettext(" 17 Triple-parity RAID-Z\n")); 5082219089Spjd (void) printf(gettext(" 18 Snapshot user holds\n")); 5083219089Spjd (void) printf(gettext(" 19 Log device removal\n")); 5084219089Spjd (void) printf(gettext(" 20 Compression using zle " 5085219089Spjd "(zero-length encoding)\n")); 5086219089Spjd (void) printf(gettext(" 21 Deduplication\n")); 5087219089Spjd (void) printf(gettext(" 22 Received properties\n")); 5088219089Spjd (void) printf(gettext(" 23 Slim ZIL\n")); 5089219089Spjd (void) printf(gettext(" 24 System attributes\n")); 5090219089Spjd (void) printf(gettext(" 25 Improved scrub stats\n")); 5091219089Spjd (void) printf(gettext(" 26 Improved snapshot deletion " 5092219089Spjd "performance\n")); 5093219089Spjd (void) printf(gettext(" 27 Improved snapshot creation " 5094219089Spjd "performance\n")); 5095219089Spjd (void) printf(gettext(" 28 Multiple vdev replacements\n")); 5096219089Spjd (void) printf(gettext("\nFor more information on a particular " 5097219089Spjd "version, including supported releases,\n")); 5098219089Spjd (void) printf(gettext("see the ZFS Administration Guide.\n\n")); 5099238926Smm } else if (argc == 0 && upgradeall) { 5100238926Smm cb.cb_first = B_TRUE; 5101168404Spjd ret = zpool_iter(g_zfs, upgrade_cb, &cb); 5102238926Smm if (ret == 0 && cb.cb_first) { 5103238926Smm if (cb.cb_version == SPA_VERSION) { 5104276226Ssmh (void) printf(gettext("All %spools are already " 5105276226Ssmh "formatted using feature flags.\n\n"), 5106276226Ssmh cb.cb_unavail ? gettext("available ") : ""); 5107276226Ssmh (void) printf(gettext("Every %sfeature flags " 5108238926Smm "pool already has all supported features " 5109276226Ssmh "enabled.\n"), 5110276226Ssmh cb.cb_unavail ? gettext("available ") : ""); 5111238926Smm } else { 5112238926Smm (void) printf(gettext("All pools are already " 5113238926Smm "formatted with version %llu or higher.\n"), 5114238926Smm cb.cb_version); 5115168404Spjd } 5116168404Spjd } 5117238926Smm } else if (argc == 0) { 5118238926Smm cb.cb_first = B_TRUE; 5119276226Ssmh ret = zpool_iter(g_zfs, upgrade_list_unavail, &cb); 5120276226Ssmh assert(ret == 0); 5121276226Ssmh 5122276226Ssmh if (!cb.cb_first) { 5123276226Ssmh (void) fprintf(stderr, "\n"); 5124276226Ssmh } 5125276226Ssmh 5126276226Ssmh cb.cb_first = B_TRUE; 5127238926Smm ret = zpool_iter(g_zfs, upgrade_list_older_cb, &cb); 5128238926Smm assert(ret == 0); 5129168404Spjd 5130238926Smm if (cb.cb_first) { 5131276226Ssmh (void) printf(gettext("All %spools are formatted using " 5132276226Ssmh "feature flags.\n\n"), cb.cb_unavail ? 5133276226Ssmh gettext("available ") : ""); 5134238926Smm } else { 5135238926Smm (void) printf(gettext("\nUse 'zpool upgrade -v' " 5136238926Smm "for a list of available legacy versions.\n")); 5137168404Spjd } 5138238926Smm 5139238926Smm cb.cb_first = B_TRUE; 5140238926Smm ret = zpool_iter(g_zfs, upgrade_list_disabled_cb, &cb); 5141238926Smm assert(ret == 0); 5142238926Smm 5143238926Smm if (cb.cb_first) { 5144276226Ssmh (void) printf(gettext("Every %sfeature flags pool has " 5145276226Ssmh "all supported features enabled.\n"), 5146276226Ssmh cb.cb_unavail ? gettext("available ") : ""); 5147238926Smm } else { 5148238926Smm (void) printf(gettext("\n")); 5149238926Smm } 5150168404Spjd } else { 5151276226Ssmh ret = for_each_pool(argc, argv, B_TRUE, NULL, 5152168404Spjd upgrade_one, &cb); 5153168404Spjd } 5154168404Spjd 5155212050Spjd if (cb.cb_poolname[0] != '\0') { 5156212050Spjd (void) printf( 5157212050Spjd "If you boot from pool '%s', don't forget to update boot code.\n" 5158212050Spjd "Assuming you use GPT partitioning and da0 is your boot disk\n" 5159212050Spjd "the following command will do it:\n" 5160212050Spjd "\n" 5161212050Spjd "\tgpart bootcode -b /boot/pmbr -p /boot/gptzfsboot -i 1 da0\n\n", 5162212050Spjd cb.cb_poolname); 5163212050Spjd } 5164212050Spjd 5165168404Spjd return (ret); 5166168404Spjd} 5167168404Spjd 5168185029Spjdtypedef struct hist_cbdata { 5169185029Spjd boolean_t first; 5170248571Smm boolean_t longfmt; 5171248571Smm boolean_t internal; 5172185029Spjd} hist_cbdata_t; 5173185029Spjd 5174168404Spjd/* 5175168404Spjd * Print out the command history for a specific pool. 5176168404Spjd */ 5177168404Spjdstatic int 5178168404Spjdget_history_one(zpool_handle_t *zhp, void *data) 5179168404Spjd{ 5180168404Spjd nvlist_t *nvhis; 5181168404Spjd nvlist_t **records; 5182168404Spjd uint_t numrecords; 5183168404Spjd int ret, i; 5184185029Spjd hist_cbdata_t *cb = (hist_cbdata_t *)data; 5185168404Spjd 5186185029Spjd cb->first = B_FALSE; 5187168404Spjd 5188168404Spjd (void) printf(gettext("History for '%s':\n"), zpool_get_name(zhp)); 5189168404Spjd 5190168404Spjd if ((ret = zpool_get_history(zhp, &nvhis)) != 0) 5191168404Spjd return (ret); 5192168404Spjd 5193168404Spjd verify(nvlist_lookup_nvlist_array(nvhis, ZPOOL_HIST_RECORD, 5194168404Spjd &records, &numrecords) == 0); 5195168404Spjd for (i = 0; i < numrecords; i++) { 5196248571Smm nvlist_t *rec = records[i]; 5197248571Smm char tbuf[30] = ""; 5198185029Spjd 5199248571Smm if (nvlist_exists(rec, ZPOOL_HIST_TIME)) { 5200248571Smm time_t tsec; 5201248571Smm struct tm t; 5202185029Spjd 5203248571Smm tsec = fnvlist_lookup_uint64(records[i], 5204248571Smm ZPOOL_HIST_TIME); 5205248571Smm (void) localtime_r(&tsec, &t); 5206248571Smm (void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t); 5207248571Smm } 5208248571Smm 5209248571Smm if (nvlist_exists(rec, ZPOOL_HIST_CMD)) { 5210248571Smm (void) printf("%s %s", tbuf, 5211248571Smm fnvlist_lookup_string(rec, ZPOOL_HIST_CMD)); 5212248571Smm } else if (nvlist_exists(rec, ZPOOL_HIST_INT_EVENT)) { 5213248571Smm int ievent = 5214248571Smm fnvlist_lookup_uint64(rec, ZPOOL_HIST_INT_EVENT); 5215248571Smm if (!cb->internal) 5216185029Spjd continue; 5217248571Smm if (ievent >= ZFS_NUM_LEGACY_HISTORY_EVENTS) { 5218248571Smm (void) printf("%s unrecognized record:\n", 5219248571Smm tbuf); 5220248571Smm dump_nvlist(rec, 4); 5221185029Spjd continue; 5222248571Smm } 5223248571Smm (void) printf("%s [internal %s txg:%lld] %s", tbuf, 5224248571Smm zfs_history_event_names[ievent], 5225248571Smm fnvlist_lookup_uint64(rec, ZPOOL_HIST_TXG), 5226248571Smm fnvlist_lookup_string(rec, ZPOOL_HIST_INT_STR)); 5227248571Smm } else if (nvlist_exists(rec, ZPOOL_HIST_INT_NAME)) { 5228248571Smm if (!cb->internal) 5229248571Smm continue; 5230248571Smm (void) printf("%s [txg:%lld] %s", tbuf, 5231248571Smm fnvlist_lookup_uint64(rec, ZPOOL_HIST_TXG), 5232248571Smm fnvlist_lookup_string(rec, ZPOOL_HIST_INT_NAME)); 5233248571Smm if (nvlist_exists(rec, ZPOOL_HIST_DSNAME)) { 5234248571Smm (void) printf(" %s (%llu)", 5235248571Smm fnvlist_lookup_string(rec, 5236248571Smm ZPOOL_HIST_DSNAME), 5237248571Smm fnvlist_lookup_uint64(rec, 5238248571Smm ZPOOL_HIST_DSID)); 5239248571Smm } 5240248571Smm (void) printf(" %s", fnvlist_lookup_string(rec, 5241248571Smm ZPOOL_HIST_INT_STR)); 5242248571Smm } else if (nvlist_exists(rec, ZPOOL_HIST_IOCTL)) { 5243248571Smm if (!cb->internal) 5244248571Smm continue; 5245248571Smm (void) printf("%s ioctl %s\n", tbuf, 5246248571Smm fnvlist_lookup_string(rec, ZPOOL_HIST_IOCTL)); 5247248571Smm if (nvlist_exists(rec, ZPOOL_HIST_INPUT_NVL)) { 5248248571Smm (void) printf(" input:\n"); 5249248571Smm dump_nvlist(fnvlist_lookup_nvlist(rec, 5250248571Smm ZPOOL_HIST_INPUT_NVL), 8); 5251248571Smm } 5252248571Smm if (nvlist_exists(rec, ZPOOL_HIST_OUTPUT_NVL)) { 5253248571Smm (void) printf(" output:\n"); 5254248571Smm dump_nvlist(fnvlist_lookup_nvlist(rec, 5255248571Smm ZPOOL_HIST_OUTPUT_NVL), 8); 5256248571Smm } 5257248571Smm } else { 5258248571Smm if (!cb->internal) 5259248571Smm continue; 5260248571Smm (void) printf("%s unrecognized record:\n", tbuf); 5261248571Smm dump_nvlist(rec, 4); 5262168404Spjd } 5263185029Spjd 5264185029Spjd if (!cb->longfmt) { 5265185029Spjd (void) printf("\n"); 5266185029Spjd continue; 5267185029Spjd } 5268185029Spjd (void) printf(" ["); 5269248571Smm if (nvlist_exists(rec, ZPOOL_HIST_WHO)) { 5270248571Smm uid_t who = fnvlist_lookup_uint64(rec, ZPOOL_HIST_WHO); 5271248571Smm struct passwd *pwd = getpwuid(who); 5272248571Smm (void) printf("user %d ", (int)who); 5273248571Smm if (pwd != NULL) 5274248571Smm (void) printf("(%s) ", pwd->pw_name); 5275185029Spjd } 5276248571Smm if (nvlist_exists(rec, ZPOOL_HIST_HOST)) { 5277248571Smm (void) printf("on %s", 5278248571Smm fnvlist_lookup_string(rec, ZPOOL_HIST_HOST)); 5279185029Spjd } 5280248571Smm if (nvlist_exists(rec, ZPOOL_HIST_ZONE)) { 5281248571Smm (void) printf(":%s", 5282248571Smm fnvlist_lookup_string(rec, ZPOOL_HIST_ZONE)); 5283185029Spjd } 5284185029Spjd (void) printf("]"); 5285185029Spjd (void) printf("\n"); 5286168404Spjd } 5287168404Spjd (void) printf("\n"); 5288168404Spjd nvlist_free(nvhis); 5289168404Spjd 5290168404Spjd return (ret); 5291168404Spjd} 5292168404Spjd 5293168404Spjd/* 5294168404Spjd * zpool history <pool> 5295168404Spjd * 5296168404Spjd * Displays the history of commands that modified pools. 5297168404Spjd */ 5298168404Spjdint 5299168404Spjdzpool_do_history(int argc, char **argv) 5300168404Spjd{ 5301185029Spjd hist_cbdata_t cbdata = { 0 }; 5302168404Spjd int ret; 5303185029Spjd int c; 5304168404Spjd 5305185029Spjd cbdata.first = B_TRUE; 5306185029Spjd /* check options */ 5307185029Spjd while ((c = getopt(argc, argv, "li")) != -1) { 5308185029Spjd switch (c) { 5309185029Spjd case 'l': 5310248571Smm cbdata.longfmt = B_TRUE; 5311185029Spjd break; 5312185029Spjd case 'i': 5313248571Smm cbdata.internal = B_TRUE; 5314185029Spjd break; 5315185029Spjd case '?': 5316185029Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 5317185029Spjd optopt); 5318185029Spjd usage(B_FALSE); 5319185029Spjd } 5320185029Spjd } 5321168404Spjd argc -= optind; 5322168404Spjd argv += optind; 5323168404Spjd 5324168404Spjd ret = for_each_pool(argc, argv, B_FALSE, NULL, get_history_one, 5325185029Spjd &cbdata); 5326168404Spjd 5327185029Spjd if (argc == 0 && cbdata.first == B_TRUE) { 5328168404Spjd (void) printf(gettext("no pools available\n")); 5329168404Spjd return (0); 5330168404Spjd } 5331168404Spjd 5332168404Spjd return (ret); 5333168404Spjd} 5334168404Spjd 5335168404Spjdstatic int 5336168404Spjdget_callback(zpool_handle_t *zhp, void *data) 5337168404Spjd{ 5338185029Spjd zprop_get_cbdata_t *cbp = (zprop_get_cbdata_t *)data; 5339168404Spjd char value[MAXNAMELEN]; 5340185029Spjd zprop_source_t srctype; 5341185029Spjd zprop_list_t *pl; 5342168404Spjd 5343168404Spjd for (pl = cbp->cb_proplist; pl != NULL; pl = pl->pl_next) { 5344168404Spjd 5345168404Spjd /* 5346185029Spjd * Skip the special fake placeholder. This will also skip 5347185029Spjd * over the name property when 'all' is specified. 5348168404Spjd */ 5349185029Spjd if (pl->pl_prop == ZPOOL_PROP_NAME && 5350168404Spjd pl == cbp->cb_proplist) 5351168404Spjd continue; 5352168404Spjd 5353236884Smm if (pl->pl_prop == ZPROP_INVAL && 5354236884Smm (zpool_prop_feature(pl->pl_user_prop) || 5355236884Smm zpool_prop_unsupported(pl->pl_user_prop))) { 5356236884Smm srctype = ZPROP_SRC_LOCAL; 5357168404Spjd 5358236884Smm if (zpool_prop_get_feature(zhp, pl->pl_user_prop, 5359236884Smm value, sizeof (value)) == 0) { 5360236884Smm zprop_print_one_property(zpool_get_name(zhp), 5361236884Smm cbp, pl->pl_user_prop, value, srctype, 5362236884Smm NULL, NULL); 5363236884Smm } 5364236884Smm } else { 5365236884Smm if (zpool_get_prop(zhp, pl->pl_prop, value, 5366263889Sdelphij sizeof (value), &srctype, cbp->cb_literal) != 0) 5367236884Smm continue; 5368236884Smm 5369236884Smm zprop_print_one_property(zpool_get_name(zhp), cbp, 5370236884Smm zpool_prop_to_name(pl->pl_prop), value, srctype, 5371236884Smm NULL, NULL); 5372236884Smm } 5373168404Spjd } 5374168404Spjd return (0); 5375168404Spjd} 5376168404Spjd 5377263889Sdelphij/* 5378263889Sdelphij * zpool get [-Hp] [-o "all" | field[,...]] <"all" | property[,...]> <pool> ... 5379263889Sdelphij * 5380263889Sdelphij * -H Scripted mode. Don't display headers, and separate properties 5381263889Sdelphij * by a single tab. 5382263889Sdelphij * -o List of columns to display. Defaults to 5383263889Sdelphij * "name,property,value,source". 5384263889Sdelphij * -p Diplay values in parsable (exact) format. 5385263889Sdelphij * 5386263889Sdelphij * Get properties of pools in the system. Output space statistics 5387263889Sdelphij * for each one as well as other attributes. 5388263889Sdelphij */ 5389168404Spjdint 5390168404Spjdzpool_do_get(int argc, char **argv) 5391168404Spjd{ 5392185029Spjd zprop_get_cbdata_t cb = { 0 }; 5393185029Spjd zprop_list_t fake_name = { 0 }; 5394168404Spjd int ret; 5395263889Sdelphij int c, i; 5396263889Sdelphij char *value; 5397168404Spjd 5398263889Sdelphij cb.cb_first = B_TRUE; 5399168404Spjd 5400263889Sdelphij /* 5401263889Sdelphij * Set up default columns and sources. 5402263889Sdelphij */ 5403185029Spjd cb.cb_sources = ZPROP_SRC_ALL; 5404168404Spjd cb.cb_columns[0] = GET_COL_NAME; 5405168404Spjd cb.cb_columns[1] = GET_COL_PROPERTY; 5406168404Spjd cb.cb_columns[2] = GET_COL_VALUE; 5407168404Spjd cb.cb_columns[3] = GET_COL_SOURCE; 5408185029Spjd cb.cb_type = ZFS_TYPE_POOL; 5409168404Spjd 5410263889Sdelphij /* check options */ 5411263889Sdelphij while ((c = getopt(argc, argv, ":Hpo:")) != -1) { 5412263889Sdelphij switch (c) { 5413263889Sdelphij case 'p': 5414263889Sdelphij cb.cb_literal = B_TRUE; 5415263889Sdelphij break; 5416263889Sdelphij case 'H': 5417263889Sdelphij cb.cb_scripted = B_TRUE; 5418263889Sdelphij break; 5419263889Sdelphij case 'o': 5420263889Sdelphij bzero(&cb.cb_columns, sizeof (cb.cb_columns)); 5421263889Sdelphij i = 0; 5422263889Sdelphij while (*optarg != '\0') { 5423263889Sdelphij static char *col_subopts[] = 5424263889Sdelphij { "name", "property", "value", "source", 5425263889Sdelphij "all", NULL }; 5426263889Sdelphij 5427263889Sdelphij if (i == ZFS_GET_NCOLS) { 5428263889Sdelphij (void) fprintf(stderr, gettext("too " 5429263889Sdelphij "many fields given to -o " 5430263889Sdelphij "option\n")); 5431263889Sdelphij usage(B_FALSE); 5432263889Sdelphij } 5433263889Sdelphij 5434263889Sdelphij switch (getsubopt(&optarg, col_subopts, 5435263889Sdelphij &value)) { 5436263889Sdelphij case 0: 5437263889Sdelphij cb.cb_columns[i++] = GET_COL_NAME; 5438263889Sdelphij break; 5439263889Sdelphij case 1: 5440263889Sdelphij cb.cb_columns[i++] = GET_COL_PROPERTY; 5441263889Sdelphij break; 5442263889Sdelphij case 2: 5443263889Sdelphij cb.cb_columns[i++] = GET_COL_VALUE; 5444263889Sdelphij break; 5445263889Sdelphij case 3: 5446263889Sdelphij cb.cb_columns[i++] = GET_COL_SOURCE; 5447263889Sdelphij break; 5448263889Sdelphij case 4: 5449263889Sdelphij if (i > 0) { 5450263889Sdelphij (void) fprintf(stderr, 5451263889Sdelphij gettext("\"all\" conflicts " 5452263889Sdelphij "with specific fields " 5453263889Sdelphij "given to -o option\n")); 5454263889Sdelphij usage(B_FALSE); 5455263889Sdelphij } 5456263889Sdelphij cb.cb_columns[0] = GET_COL_NAME; 5457263889Sdelphij cb.cb_columns[1] = GET_COL_PROPERTY; 5458263889Sdelphij cb.cb_columns[2] = GET_COL_VALUE; 5459263889Sdelphij cb.cb_columns[3] = GET_COL_SOURCE; 5460263889Sdelphij i = ZFS_GET_NCOLS; 5461263889Sdelphij break; 5462263889Sdelphij default: 5463263889Sdelphij (void) fprintf(stderr, 5464263889Sdelphij gettext("invalid column name " 5465295844Sdim "'%s'\n"), suboptarg); 5466263889Sdelphij usage(B_FALSE); 5467263889Sdelphij } 5468263889Sdelphij } 5469263889Sdelphij break; 5470263889Sdelphij case '?': 5471263889Sdelphij (void) fprintf(stderr, gettext("invalid option '%c'\n"), 5472263889Sdelphij optopt); 5473263889Sdelphij usage(B_FALSE); 5474263889Sdelphij } 5475263889Sdelphij } 5476263889Sdelphij 5477263889Sdelphij argc -= optind; 5478263889Sdelphij argv += optind; 5479263889Sdelphij 5480263889Sdelphij if (argc < 1) { 5481263889Sdelphij (void) fprintf(stderr, gettext("missing property " 5482263889Sdelphij "argument\n")); 5483263889Sdelphij usage(B_FALSE); 5484263889Sdelphij } 5485263889Sdelphij 5486263889Sdelphij if (zprop_get_list(g_zfs, argv[0], &cb.cb_proplist, 5487185029Spjd ZFS_TYPE_POOL) != 0) 5488168404Spjd usage(B_FALSE); 5489168404Spjd 5490263889Sdelphij argc--; 5491263889Sdelphij argv++; 5492263889Sdelphij 5493168404Spjd if (cb.cb_proplist != NULL) { 5494185029Spjd fake_name.pl_prop = ZPOOL_PROP_NAME; 5495168404Spjd fake_name.pl_width = strlen(gettext("NAME")); 5496168404Spjd fake_name.pl_next = cb.cb_proplist; 5497168404Spjd cb.cb_proplist = &fake_name; 5498168404Spjd } 5499168404Spjd 5500263889Sdelphij ret = for_each_pool(argc, argv, B_TRUE, &cb.cb_proplist, 5501168404Spjd get_callback, &cb); 5502168404Spjd 5503168404Spjd if (cb.cb_proplist == &fake_name) 5504185029Spjd zprop_free_list(fake_name.pl_next); 5505168404Spjd else 5506185029Spjd zprop_free_list(cb.cb_proplist); 5507168404Spjd 5508168404Spjd return (ret); 5509168404Spjd} 5510168404Spjd 5511168404Spjdtypedef struct set_cbdata { 5512168404Spjd char *cb_propname; 5513168404Spjd char *cb_value; 5514168404Spjd boolean_t cb_any_successful; 5515168404Spjd} set_cbdata_t; 5516168404Spjd 5517168404Spjdint 5518168404Spjdset_callback(zpool_handle_t *zhp, void *data) 5519168404Spjd{ 5520168404Spjd int error; 5521168404Spjd set_cbdata_t *cb = (set_cbdata_t *)data; 5522168404Spjd 5523168404Spjd error = zpool_set_prop(zhp, cb->cb_propname, cb->cb_value); 5524168404Spjd 5525168404Spjd if (!error) 5526168404Spjd cb->cb_any_successful = B_TRUE; 5527168404Spjd 5528168404Spjd return (error); 5529168404Spjd} 5530168404Spjd 5531168404Spjdint 5532168404Spjdzpool_do_set(int argc, char **argv) 5533168404Spjd{ 5534168404Spjd set_cbdata_t cb = { 0 }; 5535168404Spjd int error; 5536168404Spjd 5537168404Spjd if (argc > 1 && argv[1][0] == '-') { 5538168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 5539168404Spjd argv[1][1]); 5540168404Spjd usage(B_FALSE); 5541168404Spjd } 5542168404Spjd 5543168404Spjd if (argc < 2) { 5544168404Spjd (void) fprintf(stderr, gettext("missing property=value " 5545168404Spjd "argument\n")); 5546168404Spjd usage(B_FALSE); 5547168404Spjd } 5548168404Spjd 5549168404Spjd if (argc < 3) { 5550168404Spjd (void) fprintf(stderr, gettext("missing pool name\n")); 5551168404Spjd usage(B_FALSE); 5552168404Spjd } 5553168404Spjd 5554168404Spjd if (argc > 3) { 5555168404Spjd (void) fprintf(stderr, gettext("too many pool names\n")); 5556168404Spjd usage(B_FALSE); 5557168404Spjd } 5558168404Spjd 5559168404Spjd cb.cb_propname = argv[1]; 5560168404Spjd cb.cb_value = strchr(cb.cb_propname, '='); 5561168404Spjd if (cb.cb_value == NULL) { 5562168404Spjd (void) fprintf(stderr, gettext("missing value in " 5563168404Spjd "property=value argument\n")); 5564168404Spjd usage(B_FALSE); 5565168404Spjd } 5566168404Spjd 5567168404Spjd *(cb.cb_value) = '\0'; 5568168404Spjd cb.cb_value++; 5569168404Spjd 5570168404Spjd error = for_each_pool(argc - 2, argv + 2, B_TRUE, NULL, 5571168404Spjd set_callback, &cb); 5572168404Spjd 5573168404Spjd return (error); 5574168404Spjd} 5575168404Spjd 5576168404Spjdstatic int 5577168404Spjdfind_command_idx(char *command, int *idx) 5578168404Spjd{ 5579168404Spjd int i; 5580168404Spjd 5581168404Spjd for (i = 0; i < NCOMMAND; i++) { 5582168404Spjd if (command_table[i].name == NULL) 5583168404Spjd continue; 5584168404Spjd 5585168404Spjd if (strcmp(command, command_table[i].name) == 0) { 5586168404Spjd *idx = i; 5587168404Spjd return (0); 5588168404Spjd } 5589168404Spjd } 5590168404Spjd return (1); 5591168404Spjd} 5592168404Spjd 5593168404Spjdint 5594168404Spjdmain(int argc, char **argv) 5595168404Spjd{ 5596296537Smav int ret = 0; 5597168404Spjd int i; 5598168404Spjd char *cmdname; 5599168404Spjd 5600168404Spjd (void) setlocale(LC_ALL, ""); 5601168404Spjd (void) textdomain(TEXT_DOMAIN); 5602168404Spjd 5603168404Spjd if ((g_zfs = libzfs_init()) == NULL) { 5604168404Spjd (void) fprintf(stderr, gettext("internal error: failed to " 5605168404Spjd "initialize ZFS library\n")); 5606168404Spjd return (1); 5607168404Spjd } 5608168404Spjd 5609168404Spjd libzfs_print_on_error(g_zfs, B_TRUE); 5610168404Spjd 5611168404Spjd opterr = 0; 5612168404Spjd 5613168404Spjd /* 5614168404Spjd * Make sure the user has specified some command. 5615168404Spjd */ 5616168404Spjd if (argc < 2) { 5617168404Spjd (void) fprintf(stderr, gettext("missing command\n")); 5618168404Spjd usage(B_FALSE); 5619168404Spjd } 5620168404Spjd 5621168404Spjd cmdname = argv[1]; 5622168404Spjd 5623168404Spjd /* 5624168404Spjd * Special case '-?' 5625168404Spjd */ 5626168404Spjd if (strcmp(cmdname, "-?") == 0) 5627168404Spjd usage(B_TRUE); 5628168404Spjd 5629248571Smm zfs_save_arguments(argc, argv, history_str, sizeof (history_str)); 5630185029Spjd 5631168404Spjd /* 5632168404Spjd * Run the appropriate command. 5633168404Spjd */ 5634168404Spjd if (find_command_idx(cmdname, &i) == 0) { 5635168404Spjd current_command = &command_table[i]; 5636168404Spjd ret = command_table[i].func(argc - 1, argv + 1); 5637185029Spjd } else if (strchr(cmdname, '=')) { 5638185029Spjd verify(find_command_idx("set", &i) == 0); 5639185029Spjd current_command = &command_table[i]; 5640185029Spjd ret = command_table[i].func(argc, argv); 5641185029Spjd } else if (strcmp(cmdname, "freeze") == 0 && argc == 3) { 5642185029Spjd /* 5643185029Spjd * 'freeze' is a vile debugging abomination, so we treat 5644185029Spjd * it as such. 5645185029Spjd */ 5646252059Ssmh zfs_cmd_t zc = { 0 }; 5647252059Ssmh (void) strlcpy(zc.zc_name, argv[2], sizeof (zc.zc_name)); 5648252059Ssmh return (!!zfs_ioctl(g_zfs, ZFS_IOC_POOL_FREEZE, &zc)); 5649185029Spjd } else { 5650168404Spjd (void) fprintf(stderr, gettext("unrecognized " 5651168404Spjd "command '%s'\n"), cmdname); 5652168404Spjd usage(B_FALSE); 5653168404Spjd } 5654168404Spjd 5655248571Smm if (ret == 0 && log_history) 5656248571Smm (void) zpool_log_history(g_zfs, history_str); 5657248571Smm 5658168404Spjd libzfs_fini(g_zfs); 5659168404Spjd 5660168404Spjd /* 5661168404Spjd * The 'ZFS_ABORT' environment variable causes us to dump core on exit 5662168404Spjd * for the purposes of running ::findleaks. 5663168404Spjd */ 5664168404Spjd if (getenv("ZFS_ABORT") != NULL) { 5665168404Spjd (void) printf("dumping core by request\n"); 5666168404Spjd abort(); 5667168404Spjd } 5668168404Spjd 5669168404Spjd return (ret); 5670168404Spjd} 5671