zpool_main.c revision 333194
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. 24332525Smav * Copyright (c) 2011, 2018 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> 39332547Smav#include <getopt.h> 40168404Spjd#include <libgen.h> 41168404Spjd#include <libintl.h> 42168404Spjd#include <libuutil.h> 43168404Spjd#include <locale.h> 44168404Spjd#include <stdio.h> 45168404Spjd#include <stdlib.h> 46168404Spjd#include <string.h> 47168404Spjd#include <strings.h> 48168404Spjd#include <unistd.h> 49168404Spjd#include <priv.h> 50185029Spjd#include <pwd.h> 51185029Spjd#include <zone.h> 52168404Spjd#include <sys/time.h> 53236155Smm#include <zfs_prop.h> 54168404Spjd#include <sys/fs/zfs.h> 55168404Spjd#include <sys/stat.h> 56168404Spjd 57168404Spjd#include <libzfs.h> 58168404Spjd 59168404Spjd#include "zpool_util.h" 60185029Spjd#include "zfs_comutil.h" 61236884Smm#include "zfeature_common.h" 62168404Spjd 63219089Spjd#include "statcommon.h" 64219089Spjd 65168404Spjdstatic int zpool_do_create(int, char **); 66168404Spjdstatic int zpool_do_destroy(int, char **); 67168404Spjd 68168404Spjdstatic int zpool_do_add(int, char **); 69168404Spjdstatic int zpool_do_remove(int, char **); 70224171Sgibbsstatic int zpool_do_labelclear(int, char **); 71168404Spjd 72332547Smavstatic int zpool_do_checkpoint(int, char **); 73332547Smav 74168404Spjdstatic int zpool_do_list(int, char **); 75168404Spjdstatic int zpool_do_iostat(int, char **); 76168404Spjdstatic int zpool_do_status(int, char **); 77168404Spjd 78168404Spjdstatic int zpool_do_online(int, char **); 79168404Spjdstatic int zpool_do_offline(int, char **); 80168404Spjdstatic int zpool_do_clear(int, char **); 81236155Smmstatic int zpool_do_reopen(int, char **); 82168404Spjd 83228103Smmstatic int zpool_do_reguid(int, char **); 84228103Smm 85168404Spjdstatic int zpool_do_attach(int, char **); 86168404Spjdstatic int zpool_do_detach(int, char **); 87168404Spjdstatic int zpool_do_replace(int, char **); 88219089Spjdstatic int zpool_do_split(int, char **); 89168404Spjd 90168404Spjdstatic int zpool_do_scrub(int, char **); 91168404Spjd 92168404Spjdstatic int zpool_do_import(int, char **); 93168404Spjdstatic int zpool_do_export(int, char **); 94168404Spjd 95168404Spjdstatic int zpool_do_upgrade(int, char **); 96168404Spjd 97168404Spjdstatic int zpool_do_history(int, char **); 98168404Spjd 99168404Spjdstatic int zpool_do_get(int, char **); 100168404Spjdstatic int zpool_do_set(int, char **); 101168404Spjd 102168404Spjd/* 103168404Spjd * These libumem hooks provide a reasonable set of defaults for the allocator's 104168404Spjd * debugging facilities. 105168404Spjd */ 106185029Spjd 107185029Spjd#ifdef DEBUG 108168404Spjdconst char * 109168404Spjd_umem_debug_init(void) 110168404Spjd{ 111168404Spjd return ("default,verbose"); /* $UMEM_DEBUG setting */ 112168404Spjd} 113168404Spjd 114168404Spjdconst char * 115168404Spjd_umem_logging_init(void) 116168404Spjd{ 117168404Spjd return ("fail,contents"); /* $UMEM_LOGGING setting */ 118168404Spjd} 119185029Spjd#endif 120168404Spjd 121168404Spjdtypedef enum { 122168404Spjd HELP_ADD, 123168404Spjd HELP_ATTACH, 124168404Spjd HELP_CLEAR, 125168404Spjd HELP_CREATE, 126332547Smav HELP_CHECKPOINT, 127168404Spjd HELP_DESTROY, 128168404Spjd HELP_DETACH, 129168404Spjd HELP_EXPORT, 130168404Spjd HELP_HISTORY, 131168404Spjd HELP_IMPORT, 132168404Spjd HELP_IOSTAT, 133224171Sgibbs HELP_LABELCLEAR, 134168404Spjd HELP_LIST, 135168404Spjd HELP_OFFLINE, 136168404Spjd HELP_ONLINE, 137168404Spjd HELP_REPLACE, 138168404Spjd HELP_REMOVE, 139168404Spjd HELP_SCRUB, 140168404Spjd HELP_STATUS, 141168404Spjd HELP_UPGRADE, 142168404Spjd HELP_GET, 143219089Spjd HELP_SET, 144228103Smm HELP_SPLIT, 145236155Smm HELP_REGUID, 146236155Smm HELP_REOPEN 147168404Spjd} zpool_help_t; 148168404Spjd 149168404Spjd 150168404Spjdtypedef struct zpool_command { 151168404Spjd const char *name; 152168404Spjd int (*func)(int, char **); 153168404Spjd zpool_help_t usage; 154168404Spjd} zpool_command_t; 155168404Spjd 156168404Spjd/* 157168404Spjd * Master command table. Each ZFS command has a name, associated function, and 158168404Spjd * usage message. The usage messages need to be internationalized, so we have 159168404Spjd * to have a function to return the usage message based on a command index. 160168404Spjd * 161168404Spjd * These commands are organized according to how they are displayed in the usage 162168404Spjd * message. An empty command (one with a NULL name) indicates an empty line in 163168404Spjd * the generic usage message. 164168404Spjd */ 165168404Spjdstatic zpool_command_t command_table[] = { 166168404Spjd { "create", zpool_do_create, HELP_CREATE }, 167168404Spjd { "destroy", zpool_do_destroy, HELP_DESTROY }, 168168404Spjd { NULL }, 169168404Spjd { "add", zpool_do_add, HELP_ADD }, 170168404Spjd { "remove", zpool_do_remove, HELP_REMOVE }, 171168404Spjd { NULL }, 172224171Sgibbs { "labelclear", zpool_do_labelclear, HELP_LABELCLEAR }, 173224171Sgibbs { NULL }, 174332547Smav { "checkpoint", zpool_do_checkpoint, HELP_CHECKPOINT }, 175332547Smav { NULL }, 176168404Spjd { "list", zpool_do_list, HELP_LIST }, 177168404Spjd { "iostat", zpool_do_iostat, HELP_IOSTAT }, 178168404Spjd { "status", zpool_do_status, HELP_STATUS }, 179168404Spjd { NULL }, 180168404Spjd { "online", zpool_do_online, HELP_ONLINE }, 181168404Spjd { "offline", zpool_do_offline, HELP_OFFLINE }, 182168404Spjd { "clear", zpool_do_clear, HELP_CLEAR }, 183236155Smm { "reopen", zpool_do_reopen, HELP_REOPEN }, 184168404Spjd { NULL }, 185168404Spjd { "attach", zpool_do_attach, HELP_ATTACH }, 186168404Spjd { "detach", zpool_do_detach, HELP_DETACH }, 187168404Spjd { "replace", zpool_do_replace, HELP_REPLACE }, 188219089Spjd { "split", zpool_do_split, HELP_SPLIT }, 189168404Spjd { NULL }, 190168404Spjd { "scrub", zpool_do_scrub, HELP_SCRUB }, 191168404Spjd { NULL }, 192168404Spjd { "import", zpool_do_import, HELP_IMPORT }, 193168404Spjd { "export", zpool_do_export, HELP_EXPORT }, 194168404Spjd { "upgrade", zpool_do_upgrade, HELP_UPGRADE }, 195228103Smm { "reguid", zpool_do_reguid, HELP_REGUID }, 196168404Spjd { NULL }, 197168404Spjd { "history", zpool_do_history, HELP_HISTORY }, 198168404Spjd { "get", zpool_do_get, HELP_GET }, 199168404Spjd { "set", zpool_do_set, HELP_SET }, 200168404Spjd}; 201168404Spjd 202168404Spjd#define NCOMMAND (sizeof (command_table) / sizeof (command_table[0])) 203168404Spjd 204248571Smmstatic zpool_command_t *current_command; 205185029Spjdstatic char history_str[HIS_MAX_RECORD_LEN]; 206248571Smmstatic boolean_t log_history = B_TRUE; 207219089Spjdstatic uint_t timestamp_fmt = NODATE; 208219089Spjd 209168404Spjdstatic const char * 210289562Smavget_usage(zpool_help_t idx) 211289562Smav{ 212168404Spjd switch (idx) { 213168404Spjd case HELP_ADD: 214168404Spjd return (gettext("\tadd [-fn] <pool> <vdev> ...\n")); 215168404Spjd case HELP_ATTACH: 216168404Spjd return (gettext("\tattach [-f] <pool> <device> " 217185029Spjd "<new-device>\n")); 218168404Spjd case HELP_CLEAR: 219219089Spjd return (gettext("\tclear [-nF] <pool> [device]\n")); 220168404Spjd case HELP_CREATE: 221331395Smav return (gettext("\tcreate [-fnd] [-B] " 222331395Smav "[-o property=value] ... \n" 223333194Savg "\t [-O file-system-property=value] ...\n" 224333194Savg "\t [-m mountpoint] [-R root] [-t tempname] " 225333194Savg "<pool> <vdev> ...\n")); 226332547Smav case HELP_CHECKPOINT: 227332547Smav return (gettext("\tcheckpoint [--discard] <pool> ...\n")); 228168404Spjd case HELP_DESTROY: 229168404Spjd return (gettext("\tdestroy [-f] <pool>\n")); 230168404Spjd case HELP_DETACH: 231168404Spjd return (gettext("\tdetach <pool> <device>\n")); 232168404Spjd case HELP_EXPORT: 233168404Spjd return (gettext("\texport [-f] <pool> ...\n")); 234168404Spjd case HELP_HISTORY: 235185029Spjd return (gettext("\thistory [-il] [<pool>] ...\n")); 236168404Spjd case HELP_IMPORT: 237168404Spjd return (gettext("\timport [-d dir] [-D]\n" 238185029Spjd "\timport [-o mntopts] [-o property=value] ... \n" 239219089Spjd "\t [-d dir | -c cachefile] [-D] [-f] [-m] [-N] " 240219089Spjd "[-R root] [-F [-n]] -a\n" 241185029Spjd "\timport [-o mntopts] [-o property=value] ... \n" 242219089Spjd "\t [-d dir | -c cachefile] [-D] [-f] [-m] [-N] " 243333194Savg "[-R root] [-F [-n]] [-t]\n" 244332547Smav "\t [--rewind-to-checkpoint] <pool | id> [newpool]\n")); 245168404Spjd case HELP_IOSTAT: 246219089Spjd return (gettext("\tiostat [-v] [-T d|u] [pool] ... [interval " 247168404Spjd "[count]]\n")); 248224171Sgibbs case HELP_LABELCLEAR: 249224171Sgibbs return (gettext("\tlabelclear [-f] <vdev>\n")); 250168404Spjd case HELP_LIST: 251263889Sdelphij return (gettext("\tlist [-Hpv] [-o property[,...]] " 252219089Spjd "[-T d|u] [pool] ... [interval [count]]\n")); 253168404Spjd case HELP_OFFLINE: 254168404Spjd return (gettext("\toffline [-t] <pool> <device> ...\n")); 255168404Spjd case HELP_ONLINE: 256228020Smm return (gettext("\tonline [-e] <pool> <device> ...\n")); 257168404Spjd case HELP_REPLACE: 258168404Spjd return (gettext("\treplace [-f] <pool> <device> " 259185029Spjd "[new-device]\n")); 260168404Spjd case HELP_REMOVE: 261332525Smav return (gettext("\tremove [-nps] <pool> <device> ...\n")); 262236155Smm case HELP_REOPEN: 263260138Sdelphij return (gettext("\treopen <pool>\n")); 264168404Spjd case HELP_SCRUB: 265324010Savg return (gettext("\tscrub [-s | -p] <pool> ...\n")); 266168404Spjd case HELP_STATUS: 267219089Spjd return (gettext("\tstatus [-vx] [-T d|u] [pool] ... [interval " 268219089Spjd "[count]]\n")); 269168404Spjd case HELP_UPGRADE: 270228020Smm return (gettext("\tupgrade [-v]\n" 271185029Spjd "\tupgrade [-V version] <-a | pool ...>\n")); 272168404Spjd case HELP_GET: 273263889Sdelphij return (gettext("\tget [-Hp] [-o \"all\" | field[,...]] " 274263889Sdelphij "<\"all\" | property[,...]> <pool> ...\n")); 275168404Spjd case HELP_SET: 276168404Spjd return (gettext("\tset <property=value> <pool> \n")); 277219089Spjd case HELP_SPLIT: 278219089Spjd return (gettext("\tsplit [-n] [-R altroot] [-o mntopts]\n" 279219089Spjd "\t [-o property=value] <pool> <newpool> " 280219089Spjd "[<device> ...]\n")); 281228103Smm case HELP_REGUID: 282228103Smm return (gettext("\treguid <pool>\n")); 283168404Spjd } 284168404Spjd 285168404Spjd abort(); 286168404Spjd /* NOTREACHED */ 287168404Spjd} 288168404Spjd 289168404Spjd 290168404Spjd/* 291168404Spjd * Callback routine that will print out a pool property value. 292168404Spjd */ 293185029Spjdstatic int 294185029Spjdprint_prop_cb(int prop, void *cb) 295168404Spjd{ 296168404Spjd FILE *fp = cb; 297168404Spjd 298219089Spjd (void) fprintf(fp, "\t%-15s ", zpool_prop_to_name(prop)); 299168404Spjd 300185029Spjd if (zpool_prop_readonly(prop)) 301185029Spjd (void) fprintf(fp, " NO "); 302185029Spjd else 303219089Spjd (void) fprintf(fp, " YES "); 304185029Spjd 305168404Spjd if (zpool_prop_values(prop) == NULL) 306168404Spjd (void) fprintf(fp, "-\n"); 307168404Spjd else 308168404Spjd (void) fprintf(fp, "%s\n", zpool_prop_values(prop)); 309168404Spjd 310185029Spjd return (ZPROP_CONT); 311168404Spjd} 312168404Spjd 313168404Spjd/* 314168404Spjd * Display usage message. If we're inside a command, display only the usage for 315168404Spjd * that command. Otherwise, iterate over the entire command table and display 316168404Spjd * a complete usage message. 317168404Spjd */ 318168404Spjdvoid 319168404Spjdusage(boolean_t requested) 320168404Spjd{ 321168404Spjd FILE *fp = requested ? stdout : stderr; 322168404Spjd 323168404Spjd if (current_command == NULL) { 324168404Spjd int i; 325168404Spjd 326168404Spjd (void) fprintf(fp, gettext("usage: zpool command args ...\n")); 327168404Spjd (void) fprintf(fp, 328168404Spjd gettext("where 'command' is one of the following:\n\n")); 329168404Spjd 330168404Spjd for (i = 0; i < NCOMMAND; i++) { 331168404Spjd if (command_table[i].name == NULL) 332168404Spjd (void) fprintf(fp, "\n"); 333168404Spjd else 334168404Spjd (void) fprintf(fp, "%s", 335168404Spjd get_usage(command_table[i].usage)); 336168404Spjd } 337168404Spjd } else { 338168404Spjd (void) fprintf(fp, gettext("usage:\n")); 339168404Spjd (void) fprintf(fp, "%s", get_usage(current_command->usage)); 340168404Spjd } 341168404Spjd 342168404Spjd if (current_command != NULL && 343168404Spjd ((strcmp(current_command->name, "set") == 0) || 344185029Spjd (strcmp(current_command->name, "get") == 0) || 345185029Spjd (strcmp(current_command->name, "list") == 0))) { 346168404Spjd 347168404Spjd (void) fprintf(fp, 348168404Spjd gettext("\nthe following properties are supported:\n")); 349168404Spjd 350219089Spjd (void) fprintf(fp, "\n\t%-15s %s %s\n\n", 351185029Spjd "PROPERTY", "EDIT", "VALUES"); 352168404Spjd 353168404Spjd /* Iterate over all properties */ 354185029Spjd (void) zprop_iter(print_prop_cb, fp, B_FALSE, B_TRUE, 355185029Spjd ZFS_TYPE_POOL); 356236884Smm 357236884Smm (void) fprintf(fp, "\t%-15s ", "feature@..."); 358236884Smm (void) fprintf(fp, "YES disabled | enabled | active\n"); 359236884Smm 360236884Smm (void) fprintf(fp, gettext("\nThe feature@ properties must be " 361243014Smm "appended with a feature name.\nSee zpool-features(7).\n")); 362168404Spjd } 363168404Spjd 364168404Spjd /* 365168404Spjd * See comments at end of main(). 366168404Spjd */ 367168404Spjd if (getenv("ZFS_ABORT") != NULL) { 368168404Spjd (void) printf("dumping core by request\n"); 369168404Spjd abort(); 370168404Spjd } 371168404Spjd 372168404Spjd exit(requested ? 0 : 2); 373168404Spjd} 374168404Spjd 375168404Spjdvoid 376185029Spjdprint_vdev_tree(zpool_handle_t *zhp, const char *name, nvlist_t *nv, int indent, 377185029Spjd boolean_t print_logs) 378168404Spjd{ 379168404Spjd nvlist_t **child; 380168404Spjd uint_t c, children; 381168404Spjd char *vname; 382168404Spjd 383168404Spjd if (name != NULL) 384168404Spjd (void) printf("\t%*s%s\n", indent, "", name); 385168404Spjd 386168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 387168404Spjd &child, &children) != 0) 388168404Spjd return; 389168404Spjd 390168404Spjd for (c = 0; c < children; c++) { 391185029Spjd uint64_t is_log = B_FALSE; 392185029Spjd 393185029Spjd (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 394185029Spjd &is_log); 395185029Spjd if ((is_log && !print_logs) || (!is_log && print_logs)) 396185029Spjd continue; 397185029Spjd 398219089Spjd vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE); 399185029Spjd print_vdev_tree(zhp, vname, child[c], indent + 2, 400185029Spjd B_FALSE); 401168404Spjd free(vname); 402168404Spjd } 403168404Spjd} 404168404Spjd 405238926Smmstatic boolean_t 406238926Smmprop_list_contains_feature(nvlist_t *proplist) 407238926Smm{ 408238926Smm nvpair_t *nvp; 409238926Smm for (nvp = nvlist_next_nvpair(proplist, NULL); NULL != nvp; 410238926Smm nvp = nvlist_next_nvpair(proplist, nvp)) { 411238926Smm if (zpool_prop_feature(nvpair_name(nvp))) 412238926Smm return (B_TRUE); 413238926Smm } 414238926Smm return (B_FALSE); 415238926Smm} 416238926Smm 417168404Spjd/* 418185029Spjd * Add a property pair (name, string-value) into a property nvlist. 419185029Spjd */ 420185029Spjdstatic int 421185029Spjdadd_prop_list(const char *propname, char *propval, nvlist_t **props, 422185029Spjd boolean_t poolprop) 423185029Spjd{ 424185029Spjd zpool_prop_t prop = ZPROP_INVAL; 425185029Spjd zfs_prop_t fprop; 426185029Spjd nvlist_t *proplist; 427185029Spjd const char *normnm; 428185029Spjd char *strval; 429185029Spjd 430185029Spjd if (*props == NULL && 431185029Spjd nvlist_alloc(props, NV_UNIQUE_NAME, 0) != 0) { 432185029Spjd (void) fprintf(stderr, 433185029Spjd gettext("internal error: out of memory\n")); 434185029Spjd return (1); 435185029Spjd } 436185029Spjd 437185029Spjd proplist = *props; 438185029Spjd 439185029Spjd if (poolprop) { 440238926Smm const char *vname = zpool_prop_to_name(ZPOOL_PROP_VERSION); 441238926Smm 442236884Smm if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL && 443236884Smm !zpool_prop_feature(propname)) { 444185029Spjd (void) fprintf(stderr, gettext("property '%s' is " 445185029Spjd "not a valid pool property\n"), propname); 446185029Spjd return (2); 447185029Spjd } 448238926Smm 449238926Smm /* 450238926Smm * feature@ properties and version should not be specified 451238926Smm * at the same time. 452238926Smm */ 453329493Smav if ((prop == ZPOOL_PROP_INVAL && zpool_prop_feature(propname) && 454238926Smm nvlist_exists(proplist, vname)) || 455238926Smm (prop == ZPOOL_PROP_VERSION && 456238926Smm prop_list_contains_feature(proplist))) { 457238926Smm (void) fprintf(stderr, gettext("'feature@' and " 458238926Smm "'version' properties cannot be specified " 459238926Smm "together\n")); 460238926Smm return (2); 461238926Smm } 462238926Smm 463238926Smm 464236884Smm if (zpool_prop_feature(propname)) 465236884Smm normnm = propname; 466236884Smm else 467236884Smm normnm = zpool_prop_to_name(prop); 468185029Spjd } else { 469209962Smm if ((fprop = zfs_name_to_prop(propname)) != ZPROP_INVAL) { 470209962Smm normnm = zfs_prop_to_name(fprop); 471209962Smm } else { 472209962Smm normnm = propname; 473185029Spjd } 474185029Spjd } 475185029Spjd 476185029Spjd if (nvlist_lookup_string(proplist, normnm, &strval) == 0 && 477185029Spjd prop != ZPOOL_PROP_CACHEFILE) { 478185029Spjd (void) fprintf(stderr, gettext("property '%s' " 479185029Spjd "specified multiple times\n"), propname); 480185029Spjd return (2); 481185029Spjd } 482185029Spjd 483185029Spjd if (nvlist_add_string(proplist, normnm, propval) != 0) { 484185029Spjd (void) fprintf(stderr, gettext("internal " 485185029Spjd "error: out of memory\n")); 486185029Spjd return (1); 487185029Spjd } 488185029Spjd 489185029Spjd return (0); 490185029Spjd} 491185029Spjd 492185029Spjd/* 493333194Savg * Set a default property pair (name, string-value) in a property nvlist 494333194Savg */ 495333194Savgstatic int 496333194Savgadd_prop_list_default(const char *propname, char *propval, nvlist_t **props, 497333194Savg boolean_t poolprop) 498333194Savg{ 499333194Savg char *pval; 500333194Savg 501333194Savg if (nvlist_lookup_string(*props, propname, &pval) == 0) 502333194Savg return (0); 503333194Savg 504333194Savg return (add_prop_list(propname, propval, props, poolprop)); 505333194Savg} 506333194Savg 507333194Savg/* 508168404Spjd * zpool add [-fn] <pool> <vdev> ... 509168404Spjd * 510168404Spjd * -f Force addition of devices, even if they appear in use 511168404Spjd * -n Do not add the devices, but display the resulting layout if 512168404Spjd * they were to be added. 513168404Spjd * 514168404Spjd * Adds the given vdevs to 'pool'. As with create, the bulk of this work is 515168404Spjd * handled by get_vdev_spec(), which constructs the nvlist needed to pass to 516168404Spjd * libzfs. 517168404Spjd */ 518168404Spjdint 519168404Spjdzpool_do_add(int argc, char **argv) 520168404Spjd{ 521168404Spjd boolean_t force = B_FALSE; 522168404Spjd boolean_t dryrun = B_FALSE; 523168404Spjd int c; 524168404Spjd nvlist_t *nvroot; 525168404Spjd char *poolname; 526331395Smav zpool_boot_label_t boot_type; 527331395Smav uint64_t boot_size; 528168404Spjd int ret; 529168404Spjd zpool_handle_t *zhp; 530168404Spjd nvlist_t *config; 531168404Spjd 532168404Spjd /* check options */ 533168404Spjd while ((c = getopt(argc, argv, "fn")) != -1) { 534168404Spjd switch (c) { 535168404Spjd case 'f': 536168404Spjd force = B_TRUE; 537168404Spjd break; 538168404Spjd case 'n': 539168404Spjd dryrun = B_TRUE; 540168404Spjd break; 541168404Spjd case '?': 542168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 543168404Spjd optopt); 544168404Spjd usage(B_FALSE); 545168404Spjd } 546168404Spjd } 547168404Spjd 548168404Spjd argc -= optind; 549168404Spjd argv += optind; 550168404Spjd 551168404Spjd /* get pool name and check number of arguments */ 552168404Spjd if (argc < 1) { 553168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 554168404Spjd usage(B_FALSE); 555168404Spjd } 556168404Spjd if (argc < 2) { 557168404Spjd (void) fprintf(stderr, gettext("missing vdev specification\n")); 558168404Spjd usage(B_FALSE); 559168404Spjd } 560168404Spjd 561168404Spjd poolname = argv[0]; 562168404Spjd 563168404Spjd argc--; 564168404Spjd argv++; 565168404Spjd 566168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 567168404Spjd return (1); 568168404Spjd 569168404Spjd if ((config = zpool_get_config(zhp, NULL)) == NULL) { 570168404Spjd (void) fprintf(stderr, gettext("pool '%s' is unavailable\n"), 571168404Spjd poolname); 572168404Spjd zpool_close(zhp); 573168404Spjd return (1); 574168404Spjd } 575168404Spjd 576331395Smav if (zpool_is_bootable(zhp)) 577331395Smav boot_type = ZPOOL_COPY_BOOT_LABEL; 578331395Smav else 579331395Smav boot_type = ZPOOL_NO_BOOT_LABEL; 580331395Smav 581168404Spjd /* pass off to get_vdev_spec for processing */ 582331395Smav boot_size = zpool_get_prop_int(zhp, ZPOOL_PROP_BOOTSIZE, NULL); 583185029Spjd nvroot = make_root_vdev(zhp, force, !force, B_FALSE, dryrun, 584331395Smav boot_type, boot_size, argc, argv); 585168404Spjd if (nvroot == NULL) { 586168404Spjd zpool_close(zhp); 587168404Spjd return (1); 588168404Spjd } 589168404Spjd 590168404Spjd if (dryrun) { 591168404Spjd nvlist_t *poolnvroot; 592168404Spjd 593168404Spjd verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 594168404Spjd &poolnvroot) == 0); 595168404Spjd 596168404Spjd (void) printf(gettext("would update '%s' to the following " 597168404Spjd "configuration:\n"), zpool_get_name(zhp)); 598168404Spjd 599185029Spjd /* print original main pool and new tree */ 600185029Spjd print_vdev_tree(zhp, poolname, poolnvroot, 0, B_FALSE); 601185029Spjd print_vdev_tree(zhp, NULL, nvroot, 0, B_FALSE); 602168404Spjd 603185029Spjd /* Do the same for the logs */ 604185029Spjd if (num_logs(poolnvroot) > 0) { 605185029Spjd print_vdev_tree(zhp, "logs", poolnvroot, 0, B_TRUE); 606185029Spjd print_vdev_tree(zhp, NULL, nvroot, 0, B_TRUE); 607185029Spjd } else if (num_logs(nvroot) > 0) { 608185029Spjd print_vdev_tree(zhp, "logs", nvroot, 0, B_TRUE); 609185029Spjd } 610185029Spjd 611168404Spjd ret = 0; 612168404Spjd } else { 613168404Spjd ret = (zpool_add(zhp, nvroot) != 0); 614168404Spjd } 615168404Spjd 616168404Spjd nvlist_free(nvroot); 617168404Spjd zpool_close(zhp); 618168404Spjd 619168404Spjd return (ret); 620168404Spjd} 621168404Spjd 622168404Spjd/* 623219089Spjd * zpool remove <pool> <vdev> ... 624168404Spjd * 625332525Smav * Removes the given vdev from the pool. 626168404Spjd */ 627168404Spjdint 628168404Spjdzpool_do_remove(int argc, char **argv) 629168404Spjd{ 630168404Spjd char *poolname; 631185029Spjd int i, ret = 0; 632168404Spjd zpool_handle_t *zhp; 633332525Smav boolean_t stop = B_FALSE; 634332525Smav boolean_t noop = B_FALSE; 635332525Smav boolean_t parsable = B_FALSE; 636332525Smav char c; 637168404Spjd 638332525Smav /* check options */ 639332525Smav while ((c = getopt(argc, argv, "nps")) != -1) { 640332525Smav switch (c) { 641332525Smav case 'n': 642332525Smav noop = B_TRUE; 643332525Smav break; 644332525Smav case 'p': 645332525Smav parsable = B_TRUE; 646332525Smav break; 647332525Smav case 's': 648332525Smav stop = B_TRUE; 649332525Smav break; 650332525Smav case '?': 651332525Smav (void) fprintf(stderr, gettext("invalid option '%c'\n"), 652332525Smav optopt); 653332525Smav usage(B_FALSE); 654332525Smav } 655332525Smav } 656168404Spjd 657332525Smav argc -= optind; 658332525Smav argv += optind; 659332525Smav 660168404Spjd /* get pool name and check number of arguments */ 661168404Spjd if (argc < 1) { 662168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 663168404Spjd usage(B_FALSE); 664168404Spjd } 665168404Spjd 666168404Spjd poolname = argv[0]; 667168404Spjd 668168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 669168404Spjd return (1); 670168404Spjd 671332525Smav if (stop && noop) { 672332525Smav (void) fprintf(stderr, gettext("stop request ignored\n")); 673332525Smav return (0); 674332525Smav } 675332525Smav 676332525Smav if (stop) { 677332525Smav if (argc > 1) { 678332525Smav (void) fprintf(stderr, gettext("too many arguments\n")); 679332525Smav usage(B_FALSE); 680332525Smav } 681332525Smav if (zpool_vdev_remove_cancel(zhp) != 0) 682185029Spjd ret = 1; 683332525Smav } else { 684332525Smav if (argc < 2) { 685332525Smav (void) fprintf(stderr, gettext("missing device\n")); 686332525Smav usage(B_FALSE); 687332525Smav } 688332525Smav 689332525Smav for (i = 1; i < argc; i++) { 690332525Smav if (noop) { 691332525Smav uint64_t size; 692332525Smav 693332525Smav if (zpool_vdev_indirect_size(zhp, argv[i], 694332525Smav &size) != 0) { 695332525Smav ret = 1; 696332525Smav break; 697332525Smav } 698332525Smav if (parsable) { 699332525Smav (void) printf("%s %llu\n", 700332525Smav argv[i], size); 701332525Smav } else { 702332525Smav char valstr[32]; 703332525Smav zfs_nicenum(size, valstr, 704332525Smav sizeof (valstr)); 705332525Smav (void) printf("Memory that will be " 706332525Smav "used after removing %s: %s\n", 707332525Smav argv[i], valstr); 708332525Smav } 709332525Smav } else { 710332525Smav if (zpool_vdev_remove(zhp, argv[i]) != 0) 711332525Smav ret = 1; 712332525Smav } 713332525Smav } 714168404Spjd } 715168404Spjd 716168404Spjd return (ret); 717168404Spjd} 718168404Spjd 719168404Spjd/* 720297763Smav * zpool labelclear [-f] <vdev> 721224171Sgibbs * 722297763Smav * -f Force clearing the label for the vdevs which are members of 723297763Smav * the exported or foreign pools. 724297763Smav * 725224171Sgibbs * Verifies that the vdev is not active and zeros out the label information 726224171Sgibbs * on the device. 727224171Sgibbs */ 728224171Sgibbsint 729224171Sgibbszpool_do_labelclear(int argc, char **argv) 730224171Sgibbs{ 731297763Smav char vdev[MAXPATHLEN]; 732297763Smav char *name = NULL; 733297763Smav struct stat st; 734297763Smav int c, fd, ret = 0; 735297763Smav nvlist_t *config; 736224171Sgibbs pool_state_t state; 737224171Sgibbs boolean_t inuse = B_FALSE; 738224171Sgibbs boolean_t force = B_FALSE; 739224171Sgibbs 740224171Sgibbs /* check options */ 741224171Sgibbs while ((c = getopt(argc, argv, "f")) != -1) { 742224171Sgibbs switch (c) { 743224171Sgibbs case 'f': 744224171Sgibbs force = B_TRUE; 745224171Sgibbs break; 746224171Sgibbs default: 747224171Sgibbs (void) fprintf(stderr, gettext("invalid option '%c'\n"), 748224171Sgibbs optopt); 749224171Sgibbs usage(B_FALSE); 750224171Sgibbs } 751224171Sgibbs } 752224171Sgibbs 753224171Sgibbs argc -= optind; 754224171Sgibbs argv += optind; 755224171Sgibbs 756224171Sgibbs /* get vdev name */ 757224171Sgibbs if (argc < 1) { 758297763Smav (void) fprintf(stderr, gettext("missing vdev name\n")); 759224171Sgibbs usage(B_FALSE); 760224171Sgibbs } 761297763Smav if (argc > 1) { 762297763Smav (void) fprintf(stderr, gettext("too many arguments\n")); 763297763Smav usage(B_FALSE); 764297763Smav } 765224171Sgibbs 766297763Smav /* 767297763Smav * Check if we were given absolute path and use it as is. 768297763Smav * Otherwise if the provided vdev name doesn't point to a file, 769297763Smav * try prepending dsk path and appending s0. 770297763Smav */ 771297763Smav (void) strlcpy(vdev, argv[0], sizeof (vdev)); 772297763Smav if (vdev[0] != '/' && stat(vdev, &st) != 0) { 773297763Smav char *s; 774297763Smav 775297763Smav (void) snprintf(vdev, sizeof (vdev), "%s/%s", 776297763Smav#ifdef illumos 777297763Smav ZFS_DISK_ROOT, argv[0]); 778297763Smav if ((s = strrchr(argv[0], 's')) == NULL || 779297763Smav !isdigit(*(s + 1))) 780297763Smav (void) strlcat(vdev, "s0", sizeof (vdev)); 781297763Smav#else 782297763Smav "/dev", argv[0]); 783297763Smav#endif 784297763Smav if (stat(vdev, &st) != 0) { 785297763Smav (void) fprintf(stderr, gettext( 786297763Smav "failed to find device %s, try specifying absolute " 787297763Smav "path instead\n"), argv[0]); 788297763Smav return (1); 789297763Smav } 790297763Smav } 791297763Smav 792224171Sgibbs if ((fd = open(vdev, O_RDWR)) < 0) { 793297763Smav (void) fprintf(stderr, gettext("failed to open %s: %s\n"), 794297763Smav vdev, strerror(errno)); 795297763Smav return (1); 796224171Sgibbs } 797224171Sgibbs 798324255Savg if (zpool_read_label(fd, &config) != 0) { 799224171Sgibbs (void) fprintf(stderr, 800297763Smav gettext("failed to read label from %s\n"), vdev); 801297763Smav return (1); 802297763Smav } 803297763Smav nvlist_free(config); 804224171Sgibbs 805297763Smav ret = zpool_in_use(g_zfs, fd, &state, &name, &inuse); 806297763Smav if (ret != 0) { 807297763Smav (void) fprintf(stderr, 808297763Smav gettext("failed to check state for %s\n"), vdev); 809224171Sgibbs return (1); 810224171Sgibbs } 811224171Sgibbs 812297763Smav if (!inuse) 813297763Smav goto wipe_label; 814224171Sgibbs 815297763Smav switch (state) { 816297763Smav default: 817297763Smav case POOL_STATE_ACTIVE: 818297763Smav case POOL_STATE_SPARE: 819297763Smav case POOL_STATE_L2CACHE: 820297763Smav (void) fprintf(stderr, gettext( 821297763Smav "%s is a member (%s) of pool \"%s\"\n"), 822297763Smav vdev, zpool_pool_state_to_name(state), name); 823297763Smav ret = 1; 824297763Smav goto errout; 825224171Sgibbs 826297763Smav case POOL_STATE_EXPORTED: 827297763Smav if (force) 828297763Smav break; 829297763Smav (void) fprintf(stderr, gettext( 830297763Smav "use '-f' to override the following error:\n" 831297763Smav "%s is a member of exported pool \"%s\"\n"), 832297763Smav vdev, name); 833297763Smav ret = 1; 834297763Smav goto errout; 835224171Sgibbs 836297763Smav case POOL_STATE_POTENTIALLY_ACTIVE: 837297763Smav if (force) 838297763Smav break; 839297763Smav (void) fprintf(stderr, gettext( 840297763Smav "use '-f' to override the following error:\n" 841297763Smav "%s is a member of potentially active pool \"%s\"\n"), 842297763Smav vdev, name); 843297763Smav ret = 1; 844297763Smav goto errout; 845224171Sgibbs 846297763Smav case POOL_STATE_DESTROYED: 847297763Smav /* inuse should never be set for a destroyed pool */ 848297763Smav assert(0); 849297763Smav break; 850224171Sgibbs } 851224171Sgibbs 852224171Sgibbswipe_label: 853297763Smav ret = zpool_clear_label(fd); 854297763Smav if (ret != 0) { 855224171Sgibbs (void) fprintf(stderr, 856297763Smav gettext("failed to clear label for %s\n"), vdev); 857224171Sgibbs } 858224171Sgibbs 859224171Sgibbserrout: 860297763Smav free(name); 861297763Smav (void) close(fd); 862224171Sgibbs 863224171Sgibbs return (ret); 864224171Sgibbs} 865224171Sgibbs 866224171Sgibbs/* 867331395Smav * zpool create [-fnd] [-B] [-o property=value] ... 868185029Spjd * [-O file-system-property=value] ... 869333194Savg * [-R root] [-m mountpoint] [-t tempname] <pool> <dev> ... 870168404Spjd * 871331395Smav * -B Create boot partition. 872168404Spjd * -f Force creation, even if devices appear in use 873168404Spjd * -n Do not create the pool, but display the resulting layout if it 874168404Spjd * were to be created. 875333194Savg * -R Create a pool under an alternate root 876333194Savg * -m Set default mountpoint for the root dataset. By default it's 877236884Smm * '/<pool>' 878333194Savg * -t Use the temporary name until the pool is exported. 879185029Spjd * -o Set property=value. 880236884Smm * -d Don't automatically enable all supported pool features 881236884Smm * (individual features can be enabled with -o). 882185029Spjd * -O Set fsproperty=value in the pool's root file system 883168404Spjd * 884168404Spjd * Creates the named pool according to the given vdev specification. The 885168404Spjd * bulk of the vdev processing is done in get_vdev_spec() in zpool_vdev.c. Once 886168404Spjd * we get the nvlist back from get_vdev_spec(), we either print out the contents 887168404Spjd * (if '-n' was specified), or pass it to libzfs to do the creation. 888168404Spjd */ 889331395Smav 890331395Smav#define SYSTEM256 (256 * 1024 * 1024) 891168404Spjdint 892168404Spjdzpool_do_create(int argc, char **argv) 893168404Spjd{ 894168404Spjd boolean_t force = B_FALSE; 895168404Spjd boolean_t dryrun = B_FALSE; 896236884Smm boolean_t enable_all_pool_feat = B_TRUE; 897331395Smav zpool_boot_label_t boot_type = ZPOOL_NO_BOOT_LABEL; 898331395Smav uint64_t boot_size = 0; 899168404Spjd int c; 900185029Spjd nvlist_t *nvroot = NULL; 901168404Spjd char *poolname; 902333194Savg char *tname = NULL; 903185029Spjd int ret = 1; 904168404Spjd char *altroot = NULL; 905168404Spjd char *mountpoint = NULL; 906185029Spjd nvlist_t *fsprops = NULL; 907185029Spjd nvlist_t *props = NULL; 908185029Spjd char *propval; 909168404Spjd 910168404Spjd /* check options */ 911333194Savg while ((c = getopt(argc, argv, ":fndBR:m:o:O:t:")) != -1) { 912168404Spjd switch (c) { 913168404Spjd case 'f': 914168404Spjd force = B_TRUE; 915168404Spjd break; 916168404Spjd case 'n': 917168404Spjd dryrun = B_TRUE; 918168404Spjd break; 919236884Smm case 'd': 920236884Smm enable_all_pool_feat = B_FALSE; 921236884Smm break; 922331395Smav case 'B': 923331395Smav#ifdef illumos 924331395Smav /* 925331395Smav * We should create the system partition. 926331395Smav * Also make sure the size is set. 927331395Smav */ 928331395Smav boot_type = ZPOOL_CREATE_BOOT_LABEL; 929331395Smav if (boot_size == 0) 930331395Smav boot_size = SYSTEM256; 931331395Smav break; 932331395Smav#else 933331395Smav (void) fprintf(stderr, 934331395Smav gettext("option '%c' is not supported\n"), 935331395Smav optopt); 936331395Smav goto badusage; 937331395Smav#endif 938168404Spjd case 'R': 939168404Spjd altroot = optarg; 940185029Spjd if (add_prop_list(zpool_prop_to_name( 941185029Spjd ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE)) 942185029Spjd goto errout; 943333194Savg if (add_prop_list_default(zpool_prop_to_name( 944185029Spjd ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE)) 945185029Spjd goto errout; 946168404Spjd break; 947168404Spjd case 'm': 948251634Sdelphij /* Equivalent to -O mountpoint=optarg */ 949168404Spjd mountpoint = optarg; 950168404Spjd break; 951185029Spjd case 'o': 952185029Spjd if ((propval = strchr(optarg, '=')) == NULL) { 953185029Spjd (void) fprintf(stderr, gettext("missing " 954185029Spjd "'=' for -o option\n")); 955185029Spjd goto errout; 956185029Spjd } 957185029Spjd *propval = '\0'; 958185029Spjd propval++; 959185029Spjd 960185029Spjd if (add_prop_list(optarg, propval, &props, B_TRUE)) 961185029Spjd goto errout; 962236884Smm 963236884Smm /* 964331395Smav * Get bootsize value for make_root_vdev(). 965331395Smav */ 966331395Smav if (zpool_name_to_prop(optarg) == ZPOOL_PROP_BOOTSIZE) { 967331395Smav if (zfs_nicestrtonum(g_zfs, propval, 968331395Smav &boot_size) < 0 || boot_size == 0) { 969331395Smav (void) fprintf(stderr, 970331395Smav gettext("bad boot partition size " 971331395Smav "'%s': %s\n"), propval, 972331395Smav libzfs_error_description(g_zfs)); 973331395Smav goto errout; 974331395Smav } 975331395Smav } 976331395Smav 977331395Smav /* 978236884Smm * If the user is creating a pool that doesn't support 979236884Smm * feature flags, don't enable any features. 980236884Smm */ 981236884Smm if (zpool_name_to_prop(optarg) == ZPOOL_PROP_VERSION) { 982236884Smm char *end; 983236884Smm u_longlong_t ver; 984236884Smm 985236884Smm ver = strtoull(propval, &end, 10); 986236884Smm if (*end == '\0' && 987236884Smm ver < SPA_VERSION_FEATURES) { 988236884Smm enable_all_pool_feat = B_FALSE; 989236884Smm } 990236884Smm } 991279366Sdelphij if (zpool_name_to_prop(optarg) == ZPOOL_PROP_ALTROOT) 992279366Sdelphij altroot = propval; 993185029Spjd break; 994185029Spjd case 'O': 995185029Spjd if ((propval = strchr(optarg, '=')) == NULL) { 996185029Spjd (void) fprintf(stderr, gettext("missing " 997185029Spjd "'=' for -O option\n")); 998185029Spjd goto errout; 999185029Spjd } 1000185029Spjd *propval = '\0'; 1001185029Spjd propval++; 1002185029Spjd 1003251634Sdelphij /* 1004251634Sdelphij * Mountpoints are checked and then added later. 1005251634Sdelphij * Uniquely among properties, they can be specified 1006251634Sdelphij * more than once, to avoid conflict with -m. 1007251634Sdelphij */ 1008251634Sdelphij if (0 == strcmp(optarg, 1009251634Sdelphij zfs_prop_to_name(ZFS_PROP_MOUNTPOINT))) { 1010251634Sdelphij mountpoint = propval; 1011251634Sdelphij } else if (add_prop_list(optarg, propval, &fsprops, 1012251634Sdelphij B_FALSE)) { 1013185029Spjd goto errout; 1014251634Sdelphij } 1015185029Spjd break; 1016333194Savg case 't': 1017333194Savg /* 1018333194Savg * Sanity check temporary pool name. 1019333194Savg */ 1020333194Savg if (strchr(optarg, '/') != NULL) { 1021333194Savg (void) fprintf(stderr, gettext("cannot create " 1022333194Savg "'%s': invalid character '/' in temporary " 1023333194Savg "name\n"), optarg); 1024333194Savg (void) fprintf(stderr, gettext("use 'zfs " 1025333194Savg "create' to create a dataset\n")); 1026333194Savg goto errout; 1027333194Savg } 1028333194Savg 1029333194Savg if (add_prop_list(zpool_prop_to_name( 1030333194Savg ZPOOL_PROP_TNAME), optarg, &props, B_TRUE)) 1031333194Savg goto errout; 1032333194Savg if (add_prop_list_default(zpool_prop_to_name( 1033333194Savg ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE)) 1034333194Savg goto errout; 1035333194Savg tname = optarg; 1036333194Savg break; 1037168404Spjd case ':': 1038168404Spjd (void) fprintf(stderr, gettext("missing argument for " 1039168404Spjd "'%c' option\n"), optopt); 1040185029Spjd goto badusage; 1041168404Spjd case '?': 1042168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1043168404Spjd optopt); 1044185029Spjd goto badusage; 1045168404Spjd } 1046168404Spjd } 1047168404Spjd 1048168404Spjd argc -= optind; 1049168404Spjd argv += optind; 1050168404Spjd 1051168404Spjd /* get pool name and check number of arguments */ 1052168404Spjd if (argc < 1) { 1053168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 1054185029Spjd goto badusage; 1055168404Spjd } 1056168404Spjd if (argc < 2) { 1057168404Spjd (void) fprintf(stderr, gettext("missing vdev specification\n")); 1058185029Spjd goto badusage; 1059168404Spjd } 1060168404Spjd 1061168404Spjd poolname = argv[0]; 1062168404Spjd 1063168404Spjd /* 1064168404Spjd * As a special case, check for use of '/' in the name, and direct the 1065168404Spjd * user to use 'zfs create' instead. 1066168404Spjd */ 1067168404Spjd if (strchr(poolname, '/') != NULL) { 1068168404Spjd (void) fprintf(stderr, gettext("cannot create '%s': invalid " 1069168404Spjd "character '/' in pool name\n"), poolname); 1070168404Spjd (void) fprintf(stderr, gettext("use 'zfs create' to " 1071168404Spjd "create a dataset\n")); 1072185029Spjd goto errout; 1073168404Spjd } 1074168404Spjd 1075331395Smav /* 1076331395Smav * Make sure the bootsize is set when ZPOOL_CREATE_BOOT_LABEL is used, 1077331395Smav * and not set otherwise. 1078331395Smav */ 1079331395Smav if (boot_type == ZPOOL_CREATE_BOOT_LABEL) { 1080331395Smav const char *propname; 1081331395Smav char *strptr, *buf = NULL; 1082331395Smav int rv; 1083331395Smav 1084331395Smav propname = zpool_prop_to_name(ZPOOL_PROP_BOOTSIZE); 1085331395Smav if (nvlist_lookup_string(props, propname, &strptr) != 0) { 1086331395Smav (void) asprintf(&buf, "%" PRIu64, boot_size); 1087331395Smav if (buf == NULL) { 1088331395Smav (void) fprintf(stderr, 1089331395Smav gettext("internal error: out of memory\n")); 1090331395Smav goto errout; 1091331395Smav } 1092331395Smav rv = add_prop_list(propname, buf, &props, B_TRUE); 1093331395Smav free(buf); 1094331395Smav if (rv != 0) 1095331395Smav goto errout; 1096331395Smav } 1097331395Smav } else { 1098331395Smav const char *propname; 1099331395Smav char *strptr; 1100331395Smav 1101331395Smav propname = zpool_prop_to_name(ZPOOL_PROP_BOOTSIZE); 1102331395Smav if (nvlist_lookup_string(props, propname, &strptr) == 0) { 1103331395Smav (void) fprintf(stderr, gettext("error: setting boot " 1104331395Smav "partition size requires option '-B'\n")); 1105331395Smav goto errout; 1106331395Smav } 1107331395Smav } 1108331395Smav 1109168404Spjd /* pass off to get_vdev_spec for bulk processing */ 1110185029Spjd nvroot = make_root_vdev(NULL, force, !force, B_FALSE, dryrun, 1111331395Smav boot_type, boot_size, argc - 1, argv + 1); 1112168404Spjd if (nvroot == NULL) 1113185029Spjd goto errout; 1114168404Spjd 1115168404Spjd /* make_root_vdev() allows 0 toplevel children if there are spares */ 1116185029Spjd if (!zfs_allocatable_devs(nvroot)) { 1117168404Spjd (void) fprintf(stderr, gettext("invalid vdev " 1118168404Spjd "specification: at least one toplevel vdev must be " 1119168404Spjd "specified\n")); 1120185029Spjd goto errout; 1121168404Spjd } 1122168404Spjd 1123168404Spjd if (altroot != NULL && altroot[0] != '/') { 1124168404Spjd (void) fprintf(stderr, gettext("invalid alternate root '%s': " 1125168404Spjd "must be an absolute path\n"), altroot); 1126185029Spjd goto errout; 1127168404Spjd } 1128168404Spjd 1129168404Spjd /* 1130168404Spjd * Check the validity of the mountpoint and direct the user to use the 1131168404Spjd * '-m' mountpoint option if it looks like its in use. 1132244857Spjd * Ignore the checks if the '-f' option is given. 1133168404Spjd */ 1134244857Spjd if (!force && (mountpoint == NULL || 1135168404Spjd (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0 && 1136244857Spjd strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) != 0))) { 1137168404Spjd char buf[MAXPATHLEN]; 1138185029Spjd DIR *dirp; 1139168404Spjd 1140168404Spjd if (mountpoint && mountpoint[0] != '/') { 1141168404Spjd (void) fprintf(stderr, gettext("invalid mountpoint " 1142168404Spjd "'%s': must be an absolute path, 'legacy', or " 1143168404Spjd "'none'\n"), mountpoint); 1144185029Spjd goto errout; 1145168404Spjd } 1146168404Spjd 1147168404Spjd if (mountpoint == NULL) { 1148168404Spjd if (altroot != NULL) 1149168404Spjd (void) snprintf(buf, sizeof (buf), "%s/%s", 1150168404Spjd altroot, poolname); 1151168404Spjd else 1152168404Spjd (void) snprintf(buf, sizeof (buf), "/%s", 1153168404Spjd poolname); 1154168404Spjd } else { 1155168404Spjd if (altroot != NULL) 1156168404Spjd (void) snprintf(buf, sizeof (buf), "%s%s", 1157168404Spjd altroot, mountpoint); 1158168404Spjd else 1159168404Spjd (void) snprintf(buf, sizeof (buf), "%s", 1160168404Spjd mountpoint); 1161168404Spjd } 1162168404Spjd 1163185029Spjd if ((dirp = opendir(buf)) == NULL && errno != ENOENT) { 1164185029Spjd (void) fprintf(stderr, gettext("mountpoint '%s' : " 1165185029Spjd "%s\n"), buf, strerror(errno)); 1166185029Spjd (void) fprintf(stderr, gettext("use '-m' " 1167185029Spjd "option to provide a different default\n")); 1168185029Spjd goto errout; 1169185029Spjd } else if (dirp) { 1170185029Spjd int count = 0; 1171185029Spjd 1172185029Spjd while (count < 3 && readdir(dirp) != NULL) 1173185029Spjd count++; 1174185029Spjd (void) closedir(dirp); 1175185029Spjd 1176185029Spjd if (count > 2) { 1177168404Spjd (void) fprintf(stderr, gettext("mountpoint " 1178168404Spjd "'%s' exists and is not empty\n"), buf); 1179185029Spjd (void) fprintf(stderr, gettext("use '-m' " 1180185029Spjd "option to provide a " 1181185029Spjd "different default\n")); 1182185029Spjd goto errout; 1183185029Spjd } 1184168404Spjd } 1185168404Spjd } 1186168404Spjd 1187251634Sdelphij /* 1188251634Sdelphij * Now that the mountpoint's validity has been checked, ensure that 1189251634Sdelphij * the property is set appropriately prior to creating the pool. 1190251634Sdelphij */ 1191251634Sdelphij if (mountpoint != NULL) { 1192251634Sdelphij ret = add_prop_list(zfs_prop_to_name(ZFS_PROP_MOUNTPOINT), 1193251634Sdelphij mountpoint, &fsprops, B_FALSE); 1194251634Sdelphij if (ret != 0) 1195251634Sdelphij goto errout; 1196251634Sdelphij } 1197251634Sdelphij 1198251634Sdelphij ret = 1; 1199168404Spjd if (dryrun) { 1200168404Spjd /* 1201168404Spjd * For a dry run invocation, print out a basic message and run 1202168404Spjd * through all the vdevs in the list and print out in an 1203168404Spjd * appropriate hierarchy. 1204168404Spjd */ 1205168404Spjd (void) printf(gettext("would create '%s' with the " 1206168404Spjd "following layout:\n\n"), poolname); 1207168404Spjd 1208185029Spjd print_vdev_tree(NULL, poolname, nvroot, 0, B_FALSE); 1209185029Spjd if (num_logs(nvroot) > 0) 1210185029Spjd print_vdev_tree(NULL, "logs", nvroot, 0, B_TRUE); 1211168404Spjd 1212168404Spjd ret = 0; 1213168404Spjd } else { 1214168404Spjd /* 1215168404Spjd * Hand off to libzfs. 1216168404Spjd */ 1217236884Smm if (enable_all_pool_feat) { 1218259813Sdelphij spa_feature_t i; 1219236884Smm for (i = 0; i < SPA_FEATURES; i++) { 1220236884Smm char propname[MAXPATHLEN]; 1221236884Smm zfeature_info_t *feat = &spa_feature_table[i]; 1222236884Smm 1223236884Smm (void) snprintf(propname, sizeof (propname), 1224236884Smm "feature@%s", feat->fi_uname); 1225236884Smm 1226236884Smm /* 1227236884Smm * Skip feature if user specified it manually 1228236884Smm * on the command line. 1229236884Smm */ 1230236884Smm if (nvlist_exists(props, propname)) 1231236884Smm continue; 1232236884Smm 1233251634Sdelphij ret = add_prop_list(propname, 1234251634Sdelphij ZFS_FEATURE_ENABLED, &props, B_TRUE); 1235251634Sdelphij if (ret != 0) 1236236884Smm goto errout; 1237236884Smm } 1238236884Smm } 1239251634Sdelphij 1240251634Sdelphij ret = 1; 1241185029Spjd if (zpool_create(g_zfs, poolname, 1242185029Spjd nvroot, props, fsprops) == 0) { 1243333194Savg zfs_handle_t *pool = zfs_open(g_zfs, 1244333194Savg tname ? tname : poolname, ZFS_TYPE_FILESYSTEM); 1245168404Spjd if (pool != NULL) { 1246168404Spjd if (zfs_mount(pool, NULL, 0) == 0) 1247185029Spjd ret = zfs_shareall(pool); 1248168404Spjd zfs_close(pool); 1249168404Spjd } 1250168404Spjd } else if (libzfs_errno(g_zfs) == EZFS_INVALIDNAME) { 1251168404Spjd (void) fprintf(stderr, gettext("pool name may have " 1252168404Spjd "been omitted\n")); 1253168404Spjd } 1254168404Spjd } 1255168404Spjd 1256185029Spjderrout: 1257168404Spjd nvlist_free(nvroot); 1258185029Spjd nvlist_free(fsprops); 1259185029Spjd nvlist_free(props); 1260168404Spjd return (ret); 1261185029Spjdbadusage: 1262185029Spjd nvlist_free(fsprops); 1263185029Spjd nvlist_free(props); 1264185029Spjd usage(B_FALSE); 1265185029Spjd return (2); 1266168404Spjd} 1267168404Spjd 1268168404Spjd/* 1269168404Spjd * zpool destroy <pool> 1270168404Spjd * 1271168404Spjd * -f Forcefully unmount any datasets 1272168404Spjd * 1273168404Spjd * Destroy the given pool. Automatically unmounts any datasets in the pool. 1274168404Spjd */ 1275168404Spjdint 1276168404Spjdzpool_do_destroy(int argc, char **argv) 1277168404Spjd{ 1278168404Spjd boolean_t force = B_FALSE; 1279168404Spjd int c; 1280168404Spjd char *pool; 1281168404Spjd zpool_handle_t *zhp; 1282168404Spjd int ret; 1283168404Spjd 1284168404Spjd /* check options */ 1285168404Spjd while ((c = getopt(argc, argv, "f")) != -1) { 1286168404Spjd switch (c) { 1287168404Spjd case 'f': 1288168404Spjd force = B_TRUE; 1289168404Spjd break; 1290168404Spjd case '?': 1291168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1292168404Spjd optopt); 1293168404Spjd usage(B_FALSE); 1294168404Spjd } 1295168404Spjd } 1296168404Spjd 1297168404Spjd argc -= optind; 1298168404Spjd argv += optind; 1299168404Spjd 1300168404Spjd /* check arguments */ 1301168404Spjd if (argc < 1) { 1302168404Spjd (void) fprintf(stderr, gettext("missing pool argument\n")); 1303168404Spjd usage(B_FALSE); 1304168404Spjd } 1305168404Spjd if (argc > 1) { 1306168404Spjd (void) fprintf(stderr, gettext("too many arguments\n")); 1307168404Spjd usage(B_FALSE); 1308168404Spjd } 1309168404Spjd 1310168404Spjd pool = argv[0]; 1311168404Spjd 1312168404Spjd if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) { 1313168404Spjd /* 1314168404Spjd * As a special case, check for use of '/' in the name, and 1315168404Spjd * direct the user to use 'zfs destroy' instead. 1316168404Spjd */ 1317168404Spjd if (strchr(pool, '/') != NULL) 1318168404Spjd (void) fprintf(stderr, gettext("use 'zfs destroy' to " 1319168404Spjd "destroy a dataset\n")); 1320168404Spjd return (1); 1321168404Spjd } 1322168404Spjd 1323168404Spjd if (zpool_disable_datasets(zhp, force) != 0) { 1324168404Spjd (void) fprintf(stderr, gettext("could not destroy '%s': " 1325168404Spjd "could not unmount datasets\n"), zpool_get_name(zhp)); 1326168404Spjd return (1); 1327168404Spjd } 1328168404Spjd 1329248571Smm /* The history must be logged as part of the export */ 1330248571Smm log_history = B_FALSE; 1331168404Spjd 1332248571Smm ret = (zpool_destroy(zhp, history_str) != 0); 1333248571Smm 1334168404Spjd zpool_close(zhp); 1335168404Spjd 1336168404Spjd return (ret); 1337168404Spjd} 1338168404Spjd 1339168404Spjd/* 1340168404Spjd * zpool export [-f] <pool> ... 1341168404Spjd * 1342168404Spjd * -f Forcefully unmount datasets 1343168404Spjd * 1344168404Spjd * Export the given pools. By default, the command will attempt to cleanly 1345168404Spjd * unmount any active datasets within the pool. If the '-f' flag is specified, 1346168404Spjd * then the datasets will be forcefully unmounted. 1347168404Spjd */ 1348168404Spjdint 1349168404Spjdzpool_do_export(int argc, char **argv) 1350168404Spjd{ 1351168404Spjd boolean_t force = B_FALSE; 1352207670Smm boolean_t hardforce = B_FALSE; 1353168404Spjd int c; 1354168404Spjd zpool_handle_t *zhp; 1355168404Spjd int ret; 1356168404Spjd int i; 1357168404Spjd 1358168404Spjd /* check options */ 1359207670Smm while ((c = getopt(argc, argv, "fF")) != -1) { 1360168404Spjd switch (c) { 1361168404Spjd case 'f': 1362168404Spjd force = B_TRUE; 1363168404Spjd break; 1364207670Smm case 'F': 1365207670Smm hardforce = B_TRUE; 1366207670Smm break; 1367168404Spjd case '?': 1368168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 1369168404Spjd optopt); 1370168404Spjd usage(B_FALSE); 1371168404Spjd } 1372168404Spjd } 1373168404Spjd 1374168404Spjd argc -= optind; 1375168404Spjd argv += optind; 1376168404Spjd 1377168404Spjd /* check arguments */ 1378168404Spjd if (argc < 1) { 1379168404Spjd (void) fprintf(stderr, gettext("missing pool argument\n")); 1380168404Spjd usage(B_FALSE); 1381168404Spjd } 1382168404Spjd 1383168404Spjd ret = 0; 1384168404Spjd for (i = 0; i < argc; i++) { 1385168404Spjd if ((zhp = zpool_open_canfail(g_zfs, argv[i])) == NULL) { 1386168404Spjd ret = 1; 1387168404Spjd continue; 1388168404Spjd } 1389168404Spjd 1390168404Spjd if (zpool_disable_datasets(zhp, force) != 0) { 1391168404Spjd ret = 1; 1392168404Spjd zpool_close(zhp); 1393168404Spjd continue; 1394168404Spjd } 1395168404Spjd 1396248571Smm /* The history must be logged as part of the export */ 1397248571Smm log_history = B_FALSE; 1398248571Smm 1399207670Smm if (hardforce) { 1400248571Smm if (zpool_export_force(zhp, history_str) != 0) 1401207670Smm ret = 1; 1402248571Smm } else if (zpool_export(zhp, force, history_str) != 0) { 1403168404Spjd ret = 1; 1404207670Smm } 1405168404Spjd 1406168404Spjd zpool_close(zhp); 1407168404Spjd } 1408168404Spjd 1409168404Spjd return (ret); 1410168404Spjd} 1411168404Spjd 1412168404Spjd/* 1413168404Spjd * Given a vdev configuration, determine the maximum width needed for the device 1414168404Spjd * name column. 1415168404Spjd */ 1416168404Spjdstatic int 1417168404Spjdmax_width(zpool_handle_t *zhp, nvlist_t *nv, int depth, int max) 1418168404Spjd{ 1419219089Spjd char *name = zpool_vdev_name(g_zfs, zhp, nv, B_TRUE); 1420168404Spjd nvlist_t **child; 1421168404Spjd uint_t c, children; 1422168404Spjd int ret; 1423168404Spjd 1424168404Spjd if (strlen(name) + depth > max) 1425168404Spjd max = strlen(name) + depth; 1426168404Spjd 1427168404Spjd free(name); 1428168404Spjd 1429168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, 1430168404Spjd &child, &children) == 0) { 1431168404Spjd for (c = 0; c < children; c++) 1432168404Spjd if ((ret = max_width(zhp, child[c], depth + 2, 1433168404Spjd max)) > max) 1434168404Spjd max = ret; 1435168404Spjd } 1436168404Spjd 1437185029Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE, 1438185029Spjd &child, &children) == 0) { 1439185029Spjd for (c = 0; c < children; c++) 1440185029Spjd if ((ret = max_width(zhp, child[c], depth + 2, 1441185029Spjd max)) > max) 1442185029Spjd max = ret; 1443185029Spjd } 1444185029Spjd 1445168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 1446168404Spjd &child, &children) == 0) { 1447168404Spjd for (c = 0; c < children; c++) 1448168404Spjd if ((ret = max_width(zhp, child[c], depth + 2, 1449168404Spjd max)) > max) 1450168404Spjd max = ret; 1451168404Spjd } 1452168404Spjd 1453168404Spjd 1454168404Spjd return (max); 1455168404Spjd} 1456168404Spjd 1457213197Smmtypedef struct spare_cbdata { 1458213197Smm uint64_t cb_guid; 1459213197Smm zpool_handle_t *cb_zhp; 1460213197Smm} spare_cbdata_t; 1461168404Spjd 1462213197Smmstatic boolean_t 1463213197Smmfind_vdev(nvlist_t *nv, uint64_t search) 1464213197Smm{ 1465213197Smm uint64_t guid; 1466213197Smm nvlist_t **child; 1467213197Smm uint_t c, children; 1468213197Smm 1469213197Smm if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &guid) == 0 && 1470213197Smm search == guid) 1471213197Smm return (B_TRUE); 1472213197Smm 1473213197Smm if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 1474213197Smm &child, &children) == 0) { 1475213197Smm for (c = 0; c < children; c++) 1476213197Smm if (find_vdev(child[c], search)) 1477213197Smm return (B_TRUE); 1478213197Smm } 1479213197Smm 1480213197Smm return (B_FALSE); 1481213197Smm} 1482213197Smm 1483213197Smmstatic int 1484213197Smmfind_spare(zpool_handle_t *zhp, void *data) 1485213197Smm{ 1486213197Smm spare_cbdata_t *cbp = data; 1487213197Smm nvlist_t *config, *nvroot; 1488213197Smm 1489213197Smm config = zpool_get_config(zhp, NULL); 1490213197Smm verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 1491213197Smm &nvroot) == 0); 1492213197Smm 1493213197Smm if (find_vdev(nvroot, cbp->cb_guid)) { 1494213197Smm cbp->cb_zhp = zhp; 1495213197Smm return (1); 1496213197Smm } 1497213197Smm 1498213197Smm zpool_close(zhp); 1499213197Smm return (0); 1500213197Smm} 1501213197Smm 1502168404Spjd/* 1503213197Smm * Print out configuration state as requested by status_callback. 1504213197Smm */ 1505213197Smmvoid 1506213197Smmprint_status_config(zpool_handle_t *zhp, const char *name, nvlist_t *nv, 1507213197Smm int namewidth, int depth, boolean_t isspare) 1508213197Smm{ 1509213197Smm nvlist_t **child; 1510254591Sgibbs uint_t c, vsc, children; 1511219089Spjd pool_scan_stat_t *ps = NULL; 1512213197Smm vdev_stat_t *vs; 1513219089Spjd char rbuf[6], wbuf[6], cbuf[6]; 1514213197Smm char *vname; 1515213197Smm uint64_t notpresent; 1516254591Sgibbs uint64_t ashift; 1517213197Smm spare_cbdata_t cb; 1518224169Sgibbs const char *state; 1519332525Smav char *type; 1520213197Smm 1521213197Smm if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 1522213197Smm &child, &children) != 0) 1523213197Smm children = 0; 1524213197Smm 1525219089Spjd verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS, 1526254591Sgibbs (uint64_t **)&vs, &vsc) == 0); 1527219089Spjd 1528332525Smav verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0); 1529332525Smav 1530332525Smav if (strcmp(type, VDEV_TYPE_INDIRECT) == 0) 1531332525Smav return; 1532332525Smav 1533213197Smm state = zpool_state_to_name(vs->vs_state, vs->vs_aux); 1534213197Smm if (isspare) { 1535213197Smm /* 1536213197Smm * For hot spares, we use the terms 'INUSE' and 'AVAILABLE' for 1537213197Smm * online drives. 1538213197Smm */ 1539213197Smm if (vs->vs_aux == VDEV_AUX_SPARED) 1540213197Smm state = "INUSE"; 1541213197Smm else if (vs->vs_state == VDEV_STATE_HEALTHY) 1542213197Smm state = "AVAIL"; 1543213197Smm } 1544213197Smm 1545213197Smm (void) printf("\t%*s%-*s %-8s", depth, "", namewidth - depth, 1546213197Smm name, state); 1547213197Smm 1548213197Smm if (!isspare) { 1549213197Smm zfs_nicenum(vs->vs_read_errors, rbuf, sizeof (rbuf)); 1550213197Smm zfs_nicenum(vs->vs_write_errors, wbuf, sizeof (wbuf)); 1551213197Smm zfs_nicenum(vs->vs_checksum_errors, cbuf, sizeof (cbuf)); 1552213197Smm (void) printf(" %5s %5s %5s", rbuf, wbuf, cbuf); 1553213197Smm } 1554213197Smm 1555213197Smm if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT, 1556224170Sgibbs ¬present) == 0 || 1557224170Sgibbs vs->vs_state <= VDEV_STATE_CANT_OPEN) { 1558213197Smm char *path; 1559224170Sgibbs if (nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0) 1560224170Sgibbs (void) printf(" was %s", path); 1561213197Smm } else if (vs->vs_aux != 0) { 1562213197Smm (void) printf(" "); 1563213197Smm 1564213197Smm switch (vs->vs_aux) { 1565213197Smm case VDEV_AUX_OPEN_FAILED: 1566213197Smm (void) printf(gettext("cannot open")); 1567213197Smm break; 1568213197Smm 1569213197Smm case VDEV_AUX_BAD_GUID_SUM: 1570213197Smm (void) printf(gettext("missing device")); 1571213197Smm break; 1572213197Smm 1573213197Smm case VDEV_AUX_NO_REPLICAS: 1574213197Smm (void) printf(gettext("insufficient replicas")); 1575213197Smm break; 1576213197Smm 1577213197Smm case VDEV_AUX_VERSION_NEWER: 1578213197Smm (void) printf(gettext("newer version")); 1579213197Smm break; 1580213197Smm 1581236884Smm case VDEV_AUX_UNSUP_FEAT: 1582236884Smm (void) printf(gettext("unsupported feature(s)")); 1583236884Smm break; 1584236884Smm 1585254591Sgibbs case VDEV_AUX_ASHIFT_TOO_BIG: 1586254591Sgibbs (void) printf(gettext("unsupported minimum blocksize")); 1587254591Sgibbs break; 1588254591Sgibbs 1589213197Smm case VDEV_AUX_SPARED: 1590213197Smm verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, 1591213197Smm &cb.cb_guid) == 0); 1592213197Smm if (zpool_iter(g_zfs, find_spare, &cb) == 1) { 1593213197Smm if (strcmp(zpool_get_name(cb.cb_zhp), 1594213197Smm zpool_get_name(zhp)) == 0) 1595213197Smm (void) printf(gettext("currently in " 1596213197Smm "use")); 1597213197Smm else 1598213197Smm (void) printf(gettext("in use by " 1599213197Smm "pool '%s'"), 1600213197Smm zpool_get_name(cb.cb_zhp)); 1601213197Smm zpool_close(cb.cb_zhp); 1602213197Smm } else { 1603213197Smm (void) printf(gettext("currently in use")); 1604213197Smm } 1605213197Smm break; 1606213197Smm 1607213197Smm case VDEV_AUX_ERR_EXCEEDED: 1608213197Smm (void) printf(gettext("too many errors")); 1609213197Smm break; 1610213197Smm 1611213197Smm case VDEV_AUX_IO_FAILURE: 1612213197Smm (void) printf(gettext("experienced I/O failures")); 1613213197Smm break; 1614213197Smm 1615213197Smm case VDEV_AUX_BAD_LOG: 1616213197Smm (void) printf(gettext("bad intent log")); 1617213197Smm break; 1618213197Smm 1619219089Spjd case VDEV_AUX_EXTERNAL: 1620219089Spjd (void) printf(gettext("external device fault")); 1621219089Spjd break; 1622219089Spjd 1623219089Spjd case VDEV_AUX_SPLIT_POOL: 1624219089Spjd (void) printf(gettext("split into new pool")); 1625219089Spjd break; 1626219089Spjd 1627332536Smav case VDEV_AUX_CHILDREN_OFFLINE: 1628332536Smav (void) printf(gettext("all children offline")); 1629332536Smav break; 1630332536Smav 1631213197Smm default: 1632213197Smm (void) printf(gettext("corrupted data")); 1633213197Smm break; 1634213197Smm } 1635254591Sgibbs } else if (children == 0 && !isspare && 1636254591Sgibbs VDEV_STAT_VALID(vs_physical_ashift, vsc) && 1637254591Sgibbs vs->vs_configured_ashift < vs->vs_physical_ashift) { 1638254591Sgibbs (void) printf( 1639254591Sgibbs gettext(" block size: %dB configured, %dB native"), 1640254591Sgibbs 1 << vs->vs_configured_ashift, 1 << vs->vs_physical_ashift); 1641213197Smm } 1642213197Smm 1643219089Spjd (void) nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_SCAN_STATS, 1644219089Spjd (uint64_t **)&ps, &c); 1645219089Spjd 1646219089Spjd if (ps && ps->pss_state == DSS_SCANNING && 1647219089Spjd vs->vs_scan_processed != 0 && children == 0) { 1648219089Spjd (void) printf(gettext(" (%s)"), 1649219089Spjd (ps->pss_func == POOL_SCAN_RESILVER) ? 1650219089Spjd "resilvering" : "repairing"); 1651219089Spjd } 1652219089Spjd 1653213197Smm (void) printf("\n"); 1654213197Smm 1655213197Smm for (c = 0; c < children; c++) { 1656219089Spjd uint64_t islog = B_FALSE, ishole = B_FALSE; 1657213197Smm 1658219089Spjd /* Don't print logs or holes here */ 1659213197Smm (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 1660219089Spjd &islog); 1661219089Spjd (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_HOLE, 1662219089Spjd &ishole); 1663219089Spjd if (islog || ishole) 1664213197Smm continue; 1665219089Spjd vname = zpool_vdev_name(g_zfs, zhp, child[c], B_TRUE); 1666213197Smm print_status_config(zhp, vname, child[c], 1667213197Smm namewidth, depth + 2, isspare); 1668213197Smm free(vname); 1669213197Smm } 1670213197Smm} 1671213197Smm 1672213197Smm 1673213197Smm/* 1674168404Spjd * Print the configuration of an exported pool. Iterate over all vdevs in the 1675168404Spjd * pool, printing out the name and status for each one. 1676168404Spjd */ 1677168404Spjdvoid 1678213197Smmprint_import_config(const char *name, nvlist_t *nv, int namewidth, int depth) 1679168404Spjd{ 1680168404Spjd nvlist_t **child; 1681168404Spjd uint_t c, children; 1682168404Spjd vdev_stat_t *vs; 1683168404Spjd char *type, *vname; 1684168404Spjd 1685168404Spjd verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0); 1686219089Spjd if (strcmp(type, VDEV_TYPE_MISSING) == 0 || 1687219089Spjd strcmp(type, VDEV_TYPE_HOLE) == 0) 1688168404Spjd return; 1689168404Spjd 1690219089Spjd verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS, 1691168404Spjd (uint64_t **)&vs, &c) == 0); 1692168404Spjd 1693168404Spjd (void) printf("\t%*s%-*s", depth, "", namewidth - depth, name); 1694185029Spjd (void) printf(" %s", zpool_state_to_name(vs->vs_state, vs->vs_aux)); 1695168404Spjd 1696168404Spjd if (vs->vs_aux != 0) { 1697185029Spjd (void) printf(" "); 1698168404Spjd 1699168404Spjd switch (vs->vs_aux) { 1700168404Spjd case VDEV_AUX_OPEN_FAILED: 1701168404Spjd (void) printf(gettext("cannot open")); 1702168404Spjd break; 1703168404Spjd 1704168404Spjd case VDEV_AUX_BAD_GUID_SUM: 1705168404Spjd (void) printf(gettext("missing device")); 1706168404Spjd break; 1707168404Spjd 1708168404Spjd case VDEV_AUX_NO_REPLICAS: 1709168404Spjd (void) printf(gettext("insufficient replicas")); 1710168404Spjd break; 1711168404Spjd 1712168404Spjd case VDEV_AUX_VERSION_NEWER: 1713168404Spjd (void) printf(gettext("newer version")); 1714168404Spjd break; 1715168404Spjd 1716236884Smm case VDEV_AUX_UNSUP_FEAT: 1717236884Smm (void) printf(gettext("unsupported feature(s)")); 1718236884Smm break; 1719236884Smm 1720185029Spjd case VDEV_AUX_ERR_EXCEEDED: 1721185029Spjd (void) printf(gettext("too many errors")); 1722185029Spjd break; 1723185029Spjd 1724332536Smav case VDEV_AUX_CHILDREN_OFFLINE: 1725332536Smav (void) printf(gettext("all children offline")); 1726332536Smav break; 1727332536Smav 1728168404Spjd default: 1729168404Spjd (void) printf(gettext("corrupted data")); 1730168404Spjd break; 1731168404Spjd } 1732168404Spjd } 1733168404Spjd (void) printf("\n"); 1734168404Spjd 1735168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 1736168404Spjd &child, &children) != 0) 1737168404Spjd return; 1738168404Spjd 1739168404Spjd for (c = 0; c < children; c++) { 1740185029Spjd uint64_t is_log = B_FALSE; 1741185029Spjd 1742185029Spjd (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 1743185029Spjd &is_log); 1744213197Smm if (is_log) 1745185029Spjd continue; 1746185029Spjd 1747219089Spjd vname = zpool_vdev_name(g_zfs, NULL, child[c], B_TRUE); 1748213197Smm print_import_config(vname, child[c], namewidth, depth + 2); 1749168404Spjd free(vname); 1750168404Spjd } 1751168404Spjd 1752185029Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE, 1753185029Spjd &child, &children) == 0) { 1754185029Spjd (void) printf(gettext("\tcache\n")); 1755185029Spjd for (c = 0; c < children; c++) { 1756219089Spjd vname = zpool_vdev_name(g_zfs, NULL, child[c], B_FALSE); 1757185029Spjd (void) printf("\t %s\n", vname); 1758185029Spjd free(vname); 1759185029Spjd } 1760185029Spjd } 1761185029Spjd 1762168404Spjd if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, 1763185029Spjd &child, &children) == 0) { 1764185029Spjd (void) printf(gettext("\tspares\n")); 1765185029Spjd for (c = 0; c < children; c++) { 1766219089Spjd vname = zpool_vdev_name(g_zfs, NULL, child[c], B_FALSE); 1767185029Spjd (void) printf("\t %s\n", vname); 1768185029Spjd free(vname); 1769185029Spjd } 1770168404Spjd } 1771168404Spjd} 1772168404Spjd 1773168404Spjd/* 1774213197Smm * Print log vdevs. 1775213197Smm * Logs are recorded as top level vdevs in the main pool child array 1776213197Smm * but with "is_log" set to 1. We use either print_status_config() or 1777213197Smm * print_import_config() to print the top level logs then any log 1778213197Smm * children (eg mirrored slogs) are printed recursively - which 1779213197Smm * works because only the top level vdev is marked "is_log" 1780213197Smm */ 1781213197Smmstatic void 1782213197Smmprint_logs(zpool_handle_t *zhp, nvlist_t *nv, int namewidth, boolean_t verbose) 1783213197Smm{ 1784213197Smm uint_t c, children; 1785213197Smm nvlist_t **child; 1786213197Smm 1787213197Smm if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, &child, 1788213197Smm &children) != 0) 1789213197Smm return; 1790213197Smm 1791213197Smm (void) printf(gettext("\tlogs\n")); 1792213197Smm 1793213197Smm for (c = 0; c < children; c++) { 1794213197Smm uint64_t is_log = B_FALSE; 1795213197Smm char *name; 1796213197Smm 1797213197Smm (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 1798213197Smm &is_log); 1799213197Smm if (!is_log) 1800213197Smm continue; 1801219089Spjd name = zpool_vdev_name(g_zfs, zhp, child[c], B_TRUE); 1802213197Smm if (verbose) 1803213197Smm print_status_config(zhp, name, child[c], namewidth, 1804213197Smm 2, B_FALSE); 1805213197Smm else 1806213197Smm print_import_config(name, child[c], namewidth, 2); 1807213197Smm free(name); 1808213197Smm } 1809213197Smm} 1810219089Spjd 1811213197Smm/* 1812168404Spjd * Display the status for the given pool. 1813168404Spjd */ 1814168404Spjdstatic void 1815168404Spjdshow_import(nvlist_t *config) 1816168404Spjd{ 1817168404Spjd uint64_t pool_state; 1818168404Spjd vdev_stat_t *vs; 1819168404Spjd char *name; 1820168404Spjd uint64_t guid; 1821168404Spjd char *msgid; 1822168404Spjd nvlist_t *nvroot; 1823168404Spjd int reason; 1824168404Spjd const char *health; 1825168404Spjd uint_t vsc; 1826168404Spjd int namewidth; 1827228103Smm char *comment; 1828168404Spjd 1829168404Spjd verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, 1830168404Spjd &name) == 0); 1831168404Spjd verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, 1832168404Spjd &guid) == 0); 1833168404Spjd verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE, 1834168404Spjd &pool_state) == 0); 1835168404Spjd verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 1836168404Spjd &nvroot) == 0); 1837168404Spjd 1838219089Spjd verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS, 1839168404Spjd (uint64_t **)&vs, &vsc) == 0); 1840185029Spjd health = zpool_state_to_name(vs->vs_state, vs->vs_aux); 1841168404Spjd 1842168404Spjd reason = zpool_import_status(config, &msgid); 1843168404Spjd 1844228103Smm (void) printf(gettext(" pool: %s\n"), name); 1845228103Smm (void) printf(gettext(" id: %llu\n"), (u_longlong_t)guid); 1846228103Smm (void) printf(gettext(" state: %s"), health); 1847168404Spjd if (pool_state == POOL_STATE_DESTROYED) 1848168404Spjd (void) printf(gettext(" (DESTROYED)")); 1849168404Spjd (void) printf("\n"); 1850168404Spjd 1851168404Spjd switch (reason) { 1852168404Spjd case ZPOOL_STATUS_MISSING_DEV_R: 1853168404Spjd case ZPOOL_STATUS_MISSING_DEV_NR: 1854168404Spjd case ZPOOL_STATUS_BAD_GUID_SUM: 1855228103Smm (void) printf(gettext(" status: One or more devices are " 1856228103Smm "missing from the system.\n")); 1857168404Spjd break; 1858168404Spjd 1859168404Spjd case ZPOOL_STATUS_CORRUPT_LABEL_R: 1860168404Spjd case ZPOOL_STATUS_CORRUPT_LABEL_NR: 1861228103Smm (void) printf(gettext(" status: One or more devices contains " 1862168404Spjd "corrupted data.\n")); 1863168404Spjd break; 1864168404Spjd 1865168404Spjd case ZPOOL_STATUS_CORRUPT_DATA: 1866228103Smm (void) printf( 1867228103Smm gettext(" status: The pool data is corrupted.\n")); 1868168404Spjd break; 1869168404Spjd 1870168404Spjd case ZPOOL_STATUS_OFFLINE_DEV: 1871228103Smm (void) printf(gettext(" status: One or more devices " 1872168404Spjd "are offlined.\n")); 1873168404Spjd break; 1874168404Spjd 1875168404Spjd case ZPOOL_STATUS_CORRUPT_POOL: 1876228103Smm (void) printf(gettext(" status: The pool metadata is " 1877168404Spjd "corrupted.\n")); 1878168404Spjd break; 1879168404Spjd 1880168404Spjd case ZPOOL_STATUS_VERSION_OLDER: 1881238926Smm (void) printf(gettext(" status: The pool is formatted using a " 1882238926Smm "legacy on-disk version.\n")); 1883168404Spjd break; 1884168404Spjd 1885168404Spjd case ZPOOL_STATUS_VERSION_NEWER: 1886228103Smm (void) printf(gettext(" status: The pool is formatted using an " 1887168404Spjd "incompatible version.\n")); 1888168404Spjd break; 1889168404Spjd 1890238926Smm case ZPOOL_STATUS_FEAT_DISABLED: 1891238926Smm (void) printf(gettext(" status: Some supported features are " 1892238926Smm "not enabled on the pool.\n")); 1893238926Smm break; 1894238926Smm 1895236884Smm case ZPOOL_STATUS_UNSUP_FEAT_READ: 1896236884Smm (void) printf(gettext("status: The pool uses the following " 1897332542Smav "feature(s) not supported on this system:\n")); 1898236884Smm zpool_print_unsup_feat(config); 1899236884Smm break; 1900236884Smm 1901236884Smm case ZPOOL_STATUS_UNSUP_FEAT_WRITE: 1902236884Smm (void) printf(gettext("status: The pool can only be accessed " 1903236884Smm "in read-only mode on this system. It\n\tcannot be " 1904236884Smm "accessed in read-write mode because it uses the " 1905236884Smm "following\n\tfeature(s) not supported on this system:\n")); 1906236884Smm zpool_print_unsup_feat(config); 1907236884Smm break; 1908236884Smm 1909168498Spjd case ZPOOL_STATUS_HOSTID_MISMATCH: 1910228103Smm (void) printf(gettext(" status: The pool was last accessed by " 1911168498Spjd "another system.\n")); 1912168498Spjd break; 1913185029Spjd 1914185029Spjd case ZPOOL_STATUS_FAULTED_DEV_R: 1915185029Spjd case ZPOOL_STATUS_FAULTED_DEV_NR: 1916228103Smm (void) printf(gettext(" status: One or more devices are " 1917185029Spjd "faulted.\n")); 1918185029Spjd break; 1919185029Spjd 1920185029Spjd case ZPOOL_STATUS_BAD_LOG: 1921228103Smm (void) printf(gettext(" status: An intent log record cannot be " 1922185029Spjd "read.\n")); 1923185029Spjd break; 1924185029Spjd 1925219089Spjd case ZPOOL_STATUS_RESILVERING: 1926228103Smm (void) printf(gettext(" status: One or more devices were being " 1927219089Spjd "resilvered.\n")); 1928219089Spjd break; 1929219089Spjd 1930259131Sdelphij case ZPOOL_STATUS_NON_NATIVE_ASHIFT: 1931259131Sdelphij (void) printf(gettext("status: One or more devices were " 1932259131Sdelphij "configured to use a non-native block size.\n" 1933259131Sdelphij "\tExpect reduced performance.\n")); 1934259131Sdelphij break; 1935259131Sdelphij 1936168404Spjd default: 1937168404Spjd /* 1938168404Spjd * No other status can be seen when importing pools. 1939168404Spjd */ 1940168404Spjd assert(reason == ZPOOL_STATUS_OK); 1941168404Spjd } 1942168404Spjd 1943168404Spjd /* 1944168404Spjd * Print out an action according to the overall state of the pool. 1945168404Spjd */ 1946168404Spjd if (vs->vs_state == VDEV_STATE_HEALTHY) { 1947238926Smm if (reason == ZPOOL_STATUS_VERSION_OLDER || 1948238926Smm reason == ZPOOL_STATUS_FEAT_DISABLED) { 1949228103Smm (void) printf(gettext(" action: The pool can be " 1950168404Spjd "imported using its name or numeric identifier, " 1951168404Spjd "though\n\tsome features will not be available " 1952168404Spjd "without an explicit 'zpool upgrade'.\n")); 1953238926Smm } else if (reason == ZPOOL_STATUS_HOSTID_MISMATCH) { 1954228103Smm (void) printf(gettext(" action: The pool can be " 1955168498Spjd "imported using its name or numeric " 1956168498Spjd "identifier and\n\tthe '-f' flag.\n")); 1957238926Smm } else { 1958228103Smm (void) printf(gettext(" action: The pool can be " 1959168404Spjd "imported using its name or numeric " 1960168404Spjd "identifier.\n")); 1961238926Smm } 1962168404Spjd } else if (vs->vs_state == VDEV_STATE_DEGRADED) { 1963228103Smm (void) printf(gettext(" action: The pool can be imported " 1964168404Spjd "despite missing or damaged devices. The\n\tfault " 1965168404Spjd "tolerance of the pool may be compromised if imported.\n")); 1966168404Spjd } else { 1967168404Spjd switch (reason) { 1968168404Spjd case ZPOOL_STATUS_VERSION_NEWER: 1969228103Smm (void) printf(gettext(" action: The pool cannot be " 1970168404Spjd "imported. Access the pool on a system running " 1971168404Spjd "newer\n\tsoftware, or recreate the pool from " 1972168404Spjd "backup.\n")); 1973168404Spjd break; 1974236884Smm case ZPOOL_STATUS_UNSUP_FEAT_READ: 1975236884Smm (void) printf(gettext("action: The pool cannot be " 1976236884Smm "imported. Access the pool on a system that " 1977236884Smm "supports\n\tthe required feature(s), or recreate " 1978236884Smm "the pool from backup.\n")); 1979236884Smm break; 1980236884Smm case ZPOOL_STATUS_UNSUP_FEAT_WRITE: 1981236884Smm (void) printf(gettext("action: The pool cannot be " 1982236884Smm "imported in read-write mode. Import the pool " 1983236884Smm "with\n" 1984236884Smm "\t\"-o readonly=on\", access the pool on a system " 1985236884Smm "that supports the\n\trequired feature(s), or " 1986236884Smm "recreate the pool from backup.\n")); 1987236884Smm break; 1988168404Spjd case ZPOOL_STATUS_MISSING_DEV_R: 1989168404Spjd case ZPOOL_STATUS_MISSING_DEV_NR: 1990168404Spjd case ZPOOL_STATUS_BAD_GUID_SUM: 1991228103Smm (void) printf(gettext(" action: The pool cannot be " 1992168404Spjd "imported. Attach the missing\n\tdevices and try " 1993168404Spjd "again.\n")); 1994168404Spjd break; 1995168404Spjd default: 1996228103Smm (void) printf(gettext(" action: The pool cannot be " 1997168404Spjd "imported due to damaged devices or data.\n")); 1998168404Spjd } 1999168404Spjd } 2000168404Spjd 2001228103Smm /* Print the comment attached to the pool. */ 2002228103Smm if (nvlist_lookup_string(config, ZPOOL_CONFIG_COMMENT, &comment) == 0) 2003228103Smm (void) printf(gettext("comment: %s\n"), comment); 2004228103Smm 2005168404Spjd /* 2006168404Spjd * If the state is "closed" or "can't open", and the aux state 2007168404Spjd * is "corrupt data": 2008168404Spjd */ 2009168404Spjd if (((vs->vs_state == VDEV_STATE_CLOSED) || 2010168404Spjd (vs->vs_state == VDEV_STATE_CANT_OPEN)) && 2011168404Spjd (vs->vs_aux == VDEV_AUX_CORRUPT_DATA)) { 2012168404Spjd if (pool_state == POOL_STATE_DESTROYED) 2013168404Spjd (void) printf(gettext("\tThe pool was destroyed, " 2014168404Spjd "but can be imported using the '-Df' flags.\n")); 2015168404Spjd else if (pool_state != POOL_STATE_EXPORTED) 2016168404Spjd (void) printf(gettext("\tThe pool may be active on " 2017185029Spjd "another system, but can be imported using\n\t" 2018168404Spjd "the '-f' flag.\n")); 2019168404Spjd } 2020168404Spjd 2021168404Spjd if (msgid != NULL) 2022236146Smm (void) printf(gettext(" see: http://illumos.org/msg/%s\n"), 2023168404Spjd msgid); 2024168404Spjd 2025228103Smm (void) printf(gettext(" config:\n\n")); 2026168404Spjd 2027168404Spjd namewidth = max_width(NULL, nvroot, 0, 0); 2028168404Spjd if (namewidth < 10) 2029168404Spjd namewidth = 10; 2030168404Spjd 2031213197Smm print_import_config(name, nvroot, namewidth, 0); 2032213197Smm if (num_logs(nvroot) > 0) 2033213197Smm print_logs(NULL, nvroot, namewidth, B_FALSE); 2034185029Spjd 2035168404Spjd if (reason == ZPOOL_STATUS_BAD_GUID_SUM) { 2036168404Spjd (void) printf(gettext("\n\tAdditional devices are known to " 2037168404Spjd "be part of this pool, though their\n\texact " 2038168404Spjd "configuration cannot be determined.\n")); 2039168404Spjd } 2040168404Spjd} 2041168404Spjd 2042168404Spjd/* 2043168404Spjd * Perform the import for the given configuration. This passes the heavy 2044185029Spjd * lifting off to zpool_import_props(), and then mounts the datasets contained 2045185029Spjd * within the pool. 2046168404Spjd */ 2047168404Spjdstatic int 2048168404Spjddo_import(nvlist_t *config, const char *newname, const char *mntopts, 2049219089Spjd nvlist_t *props, int flags) 2050168404Spjd{ 2051168404Spjd zpool_handle_t *zhp; 2052168404Spjd char *name; 2053168404Spjd uint64_t state; 2054168404Spjd uint64_t version; 2055168404Spjd 2056168404Spjd verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, 2057168404Spjd &name) == 0); 2058168404Spjd 2059168404Spjd verify(nvlist_lookup_uint64(config, 2060168404Spjd ZPOOL_CONFIG_POOL_STATE, &state) == 0); 2061168404Spjd verify(nvlist_lookup_uint64(config, 2062168404Spjd ZPOOL_CONFIG_VERSION, &version) == 0); 2063236884Smm if (!SPA_VERSION_IS_SUPPORTED(version)) { 2064168404Spjd (void) fprintf(stderr, gettext("cannot import '%s': pool " 2065236884Smm "is formatted using an unsupported ZFS version\n"), name); 2066168404Spjd return (1); 2067219089Spjd } else if (state != POOL_STATE_EXPORTED && 2068219089Spjd !(flags & ZFS_IMPORT_ANY_HOST)) { 2069168498Spjd uint64_t hostid; 2070168498Spjd 2071168498Spjd if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID, 2072168498Spjd &hostid) == 0) { 2073168498Spjd if ((unsigned long)hostid != gethostid()) { 2074168498Spjd char *hostname; 2075168498Spjd uint64_t timestamp; 2076168498Spjd time_t t; 2077168498Spjd 2078168498Spjd verify(nvlist_lookup_string(config, 2079168498Spjd ZPOOL_CONFIG_HOSTNAME, &hostname) == 0); 2080168498Spjd verify(nvlist_lookup_uint64(config, 2081168498Spjd ZPOOL_CONFIG_TIMESTAMP, ×tamp) == 0); 2082168498Spjd t = timestamp; 2083168498Spjd (void) fprintf(stderr, gettext("cannot import " 2084168498Spjd "'%s': pool may be in use from other " 2085168498Spjd "system, it was last accessed by %s " 2086168498Spjd "(hostid: 0x%lx) on %s"), name, hostname, 2087168498Spjd (unsigned long)hostid, 2088168498Spjd asctime(localtime(&t))); 2089168498Spjd (void) fprintf(stderr, gettext("use '-f' to " 2090168498Spjd "import anyway\n")); 2091168498Spjd return (1); 2092168498Spjd } 2093168498Spjd } else { 2094168498Spjd (void) fprintf(stderr, gettext("cannot import '%s': " 2095168498Spjd "pool may be in use from other system\n"), name); 2096168498Spjd (void) fprintf(stderr, gettext("use '-f' to import " 2097168498Spjd "anyway\n")); 2098168498Spjd return (1); 2099168498Spjd } 2100168404Spjd } 2101168404Spjd 2102219089Spjd if (zpool_import_props(g_zfs, config, newname, props, flags) != 0) 2103168404Spjd return (1); 2104168404Spjd 2105168404Spjd if (newname != NULL) 2106168404Spjd name = (char *)newname; 2107168404Spjd 2108209962Smm if ((zhp = zpool_open_canfail(g_zfs, name)) == NULL) 2109209962Smm return (1); 2110168404Spjd 2111209962Smm if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL && 2112219089Spjd !(flags & ZFS_IMPORT_ONLY) && 2113209962Smm zpool_enable_datasets(zhp, mntopts, 0) != 0) { 2114168404Spjd zpool_close(zhp); 2115168404Spjd return (1); 2116168404Spjd } 2117168404Spjd 2118168404Spjd zpool_close(zhp); 2119219089Spjd return (0); 2120168404Spjd} 2121168404Spjd 2122168404Spjd/* 2123332547Smav * zpool checkpoint <pool> 2124332547Smav * checkpoint --discard <pool> 2125332547Smav * 2126332547Smav * -d Discard the checkpoint from a checkpointed 2127332547Smav * --discard pool. 2128332547Smav * 2129332547Smav * Checkpoints the specified pool, by taking a "snapshot" of its 2130332547Smav * current state. A pool can only have one checkpoint at a time. 2131332547Smav */ 2132332547Smavint 2133332547Smavzpool_do_checkpoint(int argc, char **argv) 2134332547Smav{ 2135332547Smav boolean_t discard; 2136332547Smav char *pool; 2137332547Smav zpool_handle_t *zhp; 2138332547Smav int c, err; 2139332547Smav 2140332547Smav struct option long_options[] = { 2141332547Smav {"discard", no_argument, NULL, 'd'}, 2142332547Smav {0, 0, 0, 0} 2143332547Smav }; 2144332547Smav 2145332547Smav discard = B_FALSE; 2146332547Smav while ((c = getopt_long(argc, argv, ":d", long_options, NULL)) != -1) { 2147332547Smav switch (c) { 2148332547Smav case 'd': 2149332547Smav discard = B_TRUE; 2150332547Smav break; 2151332547Smav case '?': 2152332547Smav (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2153332547Smav optopt); 2154332547Smav usage(B_FALSE); 2155332547Smav } 2156332547Smav } 2157332547Smav 2158332547Smav argc -= optind; 2159332547Smav argv += optind; 2160332547Smav 2161332547Smav if (argc < 1) { 2162332547Smav (void) fprintf(stderr, gettext("missing pool argument\n")); 2163332547Smav usage(B_FALSE); 2164332547Smav } 2165332547Smav 2166332547Smav if (argc > 1) { 2167332547Smav (void) fprintf(stderr, gettext("too many arguments\n")); 2168332547Smav usage(B_FALSE); 2169332547Smav } 2170332547Smav 2171332547Smav pool = argv[0]; 2172332547Smav 2173332547Smav if ((zhp = zpool_open(g_zfs, pool)) == NULL) { 2174332547Smav /* As a special case, check for use of '/' in the name */ 2175332547Smav if (strchr(pool, '/') != NULL) 2176332547Smav (void) fprintf(stderr, gettext("'zpool checkpoint' " 2177332547Smav "doesn't work on datasets. To save the state " 2178332547Smav "of a dataset from a specific point in time " 2179332547Smav "please use 'zfs snapshot'\n")); 2180332547Smav return (1); 2181332547Smav } 2182332547Smav 2183332547Smav if (discard) 2184332547Smav err = (zpool_discard_checkpoint(zhp) != 0); 2185332547Smav else 2186332547Smav err = (zpool_checkpoint(zhp) != 0); 2187332547Smav 2188332547Smav zpool_close(zhp); 2189332547Smav 2190332547Smav return (err); 2191332547Smav} 2192332547Smav 2193332547Smav#define CHECKPOINT_OPT 1024 2194332547Smav 2195332547Smav/* 2196168404Spjd * zpool import [-d dir] [-D] 2197185029Spjd * import [-o mntopts] [-o prop=value] ... [-R root] [-D] 2198185029Spjd * [-d dir | -c cachefile] [-f] -a 2199185029Spjd * import [-o mntopts] [-o prop=value] ... [-R root] [-D] 2200333194Savg * [-d dir | -c cachefile] [-f] [-n] [-F] [-t] 2201333194Savg * <pool | id> [newpool] 2202168404Spjd * 2203185029Spjd * -c Read pool information from a cachefile instead of searching 2204185029Spjd * devices. 2205185029Spjd * 2206168404Spjd * -d Scan in a specific directory, other than /dev/dsk. More than 2207168404Spjd * one directory can be specified using multiple '-d' options. 2208168404Spjd * 2209168404Spjd * -D Scan for previously destroyed pools or import all or only 2210168404Spjd * specified destroyed pools. 2211168404Spjd * 2212168404Spjd * -R Temporarily import the pool, with all mountpoints relative to 2213168404Spjd * the given root. The pool will remain exported when the machine 2214168404Spjd * is rebooted. 2215168404Spjd * 2216219089Spjd * -V Import even in the presence of faulted vdevs. This is an 2217185029Spjd * intentionally undocumented option for testing purposes, and 2218185029Spjd * treats the pool configuration as complete, leaving any bad 2219209962Smm * vdevs in the FAULTED state. In other words, it does verbatim 2220209962Smm * import. 2221185029Spjd * 2222219089Spjd * -f Force import, even if it appears that the pool is active. 2223219089Spjd * 2224219089Spjd * -F Attempt rewind if necessary. 2225219089Spjd * 2226219089Spjd * -n See if rewind would work, but don't actually rewind. 2227219089Spjd * 2228219089Spjd * -N Import the pool but don't mount datasets. 2229219089Spjd * 2230333194Savg * -t Use newpool as a temporary pool name instead of renaming 2231333194Savg * the pool. 2232333194Savg * 2233219089Spjd * -T Specify a starting txg to use for import. This option is 2234219089Spjd * intentionally undocumented option for testing purposes. 2235219089Spjd * 2236168404Spjd * -a Import all pools found. 2237168404Spjd * 2238185029Spjd * -o Set property=value and/or temporary mount options (without '='). 2239185029Spjd * 2240332547Smav * --rewind-to-checkpoint 2241332547Smav * Import the pool and revert back to the checkpoint. 2242332547Smav * 2243168404Spjd * The import command scans for pools to import, and import pools based on pool 2244168404Spjd * name and GUID. The pool can also be renamed as part of the import process. 2245168404Spjd */ 2246168404Spjdint 2247168404Spjdzpool_do_import(int argc, char **argv) 2248168404Spjd{ 2249168404Spjd char **searchdirs = NULL; 2250168404Spjd int nsearch = 0; 2251168404Spjd int c; 2252219089Spjd int err = 0; 2253185029Spjd nvlist_t *pools = NULL; 2254168404Spjd boolean_t do_all = B_FALSE; 2255168404Spjd boolean_t do_destroyed = B_FALSE; 2256168404Spjd char *mntopts = NULL; 2257168404Spjd nvpair_t *elem; 2258168404Spjd nvlist_t *config; 2259185029Spjd uint64_t searchguid = 0; 2260185029Spjd char *searchname = NULL; 2261185029Spjd char *propval; 2262168404Spjd nvlist_t *found_config; 2263219089Spjd nvlist_t *policy = NULL; 2264185029Spjd nvlist_t *props = NULL; 2265168404Spjd boolean_t first; 2266219089Spjd int flags = ZFS_IMPORT_NORMAL; 2267219089Spjd uint32_t rewind_policy = ZPOOL_NO_REWIND; 2268219089Spjd boolean_t dryrun = B_FALSE; 2269219089Spjd boolean_t do_rewind = B_FALSE; 2270219089Spjd boolean_t xtreme_rewind = B_FALSE; 2271219089Spjd uint64_t pool_state, txg = -1ULL; 2272185029Spjd char *cachefile = NULL; 2273219089Spjd importargs_t idata = { 0 }; 2274219089Spjd char *endptr; 2275168404Spjd 2276332547Smav 2277332547Smav struct option long_options[] = { 2278332547Smav {"rewind-to-checkpoint", no_argument, NULL, CHECKPOINT_OPT}, 2279332547Smav {0, 0, 0, 0} 2280332547Smav }; 2281332547Smav 2282168404Spjd /* check options */ 2283333194Savg while ((c = getopt_long(argc, argv, ":aCc:d:DEfFmnNo:rR:tT:VX", 2284332547Smav long_options, NULL)) != -1) { 2285168404Spjd switch (c) { 2286168404Spjd case 'a': 2287168404Spjd do_all = B_TRUE; 2288168404Spjd break; 2289185029Spjd case 'c': 2290185029Spjd cachefile = optarg; 2291185029Spjd break; 2292168404Spjd case 'd': 2293168404Spjd if (searchdirs == NULL) { 2294168404Spjd searchdirs = safe_malloc(sizeof (char *)); 2295168404Spjd } else { 2296168404Spjd char **tmp = safe_malloc((nsearch + 1) * 2297168404Spjd sizeof (char *)); 2298168404Spjd bcopy(searchdirs, tmp, nsearch * 2299168404Spjd sizeof (char *)); 2300168404Spjd free(searchdirs); 2301168404Spjd searchdirs = tmp; 2302168404Spjd } 2303168404Spjd searchdirs[nsearch++] = optarg; 2304168404Spjd break; 2305168404Spjd case 'D': 2306168404Spjd do_destroyed = B_TRUE; 2307168404Spjd break; 2308168404Spjd case 'f': 2309219089Spjd flags |= ZFS_IMPORT_ANY_HOST; 2310168404Spjd break; 2311185029Spjd case 'F': 2312219089Spjd do_rewind = B_TRUE; 2313185029Spjd break; 2314219089Spjd case 'm': 2315219089Spjd flags |= ZFS_IMPORT_MISSING_LOG; 2316219089Spjd break; 2317219089Spjd case 'n': 2318219089Spjd dryrun = B_TRUE; 2319219089Spjd break; 2320219089Spjd case 'N': 2321219089Spjd flags |= ZFS_IMPORT_ONLY; 2322219089Spjd break; 2323168404Spjd case 'o': 2324185029Spjd if ((propval = strchr(optarg, '=')) != NULL) { 2325185029Spjd *propval = '\0'; 2326185029Spjd propval++; 2327185029Spjd if (add_prop_list(optarg, propval, 2328185029Spjd &props, B_TRUE)) 2329185029Spjd goto error; 2330185029Spjd } else { 2331185029Spjd mntopts = optarg; 2332185029Spjd } 2333168404Spjd break; 2334168404Spjd case 'R': 2335185029Spjd if (add_prop_list(zpool_prop_to_name( 2336185029Spjd ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE)) 2337185029Spjd goto error; 2338333194Savg if (add_prop_list_default(zpool_prop_to_name( 2339185029Spjd ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE)) 2340185029Spjd goto error; 2341168404Spjd break; 2342333194Savg case 't': 2343333194Savg flags |= ZFS_IMPORT_TEMP_NAME; 2344333194Savg if (add_prop_list_default(zpool_prop_to_name( 2345333194Savg ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE)) 2346333194Savg goto error; 2347333194Savg break; 2348219089Spjd case 'T': 2349219089Spjd errno = 0; 2350268720Sdelphij txg = strtoull(optarg, &endptr, 0); 2351219089Spjd if (errno != 0 || *endptr != '\0') { 2352219089Spjd (void) fprintf(stderr, 2353219089Spjd gettext("invalid txg value\n")); 2354219089Spjd usage(B_FALSE); 2355219089Spjd } 2356219089Spjd rewind_policy = ZPOOL_DO_REWIND | ZPOOL_EXTREME_REWIND; 2357219089Spjd break; 2358219089Spjd case 'V': 2359219089Spjd flags |= ZFS_IMPORT_VERBATIM; 2360219089Spjd break; 2361219089Spjd case 'X': 2362219089Spjd xtreme_rewind = B_TRUE; 2363219089Spjd break; 2364332547Smav case CHECKPOINT_OPT: 2365332547Smav flags |= ZFS_IMPORT_CHECKPOINT; 2366332547Smav break; 2367168404Spjd case ':': 2368168404Spjd (void) fprintf(stderr, gettext("missing argument for " 2369168404Spjd "'%c' option\n"), optopt); 2370168404Spjd usage(B_FALSE); 2371168404Spjd break; 2372168404Spjd case '?': 2373168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2374168404Spjd optopt); 2375168404Spjd usage(B_FALSE); 2376168404Spjd } 2377168404Spjd } 2378168404Spjd 2379168404Spjd argc -= optind; 2380168404Spjd argv += optind; 2381168404Spjd 2382185029Spjd if (cachefile && nsearch != 0) { 2383185029Spjd (void) fprintf(stderr, gettext("-c is incompatible with -d\n")); 2384185029Spjd usage(B_FALSE); 2385185029Spjd } 2386185029Spjd 2387219089Spjd if ((dryrun || xtreme_rewind) && !do_rewind) { 2388219089Spjd (void) fprintf(stderr, 2389219089Spjd gettext("-n or -X only meaningful with -F\n")); 2390219089Spjd usage(B_FALSE); 2391219089Spjd } 2392219089Spjd if (dryrun) 2393219089Spjd rewind_policy = ZPOOL_TRY_REWIND; 2394219089Spjd else if (do_rewind) 2395219089Spjd rewind_policy = ZPOOL_DO_REWIND; 2396219089Spjd if (xtreme_rewind) 2397219089Spjd rewind_policy |= ZPOOL_EXTREME_REWIND; 2398219089Spjd 2399219089Spjd /* In the future, we can capture further policy and include it here */ 2400219089Spjd if (nvlist_alloc(&policy, NV_UNIQUE_NAME, 0) != 0 || 2401332550Smav nvlist_add_uint64(policy, ZPOOL_LOAD_REQUEST_TXG, txg) != 0 || 2402332550Smav nvlist_add_uint32(policy, ZPOOL_LOAD_REWIND_POLICY, 2403332550Smav rewind_policy) != 0) 2404219089Spjd goto error; 2405219089Spjd 2406168404Spjd if (searchdirs == NULL) { 2407168404Spjd searchdirs = safe_malloc(sizeof (char *)); 2408235478Savg searchdirs[0] = "/dev"; 2409168404Spjd nsearch = 1; 2410168404Spjd } 2411168404Spjd 2412168404Spjd /* check argument count */ 2413168404Spjd if (do_all) { 2414168404Spjd if (argc != 0) { 2415168404Spjd (void) fprintf(stderr, gettext("too many arguments\n")); 2416168404Spjd usage(B_FALSE); 2417168404Spjd } 2418168404Spjd } else { 2419168404Spjd if (argc > 2) { 2420168404Spjd (void) fprintf(stderr, gettext("too many arguments\n")); 2421168404Spjd usage(B_FALSE); 2422168404Spjd } 2423168404Spjd 2424168404Spjd /* 2425168404Spjd * Check for the SYS_CONFIG privilege. We do this explicitly 2426168404Spjd * here because otherwise any attempt to discover pools will 2427168404Spjd * silently fail. 2428168404Spjd */ 2429168404Spjd if (argc == 0 && !priv_ineffect(PRIV_SYS_CONFIG)) { 2430168404Spjd (void) fprintf(stderr, gettext("cannot " 2431168404Spjd "discover pools: permission denied\n")); 2432168404Spjd free(searchdirs); 2433219089Spjd nvlist_free(policy); 2434168404Spjd return (1); 2435168404Spjd } 2436168404Spjd } 2437168404Spjd 2438168404Spjd /* 2439168404Spjd * Depending on the arguments given, we do one of the following: 2440168404Spjd * 2441168404Spjd * <none> Iterate through all pools and display information about 2442168404Spjd * each one. 2443168404Spjd * 2444168404Spjd * -a Iterate through all pools and try to import each one. 2445168404Spjd * 2446168404Spjd * <id> Find the pool that corresponds to the given GUID/pool 2447168404Spjd * name and import that one. 2448168404Spjd * 2449168404Spjd * -D Above options applies only to destroyed pools. 2450168404Spjd */ 2451168404Spjd if (argc != 0) { 2452168404Spjd char *endptr; 2453168404Spjd 2454168404Spjd errno = 0; 2455168404Spjd searchguid = strtoull(argv[0], &endptr, 10); 2456254758Sdelphij if (errno != 0 || *endptr != '\0') { 2457168404Spjd searchname = argv[0]; 2458254758Sdelphij searchguid = 0; 2459254758Sdelphij } 2460168404Spjd found_config = NULL; 2461168404Spjd 2462185029Spjd /* 2463219089Spjd * User specified a name or guid. Ensure it's unique. 2464185029Spjd */ 2465219089Spjd idata.unique = B_TRUE; 2466185029Spjd } 2467185029Spjd 2468219089Spjd 2469219089Spjd idata.path = searchdirs; 2470219089Spjd idata.paths = nsearch; 2471219089Spjd idata.poolname = searchname; 2472219089Spjd idata.guid = searchguid; 2473219089Spjd idata.cachefile = cachefile; 2474332536Smav idata.policy = policy; 2475219089Spjd 2476219089Spjd pools = zpool_search_import(g_zfs, &idata); 2477219089Spjd 2478219089Spjd if (pools != NULL && idata.exists && 2479219089Spjd (argc == 1 || strcmp(argv[0], argv[1]) == 0)) { 2480219089Spjd (void) fprintf(stderr, gettext("cannot import '%s': " 2481219089Spjd "a pool with that name already exists\n"), 2482219089Spjd argv[0]); 2483333194Savg (void) fprintf(stderr, gettext("use the form 'zpool import " 2484333194Savg "[-t] <pool | id> <newpool>' to give it a new temporary " 2485333194Savg "or permanent name\n")); 2486219089Spjd err = 1; 2487219089Spjd } else if (pools == NULL && idata.exists) { 2488219089Spjd (void) fprintf(stderr, gettext("cannot import '%s': " 2489219089Spjd "a pool with that name is already created/imported,\n"), 2490219089Spjd argv[0]); 2491219089Spjd (void) fprintf(stderr, gettext("and no additional pools " 2492219089Spjd "with that name were found\n")); 2493219089Spjd err = 1; 2494219089Spjd } else if (pools == NULL) { 2495185029Spjd if (argc != 0) { 2496185029Spjd (void) fprintf(stderr, gettext("cannot import '%s': " 2497185029Spjd "no such pool available\n"), argv[0]); 2498185029Spjd } 2499219089Spjd err = 1; 2500219089Spjd } 2501219089Spjd 2502219089Spjd if (err == 1) { 2503185029Spjd free(searchdirs); 2504219089Spjd nvlist_free(policy); 2505185029Spjd return (1); 2506185029Spjd } 2507185029Spjd 2508185029Spjd /* 2509185029Spjd * At this point we have a list of import candidate configs. Even if 2510185029Spjd * we were searching by pool name or guid, we still need to 2511185029Spjd * post-process the list to deal with pool state and possible 2512185029Spjd * duplicate names. 2513185029Spjd */ 2514168404Spjd err = 0; 2515168404Spjd elem = NULL; 2516168404Spjd first = B_TRUE; 2517168404Spjd while ((elem = nvlist_next_nvpair(pools, elem)) != NULL) { 2518168404Spjd 2519168404Spjd verify(nvpair_value_nvlist(elem, &config) == 0); 2520168404Spjd 2521168404Spjd verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE, 2522168404Spjd &pool_state) == 0); 2523168404Spjd if (!do_destroyed && pool_state == POOL_STATE_DESTROYED) 2524168404Spjd continue; 2525168404Spjd if (do_destroyed && pool_state != POOL_STATE_DESTROYED) 2526168404Spjd continue; 2527168404Spjd 2528332550Smav verify(nvlist_add_nvlist(config, ZPOOL_LOAD_POLICY, 2529219089Spjd policy) == 0); 2530219089Spjd 2531168404Spjd if (argc == 0) { 2532168404Spjd if (first) 2533168404Spjd first = B_FALSE; 2534168404Spjd else if (!do_all) 2535168404Spjd (void) printf("\n"); 2536168404Spjd 2537219089Spjd if (do_all) { 2538168404Spjd err |= do_import(config, NULL, mntopts, 2539219089Spjd props, flags); 2540219089Spjd } else { 2541168404Spjd show_import(config); 2542219089Spjd } 2543168404Spjd } else if (searchname != NULL) { 2544168404Spjd char *name; 2545168404Spjd 2546168404Spjd /* 2547168404Spjd * We are searching for a pool based on name. 2548168404Spjd */ 2549168404Spjd verify(nvlist_lookup_string(config, 2550168404Spjd ZPOOL_CONFIG_POOL_NAME, &name) == 0); 2551168404Spjd 2552168404Spjd if (strcmp(name, searchname) == 0) { 2553168404Spjd if (found_config != NULL) { 2554168404Spjd (void) fprintf(stderr, gettext( 2555168404Spjd "cannot import '%s': more than " 2556168404Spjd "one matching pool\n"), searchname); 2557168404Spjd (void) fprintf(stderr, gettext( 2558168404Spjd "import by numeric ID instead\n")); 2559168404Spjd err = B_TRUE; 2560168404Spjd } 2561168404Spjd found_config = config; 2562168404Spjd } 2563168404Spjd } else { 2564168404Spjd uint64_t guid; 2565168404Spjd 2566168404Spjd /* 2567168404Spjd * Search for a pool by guid. 2568168404Spjd */ 2569168404Spjd verify(nvlist_lookup_uint64(config, 2570168404Spjd ZPOOL_CONFIG_POOL_GUID, &guid) == 0); 2571168404Spjd 2572168404Spjd if (guid == searchguid) 2573168404Spjd found_config = config; 2574168404Spjd } 2575168404Spjd } 2576168404Spjd 2577168404Spjd /* 2578168404Spjd * If we were searching for a specific pool, verify that we found a 2579168404Spjd * pool, and then do the import. 2580168404Spjd */ 2581168404Spjd if (argc != 0 && err == 0) { 2582168404Spjd if (found_config == NULL) { 2583168404Spjd (void) fprintf(stderr, gettext("cannot import '%s': " 2584168404Spjd "no such pool available\n"), argv[0]); 2585168404Spjd err = B_TRUE; 2586168404Spjd } else { 2587168404Spjd err |= do_import(found_config, argc == 1 ? NULL : 2588219089Spjd argv[1], mntopts, props, flags); 2589168404Spjd } 2590168404Spjd } 2591168404Spjd 2592168404Spjd /* 2593168404Spjd * If we were just looking for pools, report an error if none were 2594168404Spjd * found. 2595168404Spjd */ 2596168404Spjd if (argc == 0 && first) 2597168404Spjd (void) fprintf(stderr, 2598168404Spjd gettext("no pools available to import\n")); 2599168404Spjd 2600185029Spjderror: 2601185029Spjd nvlist_free(props); 2602168404Spjd nvlist_free(pools); 2603219089Spjd nvlist_free(policy); 2604168404Spjd free(searchdirs); 2605168404Spjd 2606168404Spjd return (err ? 1 : 0); 2607168404Spjd} 2608168404Spjd 2609168404Spjdtypedef struct iostat_cbdata { 2610236155Smm boolean_t cb_verbose; 2611236155Smm int cb_namewidth; 2612236155Smm int cb_iteration; 2613168404Spjd zpool_list_t *cb_list; 2614168404Spjd} iostat_cbdata_t; 2615168404Spjd 2616168404Spjdstatic void 2617168404Spjdprint_iostat_separator(iostat_cbdata_t *cb) 2618168404Spjd{ 2619168404Spjd int i = 0; 2620168404Spjd 2621168404Spjd for (i = 0; i < cb->cb_namewidth; i++) 2622168404Spjd (void) printf("-"); 2623168404Spjd (void) printf(" ----- ----- ----- ----- ----- -----\n"); 2624168404Spjd} 2625168404Spjd 2626168404Spjdstatic void 2627168404Spjdprint_iostat_header(iostat_cbdata_t *cb) 2628168404Spjd{ 2629168404Spjd (void) printf("%*s capacity operations bandwidth\n", 2630168404Spjd cb->cb_namewidth, ""); 2631219089Spjd (void) printf("%-*s alloc free read write read write\n", 2632168404Spjd cb->cb_namewidth, "pool"); 2633168404Spjd print_iostat_separator(cb); 2634168404Spjd} 2635168404Spjd 2636168404Spjd/* 2637168404Spjd * Display a single statistic. 2638168404Spjd */ 2639185029Spjdstatic void 2640168404Spjdprint_one_stat(uint64_t value) 2641168404Spjd{ 2642168404Spjd char buf[64]; 2643168404Spjd 2644168404Spjd zfs_nicenum(value, buf, sizeof (buf)); 2645168404Spjd (void) printf(" %5s", buf); 2646168404Spjd} 2647168404Spjd 2648168404Spjd/* 2649168404Spjd * Print out all the statistics for the given vdev. This can either be the 2650168404Spjd * toplevel configuration, or called recursively. If 'name' is NULL, then this 2651168404Spjd * is a verbose output, and we don't want to display the toplevel pool stats. 2652168404Spjd */ 2653168404Spjdvoid 2654168404Spjdprint_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv, 2655168404Spjd nvlist_t *newnv, iostat_cbdata_t *cb, int depth) 2656168404Spjd{ 2657168404Spjd nvlist_t **oldchild, **newchild; 2658168404Spjd uint_t c, children; 2659168404Spjd vdev_stat_t *oldvs, *newvs; 2660168404Spjd vdev_stat_t zerovs = { 0 }; 2661168404Spjd uint64_t tdelta; 2662168404Spjd double scale; 2663168404Spjd char *vname; 2664168404Spjd 2665332525Smav if (strcmp(name, VDEV_TYPE_INDIRECT) == 0) 2666332525Smav return; 2667332525Smav 2668168404Spjd if (oldnv != NULL) { 2669219089Spjd verify(nvlist_lookup_uint64_array(oldnv, 2670219089Spjd ZPOOL_CONFIG_VDEV_STATS, (uint64_t **)&oldvs, &c) == 0); 2671168404Spjd } else { 2672168404Spjd oldvs = &zerovs; 2673168404Spjd } 2674168404Spjd 2675219089Spjd verify(nvlist_lookup_uint64_array(newnv, ZPOOL_CONFIG_VDEV_STATS, 2676168404Spjd (uint64_t **)&newvs, &c) == 0); 2677168404Spjd 2678168404Spjd if (strlen(name) + depth > cb->cb_namewidth) 2679168404Spjd (void) printf("%*s%s", depth, "", name); 2680168404Spjd else 2681168404Spjd (void) printf("%*s%s%*s", depth, "", name, 2682168404Spjd (int)(cb->cb_namewidth - strlen(name) - depth), ""); 2683168404Spjd 2684168404Spjd tdelta = newvs->vs_timestamp - oldvs->vs_timestamp; 2685168404Spjd 2686168404Spjd if (tdelta == 0) 2687168404Spjd scale = 1.0; 2688168404Spjd else 2689168404Spjd scale = (double)NANOSEC / tdelta; 2690168404Spjd 2691168404Spjd /* only toplevel vdevs have capacity stats */ 2692168404Spjd if (newvs->vs_space == 0) { 2693168404Spjd (void) printf(" - -"); 2694168404Spjd } else { 2695168404Spjd print_one_stat(newvs->vs_alloc); 2696168404Spjd print_one_stat(newvs->vs_space - newvs->vs_alloc); 2697168404Spjd } 2698168404Spjd 2699168404Spjd print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_READ] - 2700168404Spjd oldvs->vs_ops[ZIO_TYPE_READ]))); 2701168404Spjd 2702168404Spjd print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_WRITE] - 2703168404Spjd oldvs->vs_ops[ZIO_TYPE_WRITE]))); 2704168404Spjd 2705168404Spjd print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_READ] - 2706168404Spjd oldvs->vs_bytes[ZIO_TYPE_READ]))); 2707168404Spjd 2708168404Spjd print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_WRITE] - 2709168404Spjd oldvs->vs_bytes[ZIO_TYPE_WRITE]))); 2710168404Spjd 2711168404Spjd (void) printf("\n"); 2712168404Spjd 2713168404Spjd if (!cb->cb_verbose) 2714168404Spjd return; 2715168404Spjd 2716168404Spjd if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_CHILDREN, 2717168404Spjd &newchild, &children) != 0) 2718168404Spjd return; 2719168404Spjd 2720168404Spjd if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_CHILDREN, 2721168404Spjd &oldchild, &c) != 0) 2722168404Spjd return; 2723168404Spjd 2724168404Spjd for (c = 0; c < children; c++) { 2725227497Smm uint64_t ishole = B_FALSE, islog = B_FALSE; 2726219089Spjd 2727227497Smm (void) nvlist_lookup_uint64(newchild[c], ZPOOL_CONFIG_IS_HOLE, 2728227497Smm &ishole); 2729227497Smm 2730227497Smm (void) nvlist_lookup_uint64(newchild[c], ZPOOL_CONFIG_IS_LOG, 2731227497Smm &islog); 2732227497Smm 2733227497Smm if (ishole || islog) 2734219089Spjd continue; 2735219089Spjd 2736219089Spjd vname = zpool_vdev_name(g_zfs, zhp, newchild[c], B_FALSE); 2737168404Spjd print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL, 2738168404Spjd newchild[c], cb, depth + 2); 2739168404Spjd free(vname); 2740168404Spjd } 2741185029Spjd 2742185029Spjd /* 2743227497Smm * Log device section 2744227497Smm */ 2745227497Smm 2746227497Smm if (num_logs(newnv) > 0) { 2747227497Smm (void) printf("%-*s - - - - - " 2748227497Smm "-\n", cb->cb_namewidth, "logs"); 2749227497Smm 2750227497Smm for (c = 0; c < children; c++) { 2751227497Smm uint64_t islog = B_FALSE; 2752227497Smm (void) nvlist_lookup_uint64(newchild[c], 2753227497Smm ZPOOL_CONFIG_IS_LOG, &islog); 2754227497Smm 2755227497Smm if (islog) { 2756227497Smm vname = zpool_vdev_name(g_zfs, zhp, newchild[c], 2757227497Smm B_FALSE); 2758227497Smm print_vdev_stats(zhp, vname, oldnv ? 2759227497Smm oldchild[c] : NULL, newchild[c], 2760227497Smm cb, depth + 2); 2761227497Smm free(vname); 2762227497Smm } 2763227497Smm } 2764227497Smm 2765227497Smm } 2766227497Smm 2767227497Smm /* 2768185029Spjd * Include level 2 ARC devices in iostat output 2769185029Spjd */ 2770185029Spjd if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_L2CACHE, 2771185029Spjd &newchild, &children) != 0) 2772185029Spjd return; 2773185029Spjd 2774185029Spjd if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_L2CACHE, 2775185029Spjd &oldchild, &c) != 0) 2776185029Spjd return; 2777185029Spjd 2778185029Spjd if (children > 0) { 2779185029Spjd (void) printf("%-*s - - - - - " 2780185029Spjd "-\n", cb->cb_namewidth, "cache"); 2781185029Spjd for (c = 0; c < children; c++) { 2782219089Spjd vname = zpool_vdev_name(g_zfs, zhp, newchild[c], 2783219089Spjd B_FALSE); 2784185029Spjd print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL, 2785185029Spjd newchild[c], cb, depth + 2); 2786185029Spjd free(vname); 2787185029Spjd } 2788185029Spjd } 2789168404Spjd} 2790168404Spjd 2791168404Spjdstatic int 2792168404Spjdrefresh_iostat(zpool_handle_t *zhp, void *data) 2793168404Spjd{ 2794168404Spjd iostat_cbdata_t *cb = data; 2795168404Spjd boolean_t missing; 2796168404Spjd 2797168404Spjd /* 2798168404Spjd * If the pool has disappeared, remove it from the list and continue. 2799168404Spjd */ 2800168404Spjd if (zpool_refresh_stats(zhp, &missing) != 0) 2801168404Spjd return (-1); 2802168404Spjd 2803168404Spjd if (missing) 2804168404Spjd pool_list_remove(cb->cb_list, zhp); 2805168404Spjd 2806168404Spjd return (0); 2807168404Spjd} 2808168404Spjd 2809168404Spjd/* 2810168404Spjd * Callback to print out the iostats for the given pool. 2811168404Spjd */ 2812168404Spjdint 2813168404Spjdprint_iostat(zpool_handle_t *zhp, void *data) 2814168404Spjd{ 2815168404Spjd iostat_cbdata_t *cb = data; 2816168404Spjd nvlist_t *oldconfig, *newconfig; 2817168404Spjd nvlist_t *oldnvroot, *newnvroot; 2818168404Spjd 2819168404Spjd newconfig = zpool_get_config(zhp, &oldconfig); 2820168404Spjd 2821168404Spjd if (cb->cb_iteration == 1) 2822168404Spjd oldconfig = NULL; 2823168404Spjd 2824168404Spjd verify(nvlist_lookup_nvlist(newconfig, ZPOOL_CONFIG_VDEV_TREE, 2825168404Spjd &newnvroot) == 0); 2826168404Spjd 2827168404Spjd if (oldconfig == NULL) 2828168404Spjd oldnvroot = NULL; 2829168404Spjd else 2830168404Spjd verify(nvlist_lookup_nvlist(oldconfig, ZPOOL_CONFIG_VDEV_TREE, 2831168404Spjd &oldnvroot) == 0); 2832168404Spjd 2833168404Spjd /* 2834168404Spjd * Print out the statistics for the pool. 2835168404Spjd */ 2836168404Spjd print_vdev_stats(zhp, zpool_get_name(zhp), oldnvroot, newnvroot, cb, 0); 2837168404Spjd 2838168404Spjd if (cb->cb_verbose) 2839168404Spjd print_iostat_separator(cb); 2840168404Spjd 2841168404Spjd return (0); 2842168404Spjd} 2843168404Spjd 2844168404Spjdint 2845168404Spjdget_namewidth(zpool_handle_t *zhp, void *data) 2846168404Spjd{ 2847168404Spjd iostat_cbdata_t *cb = data; 2848168404Spjd nvlist_t *config, *nvroot; 2849168404Spjd 2850168404Spjd if ((config = zpool_get_config(zhp, NULL)) != NULL) { 2851168404Spjd verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 2852168404Spjd &nvroot) == 0); 2853168404Spjd if (!cb->cb_verbose) 2854168404Spjd cb->cb_namewidth = strlen(zpool_get_name(zhp)); 2855168404Spjd else 2856236145Smm cb->cb_namewidth = max_width(zhp, nvroot, 0, 2857236145Smm cb->cb_namewidth); 2858168404Spjd } 2859168404Spjd 2860168404Spjd /* 2861168404Spjd * The width must fall into the range [10,38]. The upper limit is the 2862168404Spjd * maximum we can have and still fit in 80 columns. 2863168404Spjd */ 2864168404Spjd if (cb->cb_namewidth < 10) 2865168404Spjd cb->cb_namewidth = 10; 2866168404Spjd if (cb->cb_namewidth > 38) 2867168404Spjd cb->cb_namewidth = 38; 2868168404Spjd 2869168404Spjd return (0); 2870168404Spjd} 2871168404Spjd 2872168404Spjd/* 2873219089Spjd * Parse the input string, get the 'interval' and 'count' value if there is one. 2874168404Spjd */ 2875219089Spjdstatic void 2876219089Spjdget_interval_count(int *argcp, char **argv, unsigned long *iv, 2877219089Spjd unsigned long *cnt) 2878168404Spjd{ 2879168404Spjd unsigned long interval = 0, count = 0; 2880219089Spjd int argc = *argcp, errno; 2881168404Spjd 2882168404Spjd /* 2883168404Spjd * Determine if the last argument is an integer or a pool name 2884168404Spjd */ 2885168404Spjd if (argc > 0 && isdigit(argv[argc - 1][0])) { 2886168404Spjd char *end; 2887168404Spjd 2888168404Spjd errno = 0; 2889168404Spjd interval = strtoul(argv[argc - 1], &end, 10); 2890168404Spjd 2891168404Spjd if (*end == '\0' && errno == 0) { 2892168404Spjd if (interval == 0) { 2893168404Spjd (void) fprintf(stderr, gettext("interval " 2894168404Spjd "cannot be zero\n")); 2895168404Spjd usage(B_FALSE); 2896168404Spjd } 2897168404Spjd /* 2898168404Spjd * Ignore the last parameter 2899168404Spjd */ 2900168404Spjd argc--; 2901168404Spjd } else { 2902168404Spjd /* 2903168404Spjd * If this is not a valid number, just plow on. The 2904168404Spjd * user will get a more informative error message later 2905168404Spjd * on. 2906168404Spjd */ 2907168404Spjd interval = 0; 2908168404Spjd } 2909168404Spjd } 2910168404Spjd 2911168404Spjd /* 2912168404Spjd * If the last argument is also an integer, then we have both a count 2913219089Spjd * and an interval. 2914168404Spjd */ 2915168404Spjd if (argc > 0 && isdigit(argv[argc - 1][0])) { 2916168404Spjd char *end; 2917168404Spjd 2918168404Spjd errno = 0; 2919168404Spjd count = interval; 2920168404Spjd interval = strtoul(argv[argc - 1], &end, 10); 2921168404Spjd 2922168404Spjd if (*end == '\0' && errno == 0) { 2923168404Spjd if (interval == 0) { 2924168404Spjd (void) fprintf(stderr, gettext("interval " 2925168404Spjd "cannot be zero\n")); 2926168404Spjd usage(B_FALSE); 2927168404Spjd } 2928168404Spjd 2929168404Spjd /* 2930168404Spjd * Ignore the last parameter 2931168404Spjd */ 2932168404Spjd argc--; 2933168404Spjd } else { 2934168404Spjd interval = 0; 2935168404Spjd } 2936168404Spjd } 2937168404Spjd 2938219089Spjd *iv = interval; 2939219089Spjd *cnt = count; 2940219089Spjd *argcp = argc; 2941219089Spjd} 2942219089Spjd 2943219089Spjdstatic void 2944219089Spjdget_timestamp_arg(char c) 2945219089Spjd{ 2946219089Spjd if (c == 'u') 2947219089Spjd timestamp_fmt = UDATE; 2948219089Spjd else if (c == 'd') 2949219089Spjd timestamp_fmt = DDATE; 2950219089Spjd else 2951219089Spjd usage(B_FALSE); 2952219089Spjd} 2953219089Spjd 2954219089Spjd/* 2955219089Spjd * zpool iostat [-v] [-T d|u] [pool] ... [interval [count]] 2956219089Spjd * 2957219089Spjd * -v Display statistics for individual vdevs 2958219089Spjd * -T Display a timestamp in date(1) or Unix format 2959219089Spjd * 2960219089Spjd * This command can be tricky because we want to be able to deal with pool 2961219089Spjd * creation/destruction as well as vdev configuration changes. The bulk of this 2962219089Spjd * processing is handled by the pool_list_* routines in zpool_iter.c. We rely 2963219089Spjd * on pool_list_update() to detect the addition of new pools. Configuration 2964219089Spjd * changes are all handled within libzfs. 2965219089Spjd */ 2966219089Spjdint 2967219089Spjdzpool_do_iostat(int argc, char **argv) 2968219089Spjd{ 2969219089Spjd int c; 2970219089Spjd int ret; 2971219089Spjd int npools; 2972219089Spjd unsigned long interval = 0, count = 0; 2973219089Spjd zpool_list_t *list; 2974219089Spjd boolean_t verbose = B_FALSE; 2975219089Spjd iostat_cbdata_t cb; 2976219089Spjd 2977219089Spjd /* check options */ 2978219089Spjd while ((c = getopt(argc, argv, "T:v")) != -1) { 2979219089Spjd switch (c) { 2980219089Spjd case 'T': 2981219089Spjd get_timestamp_arg(*optarg); 2982219089Spjd break; 2983219089Spjd case 'v': 2984219089Spjd verbose = B_TRUE; 2985219089Spjd break; 2986219089Spjd case '?': 2987219089Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 2988219089Spjd optopt); 2989219089Spjd usage(B_FALSE); 2990219089Spjd } 2991219089Spjd } 2992219089Spjd 2993219089Spjd argc -= optind; 2994219089Spjd argv += optind; 2995219089Spjd 2996219089Spjd get_interval_count(&argc, argv, &interval, &count); 2997219089Spjd 2998168404Spjd /* 2999168404Spjd * Construct the list of all interesting pools. 3000168404Spjd */ 3001168404Spjd ret = 0; 3002168404Spjd if ((list = pool_list_get(argc, argv, NULL, &ret)) == NULL) 3003168404Spjd return (1); 3004168404Spjd 3005168404Spjd if (pool_list_count(list) == 0 && argc != 0) { 3006168404Spjd pool_list_free(list); 3007168404Spjd return (1); 3008168404Spjd } 3009168404Spjd 3010168404Spjd if (pool_list_count(list) == 0 && interval == 0) { 3011168404Spjd pool_list_free(list); 3012168404Spjd (void) fprintf(stderr, gettext("no pools available\n")); 3013168404Spjd return (1); 3014168404Spjd } 3015168404Spjd 3016168404Spjd /* 3017168404Spjd * Enter the main iostat loop. 3018168404Spjd */ 3019168404Spjd cb.cb_list = list; 3020168404Spjd cb.cb_verbose = verbose; 3021168404Spjd cb.cb_iteration = 0; 3022168404Spjd cb.cb_namewidth = 0; 3023168404Spjd 3024168404Spjd for (;;) { 3025168404Spjd pool_list_update(list); 3026168404Spjd 3027168404Spjd if ((npools = pool_list_count(list)) == 0) 3028168404Spjd break; 3029168404Spjd 3030168404Spjd /* 3031168404Spjd * Refresh all statistics. This is done as an explicit step 3032168404Spjd * before calculating the maximum name width, so that any 3033168404Spjd * configuration changes are properly accounted for. 3034168404Spjd */ 3035168404Spjd (void) pool_list_iter(list, B_FALSE, refresh_iostat, &cb); 3036168404Spjd 3037168404Spjd /* 3038168404Spjd * Iterate over all pools to determine the maximum width 3039168404Spjd * for the pool / device name column across all pools. 3040168404Spjd */ 3041168404Spjd cb.cb_namewidth = 0; 3042168404Spjd (void) pool_list_iter(list, B_FALSE, get_namewidth, &cb); 3043168404Spjd 3044219089Spjd if (timestamp_fmt != NODATE) 3045219089Spjd print_timestamp(timestamp_fmt); 3046219089Spjd 3047168404Spjd /* 3048168404Spjd * If it's the first time, or verbose mode, print the header. 3049168404Spjd */ 3050168404Spjd if (++cb.cb_iteration == 1 || verbose) 3051168404Spjd print_iostat_header(&cb); 3052168404Spjd 3053168404Spjd (void) pool_list_iter(list, B_FALSE, print_iostat, &cb); 3054168404Spjd 3055168404Spjd /* 3056168404Spjd * If there's more than one pool, and we're not in verbose mode 3057168404Spjd * (which prints a separator for us), then print a separator. 3058168404Spjd */ 3059168404Spjd if (npools > 1 && !verbose) 3060168404Spjd print_iostat_separator(&cb); 3061168404Spjd 3062168404Spjd if (verbose) 3063168404Spjd (void) printf("\n"); 3064168404Spjd 3065168404Spjd /* 3066168404Spjd * Flush the output so that redirection to a file isn't buffered 3067168404Spjd * indefinitely. 3068168404Spjd */ 3069168404Spjd (void) fflush(stdout); 3070168404Spjd 3071168404Spjd if (interval == 0) 3072168404Spjd break; 3073168404Spjd 3074168404Spjd if (count != 0 && --count == 0) 3075168404Spjd break; 3076168404Spjd 3077168404Spjd (void) sleep(interval); 3078168404Spjd } 3079168404Spjd 3080168404Spjd pool_list_free(list); 3081168404Spjd 3082168404Spjd return (ret); 3083168404Spjd} 3084168404Spjd 3085168404Spjdtypedef struct list_cbdata { 3086236155Smm boolean_t cb_verbose; 3087236155Smm int cb_namewidth; 3088168404Spjd boolean_t cb_scripted; 3089185029Spjd zprop_list_t *cb_proplist; 3090263889Sdelphij boolean_t cb_literal; 3091168404Spjd} list_cbdata_t; 3092168404Spjd 3093168404Spjd/* 3094168404Spjd * Given a list of columns to display, output appropriate headers for each one. 3095168404Spjd */ 3096185029Spjdstatic void 3097236155Smmprint_header(list_cbdata_t *cb) 3098168404Spjd{ 3099236155Smm zprop_list_t *pl = cb->cb_proplist; 3100236884Smm char headerbuf[ZPOOL_MAXPROPLEN]; 3101185029Spjd const char *header; 3102185029Spjd boolean_t first = B_TRUE; 3103185029Spjd boolean_t right_justify; 3104236155Smm size_t width = 0; 3105168404Spjd 3106185029Spjd for (; pl != NULL; pl = pl->pl_next) { 3107236155Smm width = pl->pl_width; 3108236155Smm if (first && cb->cb_verbose) { 3109236155Smm /* 3110236155Smm * Reset the width to accommodate the verbose listing 3111236155Smm * of devices. 3112236155Smm */ 3113236155Smm width = cb->cb_namewidth; 3114236155Smm } 3115236155Smm 3116185029Spjd if (!first) 3117168404Spjd (void) printf(" "); 3118168404Spjd else 3119185029Spjd first = B_FALSE; 3120168404Spjd 3121236884Smm right_justify = B_FALSE; 3122236884Smm if (pl->pl_prop != ZPROP_INVAL) { 3123236884Smm header = zpool_prop_column_name(pl->pl_prop); 3124236884Smm right_justify = zpool_prop_align_right(pl->pl_prop); 3125236884Smm } else { 3126236884Smm int i; 3127185029Spjd 3128236884Smm for (i = 0; pl->pl_user_prop[i] != '\0'; i++) 3129236884Smm headerbuf[i] = toupper(pl->pl_user_prop[i]); 3130236884Smm headerbuf[i] = '\0'; 3131236884Smm header = headerbuf; 3132236884Smm } 3133236884Smm 3134185029Spjd if (pl->pl_next == NULL && !right_justify) 3135185029Spjd (void) printf("%s", header); 3136185029Spjd else if (right_justify) 3137236155Smm (void) printf("%*s", width, header); 3138185029Spjd else 3139236155Smm (void) printf("%-*s", width, header); 3140236155Smm 3141168404Spjd } 3142168404Spjd 3143168404Spjd (void) printf("\n"); 3144168404Spjd} 3145168404Spjd 3146185029Spjd/* 3147185029Spjd * Given a pool and a list of properties, print out all the properties according 3148185029Spjd * to the described layout. 3149185029Spjd */ 3150185029Spjdstatic void 3151236155Smmprint_pool(zpool_handle_t *zhp, list_cbdata_t *cb) 3152168404Spjd{ 3153236155Smm zprop_list_t *pl = cb->cb_proplist; 3154185029Spjd boolean_t first = B_TRUE; 3155185029Spjd char property[ZPOOL_MAXPROPLEN]; 3156185029Spjd char *propstr; 3157185029Spjd boolean_t right_justify; 3158236155Smm size_t width; 3159168404Spjd 3160185029Spjd for (; pl != NULL; pl = pl->pl_next) { 3161236155Smm 3162236155Smm width = pl->pl_width; 3163236155Smm if (first && cb->cb_verbose) { 3164236155Smm /* 3165236155Smm * Reset the width to accommodate the verbose listing 3166236155Smm * of devices. 3167236155Smm */ 3168236155Smm width = cb->cb_namewidth; 3169236155Smm } 3170236155Smm 3171185029Spjd if (!first) { 3172236155Smm if (cb->cb_scripted) 3173168404Spjd (void) printf("\t"); 3174168404Spjd else 3175168404Spjd (void) printf(" "); 3176185029Spjd } else { 3177185029Spjd first = B_FALSE; 3178168404Spjd } 3179168404Spjd 3180185029Spjd right_justify = B_FALSE; 3181185029Spjd if (pl->pl_prop != ZPROP_INVAL) { 3182272502Sdelphij if (zpool_get_prop(zhp, pl->pl_prop, property, 3183263889Sdelphij sizeof (property), NULL, cb->cb_literal) != 0) 3184185029Spjd propstr = "-"; 3185168404Spjd else 3186185029Spjd propstr = property; 3187168404Spjd 3188185029Spjd right_justify = zpool_prop_align_right(pl->pl_prop); 3189236884Smm } else if ((zpool_prop_feature(pl->pl_user_prop) || 3190236884Smm zpool_prop_unsupported(pl->pl_user_prop)) && 3191236884Smm zpool_prop_get_feature(zhp, pl->pl_user_prop, property, 3192236884Smm sizeof (property)) == 0) { 3193236884Smm propstr = property; 3194185029Spjd } else { 3195185029Spjd propstr = "-"; 3196185029Spjd } 3197168404Spjd 3198168404Spjd 3199185029Spjd /* 3200185029Spjd * If this is being called in scripted mode, or if this is the 3201185029Spjd * last column and it is left-justified, don't include a width 3202185029Spjd * format specifier. 3203185029Spjd */ 3204236155Smm if (cb->cb_scripted || (pl->pl_next == NULL && !right_justify)) 3205185029Spjd (void) printf("%s", propstr); 3206185029Spjd else if (right_justify) 3207185029Spjd (void) printf("%*s", width, propstr); 3208185029Spjd else 3209185029Spjd (void) printf("%-*s", width, propstr); 3210185029Spjd } 3211168404Spjd 3212185029Spjd (void) printf("\n"); 3213185029Spjd} 3214168404Spjd 3215236155Smmstatic void 3216272502Sdelphijprint_one_column(zpool_prop_t prop, uint64_t value, boolean_t scripted, 3217272502Sdelphij boolean_t valid) 3218236155Smm{ 3219236155Smm char propval[64]; 3220236155Smm boolean_t fixed; 3221236155Smm size_t width = zprop_width(prop, &fixed, ZFS_TYPE_POOL); 3222236155Smm 3223272502Sdelphij switch (prop) { 3224272502Sdelphij case ZPOOL_PROP_EXPANDSZ: 3225332547Smav case ZPOOL_PROP_CHECKPOINT: 3226272502Sdelphij if (value == 0) 3227272502Sdelphij (void) strlcpy(propval, "-", sizeof (propval)); 3228272502Sdelphij else 3229272502Sdelphij zfs_nicenum(value, propval, sizeof (propval)); 3230272502Sdelphij break; 3231272502Sdelphij case ZPOOL_PROP_FRAGMENTATION: 3232272502Sdelphij if (value == ZFS_FRAG_INVALID) { 3233272502Sdelphij (void) strlcpy(propval, "-", sizeof (propval)); 3234272502Sdelphij } else { 3235272502Sdelphij (void) snprintf(propval, sizeof (propval), "%llu%%", 3236272502Sdelphij value); 3237272502Sdelphij } 3238272502Sdelphij break; 3239272502Sdelphij case ZPOOL_PROP_CAPACITY: 3240269118Sdelphij (void) snprintf(propval, sizeof (propval), "%llu%%", value); 3241272502Sdelphij break; 3242272502Sdelphij default: 3243269118Sdelphij zfs_nicenum(value, propval, sizeof (propval)); 3244272502Sdelphij } 3245236155Smm 3246272502Sdelphij if (!valid) 3247272502Sdelphij (void) strlcpy(propval, "-", sizeof (propval)); 3248272502Sdelphij 3249236155Smm if (scripted) 3250236155Smm (void) printf("\t%s", propval); 3251236155Smm else 3252236155Smm (void) printf(" %*s", width, propval); 3253236155Smm} 3254236155Smm 3255236155Smmvoid 3256236155Smmprint_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv, 3257236155Smm list_cbdata_t *cb, int depth) 3258236155Smm{ 3259236155Smm nvlist_t **child; 3260236155Smm vdev_stat_t *vs; 3261236155Smm uint_t c, children; 3262236155Smm char *vname; 3263236155Smm boolean_t scripted = cb->cb_scripted; 3264289536Smav uint64_t islog = B_FALSE; 3265289536Smav boolean_t haslog = B_FALSE; 3266289536Smav char *dashes = "%-*s - - - - - -\n"; 3267236155Smm 3268236155Smm verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS, 3269236155Smm (uint64_t **)&vs, &c) == 0); 3270236155Smm 3271236155Smm if (name != NULL) { 3272272502Sdelphij boolean_t toplevel = (vs->vs_space != 0); 3273272502Sdelphij uint64_t cap; 3274272502Sdelphij 3275332525Smav if (strcmp(name, VDEV_TYPE_INDIRECT) == 0) 3276332525Smav return; 3277332525Smav 3278236155Smm if (scripted) 3279236155Smm (void) printf("\t%s", name); 3280236155Smm else if (strlen(name) + depth > cb->cb_namewidth) 3281236155Smm (void) printf("%*s%s", depth, "", name); 3282236155Smm else 3283236155Smm (void) printf("%*s%s%*s", depth, "", name, 3284236155Smm (int)(cb->cb_namewidth - strlen(name) - depth), ""); 3285236155Smm 3286272502Sdelphij /* 3287272502Sdelphij * Print the properties for the individual vdevs. Some 3288272502Sdelphij * properties are only applicable to toplevel vdevs. The 3289272502Sdelphij * 'toplevel' boolean value is passed to the print_one_column() 3290272502Sdelphij * to indicate that the value is valid. 3291272502Sdelphij */ 3292272502Sdelphij print_one_column(ZPOOL_PROP_SIZE, vs->vs_space, scripted, 3293272502Sdelphij toplevel); 3294272502Sdelphij print_one_column(ZPOOL_PROP_ALLOCATED, vs->vs_alloc, scripted, 3295272502Sdelphij toplevel); 3296272502Sdelphij print_one_column(ZPOOL_PROP_FREE, vs->vs_space - vs->vs_alloc, 3297272502Sdelphij scripted, toplevel); 3298332547Smav print_one_column(ZPOOL_PROP_CHECKPOINT, 3299332547Smav vs->vs_checkpoint_space, scripted, toplevel); 3300272502Sdelphij print_one_column(ZPOOL_PROP_EXPANDSZ, vs->vs_esize, scripted, 3301272502Sdelphij B_TRUE); 3302272502Sdelphij print_one_column(ZPOOL_PROP_FRAGMENTATION, 3303272502Sdelphij vs->vs_fragmentation, scripted, 3304272502Sdelphij (vs->vs_fragmentation != ZFS_FRAG_INVALID && toplevel)); 3305272502Sdelphij cap = (vs->vs_space == 0) ? 0 : 3306272502Sdelphij (vs->vs_alloc * 100 / vs->vs_space); 3307272502Sdelphij print_one_column(ZPOOL_PROP_CAPACITY, cap, scripted, toplevel); 3308236155Smm (void) printf("\n"); 3309236155Smm } 3310236155Smm 3311236155Smm if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 3312236155Smm &child, &children) != 0) 3313236155Smm return; 3314236155Smm 3315236155Smm for (c = 0; c < children; c++) { 3316236155Smm uint64_t ishole = B_FALSE; 3317236155Smm 3318236155Smm if (nvlist_lookup_uint64(child[c], 3319236155Smm ZPOOL_CONFIG_IS_HOLE, &ishole) == 0 && ishole) 3320236155Smm continue; 3321236155Smm 3322289536Smav if (nvlist_lookup_uint64(child[c], 3323289536Smav ZPOOL_CONFIG_IS_LOG, &islog) == 0 && islog) { 3324289536Smav haslog = B_TRUE; 3325289536Smav continue; 3326289536Smav } 3327289536Smav 3328236155Smm vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE); 3329236155Smm print_list_stats(zhp, vname, child[c], cb, depth + 2); 3330236155Smm free(vname); 3331236155Smm } 3332236155Smm 3333289536Smav if (haslog == B_TRUE) { 3334289536Smav /* LINTED E_SEC_PRINTF_VAR_FMT */ 3335289536Smav (void) printf(dashes, cb->cb_namewidth, "log"); 3336289536Smav for (c = 0; c < children; c++) { 3337289536Smav if (nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, 3338289536Smav &islog) != 0 || !islog) 3339289536Smav continue; 3340289536Smav vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE); 3341289536Smav print_list_stats(zhp, vname, child[c], cb, depth + 2); 3342289536Smav free(vname); 3343289536Smav } 3344289536Smav } 3345289536Smav 3346236155Smm if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE, 3347289536Smav &child, &children) == 0 && children > 0) { 3348289536Smav /* LINTED E_SEC_PRINTF_VAR_FMT */ 3349289536Smav (void) printf(dashes, cb->cb_namewidth, "cache"); 3350289536Smav for (c = 0; c < children; c++) { 3351289536Smav vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE); 3352289536Smav print_list_stats(zhp, vname, child[c], cb, depth + 2); 3353289536Smav free(vname); 3354289536Smav } 3355289536Smav } 3356236155Smm 3357289536Smav if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, &child, 3358289536Smav &children) == 0 && children > 0) { 3359289536Smav /* LINTED E_SEC_PRINTF_VAR_FMT */ 3360289536Smav (void) printf(dashes, cb->cb_namewidth, "spare"); 3361236155Smm for (c = 0; c < children; c++) { 3362289536Smav vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE); 3363236155Smm print_list_stats(zhp, vname, child[c], cb, depth + 2); 3364236155Smm free(vname); 3365236155Smm } 3366236155Smm } 3367236155Smm} 3368236155Smm 3369236155Smm 3370185029Spjd/* 3371185029Spjd * Generic callback function to list a pool. 3372185029Spjd */ 3373185029Spjdint 3374185029Spjdlist_callback(zpool_handle_t *zhp, void *data) 3375185029Spjd{ 3376185029Spjd list_cbdata_t *cbp = data; 3377236155Smm nvlist_t *config; 3378236155Smm nvlist_t *nvroot; 3379168404Spjd 3380236155Smm config = zpool_get_config(zhp, NULL); 3381168404Spjd 3382236155Smm print_pool(zhp, cbp); 3383236155Smm if (!cbp->cb_verbose) 3384236155Smm return (0); 3385168404Spjd 3386236155Smm verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 3387236155Smm &nvroot) == 0); 3388236155Smm print_list_stats(zhp, NULL, nvroot, cbp, 0); 3389236155Smm 3390168404Spjd return (0); 3391168404Spjd} 3392168404Spjd 3393168404Spjd/* 3394263889Sdelphij * zpool list [-Hp] [-o prop[,prop]*] [-T d|u] [pool] ... [interval [count]] 3395168404Spjd * 3396185029Spjd * -H Scripted mode. Don't display headers, and separate properties 3397185029Spjd * by a single tab. 3398185029Spjd * -o List of properties to display. Defaults to 3399272502Sdelphij * "name,size,allocated,free,expandsize,fragmentation,capacity," 3400272502Sdelphij * "dedupratio,health,altroot" 3401263889Sdelphij * -p Diplay values in parsable (exact) format. 3402219089Spjd * -T Display a timestamp in date(1) or Unix format 3403168404Spjd * 3404168404Spjd * List all pools in the system, whether or not they're healthy. Output space 3405168404Spjd * statistics for each one, as well as health status summary. 3406168404Spjd */ 3407168404Spjdint 3408168404Spjdzpool_do_list(int argc, char **argv) 3409168404Spjd{ 3410168404Spjd int c; 3411168404Spjd int ret; 3412168404Spjd list_cbdata_t cb = { 0 }; 3413185029Spjd static char default_props[] = 3414332547Smav "name,size,allocated,free,checkpoint,expandsize,fragmentation," 3415332547Smav "capacity,dedupratio,health,altroot"; 3416185029Spjd char *props = default_props; 3417219089Spjd unsigned long interval = 0, count = 0; 3418236155Smm zpool_list_t *list; 3419236155Smm boolean_t first = B_TRUE; 3420168404Spjd 3421168404Spjd /* check options */ 3422263889Sdelphij while ((c = getopt(argc, argv, ":Ho:pT:v")) != -1) { 3423168404Spjd switch (c) { 3424168404Spjd case 'H': 3425168404Spjd cb.cb_scripted = B_TRUE; 3426168404Spjd break; 3427168404Spjd case 'o': 3428185029Spjd props = optarg; 3429168404Spjd break; 3430263889Sdelphij case 'p': 3431263889Sdelphij cb.cb_literal = B_TRUE; 3432263889Sdelphij break; 3433219089Spjd case 'T': 3434219089Spjd get_timestamp_arg(*optarg); 3435219089Spjd break; 3436236155Smm case 'v': 3437236155Smm cb.cb_verbose = B_TRUE; 3438236155Smm break; 3439168404Spjd case ':': 3440168404Spjd (void) fprintf(stderr, gettext("missing argument for " 3441168404Spjd "'%c' option\n"), optopt); 3442168404Spjd usage(B_FALSE); 3443168404Spjd break; 3444168404Spjd case '?': 3445168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3446168404Spjd optopt); 3447168404Spjd usage(B_FALSE); 3448168404Spjd } 3449168404Spjd } 3450168404Spjd 3451168404Spjd argc -= optind; 3452168404Spjd argv += optind; 3453168404Spjd 3454219089Spjd get_interval_count(&argc, argv, &interval, &count); 3455219089Spjd 3456185029Spjd if (zprop_get_list(g_zfs, props, &cb.cb_proplist, ZFS_TYPE_POOL) != 0) 3457185029Spjd usage(B_FALSE); 3458168404Spjd 3459219089Spjd for (;;) { 3460268470Sdelphij if ((list = pool_list_get(argc, argv, &cb.cb_proplist, 3461268470Sdelphij &ret)) == NULL) 3462268470Sdelphij return (1); 3463168404Spjd 3464236155Smm if (pool_list_count(list) == 0) 3465236155Smm break; 3466236155Smm 3467236155Smm cb.cb_namewidth = 0; 3468236155Smm (void) pool_list_iter(list, B_FALSE, get_namewidth, &cb); 3469236155Smm 3470219089Spjd if (timestamp_fmt != NODATE) 3471219089Spjd print_timestamp(timestamp_fmt); 3472168404Spjd 3473236155Smm if (!cb.cb_scripted && (first || cb.cb_verbose)) { 3474236155Smm print_header(&cb); 3475236155Smm first = B_FALSE; 3476219089Spjd } 3477236155Smm ret = pool_list_iter(list, B_TRUE, list_callback, &cb); 3478219089Spjd 3479219089Spjd if (interval == 0) 3480219089Spjd break; 3481219089Spjd 3482219089Spjd if (count != 0 && --count == 0) 3483219089Spjd break; 3484219089Spjd 3485268470Sdelphij pool_list_free(list); 3486219089Spjd (void) sleep(interval); 3487168404Spjd } 3488168404Spjd 3489268470Sdelphij if (argc == 0 && !cb.cb_scripted && pool_list_count(list) == 0) { 3490268470Sdelphij (void) printf(gettext("no pools available\n")); 3491268470Sdelphij ret = 0; 3492268470Sdelphij } 3493268470Sdelphij 3494268470Sdelphij pool_list_free(list); 3495219089Spjd zprop_free_list(cb.cb_proplist); 3496168404Spjd return (ret); 3497168404Spjd} 3498168404Spjd 3499168404Spjdstatic int 3500168404Spjdzpool_do_attach_or_replace(int argc, char **argv, int replacing) 3501168404Spjd{ 3502168404Spjd boolean_t force = B_FALSE; 3503168404Spjd int c; 3504168404Spjd nvlist_t *nvroot; 3505168404Spjd char *poolname, *old_disk, *new_disk; 3506168404Spjd zpool_handle_t *zhp; 3507331395Smav zpool_boot_label_t boot_type; 3508331395Smav uint64_t boot_size; 3509168404Spjd int ret; 3510168404Spjd 3511168404Spjd /* check options */ 3512168404Spjd while ((c = getopt(argc, argv, "f")) != -1) { 3513168404Spjd switch (c) { 3514168404Spjd case 'f': 3515168404Spjd force = B_TRUE; 3516168404Spjd break; 3517168404Spjd case '?': 3518168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3519168404Spjd optopt); 3520168404Spjd usage(B_FALSE); 3521168404Spjd } 3522168404Spjd } 3523168404Spjd 3524168404Spjd argc -= optind; 3525168404Spjd argv += optind; 3526168404Spjd 3527168404Spjd /* get pool name and check number of arguments */ 3528168404Spjd if (argc < 1) { 3529168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 3530168404Spjd usage(B_FALSE); 3531168404Spjd } 3532168404Spjd 3533168404Spjd poolname = argv[0]; 3534168404Spjd 3535168404Spjd if (argc < 2) { 3536168404Spjd (void) fprintf(stderr, 3537168404Spjd gettext("missing <device> specification\n")); 3538168404Spjd usage(B_FALSE); 3539168404Spjd } 3540168404Spjd 3541168404Spjd old_disk = argv[1]; 3542168404Spjd 3543168404Spjd if (argc < 3) { 3544168404Spjd if (!replacing) { 3545168404Spjd (void) fprintf(stderr, 3546168404Spjd gettext("missing <new_device> specification\n")); 3547168404Spjd usage(B_FALSE); 3548168404Spjd } 3549168404Spjd new_disk = old_disk; 3550168404Spjd argc -= 1; 3551168404Spjd argv += 1; 3552168404Spjd } else { 3553168404Spjd new_disk = argv[2]; 3554168404Spjd argc -= 2; 3555168404Spjd argv += 2; 3556168404Spjd } 3557168404Spjd 3558168404Spjd if (argc > 1) { 3559168404Spjd (void) fprintf(stderr, gettext("too many arguments\n")); 3560168404Spjd usage(B_FALSE); 3561168404Spjd } 3562168404Spjd 3563168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 3564168404Spjd return (1); 3565168404Spjd 3566185029Spjd if (zpool_get_config(zhp, NULL) == NULL) { 3567168404Spjd (void) fprintf(stderr, gettext("pool '%s' is unavailable\n"), 3568168404Spjd poolname); 3569168404Spjd zpool_close(zhp); 3570168404Spjd return (1); 3571168404Spjd } 3572168404Spjd 3573331395Smav if (zpool_is_bootable(zhp)) 3574331395Smav boot_type = ZPOOL_COPY_BOOT_LABEL; 3575331395Smav else 3576331395Smav boot_type = ZPOOL_NO_BOOT_LABEL; 3577331395Smav 3578331395Smav boot_size = zpool_get_prop_int(zhp, ZPOOL_PROP_BOOTSIZE, NULL); 3579185029Spjd nvroot = make_root_vdev(zhp, force, B_FALSE, replacing, B_FALSE, 3580331395Smav boot_type, boot_size, argc, argv); 3581168404Spjd if (nvroot == NULL) { 3582168404Spjd zpool_close(zhp); 3583168404Spjd return (1); 3584168404Spjd } 3585168404Spjd 3586168404Spjd ret = zpool_vdev_attach(zhp, old_disk, new_disk, nvroot, replacing); 3587168404Spjd 3588168404Spjd nvlist_free(nvroot); 3589168404Spjd zpool_close(zhp); 3590168404Spjd 3591168404Spjd return (ret); 3592168404Spjd} 3593168404Spjd 3594168404Spjd/* 3595168404Spjd * zpool replace [-f] <pool> <device> <new_device> 3596168404Spjd * 3597168404Spjd * -f Force attach, even if <new_device> appears to be in use. 3598168404Spjd * 3599168404Spjd * Replace <device> with <new_device>. 3600168404Spjd */ 3601168404Spjd/* ARGSUSED */ 3602168404Spjdint 3603168404Spjdzpool_do_replace(int argc, char **argv) 3604168404Spjd{ 3605168404Spjd return (zpool_do_attach_or_replace(argc, argv, B_TRUE)); 3606168404Spjd} 3607168404Spjd 3608168404Spjd/* 3609168404Spjd * zpool attach [-f] <pool> <device> <new_device> 3610168404Spjd * 3611168404Spjd * -f Force attach, even if <new_device> appears to be in use. 3612168404Spjd * 3613168404Spjd * Attach <new_device> to the mirror containing <device>. If <device> is not 3614168404Spjd * part of a mirror, then <device> will be transformed into a mirror of 3615168404Spjd * <device> and <new_device>. In either case, <new_device> will begin life 3616168404Spjd * with a DTL of [0, now], and will immediately begin to resilver itself. 3617168404Spjd */ 3618168404Spjdint 3619168404Spjdzpool_do_attach(int argc, char **argv) 3620168404Spjd{ 3621168404Spjd return (zpool_do_attach_or_replace(argc, argv, B_FALSE)); 3622168404Spjd} 3623168404Spjd 3624168404Spjd/* 3625168404Spjd * zpool detach [-f] <pool> <device> 3626168404Spjd * 3627168404Spjd * -f Force detach of <device>, even if DTLs argue against it 3628168404Spjd * (not supported yet) 3629168404Spjd * 3630168404Spjd * Detach a device from a mirror. The operation will be refused if <device> 3631168404Spjd * is the last device in the mirror, or if the DTLs indicate that this device 3632168404Spjd * has the only valid copy of some data. 3633168404Spjd */ 3634168404Spjd/* ARGSUSED */ 3635168404Spjdint 3636168404Spjdzpool_do_detach(int argc, char **argv) 3637168404Spjd{ 3638168404Spjd int c; 3639168404Spjd char *poolname, *path; 3640168404Spjd zpool_handle_t *zhp; 3641168404Spjd int ret; 3642168404Spjd 3643168404Spjd /* check options */ 3644168404Spjd while ((c = getopt(argc, argv, "f")) != -1) { 3645168404Spjd switch (c) { 3646168404Spjd case 'f': 3647168404Spjd case '?': 3648168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3649168404Spjd optopt); 3650168404Spjd usage(B_FALSE); 3651168404Spjd } 3652168404Spjd } 3653168404Spjd 3654168404Spjd argc -= optind; 3655168404Spjd argv += optind; 3656168404Spjd 3657168404Spjd /* get pool name and check number of arguments */ 3658168404Spjd if (argc < 1) { 3659168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 3660168404Spjd usage(B_FALSE); 3661168404Spjd } 3662168404Spjd 3663168404Spjd if (argc < 2) { 3664168404Spjd (void) fprintf(stderr, 3665168404Spjd gettext("missing <device> specification\n")); 3666168404Spjd usage(B_FALSE); 3667168404Spjd } 3668168404Spjd 3669168404Spjd poolname = argv[0]; 3670168404Spjd path = argv[1]; 3671168404Spjd 3672168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 3673168404Spjd return (1); 3674168404Spjd 3675168404Spjd ret = zpool_vdev_detach(zhp, path); 3676168404Spjd 3677168404Spjd zpool_close(zhp); 3678168404Spjd 3679168404Spjd return (ret); 3680168404Spjd} 3681168404Spjd 3682168404Spjd/* 3683219089Spjd * zpool split [-n] [-o prop=val] ... 3684219089Spjd * [-o mntopt] ... 3685219089Spjd * [-R altroot] <pool> <newpool> [<device> ...] 3686219089Spjd * 3687219089Spjd * -n Do not split the pool, but display the resulting layout if 3688219089Spjd * it were to be split. 3689219089Spjd * -o Set property=value, or set mount options. 3690219089Spjd * -R Mount the split-off pool under an alternate root. 3691219089Spjd * 3692219089Spjd * Splits the named pool and gives it the new pool name. Devices to be split 3693219089Spjd * off may be listed, provided that no more than one device is specified 3694219089Spjd * per top-level vdev mirror. The newly split pool is left in an exported 3695219089Spjd * state unless -R is specified. 3696219089Spjd * 3697219089Spjd * Restrictions: the top-level of the pool pool must only be made up of 3698219089Spjd * mirrors; all devices in the pool must be healthy; no device may be 3699219089Spjd * undergoing a resilvering operation. 3700219089Spjd */ 3701219089Spjdint 3702219089Spjdzpool_do_split(int argc, char **argv) 3703219089Spjd{ 3704219089Spjd char *srcpool, *newpool, *propval; 3705219089Spjd char *mntopts = NULL; 3706219089Spjd splitflags_t flags; 3707219089Spjd int c, ret = 0; 3708219089Spjd zpool_handle_t *zhp; 3709219089Spjd nvlist_t *config, *props = NULL; 3710219089Spjd 3711219089Spjd flags.dryrun = B_FALSE; 3712219089Spjd flags.import = B_FALSE; 3713219089Spjd 3714219089Spjd /* check options */ 3715219089Spjd while ((c = getopt(argc, argv, ":R:no:")) != -1) { 3716219089Spjd switch (c) { 3717219089Spjd case 'R': 3718219089Spjd flags.import = B_TRUE; 3719219089Spjd if (add_prop_list( 3720219089Spjd zpool_prop_to_name(ZPOOL_PROP_ALTROOT), optarg, 3721219089Spjd &props, B_TRUE) != 0) { 3722296528Smav nvlist_free(props); 3723219089Spjd usage(B_FALSE); 3724219089Spjd } 3725219089Spjd break; 3726219089Spjd case 'n': 3727219089Spjd flags.dryrun = B_TRUE; 3728219089Spjd break; 3729219089Spjd case 'o': 3730219089Spjd if ((propval = strchr(optarg, '=')) != NULL) { 3731219089Spjd *propval = '\0'; 3732219089Spjd propval++; 3733219089Spjd if (add_prop_list(optarg, propval, 3734219089Spjd &props, B_TRUE) != 0) { 3735296528Smav nvlist_free(props); 3736219089Spjd usage(B_FALSE); 3737219089Spjd } 3738219089Spjd } else { 3739219089Spjd mntopts = optarg; 3740219089Spjd } 3741219089Spjd break; 3742219089Spjd case ':': 3743219089Spjd (void) fprintf(stderr, gettext("missing argument for " 3744219089Spjd "'%c' option\n"), optopt); 3745219089Spjd usage(B_FALSE); 3746219089Spjd break; 3747219089Spjd case '?': 3748219089Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3749219089Spjd optopt); 3750219089Spjd usage(B_FALSE); 3751219089Spjd break; 3752219089Spjd } 3753219089Spjd } 3754219089Spjd 3755219089Spjd if (!flags.import && mntopts != NULL) { 3756219089Spjd (void) fprintf(stderr, gettext("setting mntopts is only " 3757219089Spjd "valid when importing the pool\n")); 3758219089Spjd usage(B_FALSE); 3759219089Spjd } 3760219089Spjd 3761219089Spjd argc -= optind; 3762219089Spjd argv += optind; 3763219089Spjd 3764219089Spjd if (argc < 1) { 3765219089Spjd (void) fprintf(stderr, gettext("Missing pool name\n")); 3766219089Spjd usage(B_FALSE); 3767219089Spjd } 3768219089Spjd if (argc < 2) { 3769219089Spjd (void) fprintf(stderr, gettext("Missing new pool name\n")); 3770219089Spjd usage(B_FALSE); 3771219089Spjd } 3772219089Spjd 3773219089Spjd srcpool = argv[0]; 3774219089Spjd newpool = argv[1]; 3775219089Spjd 3776219089Spjd argc -= 2; 3777219089Spjd argv += 2; 3778219089Spjd 3779219089Spjd if ((zhp = zpool_open(g_zfs, srcpool)) == NULL) 3780219089Spjd return (1); 3781219089Spjd 3782219089Spjd config = split_mirror_vdev(zhp, newpool, props, flags, argc, argv); 3783219089Spjd if (config == NULL) { 3784219089Spjd ret = 1; 3785219089Spjd } else { 3786219089Spjd if (flags.dryrun) { 3787219089Spjd (void) printf(gettext("would create '%s' with the " 3788219089Spjd "following layout:\n\n"), newpool); 3789219089Spjd print_vdev_tree(NULL, newpool, config, 0, B_FALSE); 3790219089Spjd } 3791219089Spjd nvlist_free(config); 3792219089Spjd } 3793219089Spjd 3794219089Spjd zpool_close(zhp); 3795219089Spjd 3796219089Spjd if (ret != 0 || flags.dryrun || !flags.import) 3797219089Spjd return (ret); 3798219089Spjd 3799219089Spjd /* 3800219089Spjd * The split was successful. Now we need to open the new 3801219089Spjd * pool and import it. 3802219089Spjd */ 3803219089Spjd if ((zhp = zpool_open_canfail(g_zfs, newpool)) == NULL) 3804219089Spjd return (1); 3805219089Spjd if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL && 3806219089Spjd zpool_enable_datasets(zhp, mntopts, 0) != 0) { 3807219089Spjd ret = 1; 3808240415Smm (void) fprintf(stderr, gettext("Split was successful, but " 3809219089Spjd "the datasets could not all be mounted\n")); 3810219089Spjd (void) fprintf(stderr, gettext("Try doing '%s' with a " 3811219089Spjd "different altroot\n"), "zpool import"); 3812219089Spjd } 3813219089Spjd zpool_close(zhp); 3814219089Spjd 3815219089Spjd return (ret); 3816219089Spjd} 3817219089Spjd 3818219089Spjd 3819219089Spjd 3820219089Spjd/* 3821168404Spjd * zpool online <pool> <device> ... 3822168404Spjd */ 3823168404Spjdint 3824168404Spjdzpool_do_online(int argc, char **argv) 3825168404Spjd{ 3826168404Spjd int c, i; 3827168404Spjd char *poolname; 3828168404Spjd zpool_handle_t *zhp; 3829168404Spjd int ret = 0; 3830185029Spjd vdev_state_t newstate; 3831219089Spjd int flags = 0; 3832168404Spjd 3833168404Spjd /* check options */ 3834219089Spjd while ((c = getopt(argc, argv, "et")) != -1) { 3835168404Spjd switch (c) { 3836219089Spjd case 'e': 3837219089Spjd flags |= ZFS_ONLINE_EXPAND; 3838219089Spjd break; 3839168404Spjd case 't': 3840168404Spjd case '?': 3841168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3842168404Spjd optopt); 3843168404Spjd usage(B_FALSE); 3844168404Spjd } 3845168404Spjd } 3846168404Spjd 3847168404Spjd argc -= optind; 3848168404Spjd argv += optind; 3849168404Spjd 3850168404Spjd /* get pool name and check number of arguments */ 3851168404Spjd if (argc < 1) { 3852168404Spjd (void) fprintf(stderr, gettext("missing pool name\n")); 3853168404Spjd usage(B_FALSE); 3854168404Spjd } 3855168404Spjd if (argc < 2) { 3856168404Spjd (void) fprintf(stderr, gettext("missing device name\n")); 3857168404Spjd usage(B_FALSE); 3858168404Spjd } 3859168404Spjd 3860168404Spjd poolname = argv[0]; 3861168404Spjd 3862168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 3863168404Spjd return (1); 3864168404Spjd 3865185029Spjd for (i = 1; i < argc; i++) { 3866219089Spjd if (zpool_vdev_online(zhp, argv[i], flags, &newstate) == 0) { 3867185029Spjd if (newstate != VDEV_STATE_HEALTHY) { 3868185029Spjd (void) printf(gettext("warning: device '%s' " 3869185029Spjd "onlined, but remains in faulted state\n"), 3870185029Spjd argv[i]); 3871185029Spjd if (newstate == VDEV_STATE_FAULTED) 3872185029Spjd (void) printf(gettext("use 'zpool " 3873185029Spjd "clear' to restore a faulted " 3874185029Spjd "device\n")); 3875185029Spjd else 3876185029Spjd (void) printf(gettext("use 'zpool " 3877185029Spjd "replace' to replace devices " 3878185029Spjd "that are no longer present\n")); 3879185029Spjd } 3880185029Spjd } else { 3881168404Spjd ret = 1; 3882185029Spjd } 3883185029Spjd } 3884168404Spjd 3885168404Spjd zpool_close(zhp); 3886168404Spjd 3887168404Spjd return (ret); 3888168404Spjd} 3889168404Spjd 3890168404Spjd/* 3891168404Spjd * zpool offline [-ft] <pool> <device> ... 3892168404Spjd * 3893168404Spjd * -f Force the device into the offline state, even if doing 3894168404Spjd * so would appear to compromise pool availability. 3895168404Spjd * (not supported yet) 3896168404Spjd * 3897168404Spjd * -t Only take the device off-line temporarily. The offline 3898168404Spjd * state will not be persistent across reboots. 3899168404Spjd */ 3900168404Spjd/* ARGSUSED */ 3901168404Spjdint 3902168404Spjdzpool_do_offline(int argc, char **argv) 3903168404Spjd{ 3904168404Spjd int c, i; 3905168404Spjd char *poolname; 3906168404Spjd zpool_handle_t *zhp; 3907168404Spjd int ret = 0; 3908168404Spjd boolean_t istmp = B_FALSE; 3909168404Spjd 3910168404Spjd /* check options */ 3911168404Spjd while ((c = getopt(argc, argv, "ft")) != -1) { 3912168404Spjd switch (c) { 3913168404Spjd case 't': 3914168404Spjd istmp = B_TRUE; 3915168404Spjd break; 3916168404Spjd case 'f': 3917168404Spjd case '?': 3918168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3919168404Spjd optopt); 3920168404Spjd usage(B_FALSE); 3921168404Spjd } 3922168404Spjd } 3923168404Spjd 3924168404Spjd argc -= optind; 3925168404Spjd argv += optind; 3926168404Spjd 3927168404Spjd /* get pool name and check number of arguments */ 3928168404Spjd if (argc < 1) { 3929168404Spjd (void) fprintf(stderr, gettext("missing pool name\n")); 3930168404Spjd usage(B_FALSE); 3931168404Spjd } 3932168404Spjd if (argc < 2) { 3933168404Spjd (void) fprintf(stderr, gettext("missing device name\n")); 3934168404Spjd usage(B_FALSE); 3935168404Spjd } 3936168404Spjd 3937168404Spjd poolname = argv[0]; 3938168404Spjd 3939168404Spjd if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 3940168404Spjd return (1); 3941168404Spjd 3942185029Spjd for (i = 1; i < argc; i++) { 3943185029Spjd if (zpool_vdev_offline(zhp, argv[i], istmp) != 0) 3944168404Spjd ret = 1; 3945185029Spjd } 3946168404Spjd 3947168404Spjd zpool_close(zhp); 3948168404Spjd 3949168404Spjd return (ret); 3950168404Spjd} 3951168404Spjd 3952168404Spjd/* 3953168404Spjd * zpool clear <pool> [device] 3954168404Spjd * 3955168404Spjd * Clear all errors associated with a pool or a particular device. 3956168404Spjd */ 3957168404Spjdint 3958168404Spjdzpool_do_clear(int argc, char **argv) 3959168404Spjd{ 3960219089Spjd int c; 3961168404Spjd int ret = 0; 3962219089Spjd boolean_t dryrun = B_FALSE; 3963219089Spjd boolean_t do_rewind = B_FALSE; 3964219089Spjd boolean_t xtreme_rewind = B_FALSE; 3965219089Spjd uint32_t rewind_policy = ZPOOL_NO_REWIND; 3966219089Spjd nvlist_t *policy = NULL; 3967168404Spjd zpool_handle_t *zhp; 3968168404Spjd char *pool, *device; 3969168404Spjd 3970219089Spjd /* check options */ 3971219089Spjd while ((c = getopt(argc, argv, "FnX")) != -1) { 3972219089Spjd switch (c) { 3973219089Spjd case 'F': 3974219089Spjd do_rewind = B_TRUE; 3975219089Spjd break; 3976219089Spjd case 'n': 3977219089Spjd dryrun = B_TRUE; 3978219089Spjd break; 3979219089Spjd case 'X': 3980219089Spjd xtreme_rewind = B_TRUE; 3981219089Spjd break; 3982219089Spjd case '?': 3983219089Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 3984219089Spjd optopt); 3985219089Spjd usage(B_FALSE); 3986219089Spjd } 3987219089Spjd } 3988219089Spjd 3989219089Spjd argc -= optind; 3990219089Spjd argv += optind; 3991219089Spjd 3992219089Spjd if (argc < 1) { 3993168404Spjd (void) fprintf(stderr, gettext("missing pool name\n")); 3994168404Spjd usage(B_FALSE); 3995168404Spjd } 3996168404Spjd 3997219089Spjd if (argc > 2) { 3998168404Spjd (void) fprintf(stderr, gettext("too many arguments\n")); 3999168404Spjd usage(B_FALSE); 4000168404Spjd } 4001168404Spjd 4002219089Spjd if ((dryrun || xtreme_rewind) && !do_rewind) { 4003219089Spjd (void) fprintf(stderr, 4004219089Spjd gettext("-n or -X only meaningful with -F\n")); 4005219089Spjd usage(B_FALSE); 4006219089Spjd } 4007219089Spjd if (dryrun) 4008219089Spjd rewind_policy = ZPOOL_TRY_REWIND; 4009219089Spjd else if (do_rewind) 4010219089Spjd rewind_policy = ZPOOL_DO_REWIND; 4011219089Spjd if (xtreme_rewind) 4012219089Spjd rewind_policy |= ZPOOL_EXTREME_REWIND; 4013168404Spjd 4014219089Spjd /* In future, further rewind policy choices can be passed along here */ 4015219089Spjd if (nvlist_alloc(&policy, NV_UNIQUE_NAME, 0) != 0 || 4016332550Smav nvlist_add_uint32(policy, ZPOOL_LOAD_REWIND_POLICY, 4017332550Smav rewind_policy) != 0) { 4018168404Spjd return (1); 4019332550Smav } 4020168404Spjd 4021219089Spjd pool = argv[0]; 4022219089Spjd device = argc == 2 ? argv[1] : NULL; 4023219089Spjd 4024219089Spjd if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) { 4025219089Spjd nvlist_free(policy); 4026219089Spjd return (1); 4027219089Spjd } 4028219089Spjd 4029219089Spjd if (zpool_clear(zhp, device, policy) != 0) 4030168404Spjd ret = 1; 4031168404Spjd 4032168404Spjd zpool_close(zhp); 4033168404Spjd 4034219089Spjd nvlist_free(policy); 4035219089Spjd 4036168404Spjd return (ret); 4037168404Spjd} 4038168404Spjd 4039228103Smm/* 4040228103Smm * zpool reguid <pool> 4041228103Smm */ 4042228103Smmint 4043228103Smmzpool_do_reguid(int argc, char **argv) 4044228103Smm{ 4045228103Smm int c; 4046228103Smm char *poolname; 4047228103Smm zpool_handle_t *zhp; 4048228103Smm int ret = 0; 4049228103Smm 4050228103Smm /* check options */ 4051228103Smm while ((c = getopt(argc, argv, "")) != -1) { 4052228103Smm switch (c) { 4053228103Smm case '?': 4054228103Smm (void) fprintf(stderr, gettext("invalid option '%c'\n"), 4055228103Smm optopt); 4056228103Smm usage(B_FALSE); 4057228103Smm } 4058228103Smm } 4059228103Smm 4060228103Smm argc -= optind; 4061228103Smm argv += optind; 4062228103Smm 4063228103Smm /* get pool name and check number of arguments */ 4064228103Smm if (argc < 1) { 4065228103Smm (void) fprintf(stderr, gettext("missing pool name\n")); 4066228103Smm usage(B_FALSE); 4067228103Smm } 4068228103Smm 4069228103Smm if (argc > 1) { 4070228103Smm (void) fprintf(stderr, gettext("too many arguments\n")); 4071228103Smm usage(B_FALSE); 4072228103Smm } 4073228103Smm 4074228103Smm poolname = argv[0]; 4075228103Smm if ((zhp = zpool_open(g_zfs, poolname)) == NULL) 4076228103Smm return (1); 4077228103Smm 4078228103Smm ret = zpool_reguid(zhp); 4079228103Smm 4080228103Smm zpool_close(zhp); 4081228103Smm return (ret); 4082228103Smm} 4083228103Smm 4084228103Smm 4085236155Smm/* 4086236155Smm * zpool reopen <pool> 4087236155Smm * 4088236155Smm * Reopen the pool so that the kernel can update the sizes of all vdevs. 4089236155Smm */ 4090236155Smmint 4091236155Smmzpool_do_reopen(int argc, char **argv) 4092236155Smm{ 4093260138Sdelphij int c; 4094236155Smm int ret = 0; 4095236155Smm zpool_handle_t *zhp; 4096236155Smm char *pool; 4097236155Smm 4098260138Sdelphij /* check options */ 4099260138Sdelphij while ((c = getopt(argc, argv, "")) != -1) { 4100260138Sdelphij switch (c) { 4101260138Sdelphij case '?': 4102260138Sdelphij (void) fprintf(stderr, gettext("invalid option '%c'\n"), 4103260138Sdelphij optopt); 4104260138Sdelphij usage(B_FALSE); 4105260138Sdelphij } 4106260138Sdelphij } 4107260138Sdelphij 4108236155Smm argc--; 4109236155Smm argv++; 4110236155Smm 4111260138Sdelphij if (argc < 1) { 4112260138Sdelphij (void) fprintf(stderr, gettext("missing pool name\n")); 4113260138Sdelphij usage(B_FALSE); 4114260138Sdelphij } 4115236155Smm 4116260138Sdelphij if (argc > 1) { 4117260138Sdelphij (void) fprintf(stderr, gettext("too many arguments\n")); 4118260138Sdelphij usage(B_FALSE); 4119260138Sdelphij } 4120260138Sdelphij 4121236155Smm pool = argv[0]; 4122236155Smm if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) 4123236155Smm return (1); 4124236155Smm 4125236155Smm ret = zpool_reopen(zhp); 4126236155Smm zpool_close(zhp); 4127236155Smm return (ret); 4128236155Smm} 4129236155Smm 4130168404Spjdtypedef struct scrub_cbdata { 4131168404Spjd int cb_type; 4132168404Spjd int cb_argc; 4133168404Spjd char **cb_argv; 4134324010Savg pool_scrub_cmd_t cb_scrub_cmd; 4135168404Spjd} scrub_cbdata_t; 4136168404Spjd 4137332547Smavstatic boolean_t 4138332547Smavzpool_has_checkpoint(zpool_handle_t *zhp) 4139332547Smav{ 4140332547Smav nvlist_t *config, *nvroot; 4141332547Smav 4142332547Smav config = zpool_get_config(zhp, NULL); 4143332547Smav 4144332547Smav if (config != NULL) { 4145332547Smav pool_checkpoint_stat_t *pcs = NULL; 4146332547Smav uint_t c; 4147332547Smav 4148332547Smav nvroot = fnvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE); 4149332547Smav (void) nvlist_lookup_uint64_array(nvroot, 4150332547Smav ZPOOL_CONFIG_CHECKPOINT_STATS, (uint64_t **)&pcs, &c); 4151332547Smav 4152332547Smav if (pcs == NULL || pcs->pcs_state == CS_NONE) 4153332547Smav return (B_FALSE); 4154332547Smav 4155332547Smav assert(pcs->pcs_state == CS_CHECKPOINT_EXISTS || 4156332547Smav pcs->pcs_state == CS_CHECKPOINT_DISCARDING); 4157332547Smav return (B_TRUE); 4158332547Smav } 4159332547Smav 4160332547Smav return (B_FALSE); 4161332547Smav} 4162332547Smav 4163168404Spjdint 4164168404Spjdscrub_callback(zpool_handle_t *zhp, void *data) 4165168404Spjd{ 4166168404Spjd scrub_cbdata_t *cb = data; 4167168404Spjd int err; 4168168404Spjd 4169168404Spjd /* 4170168404Spjd * Ignore faulted pools. 4171168404Spjd */ 4172168404Spjd if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) { 4173168404Spjd (void) fprintf(stderr, gettext("cannot scrub '%s': pool is " 4174168404Spjd "currently unavailable\n"), zpool_get_name(zhp)); 4175168404Spjd return (1); 4176168404Spjd } 4177168404Spjd 4178324010Savg err = zpool_scan(zhp, cb->cb_type, cb->cb_scrub_cmd); 4179168404Spjd 4180332547Smav if (err == 0 && zpool_has_checkpoint(zhp) && 4181332547Smav cb->cb_type == POOL_SCAN_SCRUB) { 4182332547Smav (void) printf(gettext("warning: will not scrub state that " 4183332547Smav "belongs to the checkpoint of pool '%s'\n"), 4184332547Smav zpool_get_name(zhp)); 4185332547Smav } 4186332547Smav 4187168404Spjd return (err != 0); 4188168404Spjd} 4189168404Spjd 4190168404Spjd/* 4191324010Savg * zpool scrub [-s | -p] <pool> ... 4192168404Spjd * 4193168404Spjd * -s Stop. Stops any in-progress scrub. 4194324010Savg * -p Pause. Pause in-progress scrub. 4195168404Spjd */ 4196168404Spjdint 4197168404Spjdzpool_do_scrub(int argc, char **argv) 4198168404Spjd{ 4199168404Spjd int c; 4200168404Spjd scrub_cbdata_t cb; 4201168404Spjd 4202219089Spjd cb.cb_type = POOL_SCAN_SCRUB; 4203324010Savg cb.cb_scrub_cmd = POOL_SCRUB_NORMAL; 4204168404Spjd 4205168404Spjd /* check options */ 4206324010Savg while ((c = getopt(argc, argv, "sp")) != -1) { 4207168404Spjd switch (c) { 4208168404Spjd case 's': 4209219089Spjd cb.cb_type = POOL_SCAN_NONE; 4210168404Spjd break; 4211324010Savg case 'p': 4212324010Savg cb.cb_scrub_cmd = POOL_SCRUB_PAUSE; 4213324010Savg break; 4214168404Spjd case '?': 4215168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 4216168404Spjd optopt); 4217168404Spjd usage(B_FALSE); 4218168404Spjd } 4219168404Spjd } 4220168404Spjd 4221324010Savg if (cb.cb_type == POOL_SCAN_NONE && 4222324010Savg cb.cb_scrub_cmd == POOL_SCRUB_PAUSE) { 4223324010Savg (void) fprintf(stderr, gettext("invalid option combination: " 4224324010Savg "-s and -p are mutually exclusive\n")); 4225324010Savg usage(B_FALSE); 4226324010Savg } 4227324010Savg 4228168404Spjd cb.cb_argc = argc; 4229168404Spjd cb.cb_argv = argv; 4230168404Spjd argc -= optind; 4231168404Spjd argv += optind; 4232168404Spjd 4233168404Spjd if (argc < 1) { 4234168404Spjd (void) fprintf(stderr, gettext("missing pool name argument\n")); 4235168404Spjd usage(B_FALSE); 4236168404Spjd } 4237168404Spjd 4238168404Spjd return (for_each_pool(argc, argv, B_TRUE, NULL, scrub_callback, &cb)); 4239168404Spjd} 4240168404Spjd 4241168404Spjdtypedef struct status_cbdata { 4242168404Spjd int cb_count; 4243168404Spjd boolean_t cb_allpools; 4244168404Spjd boolean_t cb_verbose; 4245168404Spjd boolean_t cb_explain; 4246168404Spjd boolean_t cb_first; 4247219089Spjd boolean_t cb_dedup_stats; 4248168404Spjd} status_cbdata_t; 4249168404Spjd 4250168404Spjd/* 4251168404Spjd * Print out detailed scrub status. 4252168404Spjd */ 4253332525Smavstatic void 4254219089Spjdprint_scan_status(pool_scan_stat_t *ps) 4255168404Spjd{ 4256324010Savg time_t start, end, pause; 4257219089Spjd uint64_t elapsed, mins_left, hours_left; 4258219089Spjd uint64_t pass_exam, examined, total; 4259219089Spjd uint_t rate; 4260168404Spjd double fraction_done; 4261219089Spjd char processed_buf[7], examined_buf[7], total_buf[7], rate_buf[7]; 4262168404Spjd 4263226583Spjd (void) printf(gettext(" scan: ")); 4264168404Spjd 4265219089Spjd /* If there's never been a scan, there's not much to say. */ 4266219089Spjd if (ps == NULL || ps->pss_func == POOL_SCAN_NONE || 4267219089Spjd ps->pss_func >= POOL_SCAN_FUNCS) { 4268168404Spjd (void) printf(gettext("none requested\n")); 4269168404Spjd return; 4270168404Spjd } 4271168404Spjd 4272219089Spjd start = ps->pss_start_time; 4273219089Spjd end = ps->pss_end_time; 4274324010Savg pause = ps->pss_pass_scrub_pause; 4275219089Spjd zfs_nicenum(ps->pss_processed, processed_buf, sizeof (processed_buf)); 4276168404Spjd 4277219089Spjd assert(ps->pss_func == POOL_SCAN_SCRUB || 4278219089Spjd ps->pss_func == POOL_SCAN_RESILVER); 4279219089Spjd /* 4280219089Spjd * Scan is finished or canceled. 4281219089Spjd */ 4282219089Spjd if (ps->pss_state == DSS_FINISHED) { 4283219089Spjd uint64_t minutes_taken = (end - start) / 60; 4284296537Smav char *fmt = NULL; 4285168404Spjd 4286219089Spjd if (ps->pss_func == POOL_SCAN_SCRUB) { 4287219089Spjd fmt = gettext("scrub repaired %s in %lluh%um with " 4288219089Spjd "%llu errors on %s"); 4289219089Spjd } else if (ps->pss_func == POOL_SCAN_RESILVER) { 4290219089Spjd fmt = gettext("resilvered %s in %lluh%um with " 4291219089Spjd "%llu errors on %s"); 4292219089Spjd } 4293219089Spjd /* LINTED */ 4294219089Spjd (void) printf(fmt, processed_buf, 4295185029Spjd (u_longlong_t)(minutes_taken / 60), 4296185029Spjd (uint_t)(minutes_taken % 60), 4297219089Spjd (u_longlong_t)ps->pss_errors, 4298219089Spjd ctime((time_t *)&end)); 4299168404Spjd return; 4300219089Spjd } else if (ps->pss_state == DSS_CANCELED) { 4301219089Spjd if (ps->pss_func == POOL_SCAN_SCRUB) { 4302219089Spjd (void) printf(gettext("scrub canceled on %s"), 4303219089Spjd ctime(&end)); 4304219089Spjd } else if (ps->pss_func == POOL_SCAN_RESILVER) { 4305219089Spjd (void) printf(gettext("resilver canceled on %s"), 4306219089Spjd ctime(&end)); 4307219089Spjd } 4308219089Spjd return; 4309168404Spjd } 4310168404Spjd 4311219089Spjd assert(ps->pss_state == DSS_SCANNING); 4312168404Spjd 4313219089Spjd /* 4314219089Spjd * Scan is in progress. 4315219089Spjd */ 4316219089Spjd if (ps->pss_func == POOL_SCAN_SCRUB) { 4317324010Savg if (pause == 0) { 4318324010Savg (void) printf(gettext("scrub in progress since %s"), 4319324010Savg ctime(&start)); 4320324010Savg } else { 4321324010Savg char buf[32]; 4322324010Savg struct tm *p = localtime(&pause); 4323324010Savg (void) strftime(buf, sizeof (buf), "%a %b %e %T %Y", p); 4324324010Savg (void) printf(gettext("scrub paused since %s\n"), buf); 4325324010Savg (void) printf(gettext("\tscrub started on %s"), 4326324010Savg ctime(&start)); 4327324010Savg } 4328219089Spjd } else if (ps->pss_func == POOL_SCAN_RESILVER) { 4329219089Spjd (void) printf(gettext("resilver in progress since %s"), 4330219089Spjd ctime(&start)); 4331219089Spjd } 4332219089Spjd 4333219089Spjd examined = ps->pss_examined ? ps->pss_examined : 1; 4334219089Spjd total = ps->pss_to_examine; 4335168404Spjd fraction_done = (double)examined / total; 4336168404Spjd 4337219089Spjd /* elapsed time for this pass */ 4338219089Spjd elapsed = time(NULL) - ps->pss_pass_start; 4339324010Savg elapsed -= ps->pss_pass_scrub_spent_paused; 4340219089Spjd elapsed = elapsed ? elapsed : 1; 4341219089Spjd pass_exam = ps->pss_pass_exam ? ps->pss_pass_exam : 1; 4342219089Spjd rate = pass_exam / elapsed; 4343219089Spjd rate = rate ? rate : 1; 4344219089Spjd mins_left = ((total - examined) / rate) / 60; 4345219089Spjd hours_left = mins_left / 60; 4346219089Spjd 4347219089Spjd zfs_nicenum(examined, examined_buf, sizeof (examined_buf)); 4348219089Spjd zfs_nicenum(total, total_buf, sizeof (total_buf)); 4349219089Spjd 4350219089Spjd /* 4351219089Spjd * do not print estimated time if hours_left is more than 30 days 4352324010Savg * or we have a paused scrub 4353219089Spjd */ 4354324010Savg if (pause == 0) { 4355324010Savg zfs_nicenum(rate, rate_buf, sizeof (rate_buf)); 4356324010Savg (void) printf(gettext("\t%s scanned out of %s at %s/s"), 4357324010Savg examined_buf, total_buf, rate_buf); 4358324010Savg if (hours_left < (30 * 24)) { 4359324010Savg (void) printf(gettext(", %lluh%um to go\n"), 4360324010Savg (u_longlong_t)hours_left, (uint_t)(mins_left % 60)); 4361324010Savg } else { 4362324010Savg (void) printf(gettext( 4363324010Savg ", (scan is slow, no estimated time)\n")); 4364324010Savg } 4365219089Spjd } else { 4366324010Savg (void) printf(gettext("\t%s scanned out of %s\n"), 4367324010Savg examined_buf, total_buf); 4368219089Spjd } 4369219089Spjd 4370219089Spjd if (ps->pss_func == POOL_SCAN_RESILVER) { 4371226583Spjd (void) printf(gettext(" %s resilvered, %.2f%% done\n"), 4372219089Spjd processed_buf, 100 * fraction_done); 4373219089Spjd } else if (ps->pss_func == POOL_SCAN_SCRUB) { 4374226583Spjd (void) printf(gettext(" %s repaired, %.2f%% done\n"), 4375219089Spjd processed_buf, 100 * fraction_done); 4376219089Spjd } 4377168404Spjd} 4378168404Spjd 4379332525Smav/* 4380332547Smav * As we don't scrub checkpointed blocks, we want to warn the 4381332547Smav * user that we skipped scanning some blocks if a checkpoint exists 4382332547Smav * or existed at any time during the scan. 4383332547Smav */ 4384332547Smavstatic void 4385332547Smavprint_checkpoint_scan_warning(pool_scan_stat_t *ps, pool_checkpoint_stat_t *pcs) 4386332547Smav{ 4387332547Smav if (ps == NULL || pcs == NULL) 4388332547Smav return; 4389332547Smav 4390332547Smav if (pcs->pcs_state == CS_NONE || 4391332547Smav pcs->pcs_state == CS_CHECKPOINT_DISCARDING) 4392332547Smav return; 4393332547Smav 4394332547Smav assert(pcs->pcs_state == CS_CHECKPOINT_EXISTS); 4395332547Smav 4396332547Smav if (ps->pss_state == DSS_NONE) 4397332547Smav return; 4398332547Smav 4399332547Smav if ((ps->pss_state == DSS_FINISHED || ps->pss_state == DSS_CANCELED) && 4400332547Smav ps->pss_end_time < pcs->pcs_start_time) 4401332547Smav return; 4402332547Smav 4403332547Smav if (ps->pss_state == DSS_FINISHED || ps->pss_state == DSS_CANCELED) { 4404332547Smav (void) printf(gettext(" scan warning: skipped blocks " 4405332547Smav "that are only referenced by the checkpoint.\n")); 4406332547Smav } else { 4407332547Smav assert(ps->pss_state == DSS_SCANNING); 4408332547Smav (void) printf(gettext(" scan warning: skipping blocks " 4409332547Smav "that are only referenced by the checkpoint.\n")); 4410332547Smav } 4411332547Smav} 4412332547Smav 4413332547Smav/* 4414332525Smav * Print out detailed removal status. 4415332525Smav */ 4416168404Spjdstatic void 4417332525Smavprint_removal_status(zpool_handle_t *zhp, pool_removal_stat_t *prs) 4418332525Smav{ 4419332525Smav char copied_buf[7], examined_buf[7], total_buf[7], rate_buf[7]; 4420332525Smav time_t start, end; 4421332525Smav nvlist_t *config, *nvroot; 4422332525Smav nvlist_t **child; 4423332525Smav uint_t children; 4424332525Smav char *vdev_name; 4425332525Smav 4426332525Smav if (prs == NULL || prs->prs_state == DSS_NONE) 4427332525Smav return; 4428332525Smav 4429332525Smav /* 4430332525Smav * Determine name of vdev. 4431332525Smav */ 4432332525Smav config = zpool_get_config(zhp, NULL); 4433332525Smav nvroot = fnvlist_lookup_nvlist(config, 4434332525Smav ZPOOL_CONFIG_VDEV_TREE); 4435332525Smav verify(nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN, 4436332525Smav &child, &children) == 0); 4437332525Smav assert(prs->prs_removing_vdev < children); 4438332525Smav vdev_name = zpool_vdev_name(g_zfs, zhp, 4439332525Smav child[prs->prs_removing_vdev], B_TRUE); 4440332525Smav 4441332525Smav (void) printf(gettext("remove: ")); 4442332525Smav 4443332525Smav start = prs->prs_start_time; 4444332525Smav end = prs->prs_end_time; 4445332525Smav zfs_nicenum(prs->prs_copied, copied_buf, sizeof (copied_buf)); 4446332525Smav 4447332525Smav /* 4448332525Smav * Removal is finished or canceled. 4449332525Smav */ 4450332525Smav if (prs->prs_state == DSS_FINISHED) { 4451332525Smav uint64_t minutes_taken = (end - start) / 60; 4452332525Smav 4453332525Smav (void) printf(gettext("Removal of vdev %llu copied %s " 4454332525Smav "in %lluh%um, completed on %s"), 4455332525Smav (longlong_t)prs->prs_removing_vdev, 4456332525Smav copied_buf, 4457332525Smav (u_longlong_t)(minutes_taken / 60), 4458332525Smav (uint_t)(minutes_taken % 60), 4459332525Smav ctime((time_t *)&end)); 4460332525Smav } else if (prs->prs_state == DSS_CANCELED) { 4461332525Smav (void) printf(gettext("Removal of %s canceled on %s"), 4462332525Smav vdev_name, ctime(&end)); 4463332525Smav } else { 4464332525Smav uint64_t copied, total, elapsed, mins_left, hours_left; 4465332525Smav double fraction_done; 4466332525Smav uint_t rate; 4467332525Smav 4468332525Smav assert(prs->prs_state == DSS_SCANNING); 4469332525Smav 4470332525Smav /* 4471332525Smav * Removal is in progress. 4472332525Smav */ 4473332525Smav (void) printf(gettext( 4474332525Smav "Evacuation of %s in progress since %s"), 4475332525Smav vdev_name, ctime(&start)); 4476332525Smav 4477332525Smav copied = prs->prs_copied > 0 ? prs->prs_copied : 1; 4478332525Smav total = prs->prs_to_copy; 4479332525Smav fraction_done = (double)copied / total; 4480332525Smav 4481332525Smav /* elapsed time for this pass */ 4482332525Smav elapsed = time(NULL) - prs->prs_start_time; 4483332525Smav elapsed = elapsed > 0 ? elapsed : 1; 4484332525Smav rate = copied / elapsed; 4485332525Smav rate = rate > 0 ? rate : 1; 4486332525Smav mins_left = ((total - copied) / rate) / 60; 4487332525Smav hours_left = mins_left / 60; 4488332525Smav 4489332525Smav zfs_nicenum(copied, examined_buf, sizeof (examined_buf)); 4490332525Smav zfs_nicenum(total, total_buf, sizeof (total_buf)); 4491332525Smav zfs_nicenum(rate, rate_buf, sizeof (rate_buf)); 4492332525Smav 4493332525Smav /* 4494332525Smav * do not print estimated time if hours_left is more than 4495332525Smav * 30 days 4496332525Smav */ 4497332525Smav (void) printf(gettext(" %s copied out of %s at %s/s, " 4498332525Smav "%.2f%% done"), 4499332525Smav examined_buf, total_buf, rate_buf, 100 * fraction_done); 4500332525Smav if (hours_left < (30 * 24)) { 4501332525Smav (void) printf(gettext(", %lluh%um to go\n"), 4502332525Smav (u_longlong_t)hours_left, (uint_t)(mins_left % 60)); 4503332525Smav } else { 4504332525Smav (void) printf(gettext( 4505332525Smav ", (copy is slow, no estimated time)\n")); 4506332525Smav } 4507332525Smav } 4508332525Smav 4509332525Smav if (prs->prs_mapping_memory > 0) { 4510332525Smav char mem_buf[7]; 4511332525Smav zfs_nicenum(prs->prs_mapping_memory, mem_buf, sizeof (mem_buf)); 4512332525Smav (void) printf(gettext(" %s memory used for " 4513332525Smav "removed device mappings\n"), 4514332525Smav mem_buf); 4515332525Smav } 4516332525Smav} 4517332525Smav 4518332525Smavstatic void 4519332547Smavprint_checkpoint_status(pool_checkpoint_stat_t *pcs) 4520332547Smav{ 4521332547Smav time_t start; 4522332547Smav char space_buf[7]; 4523332547Smav 4524332547Smav if (pcs == NULL || pcs->pcs_state == CS_NONE) 4525332547Smav return; 4526332547Smav 4527332547Smav (void) printf(gettext("checkpoint: ")); 4528332547Smav 4529332547Smav start = pcs->pcs_start_time; 4530332547Smav zfs_nicenum(pcs->pcs_space, space_buf, sizeof (space_buf)); 4531332547Smav 4532332547Smav if (pcs->pcs_state == CS_CHECKPOINT_EXISTS) { 4533332547Smav char *date = ctime(&start); 4534332547Smav 4535332547Smav /* 4536332547Smav * ctime() adds a newline at the end of the generated 4537332547Smav * string, thus the weird format specifier and the 4538332547Smav * strlen() call used to chop it off from the output. 4539332547Smav */ 4540332547Smav (void) printf(gettext("created %.*s, consumes %s\n"), 4541332547Smav strlen(date) - 1, date, space_buf); 4542332547Smav return; 4543332547Smav } 4544332547Smav 4545332547Smav assert(pcs->pcs_state == CS_CHECKPOINT_DISCARDING); 4546332547Smav 4547332547Smav (void) printf(gettext("discarding, %s remaining.\n"), 4548332547Smav space_buf); 4549332547Smav} 4550332547Smav 4551332547Smavstatic void 4552168404Spjdprint_error_log(zpool_handle_t *zhp) 4553168404Spjd{ 4554185029Spjd nvlist_t *nverrlist = NULL; 4555168404Spjd nvpair_t *elem; 4556168404Spjd char *pathname; 4557168404Spjd size_t len = MAXPATHLEN * 2; 4558168404Spjd 4559168404Spjd if (zpool_get_errlog(zhp, &nverrlist) != 0) { 4560168404Spjd (void) printf("errors: List of errors unavailable " 4561168404Spjd "(insufficient privileges)\n"); 4562168404Spjd return; 4563168404Spjd } 4564168404Spjd 4565168404Spjd (void) printf("errors: Permanent errors have been " 4566168404Spjd "detected in the following files:\n\n"); 4567168404Spjd 4568168404Spjd pathname = safe_malloc(len); 4569168404Spjd elem = NULL; 4570168404Spjd while ((elem = nvlist_next_nvpair(nverrlist, elem)) != NULL) { 4571168404Spjd nvlist_t *nv; 4572168404Spjd uint64_t dsobj, obj; 4573168404Spjd 4574168404Spjd verify(nvpair_value_nvlist(elem, &nv) == 0); 4575168404Spjd verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_DATASET, 4576168404Spjd &dsobj) == 0); 4577168404Spjd verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_OBJECT, 4578168404Spjd &obj) == 0); 4579168404Spjd zpool_obj_to_path(zhp, dsobj, obj, pathname, len); 4580168404Spjd (void) printf("%7s %s\n", "", pathname); 4581168404Spjd } 4582168404Spjd free(pathname); 4583168404Spjd nvlist_free(nverrlist); 4584168404Spjd} 4585168404Spjd 4586168404Spjdstatic void 4587168404Spjdprint_spares(zpool_handle_t *zhp, nvlist_t **spares, uint_t nspares, 4588168404Spjd int namewidth) 4589168404Spjd{ 4590168404Spjd uint_t i; 4591168404Spjd char *name; 4592168404Spjd 4593168404Spjd if (nspares == 0) 4594168404Spjd return; 4595168404Spjd 4596168404Spjd (void) printf(gettext("\tspares\n")); 4597168404Spjd 4598168404Spjd for (i = 0; i < nspares; i++) { 4599219089Spjd name = zpool_vdev_name(g_zfs, zhp, spares[i], B_FALSE); 4600168404Spjd print_status_config(zhp, name, spares[i], 4601209962Smm namewidth, 2, B_TRUE); 4602168404Spjd free(name); 4603168404Spjd } 4604168404Spjd} 4605168404Spjd 4606185029Spjdstatic void 4607185029Spjdprint_l2cache(zpool_handle_t *zhp, nvlist_t **l2cache, uint_t nl2cache, 4608185029Spjd int namewidth) 4609185029Spjd{ 4610185029Spjd uint_t i; 4611185029Spjd char *name; 4612185029Spjd 4613185029Spjd if (nl2cache == 0) 4614185029Spjd return; 4615185029Spjd 4616185029Spjd (void) printf(gettext("\tcache\n")); 4617185029Spjd 4618185029Spjd for (i = 0; i < nl2cache; i++) { 4619219089Spjd name = zpool_vdev_name(g_zfs, zhp, l2cache[i], B_FALSE); 4620185029Spjd print_status_config(zhp, name, l2cache[i], 4621209962Smm namewidth, 2, B_FALSE); 4622185029Spjd free(name); 4623185029Spjd } 4624185029Spjd} 4625185029Spjd 4626219089Spjdstatic void 4627219089Spjdprint_dedup_stats(nvlist_t *config) 4628219089Spjd{ 4629219089Spjd ddt_histogram_t *ddh; 4630219089Spjd ddt_stat_t *dds; 4631219089Spjd ddt_object_t *ddo; 4632219089Spjd uint_t c; 4633219089Spjd 4634219089Spjd /* 4635219089Spjd * If the pool was faulted then we may not have been able to 4636253441Sdelphij * obtain the config. Otherwise, if we have anything in the dedup 4637219089Spjd * table continue processing the stats. 4638219089Spjd */ 4639219089Spjd if (nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_OBJ_STATS, 4640227497Smm (uint64_t **)&ddo, &c) != 0) 4641219089Spjd return; 4642219089Spjd 4643219089Spjd (void) printf("\n"); 4644227497Smm (void) printf(gettext(" dedup: ")); 4645227497Smm if (ddo->ddo_count == 0) { 4646227497Smm (void) printf(gettext("no DDT entries\n")); 4647227497Smm return; 4648227497Smm } 4649227497Smm 4650219089Spjd (void) printf("DDT entries %llu, size %llu on disk, %llu in core\n", 4651219089Spjd (u_longlong_t)ddo->ddo_count, 4652219089Spjd (u_longlong_t)ddo->ddo_dspace, 4653219089Spjd (u_longlong_t)ddo->ddo_mspace); 4654219089Spjd 4655219089Spjd verify(nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_STATS, 4656219089Spjd (uint64_t **)&dds, &c) == 0); 4657219089Spjd verify(nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_HISTOGRAM, 4658219089Spjd (uint64_t **)&ddh, &c) == 0); 4659219089Spjd zpool_dump_ddt(dds, ddh); 4660219089Spjd} 4661219089Spjd 4662168404Spjd/* 4663168404Spjd * Display a summary of pool status. Displays a summary such as: 4664168404Spjd * 4665168404Spjd * pool: tank 4666168404Spjd * status: DEGRADED 4667168404Spjd * reason: One or more devices ... 4668236146Smm * see: http://illumos.org/msg/ZFS-xxxx-01 4669168404Spjd * config: 4670168404Spjd * mirror DEGRADED 4671168404Spjd * c1t0d0 OK 4672168404Spjd * c2t0d0 UNAVAIL 4673168404Spjd * 4674168404Spjd * When given the '-v' option, we print out the complete config. If the '-e' 4675168404Spjd * option is specified, then we print out error rate information as well. 4676168404Spjd */ 4677168404Spjdint 4678168404Spjdstatus_callback(zpool_handle_t *zhp, void *data) 4679168404Spjd{ 4680168404Spjd status_cbdata_t *cbp = data; 4681168404Spjd nvlist_t *config, *nvroot; 4682168404Spjd char *msgid; 4683168404Spjd int reason; 4684168404Spjd const char *health; 4685168404Spjd uint_t c; 4686168404Spjd vdev_stat_t *vs; 4687168404Spjd 4688168404Spjd config = zpool_get_config(zhp, NULL); 4689168404Spjd reason = zpool_get_status(zhp, &msgid); 4690168404Spjd 4691168404Spjd cbp->cb_count++; 4692168404Spjd 4693168404Spjd /* 4694168404Spjd * If we were given 'zpool status -x', only report those pools with 4695168404Spjd * problems. 4696168404Spjd */ 4697248267Smm if (cbp->cb_explain && 4698248267Smm (reason == ZPOOL_STATUS_OK || 4699248267Smm reason == ZPOOL_STATUS_VERSION_OLDER || 4700268621Ssmh reason == ZPOOL_STATUS_NON_NATIVE_ASHIFT || 4701248267Smm reason == ZPOOL_STATUS_FEAT_DISABLED)) { 4702168404Spjd if (!cbp->cb_allpools) { 4703168404Spjd (void) printf(gettext("pool '%s' is healthy\n"), 4704168404Spjd zpool_get_name(zhp)); 4705168404Spjd if (cbp->cb_first) 4706168404Spjd cbp->cb_first = B_FALSE; 4707168404Spjd } 4708168404Spjd return (0); 4709168404Spjd } 4710168404Spjd 4711168404Spjd if (cbp->cb_first) 4712168404Spjd cbp->cb_first = B_FALSE; 4713168404Spjd else 4714168404Spjd (void) printf("\n"); 4715168404Spjd 4716332525Smav nvroot = fnvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE); 4717219089Spjd verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS, 4718168404Spjd (uint64_t **)&vs, &c) == 0); 4719185029Spjd health = zpool_state_to_name(vs->vs_state, vs->vs_aux); 4720168404Spjd 4721168404Spjd (void) printf(gettext(" pool: %s\n"), zpool_get_name(zhp)); 4722168404Spjd (void) printf(gettext(" state: %s\n"), health); 4723168404Spjd 4724168404Spjd switch (reason) { 4725168404Spjd case ZPOOL_STATUS_MISSING_DEV_R: 4726168404Spjd (void) printf(gettext("status: One or more devices could not " 4727168404Spjd "be opened. Sufficient replicas exist for\n\tthe pool to " 4728168404Spjd "continue functioning in a degraded state.\n")); 4729168404Spjd (void) printf(gettext("action: Attach the missing device and " 4730168404Spjd "online it using 'zpool online'.\n")); 4731168404Spjd break; 4732168404Spjd 4733168404Spjd case ZPOOL_STATUS_MISSING_DEV_NR: 4734168404Spjd (void) printf(gettext("status: One or more devices could not " 4735168404Spjd "be opened. There are insufficient\n\treplicas for the " 4736168404Spjd "pool to continue functioning.\n")); 4737168404Spjd (void) printf(gettext("action: Attach the missing device and " 4738168404Spjd "online it using 'zpool online'.\n")); 4739168404Spjd break; 4740168404Spjd 4741168404Spjd case ZPOOL_STATUS_CORRUPT_LABEL_R: 4742168404Spjd (void) printf(gettext("status: One or more devices could not " 4743168404Spjd "be used because the label is missing or\n\tinvalid. " 4744168404Spjd "Sufficient replicas exist for the pool to continue\n\t" 4745168404Spjd "functioning in a degraded state.\n")); 4746168404Spjd (void) printf(gettext("action: Replace the device using " 4747168404Spjd "'zpool replace'.\n")); 4748168404Spjd break; 4749168404Spjd 4750168404Spjd case ZPOOL_STATUS_CORRUPT_LABEL_NR: 4751168404Spjd (void) printf(gettext("status: One or more devices could not " 4752168404Spjd "be used because the label is missing \n\tor invalid. " 4753168404Spjd "There are insufficient replicas for the pool to " 4754168404Spjd "continue\n\tfunctioning.\n")); 4755219089Spjd zpool_explain_recover(zpool_get_handle(zhp), 4756219089Spjd zpool_get_name(zhp), reason, config); 4757168404Spjd break; 4758168404Spjd 4759168404Spjd case ZPOOL_STATUS_FAILING_DEV: 4760168404Spjd (void) printf(gettext("status: One or more devices has " 4761168404Spjd "experienced an unrecoverable error. An\n\tattempt was " 4762168404Spjd "made to correct the error. Applications are " 4763168404Spjd "unaffected.\n")); 4764168404Spjd (void) printf(gettext("action: Determine if the device needs " 4765168404Spjd "to be replaced, and clear the errors\n\tusing " 4766168404Spjd "'zpool clear' or replace the device with 'zpool " 4767168404Spjd "replace'.\n")); 4768168404Spjd break; 4769168404Spjd 4770168404Spjd case ZPOOL_STATUS_OFFLINE_DEV: 4771168404Spjd (void) printf(gettext("status: One or more devices has " 4772168404Spjd "been taken offline by the administrator.\n\tSufficient " 4773168404Spjd "replicas exist for the pool to continue functioning in " 4774168404Spjd "a\n\tdegraded state.\n")); 4775168404Spjd (void) printf(gettext("action: Online the device using " 4776168404Spjd "'zpool online' or replace the device with\n\t'zpool " 4777168404Spjd "replace'.\n")); 4778168404Spjd break; 4779168404Spjd 4780219089Spjd case ZPOOL_STATUS_REMOVED_DEV: 4781219089Spjd (void) printf(gettext("status: One or more devices has " 4782219089Spjd "been removed by the administrator.\n\tSufficient " 4783219089Spjd "replicas exist for the pool to continue functioning in " 4784219089Spjd "a\n\tdegraded state.\n")); 4785219089Spjd (void) printf(gettext("action: Online the device using " 4786219089Spjd "'zpool online' or replace the device with\n\t'zpool " 4787219089Spjd "replace'.\n")); 4788219089Spjd break; 4789219089Spjd 4790168404Spjd case ZPOOL_STATUS_RESILVERING: 4791168404Spjd (void) printf(gettext("status: One or more devices is " 4792168404Spjd "currently being resilvered. The pool will\n\tcontinue " 4793168404Spjd "to function, possibly in a degraded state.\n")); 4794168404Spjd (void) printf(gettext("action: Wait for the resilver to " 4795168404Spjd "complete.\n")); 4796168404Spjd break; 4797168404Spjd 4798168404Spjd case ZPOOL_STATUS_CORRUPT_DATA: 4799168404Spjd (void) printf(gettext("status: One or more devices has " 4800168404Spjd "experienced an error resulting in data\n\tcorruption. " 4801168404Spjd "Applications may be affected.\n")); 4802168404Spjd (void) printf(gettext("action: Restore the file in question " 4803168404Spjd "if possible. Otherwise restore the\n\tentire pool from " 4804168404Spjd "backup.\n")); 4805168404Spjd break; 4806168404Spjd 4807168404Spjd case ZPOOL_STATUS_CORRUPT_POOL: 4808168404Spjd (void) printf(gettext("status: The pool metadata is corrupted " 4809168404Spjd "and the pool cannot be opened.\n")); 4810219089Spjd zpool_explain_recover(zpool_get_handle(zhp), 4811219089Spjd zpool_get_name(zhp), reason, config); 4812168404Spjd break; 4813168404Spjd 4814168404Spjd case ZPOOL_STATUS_VERSION_OLDER: 4815238926Smm (void) printf(gettext("status: The pool is formatted using a " 4816238926Smm "legacy on-disk format. The pool can\n\tstill be used, " 4817238926Smm "but some features are unavailable.\n")); 4818168404Spjd (void) printf(gettext("action: Upgrade the pool using 'zpool " 4819168404Spjd "upgrade'. Once this is done, the\n\tpool will no longer " 4820238926Smm "be accessible on software that does not support feature\n" 4821238926Smm "\tflags.\n")); 4822168404Spjd break; 4823168404Spjd 4824168404Spjd case ZPOOL_STATUS_VERSION_NEWER: 4825168404Spjd (void) printf(gettext("status: The pool has been upgraded to a " 4826168404Spjd "newer, incompatible on-disk version.\n\tThe pool cannot " 4827168404Spjd "be accessed on this system.\n")); 4828168404Spjd (void) printf(gettext("action: Access the pool from a system " 4829168404Spjd "running more recent software, or\n\trestore the pool from " 4830168404Spjd "backup.\n")); 4831168404Spjd break; 4832168404Spjd 4833238926Smm case ZPOOL_STATUS_FEAT_DISABLED: 4834238926Smm (void) printf(gettext("status: Some supported features are not " 4835238926Smm "enabled on the pool. The pool can\n\tstill be used, but " 4836238926Smm "some features are unavailable.\n")); 4837238926Smm (void) printf(gettext("action: Enable all features using " 4838238926Smm "'zpool upgrade'. Once this is done,\n\tthe pool may no " 4839238926Smm "longer be accessible by software that does not support\n\t" 4840243014Smm "the features. See zpool-features(7) for details.\n")); 4841238926Smm break; 4842238926Smm 4843236884Smm case ZPOOL_STATUS_UNSUP_FEAT_READ: 4844236884Smm (void) printf(gettext("status: The pool cannot be accessed on " 4845236884Smm "this system because it uses the\n\tfollowing feature(s) " 4846236884Smm "not supported on this system:\n")); 4847236884Smm zpool_print_unsup_feat(config); 4848236884Smm (void) printf("\n"); 4849236884Smm (void) printf(gettext("action: Access the pool from a system " 4850236884Smm "that supports the required feature(s),\n\tor restore the " 4851236884Smm "pool from backup.\n")); 4852236884Smm break; 4853236884Smm 4854236884Smm case ZPOOL_STATUS_UNSUP_FEAT_WRITE: 4855236884Smm (void) printf(gettext("status: The pool can only be accessed " 4856236884Smm "in read-only mode on this system. It\n\tcannot be " 4857236884Smm "accessed in read-write mode because it uses the " 4858236884Smm "following\n\tfeature(s) not supported on this system:\n")); 4859236884Smm zpool_print_unsup_feat(config); 4860236884Smm (void) printf("\n"); 4861236884Smm (void) printf(gettext("action: The pool cannot be accessed in " 4862236884Smm "read-write mode. Import the pool with\n" 4863236884Smm "\t\"-o readonly=on\", access the pool from a system that " 4864236884Smm "supports the\n\trequired feature(s), or restore the " 4865236884Smm "pool from backup.\n")); 4866236884Smm break; 4867236884Smm 4868185029Spjd case ZPOOL_STATUS_FAULTED_DEV_R: 4869185029Spjd (void) printf(gettext("status: One or more devices are " 4870185029Spjd "faulted in response to persistent errors.\n\tSufficient " 4871185029Spjd "replicas exist for the pool to continue functioning " 4872185029Spjd "in a\n\tdegraded state.\n")); 4873185029Spjd (void) printf(gettext("action: Replace the faulted device, " 4874185029Spjd "or use 'zpool clear' to mark the device\n\trepaired.\n")); 4875185029Spjd break; 4876185029Spjd 4877185029Spjd case ZPOOL_STATUS_FAULTED_DEV_NR: 4878185029Spjd (void) printf(gettext("status: One or more devices are " 4879185029Spjd "faulted in response to persistent errors. There are " 4880185029Spjd "insufficient replicas for the pool to\n\tcontinue " 4881185029Spjd "functioning.\n")); 4882185029Spjd (void) printf(gettext("action: Destroy and re-create the pool " 4883185029Spjd "from a backup source. Manually marking the device\n" 4884185029Spjd "\trepaired using 'zpool clear' may allow some data " 4885185029Spjd "to be recovered.\n")); 4886185029Spjd break; 4887185029Spjd 4888185029Spjd case ZPOOL_STATUS_IO_FAILURE_WAIT: 4889185029Spjd case ZPOOL_STATUS_IO_FAILURE_CONTINUE: 4890185029Spjd (void) printf(gettext("status: One or more devices are " 4891185029Spjd "faulted in response to IO failures.\n")); 4892185029Spjd (void) printf(gettext("action: Make sure the affected devices " 4893185029Spjd "are connected, then run 'zpool clear'.\n")); 4894185029Spjd break; 4895185029Spjd 4896185029Spjd case ZPOOL_STATUS_BAD_LOG: 4897185029Spjd (void) printf(gettext("status: An intent log record " 4898185029Spjd "could not be read.\n" 4899185029Spjd "\tWaiting for adminstrator intervention to fix the " 4900185029Spjd "faulted pool.\n")); 4901185029Spjd (void) printf(gettext("action: Either restore the affected " 4902185029Spjd "device(s) and run 'zpool online',\n" 4903185029Spjd "\tor ignore the intent log records by running " 4904185029Spjd "'zpool clear'.\n")); 4905185029Spjd break; 4906185029Spjd 4907254591Sgibbs case ZPOOL_STATUS_NON_NATIVE_ASHIFT: 4908254591Sgibbs (void) printf(gettext("status: One or more devices are " 4909254591Sgibbs "configured to use a non-native block size.\n" 4910254591Sgibbs "\tExpect reduced performance.\n")); 4911254591Sgibbs (void) printf(gettext("action: Replace affected devices with " 4912254591Sgibbs "devices that support the\n\tconfigured block size, or " 4913254591Sgibbs "migrate data to a properly configured\n\tpool.\n")); 4914254591Sgibbs break; 4915254591Sgibbs 4916168404Spjd default: 4917168404Spjd /* 4918168404Spjd * The remaining errors can't actually be generated, yet. 4919168404Spjd */ 4920168404Spjd assert(reason == ZPOOL_STATUS_OK); 4921168404Spjd } 4922168404Spjd 4923168404Spjd if (msgid != NULL) 4924236146Smm (void) printf(gettext(" see: http://illumos.org/msg/%s\n"), 4925168404Spjd msgid); 4926168404Spjd 4927168404Spjd if (config != NULL) { 4928168404Spjd int namewidth; 4929168404Spjd uint64_t nerr; 4930185029Spjd nvlist_t **spares, **l2cache; 4931185029Spjd uint_t nspares, nl2cache; 4932332547Smav pool_checkpoint_stat_t *pcs = NULL; 4933219089Spjd pool_scan_stat_t *ps = NULL; 4934332525Smav pool_removal_stat_t *prs = NULL; 4935168404Spjd 4936219089Spjd (void) nvlist_lookup_uint64_array(nvroot, 4937332547Smav ZPOOL_CONFIG_CHECKPOINT_STATS, (uint64_t **)&pcs, &c); 4938332547Smav (void) nvlist_lookup_uint64_array(nvroot, 4939219089Spjd ZPOOL_CONFIG_SCAN_STATS, (uint64_t **)&ps, &c); 4940332525Smav (void) nvlist_lookup_uint64_array(nvroot, 4941332525Smav ZPOOL_CONFIG_REMOVAL_STATS, (uint64_t **)&prs, &c); 4942332547Smav 4943332547Smav print_scan_status(ps); 4944332547Smav print_checkpoint_scan_warning(ps, pcs); 4945332525Smav print_removal_status(zhp, prs); 4946332547Smav print_checkpoint_status(pcs); 4947332525Smav 4948168404Spjd namewidth = max_width(zhp, nvroot, 0, 0); 4949168404Spjd if (namewidth < 10) 4950168404Spjd namewidth = 10; 4951168404Spjd 4952168404Spjd (void) printf(gettext("config:\n\n")); 4953168404Spjd (void) printf(gettext("\t%-*s %-8s %5s %5s %5s\n"), namewidth, 4954168404Spjd "NAME", "STATE", "READ", "WRITE", "CKSUM"); 4955168404Spjd print_status_config(zhp, zpool_get_name(zhp), nvroot, 4956209962Smm namewidth, 0, B_FALSE); 4957209962Smm 4958185029Spjd if (num_logs(nvroot) > 0) 4959213197Smm print_logs(zhp, nvroot, namewidth, B_TRUE); 4960185029Spjd if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE, 4961185029Spjd &l2cache, &nl2cache) == 0) 4962185029Spjd print_l2cache(zhp, l2cache, nl2cache, namewidth); 4963185029Spjd 4964168404Spjd if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES, 4965168404Spjd &spares, &nspares) == 0) 4966168404Spjd print_spares(zhp, spares, nspares, namewidth); 4967168404Spjd 4968168404Spjd if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRCOUNT, 4969168404Spjd &nerr) == 0) { 4970168404Spjd nvlist_t *nverrlist = NULL; 4971168404Spjd 4972168404Spjd /* 4973168404Spjd * If the approximate error count is small, get a 4974168404Spjd * precise count by fetching the entire log and 4975168404Spjd * uniquifying the results. 4976168404Spjd */ 4977185029Spjd if (nerr > 0 && nerr < 100 && !cbp->cb_verbose && 4978168404Spjd zpool_get_errlog(zhp, &nverrlist) == 0) { 4979168404Spjd nvpair_t *elem; 4980168404Spjd 4981168404Spjd elem = NULL; 4982168404Spjd nerr = 0; 4983168404Spjd while ((elem = nvlist_next_nvpair(nverrlist, 4984168404Spjd elem)) != NULL) { 4985168404Spjd nerr++; 4986168404Spjd } 4987168404Spjd } 4988168404Spjd nvlist_free(nverrlist); 4989168404Spjd 4990168404Spjd (void) printf("\n"); 4991168404Spjd 4992168404Spjd if (nerr == 0) 4993168404Spjd (void) printf(gettext("errors: No known data " 4994168404Spjd "errors\n")); 4995168404Spjd else if (!cbp->cb_verbose) 4996168404Spjd (void) printf(gettext("errors: %llu data " 4997168404Spjd "errors, use '-v' for a list\n"), 4998168404Spjd (u_longlong_t)nerr); 4999168404Spjd else 5000168404Spjd print_error_log(zhp); 5001168404Spjd } 5002219089Spjd 5003219089Spjd if (cbp->cb_dedup_stats) 5004219089Spjd print_dedup_stats(config); 5005168404Spjd } else { 5006168404Spjd (void) printf(gettext("config: The configuration cannot be " 5007168404Spjd "determined.\n")); 5008168404Spjd } 5009168404Spjd 5010168404Spjd return (0); 5011168404Spjd} 5012168404Spjd 5013168404Spjd/* 5014219089Spjd * zpool status [-vx] [-T d|u] [pool] ... [interval [count]] 5015168404Spjd * 5016168404Spjd * -v Display complete error logs 5017168404Spjd * -x Display only pools with potential problems 5018219089Spjd * -D Display dedup status (undocumented) 5019219089Spjd * -T Display a timestamp in date(1) or Unix format 5020168404Spjd * 5021168404Spjd * Describes the health status of all pools or some subset. 5022168404Spjd */ 5023168404Spjdint 5024168404Spjdzpool_do_status(int argc, char **argv) 5025168404Spjd{ 5026168404Spjd int c; 5027168404Spjd int ret; 5028219089Spjd unsigned long interval = 0, count = 0; 5029168404Spjd status_cbdata_t cb = { 0 }; 5030168404Spjd 5031168404Spjd /* check options */ 5032219089Spjd while ((c = getopt(argc, argv, "vxDT:")) != -1) { 5033168404Spjd switch (c) { 5034168404Spjd case 'v': 5035168404Spjd cb.cb_verbose = B_TRUE; 5036168404Spjd break; 5037168404Spjd case 'x': 5038168404Spjd cb.cb_explain = B_TRUE; 5039168404Spjd break; 5040219089Spjd case 'D': 5041219089Spjd cb.cb_dedup_stats = B_TRUE; 5042219089Spjd break; 5043219089Spjd case 'T': 5044219089Spjd get_timestamp_arg(*optarg); 5045219089Spjd break; 5046168404Spjd case '?': 5047168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 5048168404Spjd optopt); 5049168404Spjd usage(B_FALSE); 5050168404Spjd } 5051168404Spjd } 5052168404Spjd 5053168404Spjd argc -= optind; 5054168404Spjd argv += optind; 5055168404Spjd 5056219089Spjd get_interval_count(&argc, argv, &interval, &count); 5057168404Spjd 5058168404Spjd if (argc == 0) 5059168404Spjd cb.cb_allpools = B_TRUE; 5060168404Spjd 5061219089Spjd cb.cb_first = B_TRUE; 5062168404Spjd 5063219089Spjd for (;;) { 5064219089Spjd if (timestamp_fmt != NODATE) 5065219089Spjd print_timestamp(timestamp_fmt); 5066168404Spjd 5067219089Spjd ret = for_each_pool(argc, argv, B_TRUE, NULL, 5068219089Spjd status_callback, &cb); 5069219089Spjd 5070219089Spjd if (argc == 0 && cb.cb_count == 0) 5071219089Spjd (void) printf(gettext("no pools available\n")); 5072219089Spjd else if (cb.cb_explain && cb.cb_first && cb.cb_allpools) 5073219089Spjd (void) printf(gettext("all pools are healthy\n")); 5074219089Spjd 5075219089Spjd if (ret != 0) 5076219089Spjd return (ret); 5077219089Spjd 5078219089Spjd if (interval == 0) 5079219089Spjd break; 5080219089Spjd 5081219089Spjd if (count != 0 && --count == 0) 5082219089Spjd break; 5083219089Spjd 5084219089Spjd (void) sleep(interval); 5085219089Spjd } 5086219089Spjd 5087219089Spjd return (0); 5088168404Spjd} 5089168404Spjd 5090168404Spjdtypedef struct upgrade_cbdata { 5091276226Ssmh boolean_t cb_first; 5092276226Ssmh boolean_t cb_unavail; 5093307108Smav char cb_poolname[ZFS_MAX_DATASET_NAME_LEN]; 5094276226Ssmh int cb_argc; 5095276226Ssmh uint64_t cb_version; 5096276226Ssmh char **cb_argv; 5097168404Spjd} upgrade_cbdata_t; 5098168404Spjd 5099238950Smm#ifdef __FreeBSD__ 5100168404Spjdstatic int 5101212050Spjdis_root_pool(zpool_handle_t *zhp) 5102212050Spjd{ 5103212050Spjd static struct statfs sfs; 5104212050Spjd static char *poolname = NULL; 5105212050Spjd static boolean_t stated = B_FALSE; 5106212050Spjd char *slash; 5107212050Spjd 5108212067Spjd if (!stated) { 5109212050Spjd stated = B_TRUE; 5110212050Spjd if (statfs("/", &sfs) == -1) { 5111212050Spjd (void) fprintf(stderr, 5112212050Spjd "Unable to stat root file system: %s.\n", 5113212050Spjd strerror(errno)); 5114212067Spjd return (0); 5115212050Spjd } 5116212050Spjd if (strcmp(sfs.f_fstypename, "zfs") != 0) 5117212067Spjd return (0); 5118212050Spjd poolname = sfs.f_mntfromname; 5119212050Spjd if ((slash = strchr(poolname, '/')) != NULL) 5120212050Spjd *slash = '\0'; 5121212050Spjd } 5122212050Spjd return (poolname != NULL && strcmp(poolname, zpool_get_name(zhp)) == 0); 5123212050Spjd} 5124212050Spjd 5125238950Smmstatic void 5126271934Ssmhroot_pool_upgrade_check(zpool_handle_t *zhp, char *poolname, int size) 5127271934Ssmh{ 5128238950Smm 5129238950Smm if (poolname[0] == '\0' && is_root_pool(zhp)) 5130238950Smm (void) strlcpy(poolname, zpool_get_name(zhp), size); 5131238950Smm} 5132238950Smm#endif /* FreeBSD */ 5133238950Smm 5134212050Spjdstatic int 5135238926Smmupgrade_version(zpool_handle_t *zhp, uint64_t version) 5136238926Smm{ 5137238926Smm int ret; 5138238926Smm nvlist_t *config; 5139238926Smm uint64_t oldversion; 5140238926Smm 5141238926Smm config = zpool_get_config(zhp, NULL); 5142238926Smm verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, 5143238926Smm &oldversion) == 0); 5144238926Smm 5145238926Smm assert(SPA_VERSION_IS_SUPPORTED(oldversion)); 5146238926Smm assert(oldversion < version); 5147238926Smm 5148238926Smm ret = zpool_upgrade(zhp, version); 5149238926Smm if (ret != 0) 5150238926Smm return (ret); 5151238926Smm 5152238926Smm if (version >= SPA_VERSION_FEATURES) { 5153238926Smm (void) printf(gettext("Successfully upgraded " 5154238926Smm "'%s' from version %llu to feature flags.\n"), 5155238926Smm zpool_get_name(zhp), oldversion); 5156238926Smm } else { 5157238926Smm (void) printf(gettext("Successfully upgraded " 5158238926Smm "'%s' from version %llu to version %llu.\n"), 5159238926Smm zpool_get_name(zhp), oldversion, version); 5160238926Smm } 5161238926Smm 5162238926Smm return (0); 5163238926Smm} 5164238926Smm 5165238926Smmstatic int 5166238926Smmupgrade_enable_all(zpool_handle_t *zhp, int *countp) 5167238926Smm{ 5168238926Smm int i, ret, count; 5169238926Smm boolean_t firstff = B_TRUE; 5170238926Smm nvlist_t *enabled = zpool_get_features(zhp); 5171238926Smm 5172238926Smm count = 0; 5173238926Smm for (i = 0; i < SPA_FEATURES; i++) { 5174238926Smm const char *fname = spa_feature_table[i].fi_uname; 5175238926Smm const char *fguid = spa_feature_table[i].fi_guid; 5176238926Smm if (!nvlist_exists(enabled, fguid)) { 5177238926Smm char *propname; 5178238926Smm verify(-1 != asprintf(&propname, "feature@%s", fname)); 5179238926Smm ret = zpool_set_prop(zhp, propname, 5180238926Smm ZFS_FEATURE_ENABLED); 5181238926Smm if (ret != 0) { 5182238926Smm free(propname); 5183238926Smm return (ret); 5184238926Smm } 5185238926Smm count++; 5186238926Smm 5187238926Smm if (firstff) { 5188238926Smm (void) printf(gettext("Enabled the " 5189238926Smm "following features on '%s':\n"), 5190238926Smm zpool_get_name(zhp)); 5191238926Smm firstff = B_FALSE; 5192238926Smm } 5193238926Smm (void) printf(gettext(" %s\n"), fname); 5194238926Smm free(propname); 5195238926Smm } 5196238926Smm } 5197238926Smm 5198238926Smm if (countp != NULL) 5199238926Smm *countp = count; 5200238926Smm return (0); 5201238926Smm} 5202238926Smm 5203238926Smmstatic int 5204168404Spjdupgrade_cb(zpool_handle_t *zhp, void *arg) 5205168404Spjd{ 5206168404Spjd upgrade_cbdata_t *cbp = arg; 5207168404Spjd nvlist_t *config; 5208168404Spjd uint64_t version; 5209238926Smm boolean_t printnl = B_FALSE; 5210238926Smm int ret; 5211168404Spjd 5212276194Ssmh if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) { 5213276194Ssmh (void) fprintf(stderr, gettext("cannot upgrade '%s': pool is " 5214276226Ssmh "currently unavailable.\n\n"), zpool_get_name(zhp)); 5215276226Ssmh cbp->cb_unavail = B_TRUE; 5216276194Ssmh /* Allow iteration to continue. */ 5217276194Ssmh return (0); 5218276194Ssmh } 5219276194Ssmh 5220168404Spjd config = zpool_get_config(zhp, NULL); 5221168404Spjd verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, 5222168404Spjd &version) == 0); 5223168404Spjd 5224238926Smm assert(SPA_VERSION_IS_SUPPORTED(version)); 5225168404Spjd 5226238926Smm if (version < cbp->cb_version) { 5227238926Smm cbp->cb_first = B_FALSE; 5228238926Smm ret = upgrade_version(zhp, cbp->cb_version); 5229238926Smm if (ret != 0) 5230238926Smm return (ret); 5231238926Smm#ifdef __FreeBSD__ 5232238950Smm root_pool_upgrade_check(zhp, cbp->cb_poolname, 5233238950Smm sizeof(cbp->cb_poolname)); 5234271934Ssmh#endif /* __FreeBSD__ */ 5235238926Smm printnl = B_TRUE; 5236238926Smm 5237238926Smm#ifdef illumos 5238238926Smm /* 5239238926Smm * If they did "zpool upgrade -a", then we could 5240238926Smm * be doing ioctls to different pools. We need 5241238926Smm * to log this history once to each pool, and bypass 5242238926Smm * the normal history logging that happens in main(). 5243238926Smm */ 5244238926Smm (void) zpool_log_history(g_zfs, history_str); 5245238926Smm log_history = B_FALSE; 5246238926Smm#endif 5247238926Smm } 5248238926Smm 5249238926Smm if (cbp->cb_version >= SPA_VERSION_FEATURES) { 5250238926Smm int count; 5251238926Smm ret = upgrade_enable_all(zhp, &count); 5252238926Smm if (ret != 0) 5253238926Smm return (ret); 5254238926Smm 5255238926Smm if (count > 0) { 5256168404Spjd cbp->cb_first = B_FALSE; 5257238926Smm printnl = B_TRUE; 5258271934Ssmh#ifdef __FreeBSD__ 5259271934Ssmh root_pool_upgrade_check(zhp, cbp->cb_poolname, 5260271934Ssmh sizeof(cbp->cb_poolname)); 5261271934Ssmh#endif /* __FreeBSD__ */ 5262248571Smm /* 5263248571Smm * If they did "zpool upgrade -a", then we could 5264248571Smm * be doing ioctls to different pools. We need 5265248571Smm * to log this history once to each pool, and bypass 5266248571Smm * the normal history logging that happens in main(). 5267248571Smm */ 5268248571Smm (void) zpool_log_history(g_zfs, history_str); 5269248571Smm log_history = B_FALSE; 5270168404Spjd } 5271238926Smm } 5272168404Spjd 5273238926Smm if (printnl) { 5274238926Smm (void) printf(gettext("\n")); 5275238926Smm } 5276238926Smm 5277238926Smm return (0); 5278238926Smm} 5279238926Smm 5280238926Smmstatic int 5281276226Ssmhupgrade_list_unavail(zpool_handle_t *zhp, void *arg) 5282276226Ssmh{ 5283276226Ssmh upgrade_cbdata_t *cbp = arg; 5284276226Ssmh 5285276226Ssmh if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) { 5286276226Ssmh if (cbp->cb_first) { 5287276226Ssmh (void) fprintf(stderr, gettext("The following pools " 5288276226Ssmh "are unavailable and cannot be upgraded as this " 5289276226Ssmh "time.\n\n")); 5290276226Ssmh (void) fprintf(stderr, gettext("POOL\n")); 5291276226Ssmh (void) fprintf(stderr, gettext("------------\n")); 5292276226Ssmh cbp->cb_first = B_FALSE; 5293276226Ssmh } 5294276226Ssmh (void) printf(gettext("%s\n"), zpool_get_name(zhp)); 5295276226Ssmh cbp->cb_unavail = B_TRUE; 5296276226Ssmh } 5297276226Ssmh return (0); 5298276226Ssmh} 5299276226Ssmh 5300276226Ssmhstatic int 5301238926Smmupgrade_list_older_cb(zpool_handle_t *zhp, void *arg) 5302238926Smm{ 5303238926Smm upgrade_cbdata_t *cbp = arg; 5304238926Smm nvlist_t *config; 5305238926Smm uint64_t version; 5306238926Smm 5307276226Ssmh if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) { 5308276226Ssmh /* 5309276226Ssmh * This will have been reported by upgrade_list_unavail so 5310276226Ssmh * just allow iteration to continue. 5311276226Ssmh */ 5312276226Ssmh cbp->cb_unavail = B_TRUE; 5313276226Ssmh return (0); 5314276226Ssmh } 5315276226Ssmh 5316238926Smm config = zpool_get_config(zhp, NULL); 5317238926Smm verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, 5318238926Smm &version) == 0); 5319238926Smm 5320238926Smm assert(SPA_VERSION_IS_SUPPORTED(version)); 5321238926Smm 5322238926Smm if (version < SPA_VERSION_FEATURES) { 5323168404Spjd if (cbp->cb_first) { 5324168404Spjd (void) printf(gettext("The following pools are " 5325238926Smm "formatted with legacy version numbers and can\n" 5326238926Smm "be upgraded to use feature flags. After " 5327238926Smm "being upgraded, these pools\nwill no " 5328238926Smm "longer be accessible by software that does not " 5329238926Smm "support feature\nflags.\n\n")); 5330168404Spjd (void) printf(gettext("VER POOL\n")); 5331168404Spjd (void) printf(gettext("--- ------------\n")); 5332168404Spjd cbp->cb_first = B_FALSE; 5333168404Spjd } 5334168404Spjd 5335168404Spjd (void) printf("%2llu %s\n", (u_longlong_t)version, 5336168404Spjd zpool_get_name(zhp)); 5337168404Spjd } 5338168404Spjd 5339238926Smm return (0); 5340168404Spjd} 5341168404Spjd 5342238926Smmstatic int 5343238926Smmupgrade_list_disabled_cb(zpool_handle_t *zhp, void *arg) 5344238926Smm{ 5345238926Smm upgrade_cbdata_t *cbp = arg; 5346238926Smm nvlist_t *config; 5347238926Smm uint64_t version; 5348238926Smm 5349276194Ssmh if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) { 5350276226Ssmh /* 5351276226Ssmh * This will have been reported by upgrade_list_unavail so 5352276226Ssmh * just allow iteration to continue. 5353276226Ssmh */ 5354276226Ssmh cbp->cb_unavail = B_TRUE; 5355276194Ssmh return (0); 5356276194Ssmh } 5357276194Ssmh 5358238926Smm config = zpool_get_config(zhp, NULL); 5359238926Smm verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, 5360238926Smm &version) == 0); 5361238926Smm 5362238926Smm if (version >= SPA_VERSION_FEATURES) { 5363238926Smm int i; 5364238926Smm boolean_t poolfirst = B_TRUE; 5365238926Smm nvlist_t *enabled = zpool_get_features(zhp); 5366238926Smm 5367238926Smm for (i = 0; i < SPA_FEATURES; i++) { 5368238926Smm const char *fguid = spa_feature_table[i].fi_guid; 5369238926Smm const char *fname = spa_feature_table[i].fi_uname; 5370238926Smm if (!nvlist_exists(enabled, fguid)) { 5371238926Smm if (cbp->cb_first) { 5372238926Smm (void) printf(gettext("\nSome " 5373238926Smm "supported features are not " 5374238926Smm "enabled on the following pools. " 5375238926Smm "Once a\nfeature is enabled the " 5376238926Smm "pool may become incompatible with " 5377238926Smm "software\nthat does not support " 5378238926Smm "the feature. See " 5379243014Smm "zpool-features(7) for " 5380238926Smm "details.\n\n")); 5381238926Smm (void) printf(gettext("POOL " 5382238926Smm "FEATURE\n")); 5383238926Smm (void) printf(gettext("------" 5384238926Smm "---------\n")); 5385238926Smm cbp->cb_first = B_FALSE; 5386238926Smm } 5387238926Smm 5388238926Smm if (poolfirst) { 5389238926Smm (void) printf(gettext("%s\n"), 5390238926Smm zpool_get_name(zhp)); 5391238926Smm poolfirst = B_FALSE; 5392238926Smm } 5393238926Smm 5394238926Smm (void) printf(gettext(" %s\n"), fname); 5395238926Smm } 5396238926Smm } 5397238926Smm } 5398238926Smm 5399238926Smm return (0); 5400238926Smm} 5401238926Smm 5402168404Spjd/* ARGSUSED */ 5403168404Spjdstatic int 5404168404Spjdupgrade_one(zpool_handle_t *zhp, void *data) 5405168404Spjd{ 5406238926Smm boolean_t printnl = B_FALSE; 5407185029Spjd upgrade_cbdata_t *cbp = data; 5408185029Spjd uint64_t cur_version; 5409168404Spjd int ret; 5410168404Spjd 5411276226Ssmh if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) { 5412276226Ssmh (void) fprintf(stderr, gettext("cannot upgrade '%s': pool is " 5413276226Ssmh "is currently unavailable.\n\n"), zpool_get_name(zhp)); 5414276226Ssmh cbp->cb_unavail = B_TRUE; 5415276226Ssmh return (1); 5416276226Ssmh } 5417276226Ssmh 5418185029Spjd if (strcmp("log", zpool_get_name(zhp)) == 0) { 5419185029Spjd (void) printf(gettext("'log' is now a reserved word\n" 5420185029Spjd "Pool 'log' must be renamed using export and import" 5421276226Ssmh " to upgrade.\n\n")); 5422185029Spjd return (1); 5423185029Spjd } 5424168404Spjd 5425185029Spjd cur_version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL); 5426185029Spjd if (cur_version > cbp->cb_version) { 5427168404Spjd (void) printf(gettext("Pool '%s' is already formatted " 5428238926Smm "using more current version '%llu'.\n\n"), 5429185029Spjd zpool_get_name(zhp), cur_version); 5430185029Spjd return (0); 5431185029Spjd } 5432238926Smm 5433238926Smm if (cbp->cb_version != SPA_VERSION && cur_version == cbp->cb_version) { 5434185029Spjd (void) printf(gettext("Pool '%s' is already formatted " 5435238926Smm "using version %llu.\n\n"), zpool_get_name(zhp), 5436238926Smm cbp->cb_version); 5437168404Spjd return (0); 5438168404Spjd } 5439168404Spjd 5440238926Smm if (cur_version != cbp->cb_version) { 5441238926Smm printnl = B_TRUE; 5442238926Smm ret = upgrade_version(zhp, cbp->cb_version); 5443238950Smm if (ret != 0) 5444238950Smm return (ret); 5445238926Smm#ifdef __FreeBSD__ 5446238950Smm root_pool_upgrade_check(zhp, cbp->cb_poolname, 5447238950Smm sizeof(cbp->cb_poolname)); 5448271934Ssmh#endif /* __FreeBSD__ */ 5449238926Smm } 5450168404Spjd 5451238926Smm if (cbp->cb_version >= SPA_VERSION_FEATURES) { 5452238926Smm int count = 0; 5453238926Smm ret = upgrade_enable_all(zhp, &count); 5454238926Smm if (ret != 0) 5455238926Smm return (ret); 5456238926Smm 5457238926Smm if (count != 0) { 5458238926Smm printnl = B_TRUE; 5459238950Smm#ifdef __FreeBSD__ 5460238951Smm root_pool_upgrade_check(zhp, cbp->cb_poolname, 5461238951Smm sizeof(cbp->cb_poolname)); 5462238950Smm#endif /* __FreeBSD __*/ 5463238926Smm } else if (cur_version == SPA_VERSION) { 5464238926Smm (void) printf(gettext("Pool '%s' already has all " 5465276226Ssmh "supported features enabled.\n\n"), 5466238926Smm zpool_get_name(zhp)); 5467238926Smm } 5468168404Spjd } 5469168404Spjd 5470238926Smm if (printnl) { 5471238926Smm (void) printf(gettext("\n")); 5472238926Smm } 5473238926Smm 5474238926Smm return (0); 5475168404Spjd} 5476168404Spjd 5477168404Spjd/* 5478168404Spjd * zpool upgrade 5479168404Spjd * zpool upgrade -v 5480185029Spjd * zpool upgrade [-V version] <-a | pool ...> 5481168404Spjd * 5482168404Spjd * With no arguments, display downrev'd ZFS pool available for upgrade. 5483168404Spjd * Individual pools can be upgraded by specifying the pool, and '-a' will 5484168404Spjd * upgrade all pools. 5485168404Spjd */ 5486168404Spjdint 5487168404Spjdzpool_do_upgrade(int argc, char **argv) 5488168404Spjd{ 5489168404Spjd int c; 5490168404Spjd upgrade_cbdata_t cb = { 0 }; 5491168404Spjd int ret = 0; 5492168404Spjd boolean_t showversions = B_FALSE; 5493238926Smm boolean_t upgradeall = B_FALSE; 5494185029Spjd char *end; 5495168404Spjd 5496185029Spjd 5497168404Spjd /* check options */ 5498219089Spjd while ((c = getopt(argc, argv, ":avV:")) != -1) { 5499168404Spjd switch (c) { 5500168404Spjd case 'a': 5501238926Smm upgradeall = B_TRUE; 5502168404Spjd break; 5503168404Spjd case 'v': 5504168404Spjd showversions = B_TRUE; 5505168404Spjd break; 5506185029Spjd case 'V': 5507185029Spjd cb.cb_version = strtoll(optarg, &end, 10); 5508236884Smm if (*end != '\0' || 5509236884Smm !SPA_VERSION_IS_SUPPORTED(cb.cb_version)) { 5510185029Spjd (void) fprintf(stderr, 5511185029Spjd gettext("invalid version '%s'\n"), optarg); 5512185029Spjd usage(B_FALSE); 5513185029Spjd } 5514185029Spjd break; 5515219089Spjd case ':': 5516219089Spjd (void) fprintf(stderr, gettext("missing argument for " 5517219089Spjd "'%c' option\n"), optopt); 5518219089Spjd usage(B_FALSE); 5519219089Spjd break; 5520168404Spjd case '?': 5521168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 5522168404Spjd optopt); 5523168404Spjd usage(B_FALSE); 5524168404Spjd } 5525168404Spjd } 5526168404Spjd 5527168404Spjd cb.cb_argc = argc; 5528168404Spjd cb.cb_argv = argv; 5529168404Spjd argc -= optind; 5530168404Spjd argv += optind; 5531168404Spjd 5532185029Spjd if (cb.cb_version == 0) { 5533185029Spjd cb.cb_version = SPA_VERSION; 5534238926Smm } else if (!upgradeall && argc == 0) { 5535185029Spjd (void) fprintf(stderr, gettext("-V option is " 5536185029Spjd "incompatible with other arguments\n")); 5537185029Spjd usage(B_FALSE); 5538185029Spjd } 5539185029Spjd 5540168404Spjd if (showversions) { 5541238926Smm if (upgradeall || argc != 0) { 5542168404Spjd (void) fprintf(stderr, gettext("-v option is " 5543168404Spjd "incompatible with other arguments\n")); 5544168404Spjd usage(B_FALSE); 5545168404Spjd } 5546238926Smm } else if (upgradeall) { 5547168404Spjd if (argc != 0) { 5548185029Spjd (void) fprintf(stderr, gettext("-a option should not " 5549185029Spjd "be used along with a pool name\n")); 5550168404Spjd usage(B_FALSE); 5551168404Spjd } 5552168404Spjd } 5553168404Spjd 5554236884Smm (void) printf(gettext("This system supports ZFS pool feature " 5555236884Smm "flags.\n\n")); 5556168404Spjd if (showversions) { 5557238926Smm int i; 5558238926Smm 5559238926Smm (void) printf(gettext("The following features are " 5560168404Spjd "supported:\n\n")); 5561238926Smm (void) printf(gettext("FEAT DESCRIPTION\n")); 5562238926Smm (void) printf("----------------------------------------------" 5563238926Smm "---------------\n"); 5564238926Smm for (i = 0; i < SPA_FEATURES; i++) { 5565238926Smm zfeature_info_t *fi = &spa_feature_table[i]; 5566286708Smav const char *ro = 5567286708Smav (fi->fi_flags & ZFEATURE_FLAG_READONLY_COMPAT) ? 5568238926Smm " (read-only compatible)" : ""; 5569238926Smm 5570238926Smm (void) printf("%-37s%s\n", fi->fi_uname, ro); 5571238926Smm (void) printf(" %s\n", fi->fi_desc); 5572238926Smm } 5573238926Smm (void) printf("\n"); 5574238926Smm 5575238926Smm (void) printf(gettext("The following legacy versions are also " 5576238926Smm "supported:\n\n")); 5577168404Spjd (void) printf(gettext("VER DESCRIPTION\n")); 5578168404Spjd (void) printf("--- -----------------------------------------" 5579168404Spjd "---------------\n"); 5580168404Spjd (void) printf(gettext(" 1 Initial ZFS version\n")); 5581168404Spjd (void) printf(gettext(" 2 Ditto blocks " 5582168404Spjd "(replicated metadata)\n")); 5583168404Spjd (void) printf(gettext(" 3 Hot spares and double parity " 5584168404Spjd "RAID-Z\n")); 5585168404Spjd (void) printf(gettext(" 4 zpool history\n")); 5586168404Spjd (void) printf(gettext(" 5 Compression using the gzip " 5587168404Spjd "algorithm\n")); 5588185029Spjd (void) printf(gettext(" 6 bootfs pool property\n")); 5589185029Spjd (void) printf(gettext(" 7 Separate intent log devices\n")); 5590185029Spjd (void) printf(gettext(" 8 Delegated administration\n")); 5591185029Spjd (void) printf(gettext(" 9 refquota and refreservation " 5592185029Spjd "properties\n")); 5593185029Spjd (void) printf(gettext(" 10 Cache devices\n")); 5594185029Spjd (void) printf(gettext(" 11 Improved scrub performance\n")); 5595185029Spjd (void) printf(gettext(" 12 Snapshot properties\n")); 5596185029Spjd (void) printf(gettext(" 13 snapused property\n")); 5597209962Smm (void) printf(gettext(" 14 passthrough-x aclinherit\n")); 5598209962Smm (void) printf(gettext(" 15 user/group space accounting\n")); 5599219089Spjd (void) printf(gettext(" 16 stmf property support\n")); 5600219089Spjd (void) printf(gettext(" 17 Triple-parity RAID-Z\n")); 5601219089Spjd (void) printf(gettext(" 18 Snapshot user holds\n")); 5602219089Spjd (void) printf(gettext(" 19 Log device removal\n")); 5603219089Spjd (void) printf(gettext(" 20 Compression using zle " 5604219089Spjd "(zero-length encoding)\n")); 5605219089Spjd (void) printf(gettext(" 21 Deduplication\n")); 5606219089Spjd (void) printf(gettext(" 22 Received properties\n")); 5607219089Spjd (void) printf(gettext(" 23 Slim ZIL\n")); 5608219089Spjd (void) printf(gettext(" 24 System attributes\n")); 5609219089Spjd (void) printf(gettext(" 25 Improved scrub stats\n")); 5610219089Spjd (void) printf(gettext(" 26 Improved snapshot deletion " 5611219089Spjd "performance\n")); 5612219089Spjd (void) printf(gettext(" 27 Improved snapshot creation " 5613219089Spjd "performance\n")); 5614219089Spjd (void) printf(gettext(" 28 Multiple vdev replacements\n")); 5615219089Spjd (void) printf(gettext("\nFor more information on a particular " 5616219089Spjd "version, including supported releases,\n")); 5617219089Spjd (void) printf(gettext("see the ZFS Administration Guide.\n\n")); 5618238926Smm } else if (argc == 0 && upgradeall) { 5619238926Smm cb.cb_first = B_TRUE; 5620168404Spjd ret = zpool_iter(g_zfs, upgrade_cb, &cb); 5621238926Smm if (ret == 0 && cb.cb_first) { 5622238926Smm if (cb.cb_version == SPA_VERSION) { 5623276226Ssmh (void) printf(gettext("All %spools are already " 5624276226Ssmh "formatted using feature flags.\n\n"), 5625276226Ssmh cb.cb_unavail ? gettext("available ") : ""); 5626276226Ssmh (void) printf(gettext("Every %sfeature flags " 5627238926Smm "pool already has all supported features " 5628276226Ssmh "enabled.\n"), 5629276226Ssmh cb.cb_unavail ? gettext("available ") : ""); 5630238926Smm } else { 5631238926Smm (void) printf(gettext("All pools are already " 5632238926Smm "formatted with version %llu or higher.\n"), 5633238926Smm cb.cb_version); 5634168404Spjd } 5635168404Spjd } 5636238926Smm } else if (argc == 0) { 5637238926Smm cb.cb_first = B_TRUE; 5638276226Ssmh ret = zpool_iter(g_zfs, upgrade_list_unavail, &cb); 5639276226Ssmh assert(ret == 0); 5640276226Ssmh 5641276226Ssmh if (!cb.cb_first) { 5642276226Ssmh (void) fprintf(stderr, "\n"); 5643276226Ssmh } 5644276226Ssmh 5645276226Ssmh cb.cb_first = B_TRUE; 5646238926Smm ret = zpool_iter(g_zfs, upgrade_list_older_cb, &cb); 5647238926Smm assert(ret == 0); 5648168404Spjd 5649238926Smm if (cb.cb_first) { 5650276226Ssmh (void) printf(gettext("All %spools are formatted using " 5651276226Ssmh "feature flags.\n\n"), cb.cb_unavail ? 5652276226Ssmh gettext("available ") : ""); 5653238926Smm } else { 5654238926Smm (void) printf(gettext("\nUse 'zpool upgrade -v' " 5655238926Smm "for a list of available legacy versions.\n")); 5656168404Spjd } 5657238926Smm 5658238926Smm cb.cb_first = B_TRUE; 5659238926Smm ret = zpool_iter(g_zfs, upgrade_list_disabled_cb, &cb); 5660238926Smm assert(ret == 0); 5661238926Smm 5662238926Smm if (cb.cb_first) { 5663276226Ssmh (void) printf(gettext("Every %sfeature flags pool has " 5664276226Ssmh "all supported features enabled.\n"), 5665276226Ssmh cb.cb_unavail ? gettext("available ") : ""); 5666238926Smm } else { 5667238926Smm (void) printf(gettext("\n")); 5668238926Smm } 5669168404Spjd } else { 5670276226Ssmh ret = for_each_pool(argc, argv, B_TRUE, NULL, 5671168404Spjd upgrade_one, &cb); 5672168404Spjd } 5673168404Spjd 5674212050Spjd if (cb.cb_poolname[0] != '\0') { 5675212050Spjd (void) printf( 5676212050Spjd "If you boot from pool '%s', don't forget to update boot code.\n" 5677212050Spjd "Assuming you use GPT partitioning and da0 is your boot disk\n" 5678212050Spjd "the following command will do it:\n" 5679212050Spjd "\n" 5680212050Spjd "\tgpart bootcode -b /boot/pmbr -p /boot/gptzfsboot -i 1 da0\n\n", 5681212050Spjd cb.cb_poolname); 5682212050Spjd } 5683212050Spjd 5684168404Spjd return (ret); 5685168404Spjd} 5686168404Spjd 5687185029Spjdtypedef struct hist_cbdata { 5688185029Spjd boolean_t first; 5689248571Smm boolean_t longfmt; 5690248571Smm boolean_t internal; 5691185029Spjd} hist_cbdata_t; 5692185029Spjd 5693168404Spjd/* 5694168404Spjd * Print out the command history for a specific pool. 5695168404Spjd */ 5696168404Spjdstatic int 5697168404Spjdget_history_one(zpool_handle_t *zhp, void *data) 5698168404Spjd{ 5699168404Spjd nvlist_t *nvhis; 5700168404Spjd nvlist_t **records; 5701168404Spjd uint_t numrecords; 5702168404Spjd int ret, i; 5703185029Spjd hist_cbdata_t *cb = (hist_cbdata_t *)data; 5704168404Spjd 5705185029Spjd cb->first = B_FALSE; 5706168404Spjd 5707168404Spjd (void) printf(gettext("History for '%s':\n"), zpool_get_name(zhp)); 5708168404Spjd 5709168404Spjd if ((ret = zpool_get_history(zhp, &nvhis)) != 0) 5710168404Spjd return (ret); 5711168404Spjd 5712168404Spjd verify(nvlist_lookup_nvlist_array(nvhis, ZPOOL_HIST_RECORD, 5713168404Spjd &records, &numrecords) == 0); 5714168404Spjd for (i = 0; i < numrecords; i++) { 5715248571Smm nvlist_t *rec = records[i]; 5716248571Smm char tbuf[30] = ""; 5717185029Spjd 5718248571Smm if (nvlist_exists(rec, ZPOOL_HIST_TIME)) { 5719248571Smm time_t tsec; 5720248571Smm struct tm t; 5721185029Spjd 5722248571Smm tsec = fnvlist_lookup_uint64(records[i], 5723248571Smm ZPOOL_HIST_TIME); 5724248571Smm (void) localtime_r(&tsec, &t); 5725248571Smm (void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t); 5726248571Smm } 5727248571Smm 5728248571Smm if (nvlist_exists(rec, ZPOOL_HIST_CMD)) { 5729248571Smm (void) printf("%s %s", tbuf, 5730248571Smm fnvlist_lookup_string(rec, ZPOOL_HIST_CMD)); 5731248571Smm } else if (nvlist_exists(rec, ZPOOL_HIST_INT_EVENT)) { 5732248571Smm int ievent = 5733248571Smm fnvlist_lookup_uint64(rec, ZPOOL_HIST_INT_EVENT); 5734248571Smm if (!cb->internal) 5735185029Spjd continue; 5736248571Smm if (ievent >= ZFS_NUM_LEGACY_HISTORY_EVENTS) { 5737248571Smm (void) printf("%s unrecognized record:\n", 5738248571Smm tbuf); 5739248571Smm dump_nvlist(rec, 4); 5740185029Spjd continue; 5741248571Smm } 5742248571Smm (void) printf("%s [internal %s txg:%lld] %s", tbuf, 5743248571Smm zfs_history_event_names[ievent], 5744248571Smm fnvlist_lookup_uint64(rec, ZPOOL_HIST_TXG), 5745248571Smm fnvlist_lookup_string(rec, ZPOOL_HIST_INT_STR)); 5746248571Smm } else if (nvlist_exists(rec, ZPOOL_HIST_INT_NAME)) { 5747248571Smm if (!cb->internal) 5748248571Smm continue; 5749248571Smm (void) printf("%s [txg:%lld] %s", tbuf, 5750248571Smm fnvlist_lookup_uint64(rec, ZPOOL_HIST_TXG), 5751248571Smm fnvlist_lookup_string(rec, ZPOOL_HIST_INT_NAME)); 5752248571Smm if (nvlist_exists(rec, ZPOOL_HIST_DSNAME)) { 5753248571Smm (void) printf(" %s (%llu)", 5754248571Smm fnvlist_lookup_string(rec, 5755248571Smm ZPOOL_HIST_DSNAME), 5756248571Smm fnvlist_lookup_uint64(rec, 5757248571Smm ZPOOL_HIST_DSID)); 5758248571Smm } 5759248571Smm (void) printf(" %s", fnvlist_lookup_string(rec, 5760248571Smm ZPOOL_HIST_INT_STR)); 5761248571Smm } else if (nvlist_exists(rec, ZPOOL_HIST_IOCTL)) { 5762248571Smm if (!cb->internal) 5763248571Smm continue; 5764248571Smm (void) printf("%s ioctl %s\n", tbuf, 5765248571Smm fnvlist_lookup_string(rec, ZPOOL_HIST_IOCTL)); 5766248571Smm if (nvlist_exists(rec, ZPOOL_HIST_INPUT_NVL)) { 5767248571Smm (void) printf(" input:\n"); 5768248571Smm dump_nvlist(fnvlist_lookup_nvlist(rec, 5769248571Smm ZPOOL_HIST_INPUT_NVL), 8); 5770248571Smm } 5771248571Smm if (nvlist_exists(rec, ZPOOL_HIST_OUTPUT_NVL)) { 5772248571Smm (void) printf(" output:\n"); 5773248571Smm dump_nvlist(fnvlist_lookup_nvlist(rec, 5774248571Smm ZPOOL_HIST_OUTPUT_NVL), 8); 5775248571Smm } 5776325534Savg if (nvlist_exists(rec, ZPOOL_HIST_ERRNO)) { 5777325534Savg (void) printf(" errno: %lld\n", 5778325534Savg fnvlist_lookup_int64(rec, 5779325534Savg ZPOOL_HIST_ERRNO)); 5780325534Savg } 5781248571Smm } else { 5782248571Smm if (!cb->internal) 5783248571Smm continue; 5784248571Smm (void) printf("%s unrecognized record:\n", tbuf); 5785248571Smm dump_nvlist(rec, 4); 5786168404Spjd } 5787185029Spjd 5788185029Spjd if (!cb->longfmt) { 5789185029Spjd (void) printf("\n"); 5790185029Spjd continue; 5791185029Spjd } 5792185029Spjd (void) printf(" ["); 5793248571Smm if (nvlist_exists(rec, ZPOOL_HIST_WHO)) { 5794248571Smm uid_t who = fnvlist_lookup_uint64(rec, ZPOOL_HIST_WHO); 5795248571Smm struct passwd *pwd = getpwuid(who); 5796248571Smm (void) printf("user %d ", (int)who); 5797248571Smm if (pwd != NULL) 5798248571Smm (void) printf("(%s) ", pwd->pw_name); 5799185029Spjd } 5800248571Smm if (nvlist_exists(rec, ZPOOL_HIST_HOST)) { 5801248571Smm (void) printf("on %s", 5802248571Smm fnvlist_lookup_string(rec, ZPOOL_HIST_HOST)); 5803185029Spjd } 5804248571Smm if (nvlist_exists(rec, ZPOOL_HIST_ZONE)) { 5805248571Smm (void) printf(":%s", 5806248571Smm fnvlist_lookup_string(rec, ZPOOL_HIST_ZONE)); 5807185029Spjd } 5808185029Spjd (void) printf("]"); 5809185029Spjd (void) printf("\n"); 5810168404Spjd } 5811168404Spjd (void) printf("\n"); 5812168404Spjd nvlist_free(nvhis); 5813168404Spjd 5814168404Spjd return (ret); 5815168404Spjd} 5816168404Spjd 5817168404Spjd/* 5818168404Spjd * zpool history <pool> 5819168404Spjd * 5820168404Spjd * Displays the history of commands that modified pools. 5821168404Spjd */ 5822168404Spjdint 5823168404Spjdzpool_do_history(int argc, char **argv) 5824168404Spjd{ 5825185029Spjd hist_cbdata_t cbdata = { 0 }; 5826168404Spjd int ret; 5827185029Spjd int c; 5828168404Spjd 5829185029Spjd cbdata.first = B_TRUE; 5830185029Spjd /* check options */ 5831185029Spjd while ((c = getopt(argc, argv, "li")) != -1) { 5832185029Spjd switch (c) { 5833185029Spjd case 'l': 5834248571Smm cbdata.longfmt = B_TRUE; 5835185029Spjd break; 5836185029Spjd case 'i': 5837248571Smm cbdata.internal = B_TRUE; 5838185029Spjd break; 5839185029Spjd case '?': 5840185029Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 5841185029Spjd optopt); 5842185029Spjd usage(B_FALSE); 5843185029Spjd } 5844185029Spjd } 5845168404Spjd argc -= optind; 5846168404Spjd argv += optind; 5847168404Spjd 5848168404Spjd ret = for_each_pool(argc, argv, B_FALSE, NULL, get_history_one, 5849185029Spjd &cbdata); 5850168404Spjd 5851185029Spjd if (argc == 0 && cbdata.first == B_TRUE) { 5852168404Spjd (void) printf(gettext("no pools available\n")); 5853168404Spjd return (0); 5854168404Spjd } 5855168404Spjd 5856168404Spjd return (ret); 5857168404Spjd} 5858168404Spjd 5859168404Spjdstatic int 5860168404Spjdget_callback(zpool_handle_t *zhp, void *data) 5861168404Spjd{ 5862185029Spjd zprop_get_cbdata_t *cbp = (zprop_get_cbdata_t *)data; 5863168404Spjd char value[MAXNAMELEN]; 5864185029Spjd zprop_source_t srctype; 5865185029Spjd zprop_list_t *pl; 5866168404Spjd 5867168404Spjd for (pl = cbp->cb_proplist; pl != NULL; pl = pl->pl_next) { 5868168404Spjd 5869168404Spjd /* 5870185029Spjd * Skip the special fake placeholder. This will also skip 5871185029Spjd * over the name property when 'all' is specified. 5872168404Spjd */ 5873185029Spjd if (pl->pl_prop == ZPOOL_PROP_NAME && 5874168404Spjd pl == cbp->cb_proplist) 5875168404Spjd continue; 5876168404Spjd 5877236884Smm if (pl->pl_prop == ZPROP_INVAL && 5878236884Smm (zpool_prop_feature(pl->pl_user_prop) || 5879236884Smm zpool_prop_unsupported(pl->pl_user_prop))) { 5880236884Smm srctype = ZPROP_SRC_LOCAL; 5881168404Spjd 5882236884Smm if (zpool_prop_get_feature(zhp, pl->pl_user_prop, 5883236884Smm value, sizeof (value)) == 0) { 5884236884Smm zprop_print_one_property(zpool_get_name(zhp), 5885236884Smm cbp, pl->pl_user_prop, value, srctype, 5886236884Smm NULL, NULL); 5887236884Smm } 5888236884Smm } else { 5889236884Smm if (zpool_get_prop(zhp, pl->pl_prop, value, 5890263889Sdelphij sizeof (value), &srctype, cbp->cb_literal) != 0) 5891236884Smm continue; 5892236884Smm 5893236884Smm zprop_print_one_property(zpool_get_name(zhp), cbp, 5894236884Smm zpool_prop_to_name(pl->pl_prop), value, srctype, 5895236884Smm NULL, NULL); 5896236884Smm } 5897168404Spjd } 5898168404Spjd return (0); 5899168404Spjd} 5900168404Spjd 5901263889Sdelphij/* 5902263889Sdelphij * zpool get [-Hp] [-o "all" | field[,...]] <"all" | property[,...]> <pool> ... 5903263889Sdelphij * 5904263889Sdelphij * -H Scripted mode. Don't display headers, and separate properties 5905263889Sdelphij * by a single tab. 5906263889Sdelphij * -o List of columns to display. Defaults to 5907263889Sdelphij * "name,property,value,source". 5908263889Sdelphij * -p Diplay values in parsable (exact) format. 5909263889Sdelphij * 5910263889Sdelphij * Get properties of pools in the system. Output space statistics 5911263889Sdelphij * for each one as well as other attributes. 5912263889Sdelphij */ 5913168404Spjdint 5914168404Spjdzpool_do_get(int argc, char **argv) 5915168404Spjd{ 5916185029Spjd zprop_get_cbdata_t cb = { 0 }; 5917185029Spjd zprop_list_t fake_name = { 0 }; 5918168404Spjd int ret; 5919263889Sdelphij int c, i; 5920263889Sdelphij char *value; 5921168404Spjd 5922263889Sdelphij cb.cb_first = B_TRUE; 5923168404Spjd 5924263889Sdelphij /* 5925263889Sdelphij * Set up default columns and sources. 5926263889Sdelphij */ 5927185029Spjd cb.cb_sources = ZPROP_SRC_ALL; 5928168404Spjd cb.cb_columns[0] = GET_COL_NAME; 5929168404Spjd cb.cb_columns[1] = GET_COL_PROPERTY; 5930168404Spjd cb.cb_columns[2] = GET_COL_VALUE; 5931168404Spjd cb.cb_columns[3] = GET_COL_SOURCE; 5932185029Spjd cb.cb_type = ZFS_TYPE_POOL; 5933168404Spjd 5934263889Sdelphij /* check options */ 5935263889Sdelphij while ((c = getopt(argc, argv, ":Hpo:")) != -1) { 5936263889Sdelphij switch (c) { 5937263889Sdelphij case 'p': 5938263889Sdelphij cb.cb_literal = B_TRUE; 5939263889Sdelphij break; 5940263889Sdelphij case 'H': 5941263889Sdelphij cb.cb_scripted = B_TRUE; 5942263889Sdelphij break; 5943263889Sdelphij case 'o': 5944263889Sdelphij bzero(&cb.cb_columns, sizeof (cb.cb_columns)); 5945263889Sdelphij i = 0; 5946263889Sdelphij while (*optarg != '\0') { 5947263889Sdelphij static char *col_subopts[] = 5948263889Sdelphij { "name", "property", "value", "source", 5949263889Sdelphij "all", NULL }; 5950263889Sdelphij 5951263889Sdelphij if (i == ZFS_GET_NCOLS) { 5952263889Sdelphij (void) fprintf(stderr, gettext("too " 5953263889Sdelphij "many fields given to -o " 5954263889Sdelphij "option\n")); 5955263889Sdelphij usage(B_FALSE); 5956263889Sdelphij } 5957263889Sdelphij 5958263889Sdelphij switch (getsubopt(&optarg, col_subopts, 5959263889Sdelphij &value)) { 5960263889Sdelphij case 0: 5961263889Sdelphij cb.cb_columns[i++] = GET_COL_NAME; 5962263889Sdelphij break; 5963263889Sdelphij case 1: 5964263889Sdelphij cb.cb_columns[i++] = GET_COL_PROPERTY; 5965263889Sdelphij break; 5966263889Sdelphij case 2: 5967263889Sdelphij cb.cb_columns[i++] = GET_COL_VALUE; 5968263889Sdelphij break; 5969263889Sdelphij case 3: 5970263889Sdelphij cb.cb_columns[i++] = GET_COL_SOURCE; 5971263889Sdelphij break; 5972263889Sdelphij case 4: 5973263889Sdelphij if (i > 0) { 5974263889Sdelphij (void) fprintf(stderr, 5975263889Sdelphij gettext("\"all\" conflicts " 5976263889Sdelphij "with specific fields " 5977263889Sdelphij "given to -o option\n")); 5978263889Sdelphij usage(B_FALSE); 5979263889Sdelphij } 5980263889Sdelphij cb.cb_columns[0] = GET_COL_NAME; 5981263889Sdelphij cb.cb_columns[1] = GET_COL_PROPERTY; 5982263889Sdelphij cb.cb_columns[2] = GET_COL_VALUE; 5983263889Sdelphij cb.cb_columns[3] = GET_COL_SOURCE; 5984263889Sdelphij i = ZFS_GET_NCOLS; 5985263889Sdelphij break; 5986263889Sdelphij default: 5987263889Sdelphij (void) fprintf(stderr, 5988263889Sdelphij gettext("invalid column name " 5989295844Sdim "'%s'\n"), suboptarg); 5990263889Sdelphij usage(B_FALSE); 5991263889Sdelphij } 5992263889Sdelphij } 5993263889Sdelphij break; 5994263889Sdelphij case '?': 5995263889Sdelphij (void) fprintf(stderr, gettext("invalid option '%c'\n"), 5996263889Sdelphij optopt); 5997263889Sdelphij usage(B_FALSE); 5998263889Sdelphij } 5999263889Sdelphij } 6000263889Sdelphij 6001263889Sdelphij argc -= optind; 6002263889Sdelphij argv += optind; 6003263889Sdelphij 6004263889Sdelphij if (argc < 1) { 6005263889Sdelphij (void) fprintf(stderr, gettext("missing property " 6006263889Sdelphij "argument\n")); 6007263889Sdelphij usage(B_FALSE); 6008263889Sdelphij } 6009263889Sdelphij 6010263889Sdelphij if (zprop_get_list(g_zfs, argv[0], &cb.cb_proplist, 6011185029Spjd ZFS_TYPE_POOL) != 0) 6012168404Spjd usage(B_FALSE); 6013168404Spjd 6014263889Sdelphij argc--; 6015263889Sdelphij argv++; 6016263889Sdelphij 6017168404Spjd if (cb.cb_proplist != NULL) { 6018185029Spjd fake_name.pl_prop = ZPOOL_PROP_NAME; 6019168404Spjd fake_name.pl_width = strlen(gettext("NAME")); 6020168404Spjd fake_name.pl_next = cb.cb_proplist; 6021168404Spjd cb.cb_proplist = &fake_name; 6022168404Spjd } 6023168404Spjd 6024263889Sdelphij ret = for_each_pool(argc, argv, B_TRUE, &cb.cb_proplist, 6025168404Spjd get_callback, &cb); 6026168404Spjd 6027168404Spjd if (cb.cb_proplist == &fake_name) 6028185029Spjd zprop_free_list(fake_name.pl_next); 6029168404Spjd else 6030185029Spjd zprop_free_list(cb.cb_proplist); 6031168404Spjd 6032168404Spjd return (ret); 6033168404Spjd} 6034168404Spjd 6035168404Spjdtypedef struct set_cbdata { 6036168404Spjd char *cb_propname; 6037168404Spjd char *cb_value; 6038168404Spjd boolean_t cb_any_successful; 6039168404Spjd} set_cbdata_t; 6040168404Spjd 6041168404Spjdint 6042168404Spjdset_callback(zpool_handle_t *zhp, void *data) 6043168404Spjd{ 6044168404Spjd int error; 6045168404Spjd set_cbdata_t *cb = (set_cbdata_t *)data; 6046168404Spjd 6047168404Spjd error = zpool_set_prop(zhp, cb->cb_propname, cb->cb_value); 6048168404Spjd 6049168404Spjd if (!error) 6050168404Spjd cb->cb_any_successful = B_TRUE; 6051168404Spjd 6052168404Spjd return (error); 6053168404Spjd} 6054168404Spjd 6055168404Spjdint 6056168404Spjdzpool_do_set(int argc, char **argv) 6057168404Spjd{ 6058168404Spjd set_cbdata_t cb = { 0 }; 6059168404Spjd int error; 6060168404Spjd 6061168404Spjd if (argc > 1 && argv[1][0] == '-') { 6062168404Spjd (void) fprintf(stderr, gettext("invalid option '%c'\n"), 6063168404Spjd argv[1][1]); 6064168404Spjd usage(B_FALSE); 6065168404Spjd } 6066168404Spjd 6067168404Spjd if (argc < 2) { 6068168404Spjd (void) fprintf(stderr, gettext("missing property=value " 6069168404Spjd "argument\n")); 6070168404Spjd usage(B_FALSE); 6071168404Spjd } 6072168404Spjd 6073168404Spjd if (argc < 3) { 6074168404Spjd (void) fprintf(stderr, gettext("missing pool name\n")); 6075168404Spjd usage(B_FALSE); 6076168404Spjd } 6077168404Spjd 6078168404Spjd if (argc > 3) { 6079168404Spjd (void) fprintf(stderr, gettext("too many pool names\n")); 6080168404Spjd usage(B_FALSE); 6081168404Spjd } 6082168404Spjd 6083168404Spjd cb.cb_propname = argv[1]; 6084168404Spjd cb.cb_value = strchr(cb.cb_propname, '='); 6085168404Spjd if (cb.cb_value == NULL) { 6086168404Spjd (void) fprintf(stderr, gettext("missing value in " 6087168404Spjd "property=value argument\n")); 6088168404Spjd usage(B_FALSE); 6089168404Spjd } 6090168404Spjd 6091168404Spjd *(cb.cb_value) = '\0'; 6092168404Spjd cb.cb_value++; 6093168404Spjd 6094168404Spjd error = for_each_pool(argc - 2, argv + 2, B_TRUE, NULL, 6095168404Spjd set_callback, &cb); 6096168404Spjd 6097168404Spjd return (error); 6098168404Spjd} 6099168404Spjd 6100168404Spjdstatic int 6101168404Spjdfind_command_idx(char *command, int *idx) 6102168404Spjd{ 6103168404Spjd int i; 6104168404Spjd 6105168404Spjd for (i = 0; i < NCOMMAND; i++) { 6106168404Spjd if (command_table[i].name == NULL) 6107168404Spjd continue; 6108168404Spjd 6109168404Spjd if (strcmp(command, command_table[i].name) == 0) { 6110168404Spjd *idx = i; 6111168404Spjd return (0); 6112168404Spjd } 6113168404Spjd } 6114168404Spjd return (1); 6115168404Spjd} 6116168404Spjd 6117168404Spjdint 6118168404Spjdmain(int argc, char **argv) 6119168404Spjd{ 6120296537Smav int ret = 0; 6121168404Spjd int i; 6122168404Spjd char *cmdname; 6123168404Spjd 6124168404Spjd (void) setlocale(LC_ALL, ""); 6125168404Spjd (void) textdomain(TEXT_DOMAIN); 6126168404Spjd 6127168404Spjd if ((g_zfs = libzfs_init()) == NULL) { 6128168404Spjd (void) fprintf(stderr, gettext("internal error: failed to " 6129168404Spjd "initialize ZFS library\n")); 6130168404Spjd return (1); 6131168404Spjd } 6132168404Spjd 6133168404Spjd libzfs_print_on_error(g_zfs, B_TRUE); 6134168404Spjd 6135168404Spjd opterr = 0; 6136168404Spjd 6137168404Spjd /* 6138168404Spjd * Make sure the user has specified some command. 6139168404Spjd */ 6140168404Spjd if (argc < 2) { 6141168404Spjd (void) fprintf(stderr, gettext("missing command\n")); 6142168404Spjd usage(B_FALSE); 6143168404Spjd } 6144168404Spjd 6145168404Spjd cmdname = argv[1]; 6146168404Spjd 6147168404Spjd /* 6148168404Spjd * Special case '-?' 6149168404Spjd */ 6150168404Spjd if (strcmp(cmdname, "-?") == 0) 6151168404Spjd usage(B_TRUE); 6152168404Spjd 6153248571Smm zfs_save_arguments(argc, argv, history_str, sizeof (history_str)); 6154185029Spjd 6155168404Spjd /* 6156168404Spjd * Run the appropriate command. 6157168404Spjd */ 6158168404Spjd if (find_command_idx(cmdname, &i) == 0) { 6159168404Spjd current_command = &command_table[i]; 6160168404Spjd ret = command_table[i].func(argc - 1, argv + 1); 6161185029Spjd } else if (strchr(cmdname, '=')) { 6162185029Spjd verify(find_command_idx("set", &i) == 0); 6163185029Spjd current_command = &command_table[i]; 6164185029Spjd ret = command_table[i].func(argc, argv); 6165185029Spjd } else if (strcmp(cmdname, "freeze") == 0 && argc == 3) { 6166185029Spjd /* 6167185029Spjd * 'freeze' is a vile debugging abomination, so we treat 6168185029Spjd * it as such. 6169185029Spjd */ 6170252059Ssmh zfs_cmd_t zc = { 0 }; 6171252059Ssmh (void) strlcpy(zc.zc_name, argv[2], sizeof (zc.zc_name)); 6172252059Ssmh return (!!zfs_ioctl(g_zfs, ZFS_IOC_POOL_FREEZE, &zc)); 6173185029Spjd } else { 6174168404Spjd (void) fprintf(stderr, gettext("unrecognized " 6175168404Spjd "command '%s'\n"), cmdname); 6176168404Spjd usage(B_FALSE); 6177168404Spjd } 6178168404Spjd 6179248571Smm if (ret == 0 && log_history) 6180248571Smm (void) zpool_log_history(g_zfs, history_str); 6181248571Smm 6182168404Spjd libzfs_fini(g_zfs); 6183168404Spjd 6184168404Spjd /* 6185168404Spjd * The 'ZFS_ABORT' environment variable causes us to dump core on exit 6186168404Spjd * for the purposes of running ::findleaks. 6187168404Spjd */ 6188168404Spjd if (getenv("ZFS_ABORT") != NULL) { 6189168404Spjd (void) printf("dumping core by request\n"); 6190168404Spjd abort(); 6191168404Spjd } 6192168404Spjd 6193168404Spjd return (ret); 6194168404Spjd} 6195