1fa9e4066Sahrens /* 2fa9e4066Sahrens * CDDL HEADER START 3fa9e4066Sahrens * 4fa9e4066Sahrens * The contents of this file are subject to the terms of the 5ea8dc4b6Seschrock * Common Development and Distribution License (the "License"). 6ea8dc4b6Seschrock * You may not use this file except in compliance with the License. 7fa9e4066Sahrens * 8fa9e4066Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9fa9e4066Sahrens * or http://www.opensolaris.org/os/licensing. 10fa9e4066Sahrens * See the License for the specific language governing permissions 11fa9e4066Sahrens * and limitations under the License. 12fa9e4066Sahrens * 13fa9e4066Sahrens * When distributing Covered Code, include this CDDL HEADER in each 14fa9e4066Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15fa9e4066Sahrens * If applicable, add the following below this CDDL HEADER, with the 16fa9e4066Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 17fa9e4066Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 18fa9e4066Sahrens * 19fa9e4066Sahrens * CDDL HEADER END 20fa9e4066Sahrens */ 2199653d4eSeschrock 22fa9e4066Sahrens /* 233f9d6ad7SLin Ling * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 2475fbdf9bSBasil Crow * Copyright (c) 2013 by Delphix. All rights reserved. 25*b327cd3fSIgor Kozhukhov * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>. 26fa9e4066Sahrens */ 27fa9e4066Sahrens 28fa9e4066Sahrens /* 29fa9e4066Sahrens * Functions to convert between a list of vdevs and an nvlist representing the 30fa9e4066Sahrens * configuration. Each entry in the list can be one of: 31fa9e4066Sahrens * 32fa9e4066Sahrens * Device vdevs 33fa9e4066Sahrens * disk=(path=..., devid=...) 34fa9e4066Sahrens * file=(path=...) 35fa9e4066Sahrens * 36fa9e4066Sahrens * Group vdevs 3799653d4eSeschrock * raidz[1|2]=(...) 38fa9e4066Sahrens * mirror=(...) 39fa9e4066Sahrens * 4099653d4eSeschrock * Hot spares 4199653d4eSeschrock * 42fa9e4066Sahrens * While the underlying implementation supports it, group vdevs cannot contain 43fa9e4066Sahrens * other group vdevs. All userland verification of devices is contained within 44fa9e4066Sahrens * this file. If successful, the nvlist returned can be passed directly to the 45fa9e4066Sahrens * kernel; we've done as much verification as possible in userland. 46fa9e4066Sahrens * 4799653d4eSeschrock * Hot spares are a special case, and passed down as an array of disk vdevs, at 4899653d4eSeschrock * the same level as the root of the vdev tree. 4999653d4eSeschrock * 508488aeb5Staylor * The only function exported by this file is 'make_root_vdev'. The 518488aeb5Staylor * function performs several passes: 52fa9e4066Sahrens * 53fa9e4066Sahrens * 1. Construct the vdev specification. Performs syntax validation and 54fa9e4066Sahrens * makes sure each device is valid. 55fa9e4066Sahrens * 2. Check for devices in use. Using libdiskmgt, makes sure that no 56fa9e4066Sahrens * devices are also in use. Some can be overridden using the 'force' 57fa9e4066Sahrens * flag, others cannot. 58fa9e4066Sahrens * 3. Check for replication errors if the 'force' flag is not specified. 59fa9e4066Sahrens * validates that the replication level is consistent across the 60fa9e4066Sahrens * entire pool. 618488aeb5Staylor * 4. Call libzfs to label any whole disks with an EFI label. 62fa9e4066Sahrens */ 63fa9e4066Sahrens 64fa9e4066Sahrens #include <assert.h> 65fa9e4066Sahrens #include <devid.h> 66fa9e4066Sahrens #include <errno.h> 67fa9e4066Sahrens #include <fcntl.h> 68fa9e4066Sahrens #include <libdiskmgt.h> 69fa9e4066Sahrens #include <libintl.h> 70fa9e4066Sahrens #include <libnvpair.h> 71f94275ceSAdam Leventhal #include <limits.h> 72fa9e4066Sahrens #include <stdio.h> 73fa9e4066Sahrens #include <string.h> 74fa9e4066Sahrens #include <unistd.h> 75fa9e4066Sahrens #include <sys/efi_partition.h> 76fa9e4066Sahrens #include <sys/stat.h> 77fa9e4066Sahrens #include <sys/vtoc.h> 78fa9e4066Sahrens #include <sys/mntent.h> 79fa9e4066Sahrens 80fa9e4066Sahrens #include "zpool_util.h" 81fa9e4066Sahrens 82fa9e4066Sahrens #define DISK_ROOT "/dev/dsk" 83fa9e4066Sahrens #define RDISK_ROOT "/dev/rdsk" 84fa9e4066Sahrens #define BACKUP_SLICE "s2" 85fa9e4066Sahrens 86fa9e4066Sahrens /* 87fa9e4066Sahrens * For any given vdev specification, we can have multiple errors. The 88fa9e4066Sahrens * vdev_error() function keeps track of whether we have seen an error yet, and 89fa9e4066Sahrens * prints out a header if its the first error we've seen. 90fa9e4066Sahrens */ 9199653d4eSeschrock boolean_t error_seen; 9299653d4eSeschrock boolean_t is_force; 93fa9e4066Sahrens 9499653d4eSeschrock /*PRINTFLIKE1*/ 9599653d4eSeschrock static void 96fa9e4066Sahrens vdev_error(const char *fmt, ...) 97fa9e4066Sahrens { 98fa9e4066Sahrens va_list ap; 99fa9e4066Sahrens 100fa9e4066Sahrens if (!error_seen) { 101fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid vdev specification\n")); 102fa9e4066Sahrens if (!is_force) 103fa9e4066Sahrens (void) fprintf(stderr, gettext("use '-f' to override " 104fa9e4066Sahrens "the following errors:\n")); 105fa9e4066Sahrens else 106fa9e4066Sahrens (void) fprintf(stderr, gettext("the following errors " 107fa9e4066Sahrens "must be manually repaired:\n")); 10899653d4eSeschrock error_seen = B_TRUE; 109fa9e4066Sahrens } 110fa9e4066Sahrens 111fa9e4066Sahrens va_start(ap, fmt); 112fa9e4066Sahrens (void) vfprintf(stderr, fmt, ap); 113fa9e4066Sahrens va_end(ap); 114fa9e4066Sahrens } 115fa9e4066Sahrens 11646a2abf2Seschrock static void 11746a2abf2Seschrock libdiskmgt_error(int error) 118fa9e4066Sahrens { 119ea8dc4b6Seschrock /* 12099653d4eSeschrock * ENXIO/ENODEV is a valid error message if the device doesn't live in 121ea8dc4b6Seschrock * /dev/dsk. Don't bother printing an error message in this case. 122ea8dc4b6Seschrock */ 12399653d4eSeschrock if (error == ENXIO || error == ENODEV) 124ea8dc4b6Seschrock return; 125ea8dc4b6Seschrock 12646a2abf2Seschrock (void) fprintf(stderr, gettext("warning: device in use checking " 12746a2abf2Seschrock "failed: %s\n"), strerror(error)); 128fa9e4066Sahrens } 129fa9e4066Sahrens 130fa9e4066Sahrens /* 13146a2abf2Seschrock * Validate a device, passing the bulk of the work off to libdiskmgt. 132fa9e4066Sahrens */ 1338488aeb5Staylor static int 13499653d4eSeschrock check_slice(const char *path, int force, boolean_t wholedisk, boolean_t isspare) 135fa9e4066Sahrens { 13646a2abf2Seschrock char *msg; 13746a2abf2Seschrock int error = 0; 13803a818bcSmmusante dm_who_type_t who; 139fa9e4066Sahrens 14003a818bcSmmusante if (force) 14103a818bcSmmusante who = DM_WHO_ZPOOL_FORCE; 14203a818bcSmmusante else if (isspare) 14303a818bcSmmusante who = DM_WHO_ZPOOL_SPARE; 14403a818bcSmmusante else 14503a818bcSmmusante who = DM_WHO_ZPOOL; 14603a818bcSmmusante 14703a818bcSmmusante if (dm_inuse((char *)path, &msg, who, &error) || error) { 14846a2abf2Seschrock if (error != 0) { 14946a2abf2Seschrock libdiskmgt_error(error); 15046a2abf2Seschrock return (0); 15146657f8dSmmusante } else { 15246a2abf2Seschrock vdev_error("%s", msg); 15346a2abf2Seschrock free(msg); 154181c2f42Smmusante return (-1); 15546a2abf2Seschrock } 156fa9e4066Sahrens } 157fa9e4066Sahrens 15846a2abf2Seschrock /* 15946a2abf2Seschrock * If we're given a whole disk, ignore overlapping slices since we're 16046a2abf2Seschrock * about to label it anyway. 16146a2abf2Seschrock */ 16246a2abf2Seschrock error = 0; 16346a2abf2Seschrock if (!wholedisk && !force && 16446a2abf2Seschrock (dm_isoverlapping((char *)path, &msg, &error) || error)) { 165181c2f42Smmusante if (error == 0) { 166181c2f42Smmusante /* dm_isoverlapping returned -1 */ 167181c2f42Smmusante vdev_error(gettext("%s overlaps with %s\n"), path, msg); 168181c2f42Smmusante free(msg); 169181c2f42Smmusante return (-1); 170181c2f42Smmusante } else if (error != ENODEV) { 171181c2f42Smmusante /* libdiskmgt's devcache only handles physical drives */ 17246a2abf2Seschrock libdiskmgt_error(error); 17346a2abf2Seschrock return (0); 174181c2f42Smmusante } 17546a2abf2Seschrock } 17646a2abf2Seschrock 177181c2f42Smmusante return (0); 178fa9e4066Sahrens } 179fa9e4066Sahrens 1808488aeb5Staylor 181fa9e4066Sahrens /* 182fa9e4066Sahrens * Validate a whole disk. Iterate over all slices on the disk and make sure 183fa9e4066Sahrens * that none is in use by calling check_slice(). 184fa9e4066Sahrens */ 1858488aeb5Staylor static int 18699653d4eSeschrock check_disk(const char *name, dm_descriptor_t disk, int force, int isspare) 187fa9e4066Sahrens { 188fa9e4066Sahrens dm_descriptor_t *drive, *media, *slice; 189fa9e4066Sahrens int err = 0; 190fa9e4066Sahrens int i; 191fa9e4066Sahrens int ret; 192fa9e4066Sahrens 193fa9e4066Sahrens /* 194fa9e4066Sahrens * Get the drive associated with this disk. This should never fail, 195fa9e4066Sahrens * because we already have an alias handle open for the device. 196fa9e4066Sahrens */ 197fa9e4066Sahrens if ((drive = dm_get_associated_descriptors(disk, DM_DRIVE, 19846a2abf2Seschrock &err)) == NULL || *drive == NULL) { 19946a2abf2Seschrock if (err) 20046a2abf2Seschrock libdiskmgt_error(err); 20146a2abf2Seschrock return (0); 20246a2abf2Seschrock } 203fa9e4066Sahrens 204fa9e4066Sahrens if ((media = dm_get_associated_descriptors(*drive, DM_MEDIA, 20546a2abf2Seschrock &err)) == NULL) { 20646a2abf2Seschrock dm_free_descriptors(drive); 20746a2abf2Seschrock if (err) 20846a2abf2Seschrock libdiskmgt_error(err); 20946a2abf2Seschrock return (0); 21046a2abf2Seschrock } 211fa9e4066Sahrens 212fa9e4066Sahrens dm_free_descriptors(drive); 213fa9e4066Sahrens 214fa9e4066Sahrens /* 215fa9e4066Sahrens * It is possible that the user has specified a removable media drive, 216fa9e4066Sahrens * and the media is not present. 217fa9e4066Sahrens */ 218fa9e4066Sahrens if (*media == NULL) { 219fa9e4066Sahrens dm_free_descriptors(media); 22046a2abf2Seschrock vdev_error(gettext("'%s' has no media in drive\n"), name); 221fa9e4066Sahrens return (-1); 222fa9e4066Sahrens } 223fa9e4066Sahrens 224fa9e4066Sahrens if ((slice = dm_get_associated_descriptors(*media, DM_SLICE, 22546a2abf2Seschrock &err)) == NULL) { 22646a2abf2Seschrock dm_free_descriptors(media); 22746a2abf2Seschrock if (err) 22846a2abf2Seschrock libdiskmgt_error(err); 22946a2abf2Seschrock return (0); 23046a2abf2Seschrock } 231fa9e4066Sahrens 232fa9e4066Sahrens dm_free_descriptors(media); 233fa9e4066Sahrens 234fa9e4066Sahrens ret = 0; 235fa9e4066Sahrens 236fa9e4066Sahrens /* 237fa9e4066Sahrens * Iterate over all slices and report any errors. We don't care about 238fa9e4066Sahrens * overlapping slices because we are using the whole disk. 239fa9e4066Sahrens */ 240fa9e4066Sahrens for (i = 0; slice[i] != NULL; i++) { 24199653d4eSeschrock char *name = dm_get_name(slice[i], &err); 24299653d4eSeschrock 24399653d4eSeschrock if (check_slice(name, force, B_TRUE, isspare) != 0) 244fa9e4066Sahrens ret = -1; 24599653d4eSeschrock 24699653d4eSeschrock dm_free_name(name); 247fa9e4066Sahrens } 248fa9e4066Sahrens 249fa9e4066Sahrens dm_free_descriptors(slice); 250fa9e4066Sahrens return (ret); 251fa9e4066Sahrens } 252fa9e4066Sahrens 253fa9e4066Sahrens /* 25446a2abf2Seschrock * Validate a device. 255fa9e4066Sahrens */ 2568488aeb5Staylor static int 25799653d4eSeschrock check_device(const char *path, boolean_t force, boolean_t isspare) 258fa9e4066Sahrens { 259fa9e4066Sahrens dm_descriptor_t desc; 260fa9e4066Sahrens int err; 26146a2abf2Seschrock char *dev; 262fa9e4066Sahrens 263fa9e4066Sahrens /* 264fa9e4066Sahrens * For whole disks, libdiskmgt does not include the leading dev path. 265fa9e4066Sahrens */ 266fa9e4066Sahrens dev = strrchr(path, '/'); 267fa9e4066Sahrens assert(dev != NULL); 268fa9e4066Sahrens dev++; 26946a2abf2Seschrock if ((desc = dm_get_descriptor_by_name(DM_ALIAS, dev, &err)) != NULL) { 27099653d4eSeschrock err = check_disk(path, desc, force, isspare); 27146a2abf2Seschrock dm_free_descriptor(desc); 27246a2abf2Seschrock return (err); 273fa9e4066Sahrens } 274fa9e4066Sahrens 27599653d4eSeschrock return (check_slice(path, force, B_FALSE, isspare)); 276fa9e4066Sahrens } 277fa9e4066Sahrens 278fa9e4066Sahrens /* 279fa9e4066Sahrens * Check that a file is valid. All we can do in this case is check that it's 280181c2f42Smmusante * not in use by another pool, and not in use by swap. 281fa9e4066Sahrens */ 2828488aeb5Staylor static int 28399653d4eSeschrock check_file(const char *file, boolean_t force, boolean_t isspare) 284fa9e4066Sahrens { 28546a2abf2Seschrock char *name; 286fa9e4066Sahrens int fd; 287fa9e4066Sahrens int ret = 0; 288181c2f42Smmusante int err; 28946a2abf2Seschrock pool_state_t state; 29099653d4eSeschrock boolean_t inuse; 291fa9e4066Sahrens 292181c2f42Smmusante if (dm_inuse_swap(file, &err)) { 293181c2f42Smmusante if (err) 294181c2f42Smmusante libdiskmgt_error(err); 295181c2f42Smmusante else 296181c2f42Smmusante vdev_error(gettext("%s is currently used by swap. " 297181c2f42Smmusante "Please see swap(1M).\n"), file); 298181c2f42Smmusante return (-1); 299181c2f42Smmusante } 300181c2f42Smmusante 301fa9e4066Sahrens if ((fd = open(file, O_RDONLY)) < 0) 302fa9e4066Sahrens return (0); 303fa9e4066Sahrens 30499653d4eSeschrock if (zpool_in_use(g_zfs, fd, &state, &name, &inuse) == 0 && inuse) { 30546a2abf2Seschrock const char *desc; 30646a2abf2Seschrock 30746a2abf2Seschrock switch (state) { 30846a2abf2Seschrock case POOL_STATE_ACTIVE: 30946a2abf2Seschrock desc = gettext("active"); 31046a2abf2Seschrock break; 31146a2abf2Seschrock 31246a2abf2Seschrock case POOL_STATE_EXPORTED: 31346a2abf2Seschrock desc = gettext("exported"); 31446a2abf2Seschrock break; 31546a2abf2Seschrock 31646a2abf2Seschrock case POOL_STATE_POTENTIALLY_ACTIVE: 31746a2abf2Seschrock desc = gettext("potentially active"); 31846a2abf2Seschrock break; 31946a2abf2Seschrock 32046a2abf2Seschrock default: 32146a2abf2Seschrock desc = gettext("unknown"); 32246a2abf2Seschrock break; 32346a2abf2Seschrock } 32446a2abf2Seschrock 32599653d4eSeschrock /* 32699653d4eSeschrock * Allow hot spares to be shared between pools. 32799653d4eSeschrock */ 32899653d4eSeschrock if (state == POOL_STATE_SPARE && isspare) 32999653d4eSeschrock return (0); 33099653d4eSeschrock 33199653d4eSeschrock if (state == POOL_STATE_ACTIVE || 33299653d4eSeschrock state == POOL_STATE_SPARE || !force) { 33399653d4eSeschrock switch (state) { 33499653d4eSeschrock case POOL_STATE_SPARE: 33599653d4eSeschrock vdev_error(gettext("%s is reserved as a hot " 33699653d4eSeschrock "spare for pool %s\n"), file, name); 33799653d4eSeschrock break; 33899653d4eSeschrock default: 33999653d4eSeschrock vdev_error(gettext("%s is part of %s pool " 34099653d4eSeschrock "'%s'\n"), file, desc, name); 34199653d4eSeschrock break; 34299653d4eSeschrock } 343fa9e4066Sahrens ret = -1; 344fa9e4066Sahrens } 345fa9e4066Sahrens 346fa9e4066Sahrens free(name); 347fa9e4066Sahrens } 348fa9e4066Sahrens 349fa9e4066Sahrens (void) close(fd); 350fa9e4066Sahrens return (ret); 351fa9e4066Sahrens } 352fa9e4066Sahrens 3538488aeb5Staylor 3548488aeb5Staylor /* 3558488aeb5Staylor * By "whole disk" we mean an entire physical disk (something we can 3568488aeb5Staylor * label, toggle the write cache on, etc.) as opposed to the full 3578488aeb5Staylor * capacity of a pseudo-device such as lofi or did. We act as if we 3588488aeb5Staylor * are labeling the disk, which should be a pretty good test of whether 3598488aeb5Staylor * it's a viable device or not. Returns B_TRUE if it is and B_FALSE if 3608488aeb5Staylor * it isn't. 3618488aeb5Staylor */ 36299653d4eSeschrock static boolean_t 3638488aeb5Staylor is_whole_disk(const char *arg) 364fa9e4066Sahrens { 3658488aeb5Staylor struct dk_gpt *label; 3668488aeb5Staylor int fd; 367fa9e4066Sahrens char path[MAXPATHLEN]; 368fa9e4066Sahrens 3698488aeb5Staylor (void) snprintf(path, sizeof (path), "%s%s%s", 3708488aeb5Staylor RDISK_ROOT, strrchr(arg, '/'), BACKUP_SLICE); 3718488aeb5Staylor if ((fd = open(path, O_RDWR | O_NDELAY)) < 0) 37299653d4eSeschrock return (B_FALSE); 3738488aeb5Staylor if (efi_alloc_and_init(fd, EFI_NUMPAR, &label) != 0) { 3748488aeb5Staylor (void) close(fd); 3758488aeb5Staylor return (B_FALSE); 3768488aeb5Staylor } 3778488aeb5Staylor efi_free(label); 3788488aeb5Staylor (void) close(fd); 3798488aeb5Staylor return (B_TRUE); 380fa9e4066Sahrens } 381fa9e4066Sahrens 382fa9e4066Sahrens /* 383fa9e4066Sahrens * Create a leaf vdev. Determine if this is a file or a device. If it's a 384fa9e4066Sahrens * device, fill in the device id to make a complete nvlist. Valid forms for a 385fa9e4066Sahrens * leaf vdev are: 386fa9e4066Sahrens * 387fa9e4066Sahrens * /dev/dsk/xxx Complete disk path 388fa9e4066Sahrens * /xxx Full path to file 389fa9e4066Sahrens * xxx Shorthand for /dev/dsk/xxx 390fa9e4066Sahrens */ 3918488aeb5Staylor static nvlist_t * 3928654d025Sperrin make_leaf_vdev(const char *arg, uint64_t is_log) 393fa9e4066Sahrens { 394fa9e4066Sahrens char path[MAXPATHLEN]; 395fa9e4066Sahrens struct stat64 statbuf; 396fa9e4066Sahrens nvlist_t *vdev = NULL; 397fa9e4066Sahrens char *type = NULL; 39899653d4eSeschrock boolean_t wholedisk = B_FALSE; 399fa9e4066Sahrens 400fa9e4066Sahrens /* 401fa9e4066Sahrens * Determine what type of vdev this is, and put the full path into 402fa9e4066Sahrens * 'path'. We detect whether this is a device of file afterwards by 403fa9e4066Sahrens * checking the st_mode of the file. 404fa9e4066Sahrens */ 405fa9e4066Sahrens if (arg[0] == '/') { 406fa9e4066Sahrens /* 407fa9e4066Sahrens * Complete device or file path. Exact type is determined by 408fa9e4066Sahrens * examining the file descriptor afterwards. 409fa9e4066Sahrens */ 4108488aeb5Staylor wholedisk = is_whole_disk(arg); 4118488aeb5Staylor if (!wholedisk && (stat64(arg, &statbuf) != 0)) { 412fa9e4066Sahrens (void) fprintf(stderr, 413fa9e4066Sahrens gettext("cannot open '%s': %s\n"), 414fa9e4066Sahrens arg, strerror(errno)); 415fa9e4066Sahrens return (NULL); 416fa9e4066Sahrens } 417fa9e4066Sahrens 418fa9e4066Sahrens (void) strlcpy(path, arg, sizeof (path)); 419fa9e4066Sahrens } else { 420fa9e4066Sahrens /* 421fa9e4066Sahrens * This may be a short path for a device, or it could be total 422fa9e4066Sahrens * gibberish. Check to see if it's a known device in 423fa9e4066Sahrens * /dev/dsk/. As part of this check, see if we've been given a 424fa9e4066Sahrens * an entire disk (minus the slice number). 425fa9e4066Sahrens */ 426fa9e4066Sahrens (void) snprintf(path, sizeof (path), "%s/%s", DISK_ROOT, 427fa9e4066Sahrens arg); 4288488aeb5Staylor wholedisk = is_whole_disk(path); 4298488aeb5Staylor if (!wholedisk && (stat64(path, &statbuf) != 0)) { 430fa9e4066Sahrens /* 431fa9e4066Sahrens * If we got ENOENT, then the user gave us 432fa9e4066Sahrens * gibberish, so try to direct them with a 433fa9e4066Sahrens * reasonable error message. Otherwise, 434fa9e4066Sahrens * regurgitate strerror() since it's the best we 435fa9e4066Sahrens * can do. 436fa9e4066Sahrens */ 437fa9e4066Sahrens if (errno == ENOENT) { 438fa9e4066Sahrens (void) fprintf(stderr, 439fa9e4066Sahrens gettext("cannot open '%s': no such " 440fa9e4066Sahrens "device in %s\n"), arg, DISK_ROOT); 441fa9e4066Sahrens (void) fprintf(stderr, 442fa9e4066Sahrens gettext("must be a full path or " 443fa9e4066Sahrens "shorthand device name\n")); 444fa9e4066Sahrens return (NULL); 445fa9e4066Sahrens } else { 446fa9e4066Sahrens (void) fprintf(stderr, 447fa9e4066Sahrens gettext("cannot open '%s': %s\n"), 448fa9e4066Sahrens path, strerror(errno)); 449fa9e4066Sahrens return (NULL); 450fa9e4066Sahrens } 451fa9e4066Sahrens } 452fa9e4066Sahrens } 453fa9e4066Sahrens 454fa9e4066Sahrens /* 455fa9e4066Sahrens * Determine whether this is a device or a file. 456fa9e4066Sahrens */ 4578488aeb5Staylor if (wholedisk || S_ISBLK(statbuf.st_mode)) { 458fa9e4066Sahrens type = VDEV_TYPE_DISK; 459fa9e4066Sahrens } else if (S_ISREG(statbuf.st_mode)) { 460fa9e4066Sahrens type = VDEV_TYPE_FILE; 461fa9e4066Sahrens } else { 462fa9e4066Sahrens (void) fprintf(stderr, gettext("cannot use '%s': must be a " 463fa9e4066Sahrens "block device or regular file\n"), path); 464fa9e4066Sahrens return (NULL); 465fa9e4066Sahrens } 466fa9e4066Sahrens 467fa9e4066Sahrens /* 468fa9e4066Sahrens * Finally, we have the complete device or file, and we know that it is 469fa9e4066Sahrens * acceptable to use. Construct the nvlist to describe this vdev. All 470fa9e4066Sahrens * vdevs have a 'path' element, and devices also have a 'devid' element. 471fa9e4066Sahrens */ 472fa9e4066Sahrens verify(nvlist_alloc(&vdev, NV_UNIQUE_NAME, 0) == 0); 473fa9e4066Sahrens verify(nvlist_add_string(vdev, ZPOOL_CONFIG_PATH, path) == 0); 474fa9e4066Sahrens verify(nvlist_add_string(vdev, ZPOOL_CONFIG_TYPE, type) == 0); 4758654d025Sperrin verify(nvlist_add_uint64(vdev, ZPOOL_CONFIG_IS_LOG, is_log) == 0); 476afefbcddSeschrock if (strcmp(type, VDEV_TYPE_DISK) == 0) 477afefbcddSeschrock verify(nvlist_add_uint64(vdev, ZPOOL_CONFIG_WHOLE_DISK, 478afefbcddSeschrock (uint64_t)wholedisk) == 0); 479fa9e4066Sahrens 480fa9e4066Sahrens /* 481fa9e4066Sahrens * For a whole disk, defer getting its devid until after labeling it. 482fa9e4066Sahrens */ 483fa9e4066Sahrens if (S_ISBLK(statbuf.st_mode) && !wholedisk) { 484fa9e4066Sahrens /* 485fa9e4066Sahrens * Get the devid for the device. 486fa9e4066Sahrens */ 487fa9e4066Sahrens int fd; 488fa9e4066Sahrens ddi_devid_t devid; 489fa9e4066Sahrens char *minor = NULL, *devid_str = NULL; 490fa9e4066Sahrens 491fa9e4066Sahrens if ((fd = open(path, O_RDONLY)) < 0) { 492fa9e4066Sahrens (void) fprintf(stderr, gettext("cannot open '%s': " 493fa9e4066Sahrens "%s\n"), path, strerror(errno)); 494fa9e4066Sahrens nvlist_free(vdev); 495fa9e4066Sahrens return (NULL); 496fa9e4066Sahrens } 497fa9e4066Sahrens 498fa9e4066Sahrens if (devid_get(fd, &devid) == 0) { 499fa9e4066Sahrens if (devid_get_minor_name(fd, &minor) == 0 && 500fa9e4066Sahrens (devid_str = devid_str_encode(devid, minor)) != 501fa9e4066Sahrens NULL) { 502fa9e4066Sahrens verify(nvlist_add_string(vdev, 503fa9e4066Sahrens ZPOOL_CONFIG_DEVID, devid_str) == 0); 504fa9e4066Sahrens } 505fa9e4066Sahrens if (devid_str != NULL) 506fa9e4066Sahrens devid_str_free(devid_str); 507fa9e4066Sahrens if (minor != NULL) 508fa9e4066Sahrens devid_str_free(minor); 509fa9e4066Sahrens devid_free(devid); 510fa9e4066Sahrens } 511fa9e4066Sahrens 512fa9e4066Sahrens (void) close(fd); 513fa9e4066Sahrens } 514fa9e4066Sahrens 515fa9e4066Sahrens return (vdev); 516fa9e4066Sahrens } 517fa9e4066Sahrens 518fa9e4066Sahrens /* 519fa9e4066Sahrens * Go through and verify the replication level of the pool is consistent. 520fa9e4066Sahrens * Performs the following checks: 521fa9e4066Sahrens * 522fa9e4066Sahrens * For the new spec, verifies that devices in mirrors and raidz are the 523fa9e4066Sahrens * same size. 524fa9e4066Sahrens * 525fa9e4066Sahrens * If the current configuration already has inconsistent replication 526fa9e4066Sahrens * levels, ignore any other potential problems in the new spec. 527fa9e4066Sahrens * 528fa9e4066Sahrens * Otherwise, make sure that the current spec (if there is one) and the new 529fa9e4066Sahrens * spec have consistent replication levels. 530fa9e4066Sahrens */ 531fa9e4066Sahrens typedef struct replication_level { 53299653d4eSeschrock char *zprl_type; 53399653d4eSeschrock uint64_t zprl_children; 53499653d4eSeschrock uint64_t zprl_parity; 535fa9e4066Sahrens } replication_level_t; 536fa9e4066Sahrens 5378488aeb5Staylor #define ZPOOL_FUZZ (16 * 1024 * 1024) 5388488aeb5Staylor 539fa9e4066Sahrens /* 540fa9e4066Sahrens * Given a list of toplevel vdevs, return the current replication level. If 541fa9e4066Sahrens * the config is inconsistent, then NULL is returned. If 'fatal' is set, then 542fa9e4066Sahrens * an error message will be displayed for each self-inconsistent vdev. 543fa9e4066Sahrens */ 5448488aeb5Staylor static replication_level_t * 54599653d4eSeschrock get_replication(nvlist_t *nvroot, boolean_t fatal) 546fa9e4066Sahrens { 547fa9e4066Sahrens nvlist_t **top; 548fa9e4066Sahrens uint_t t, toplevels; 549fa9e4066Sahrens nvlist_t **child; 550fa9e4066Sahrens uint_t c, children; 551fa9e4066Sahrens nvlist_t *nv; 552fa9e4066Sahrens char *type; 553*b327cd3fSIgor Kozhukhov replication_level_t lastrep = {0}; 554*b327cd3fSIgor Kozhukhov replication_level_t rep; 555*b327cd3fSIgor Kozhukhov replication_level_t *ret; 55699653d4eSeschrock boolean_t dontreport; 557fa9e4066Sahrens 558fa9e4066Sahrens ret = safe_malloc(sizeof (replication_level_t)); 559fa9e4066Sahrens 560fa9e4066Sahrens verify(nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN, 561fa9e4066Sahrens &top, &toplevels) == 0); 562fa9e4066Sahrens 56399653d4eSeschrock lastrep.zprl_type = NULL; 564fa9e4066Sahrens for (t = 0; t < toplevels; t++) { 5658654d025Sperrin uint64_t is_log = B_FALSE; 5668654d025Sperrin 567fa9e4066Sahrens nv = top[t]; 568fa9e4066Sahrens 5698654d025Sperrin /* 5708654d025Sperrin * For separate logs we ignore the top level vdev replication 5718654d025Sperrin * constraints. 5728654d025Sperrin */ 5738654d025Sperrin (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_IS_LOG, &is_log); 5748654d025Sperrin if (is_log) 5758654d025Sperrin continue; 5768654d025Sperrin 5778654d025Sperrin verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, 5788654d025Sperrin &type) == 0); 579fa9e4066Sahrens if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 580fa9e4066Sahrens &child, &children) != 0) { 581fa9e4066Sahrens /* 582fa9e4066Sahrens * This is a 'file' or 'disk' vdev. 583fa9e4066Sahrens */ 58499653d4eSeschrock rep.zprl_type = type; 58599653d4eSeschrock rep.zprl_children = 1; 58699653d4eSeschrock rep.zprl_parity = 0; 587fa9e4066Sahrens } else { 588fa9e4066Sahrens uint64_t vdev_size; 589fa9e4066Sahrens 590fa9e4066Sahrens /* 591fa9e4066Sahrens * This is a mirror or RAID-Z vdev. Go through and make 592fa9e4066Sahrens * sure the contents are all the same (files vs. disks), 593fa9e4066Sahrens * keeping track of the number of elements in the 594fa9e4066Sahrens * process. 595fa9e4066Sahrens * 596fa9e4066Sahrens * We also check that the size of each vdev (if it can 597fa9e4066Sahrens * be determined) is the same. 598fa9e4066Sahrens */ 59999653d4eSeschrock rep.zprl_type = type; 60099653d4eSeschrock rep.zprl_children = 0; 60199653d4eSeschrock 60299653d4eSeschrock if (strcmp(type, VDEV_TYPE_RAIDZ) == 0) { 60399653d4eSeschrock verify(nvlist_lookup_uint64(nv, 60499653d4eSeschrock ZPOOL_CONFIG_NPARITY, 60599653d4eSeschrock &rep.zprl_parity) == 0); 60699653d4eSeschrock assert(rep.zprl_parity != 0); 60799653d4eSeschrock } else { 60899653d4eSeschrock rep.zprl_parity = 0; 60999653d4eSeschrock } 610fa9e4066Sahrens 611fa9e4066Sahrens /* 6128654d025Sperrin * The 'dontreport' variable indicates that we've 613fa9e4066Sahrens * already reported an error for this spec, so don't 614fa9e4066Sahrens * bother doing it again. 615fa9e4066Sahrens */ 616fa9e4066Sahrens type = NULL; 617fa9e4066Sahrens dontreport = 0; 618fa9e4066Sahrens vdev_size = -1ULL; 619fa9e4066Sahrens for (c = 0; c < children; c++) { 620fa9e4066Sahrens nvlist_t *cnv = child[c]; 621fa9e4066Sahrens char *path; 622fa9e4066Sahrens struct stat64 statbuf; 623fa9e4066Sahrens uint64_t size = -1ULL; 624fa9e4066Sahrens char *childtype; 625fa9e4066Sahrens int fd, err; 626fa9e4066Sahrens 62799653d4eSeschrock rep.zprl_children++; 628fa9e4066Sahrens 629fa9e4066Sahrens verify(nvlist_lookup_string(cnv, 630fa9e4066Sahrens ZPOOL_CONFIG_TYPE, &childtype) == 0); 63194de1d4cSeschrock 63294de1d4cSeschrock /* 6338654d025Sperrin * If this is a replacing or spare vdev, then 63494de1d4cSeschrock * get the real first child of the vdev. 63594de1d4cSeschrock */ 63694de1d4cSeschrock if (strcmp(childtype, 63794de1d4cSeschrock VDEV_TYPE_REPLACING) == 0 || 63894de1d4cSeschrock strcmp(childtype, VDEV_TYPE_SPARE) == 0) { 63994de1d4cSeschrock nvlist_t **rchild; 64094de1d4cSeschrock uint_t rchildren; 64194de1d4cSeschrock 64294de1d4cSeschrock verify(nvlist_lookup_nvlist_array(cnv, 64394de1d4cSeschrock ZPOOL_CONFIG_CHILDREN, &rchild, 64494de1d4cSeschrock &rchildren) == 0); 64594de1d4cSeschrock assert(rchildren == 2); 64694de1d4cSeschrock cnv = rchild[0]; 64794de1d4cSeschrock 64894de1d4cSeschrock verify(nvlist_lookup_string(cnv, 64994de1d4cSeschrock ZPOOL_CONFIG_TYPE, 65094de1d4cSeschrock &childtype) == 0); 65194de1d4cSeschrock } 65294de1d4cSeschrock 653fa9e4066Sahrens verify(nvlist_lookup_string(cnv, 654fa9e4066Sahrens ZPOOL_CONFIG_PATH, &path) == 0); 655fa9e4066Sahrens 656fa9e4066Sahrens /* 657fa9e4066Sahrens * If we have a raidz/mirror that combines disks 658fa9e4066Sahrens * with files, report it as an error. 659fa9e4066Sahrens */ 660fa9e4066Sahrens if (!dontreport && type != NULL && 661fa9e4066Sahrens strcmp(type, childtype) != 0) { 662fa9e4066Sahrens if (ret != NULL) 663fa9e4066Sahrens free(ret); 664fa9e4066Sahrens ret = NULL; 665fa9e4066Sahrens if (fatal) 666fa9e4066Sahrens vdev_error(gettext( 667fa9e4066Sahrens "mismatched replication " 668fa9e4066Sahrens "level: %s contains both " 669fa9e4066Sahrens "files and devices\n"), 67099653d4eSeschrock rep.zprl_type); 671fa9e4066Sahrens else 672fa9e4066Sahrens return (NULL); 67399653d4eSeschrock dontreport = B_TRUE; 674fa9e4066Sahrens } 675fa9e4066Sahrens 676fa9e4066Sahrens /* 677fa9e4066Sahrens * According to stat(2), the value of 'st_size' 678fa9e4066Sahrens * is undefined for block devices and character 679fa9e4066Sahrens * devices. But there is no effective way to 680fa9e4066Sahrens * determine the real size in userland. 681fa9e4066Sahrens * 682fa9e4066Sahrens * Instead, we'll take advantage of an 683fa9e4066Sahrens * implementation detail of spec_size(). If the 684fa9e4066Sahrens * device is currently open, then we (should) 685fa9e4066Sahrens * return a valid size. 686fa9e4066Sahrens * 687fa9e4066Sahrens * If we still don't get a valid size (indicated 688fa9e4066Sahrens * by a size of 0 or MAXOFFSET_T), then ignore 689fa9e4066Sahrens * this device altogether. 690fa9e4066Sahrens */ 691fa9e4066Sahrens if ((fd = open(path, O_RDONLY)) >= 0) { 692fa9e4066Sahrens err = fstat64(fd, &statbuf); 693fa9e4066Sahrens (void) close(fd); 694fa9e4066Sahrens } else { 695fa9e4066Sahrens err = stat64(path, &statbuf); 696fa9e4066Sahrens } 697fa9e4066Sahrens 698fa9e4066Sahrens if (err != 0 || 699fa9e4066Sahrens statbuf.st_size == 0 || 700fa9e4066Sahrens statbuf.st_size == MAXOFFSET_T) 701fa9e4066Sahrens continue; 702fa9e4066Sahrens 703fa9e4066Sahrens size = statbuf.st_size; 704fa9e4066Sahrens 705fa9e4066Sahrens /* 7068488aeb5Staylor * Also make sure that devices and 7078488aeb5Staylor * slices have a consistent size. If 7088488aeb5Staylor * they differ by a significant amount 7098488aeb5Staylor * (~16MB) then report an error. 710fa9e4066Sahrens */ 7118488aeb5Staylor if (!dontreport && 7128488aeb5Staylor (vdev_size != -1ULL && 7138488aeb5Staylor (labs(size - vdev_size) > 7148488aeb5Staylor ZPOOL_FUZZ))) { 715fa9e4066Sahrens if (ret != NULL) 716fa9e4066Sahrens free(ret); 717fa9e4066Sahrens ret = NULL; 718fa9e4066Sahrens if (fatal) 719fa9e4066Sahrens vdev_error(gettext( 720fa9e4066Sahrens "%s contains devices of " 721fa9e4066Sahrens "different sizes\n"), 72299653d4eSeschrock rep.zprl_type); 723fa9e4066Sahrens else 724fa9e4066Sahrens return (NULL); 72599653d4eSeschrock dontreport = B_TRUE; 726fa9e4066Sahrens } 727fa9e4066Sahrens 728fa9e4066Sahrens type = childtype; 729fa9e4066Sahrens vdev_size = size; 730fa9e4066Sahrens } 731fa9e4066Sahrens } 732fa9e4066Sahrens 733fa9e4066Sahrens /* 734fa9e4066Sahrens * At this point, we have the replication of the last toplevel 735fa9e4066Sahrens * vdev in 'rep'. Compare it to 'lastrep' to see if its 736fa9e4066Sahrens * different. 737fa9e4066Sahrens */ 73899653d4eSeschrock if (lastrep.zprl_type != NULL) { 73999653d4eSeschrock if (strcmp(lastrep.zprl_type, rep.zprl_type) != 0) { 740fa9e4066Sahrens if (ret != NULL) 741fa9e4066Sahrens free(ret); 742fa9e4066Sahrens ret = NULL; 743fa9e4066Sahrens if (fatal) 744fa9e4066Sahrens vdev_error(gettext( 74599653d4eSeschrock "mismatched replication level: " 74699653d4eSeschrock "both %s and %s vdevs are " 747fa9e4066Sahrens "present\n"), 74899653d4eSeschrock lastrep.zprl_type, rep.zprl_type); 749fa9e4066Sahrens else 750fa9e4066Sahrens return (NULL); 75199653d4eSeschrock } else if (lastrep.zprl_parity != rep.zprl_parity) { 752fa9e4066Sahrens if (ret) 753fa9e4066Sahrens free(ret); 754fa9e4066Sahrens ret = NULL; 755fa9e4066Sahrens if (fatal) 756fa9e4066Sahrens vdev_error(gettext( 75799653d4eSeschrock "mismatched replication level: " 75899653d4eSeschrock "both %llu and %llu device parity " 75999653d4eSeschrock "%s vdevs are present\n"), 76099653d4eSeschrock lastrep.zprl_parity, 76199653d4eSeschrock rep.zprl_parity, 76299653d4eSeschrock rep.zprl_type); 76399653d4eSeschrock else 76499653d4eSeschrock return (NULL); 76599653d4eSeschrock } else if (lastrep.zprl_children != rep.zprl_children) { 76699653d4eSeschrock if (ret) 76799653d4eSeschrock free(ret); 76899653d4eSeschrock ret = NULL; 76999653d4eSeschrock if (fatal) 77099653d4eSeschrock vdev_error(gettext( 77199653d4eSeschrock "mismatched replication level: " 77299653d4eSeschrock "both %llu-way and %llu-way %s " 773fa9e4066Sahrens "vdevs are present\n"), 77499653d4eSeschrock lastrep.zprl_children, 77599653d4eSeschrock rep.zprl_children, 77699653d4eSeschrock rep.zprl_type); 777fa9e4066Sahrens else 778fa9e4066Sahrens return (NULL); 779fa9e4066Sahrens } 780fa9e4066Sahrens } 781fa9e4066Sahrens lastrep = rep; 782fa9e4066Sahrens } 783fa9e4066Sahrens 78499653d4eSeschrock if (ret != NULL) 78599653d4eSeschrock *ret = rep; 786fa9e4066Sahrens 787fa9e4066Sahrens return (ret); 788fa9e4066Sahrens } 789fa9e4066Sahrens 790fa9e4066Sahrens /* 791fa9e4066Sahrens * Check the replication level of the vdev spec against the current pool. Calls 792fa9e4066Sahrens * get_replication() to make sure the new spec is self-consistent. If the pool 793fa9e4066Sahrens * has a consistent replication level, then we ignore any errors. Otherwise, 794fa9e4066Sahrens * report any difference between the two. 795fa9e4066Sahrens */ 7968488aeb5Staylor static int 797fa9e4066Sahrens check_replication(nvlist_t *config, nvlist_t *newroot) 798fa9e4066Sahrens { 7998488aeb5Staylor nvlist_t **child; 8008488aeb5Staylor uint_t children; 801fa9e4066Sahrens replication_level_t *current = NULL, *new; 802fa9e4066Sahrens int ret; 803fa9e4066Sahrens 804fa9e4066Sahrens /* 805fa9e4066Sahrens * If we have a current pool configuration, check to see if it's 806fa9e4066Sahrens * self-consistent. If not, simply return success. 807fa9e4066Sahrens */ 808fa9e4066Sahrens if (config != NULL) { 809fa9e4066Sahrens nvlist_t *nvroot; 810fa9e4066Sahrens 811fa9e4066Sahrens verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 812fa9e4066Sahrens &nvroot) == 0); 81399653d4eSeschrock if ((current = get_replication(nvroot, B_FALSE)) == NULL) 814fa9e4066Sahrens return (0); 815fa9e4066Sahrens } 8168488aeb5Staylor /* 8178488aeb5Staylor * for spares there may be no children, and therefore no 8188488aeb5Staylor * replication level to check 8198488aeb5Staylor */ 8208488aeb5Staylor if ((nvlist_lookup_nvlist_array(newroot, ZPOOL_CONFIG_CHILDREN, 8218488aeb5Staylor &child, &children) != 0) || (children == 0)) { 8228488aeb5Staylor free(current); 8238488aeb5Staylor return (0); 8248488aeb5Staylor } 825fa9e4066Sahrens 826fa9e4066Sahrens /* 8278654d025Sperrin * If all we have is logs then there's no replication level to check. 8288654d025Sperrin */ 8298654d025Sperrin if (num_logs(newroot) == children) { 8308654d025Sperrin free(current); 8318654d025Sperrin return (0); 8328654d025Sperrin } 8338654d025Sperrin 8348654d025Sperrin /* 835fa9e4066Sahrens * Get the replication level of the new vdev spec, reporting any 836fa9e4066Sahrens * inconsistencies found. 837fa9e4066Sahrens */ 83899653d4eSeschrock if ((new = get_replication(newroot, B_TRUE)) == NULL) { 839fa9e4066Sahrens free(current); 840fa9e4066Sahrens return (-1); 841fa9e4066Sahrens } 842fa9e4066Sahrens 843fa9e4066Sahrens /* 844fa9e4066Sahrens * Check to see if the new vdev spec matches the replication level of 845fa9e4066Sahrens * the current pool. 846fa9e4066Sahrens */ 847fa9e4066Sahrens ret = 0; 848fa9e4066Sahrens if (current != NULL) { 84999653d4eSeschrock if (strcmp(current->zprl_type, new->zprl_type) != 0) { 850fa9e4066Sahrens vdev_error(gettext( 85199653d4eSeschrock "mismatched replication level: pool uses %s " 85299653d4eSeschrock "and new vdev is %s\n"), 85399653d4eSeschrock current->zprl_type, new->zprl_type); 85499653d4eSeschrock ret = -1; 85599653d4eSeschrock } else if (current->zprl_parity != new->zprl_parity) { 85699653d4eSeschrock vdev_error(gettext( 85799653d4eSeschrock "mismatched replication level: pool uses %llu " 85899653d4eSeschrock "device parity and new vdev uses %llu\n"), 85999653d4eSeschrock current->zprl_parity, new->zprl_parity); 86099653d4eSeschrock ret = -1; 86199653d4eSeschrock } else if (current->zprl_children != new->zprl_children) { 86299653d4eSeschrock vdev_error(gettext( 86399653d4eSeschrock "mismatched replication level: pool uses %llu-way " 86499653d4eSeschrock "%s and new vdev uses %llu-way %s\n"), 86599653d4eSeschrock current->zprl_children, current->zprl_type, 86699653d4eSeschrock new->zprl_children, new->zprl_type); 867fa9e4066Sahrens ret = -1; 868fa9e4066Sahrens } 869fa9e4066Sahrens } 870fa9e4066Sahrens 871fa9e4066Sahrens free(new); 872fa9e4066Sahrens if (current != NULL) 873fa9e4066Sahrens free(current); 874fa9e4066Sahrens 875fa9e4066Sahrens return (ret); 876fa9e4066Sahrens } 877fa9e4066Sahrens 878fa9e4066Sahrens /* 879fa9e4066Sahrens * Go through and find any whole disks in the vdev specification, labelling them 880fa9e4066Sahrens * as appropriate. When constructing the vdev spec, we were unable to open this 881fa9e4066Sahrens * device in order to provide a devid. Now that we have labelled the disk and 882fa9e4066Sahrens * know that slice 0 is valid, we can construct the devid now. 883fa9e4066Sahrens * 8848488aeb5Staylor * If the disk was already labeled with an EFI label, we will have gotten the 885fa9e4066Sahrens * devid already (because we were able to open the whole disk). Otherwise, we 886fa9e4066Sahrens * need to get the devid after we label the disk. 887fa9e4066Sahrens */ 8888488aeb5Staylor static int 8898488aeb5Staylor make_disks(zpool_handle_t *zhp, nvlist_t *nv) 890fa9e4066Sahrens { 891fa9e4066Sahrens nvlist_t **child; 892fa9e4066Sahrens uint_t c, children; 893fa9e4066Sahrens char *type, *path, *diskname; 894fa9e4066Sahrens char buf[MAXPATHLEN]; 895afefbcddSeschrock uint64_t wholedisk; 896fa9e4066Sahrens int fd; 897fa9e4066Sahrens int ret; 898fa9e4066Sahrens ddi_devid_t devid; 899fa9e4066Sahrens char *minor = NULL, *devid_str = NULL; 900fa9e4066Sahrens 901fa9e4066Sahrens verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0); 902fa9e4066Sahrens 903fa9e4066Sahrens if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 904fa9e4066Sahrens &child, &children) != 0) { 905fa9e4066Sahrens 906fa9e4066Sahrens if (strcmp(type, VDEV_TYPE_DISK) != 0) 907fa9e4066Sahrens return (0); 908fa9e4066Sahrens 909fa9e4066Sahrens /* 910fa9e4066Sahrens * We have a disk device. Get the path to the device 9118488aeb5Staylor * and see if it's a whole disk by appending the backup 912fa9e4066Sahrens * slice and stat()ing the device. 913fa9e4066Sahrens */ 914fa9e4066Sahrens verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0); 915afefbcddSeschrock if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK, 916afefbcddSeschrock &wholedisk) != 0 || !wholedisk) 917fa9e4066Sahrens return (0); 918fa9e4066Sahrens 919fa9e4066Sahrens diskname = strrchr(path, '/'); 920fa9e4066Sahrens assert(diskname != NULL); 921fa9e4066Sahrens diskname++; 9228488aeb5Staylor if (zpool_label_disk(g_zfs, zhp, diskname) == -1) 923fa9e4066Sahrens return (-1); 924fa9e4066Sahrens 925fa9e4066Sahrens /* 926fa9e4066Sahrens * Fill in the devid, now that we've labeled the disk. 927fa9e4066Sahrens */ 928fa9e4066Sahrens (void) snprintf(buf, sizeof (buf), "%ss0", path); 929fa9e4066Sahrens if ((fd = open(buf, O_RDONLY)) < 0) { 930fa9e4066Sahrens (void) fprintf(stderr, 931fa9e4066Sahrens gettext("cannot open '%s': %s\n"), 932fa9e4066Sahrens buf, strerror(errno)); 933fa9e4066Sahrens return (-1); 934fa9e4066Sahrens } 935fa9e4066Sahrens 936fa9e4066Sahrens if (devid_get(fd, &devid) == 0) { 937fa9e4066Sahrens if (devid_get_minor_name(fd, &minor) == 0 && 938fa9e4066Sahrens (devid_str = devid_str_encode(devid, minor)) != 939fa9e4066Sahrens NULL) { 940fa9e4066Sahrens verify(nvlist_add_string(nv, 941fa9e4066Sahrens ZPOOL_CONFIG_DEVID, devid_str) == 0); 942fa9e4066Sahrens } 943fa9e4066Sahrens if (devid_str != NULL) 944fa9e4066Sahrens devid_str_free(devid_str); 945fa9e4066Sahrens if (minor != NULL) 946fa9e4066Sahrens devid_str_free(minor); 947fa9e4066Sahrens devid_free(devid); 948fa9e4066Sahrens } 949fa9e4066Sahrens 950afefbcddSeschrock /* 951afefbcddSeschrock * Update the path to refer to the 's0' slice. The presence of 952afefbcddSeschrock * the 'whole_disk' field indicates to the CLI that we should 953afefbcddSeschrock * chop off the slice number when displaying the device in 954afefbcddSeschrock * future output. 955afefbcddSeschrock */ 956afefbcddSeschrock verify(nvlist_add_string(nv, ZPOOL_CONFIG_PATH, buf) == 0); 957afefbcddSeschrock 958fa9e4066Sahrens (void) close(fd); 959fa9e4066Sahrens 960fa9e4066Sahrens return (0); 961fa9e4066Sahrens } 962fa9e4066Sahrens 963fa9e4066Sahrens for (c = 0; c < children; c++) 9648488aeb5Staylor if ((ret = make_disks(zhp, child[c])) != 0) 965fa9e4066Sahrens return (ret); 966fa9e4066Sahrens 96799653d4eSeschrock if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, 96899653d4eSeschrock &child, &children) == 0) 96999653d4eSeschrock for (c = 0; c < children; c++) 9708488aeb5Staylor if ((ret = make_disks(zhp, child[c])) != 0) 97199653d4eSeschrock return (ret); 97299653d4eSeschrock 973fa94a07fSbrendan if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE, 974fa94a07fSbrendan &child, &children) == 0) 975fa94a07fSbrendan for (c = 0; c < children; c++) 976fa94a07fSbrendan if ((ret = make_disks(zhp, child[c])) != 0) 977fa94a07fSbrendan return (ret); 978fa94a07fSbrendan 979fa9e4066Sahrens return (0); 980fa9e4066Sahrens } 981fa9e4066Sahrens 982fa9e4066Sahrens /* 98399653d4eSeschrock * Determine if the given path is a hot spare within the given configuration. 98499653d4eSeschrock */ 98599653d4eSeschrock static boolean_t 98699653d4eSeschrock is_spare(nvlist_t *config, const char *path) 98799653d4eSeschrock { 98899653d4eSeschrock int fd; 98999653d4eSeschrock pool_state_t state; 9903ccfa83cSahrens char *name = NULL; 99199653d4eSeschrock nvlist_t *label; 99299653d4eSeschrock uint64_t guid, spareguid; 99399653d4eSeschrock nvlist_t *nvroot; 99499653d4eSeschrock nvlist_t **spares; 99599653d4eSeschrock uint_t i, nspares; 99699653d4eSeschrock boolean_t inuse; 99799653d4eSeschrock 99899653d4eSeschrock if ((fd = open(path, O_RDONLY)) < 0) 99999653d4eSeschrock return (B_FALSE); 100099653d4eSeschrock 100199653d4eSeschrock if (zpool_in_use(g_zfs, fd, &state, &name, &inuse) != 0 || 100299653d4eSeschrock !inuse || 100399653d4eSeschrock state != POOL_STATE_SPARE || 100499653d4eSeschrock zpool_read_label(fd, &label) != 0) { 10053ccfa83cSahrens free(name); 100699653d4eSeschrock (void) close(fd); 100799653d4eSeschrock return (B_FALSE); 100899653d4eSeschrock } 10093ccfa83cSahrens free(name); 101099653d4eSeschrock (void) close(fd); 10113f9d6ad7SLin Ling 101299653d4eSeschrock verify(nvlist_lookup_uint64(label, ZPOOL_CONFIG_GUID, &guid) == 0); 101399653d4eSeschrock nvlist_free(label); 101499653d4eSeschrock 101599653d4eSeschrock verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 101699653d4eSeschrock &nvroot) == 0); 101799653d4eSeschrock if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES, 101899653d4eSeschrock &spares, &nspares) == 0) { 101999653d4eSeschrock for (i = 0; i < nspares; i++) { 102099653d4eSeschrock verify(nvlist_lookup_uint64(spares[i], 102199653d4eSeschrock ZPOOL_CONFIG_GUID, &spareguid) == 0); 102299653d4eSeschrock if (spareguid == guid) 102399653d4eSeschrock return (B_TRUE); 102499653d4eSeschrock } 102599653d4eSeschrock } 102699653d4eSeschrock 102799653d4eSeschrock return (B_FALSE); 102899653d4eSeschrock } 102999653d4eSeschrock 103099653d4eSeschrock /* 1031fa9e4066Sahrens * Go through and find any devices that are in use. We rely on libdiskmgt for 1032fa9e4066Sahrens * the majority of this task. 1033fa9e4066Sahrens */ 103475fbdf9bSBasil Crow static boolean_t 103575fbdf9bSBasil Crow is_device_in_use(nvlist_t *config, nvlist_t *nv, boolean_t force, 10363f9d6ad7SLin Ling boolean_t replacing, boolean_t isspare) 1037fa9e4066Sahrens { 1038fa9e4066Sahrens nvlist_t **child; 1039fa9e4066Sahrens uint_t c, children; 1040fa9e4066Sahrens char *type, *path; 1041*b327cd3fSIgor Kozhukhov int ret = 0; 104299653d4eSeschrock char buf[MAXPATHLEN]; 104399653d4eSeschrock uint64_t wholedisk; 104475fbdf9bSBasil Crow boolean_t anyinuse = B_FALSE; 1045fa9e4066Sahrens 1046fa9e4066Sahrens verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0); 1047fa9e4066Sahrens 1048fa9e4066Sahrens if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 1049fa9e4066Sahrens &child, &children) != 0) { 1050fa9e4066Sahrens 1051fa9e4066Sahrens verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0); 1052fa9e4066Sahrens 105399653d4eSeschrock /* 105499653d4eSeschrock * As a generic check, we look to see if this is a replace of a 105599653d4eSeschrock * hot spare within the same pool. If so, we allow it 105699653d4eSeschrock * regardless of what libdiskmgt or zpool_in_use() says. 105799653d4eSeschrock */ 10583f9d6ad7SLin Ling if (replacing) { 105999653d4eSeschrock if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK, 106099653d4eSeschrock &wholedisk) == 0 && wholedisk) 106199653d4eSeschrock (void) snprintf(buf, sizeof (buf), "%ss0", 106299653d4eSeschrock path); 106399653d4eSeschrock else 106499653d4eSeschrock (void) strlcpy(buf, path, sizeof (buf)); 10653f9d6ad7SLin Ling 106699653d4eSeschrock if (is_spare(config, buf)) 106775fbdf9bSBasil Crow return (B_FALSE); 106899653d4eSeschrock } 106999653d4eSeschrock 1070fa9e4066Sahrens if (strcmp(type, VDEV_TYPE_DISK) == 0) 107199653d4eSeschrock ret = check_device(path, force, isspare); 107275fbdf9bSBasil Crow else if (strcmp(type, VDEV_TYPE_FILE) == 0) 107399653d4eSeschrock ret = check_file(path, force, isspare); 1074fa9e4066Sahrens 107575fbdf9bSBasil Crow return (ret != 0); 1076fa9e4066Sahrens } 1077fa9e4066Sahrens 1078fa9e4066Sahrens for (c = 0; c < children; c++) 107975fbdf9bSBasil Crow if (is_device_in_use(config, child[c], force, replacing, 108075fbdf9bSBasil Crow B_FALSE)) 108175fbdf9bSBasil Crow anyinuse = B_TRUE; 108299653d4eSeschrock 108399653d4eSeschrock if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, 108499653d4eSeschrock &child, &children) == 0) 108599653d4eSeschrock for (c = 0; c < children; c++) 108675fbdf9bSBasil Crow if (is_device_in_use(config, child[c], force, replacing, 108775fbdf9bSBasil Crow B_TRUE)) 108875fbdf9bSBasil Crow anyinuse = B_TRUE; 1089fa94a07fSbrendan 1090fa94a07fSbrendan if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE, 1091fa94a07fSbrendan &child, &children) == 0) 1092fa94a07fSbrendan for (c = 0; c < children; c++) 109375fbdf9bSBasil Crow if (is_device_in_use(config, child[c], force, replacing, 109475fbdf9bSBasil Crow B_FALSE)) 109575fbdf9bSBasil Crow anyinuse = B_TRUE; 1096fa94a07fSbrendan 109775fbdf9bSBasil Crow return (anyinuse); 1098fa9e4066Sahrens } 1099fa9e4066Sahrens 11008488aeb5Staylor static const char * 1101f94275ceSAdam Leventhal is_grouping(const char *type, int *mindev, int *maxdev) 110299653d4eSeschrock { 1103f94275ceSAdam Leventhal if (strncmp(type, "raidz", 5) == 0) { 1104f94275ceSAdam Leventhal const char *p = type + 5; 1105f94275ceSAdam Leventhal char *end; 1106f94275ceSAdam Leventhal long nparity; 1107f94275ceSAdam Leventhal 1108f94275ceSAdam Leventhal if (*p == '\0') { 1109f94275ceSAdam Leventhal nparity = 1; 1110f94275ceSAdam Leventhal } else if (*p == '0') { 1111f94275ceSAdam Leventhal return (NULL); /* no zero prefixes allowed */ 1112f94275ceSAdam Leventhal } else { 1113f94275ceSAdam Leventhal errno = 0; 1114f94275ceSAdam Leventhal nparity = strtol(p, &end, 10); 1115f94275ceSAdam Leventhal if (errno != 0 || nparity < 1 || nparity >= 255 || 1116f94275ceSAdam Leventhal *end != '\0') 1117f94275ceSAdam Leventhal return (NULL); 1118f94275ceSAdam Leventhal } 1119f94275ceSAdam Leventhal 112099653d4eSeschrock if (mindev != NULL) 1121f94275ceSAdam Leventhal *mindev = nparity + 1; 1122f94275ceSAdam Leventhal if (maxdev != NULL) 1123f94275ceSAdam Leventhal *maxdev = 255; 112499653d4eSeschrock return (VDEV_TYPE_RAIDZ); 112599653d4eSeschrock } 112699653d4eSeschrock 1127f94275ceSAdam Leventhal if (maxdev != NULL) 1128f94275ceSAdam Leventhal *maxdev = INT_MAX; 112999653d4eSeschrock 113099653d4eSeschrock if (strcmp(type, "mirror") == 0) { 113199653d4eSeschrock if (mindev != NULL) 113299653d4eSeschrock *mindev = 2; 113399653d4eSeschrock return (VDEV_TYPE_MIRROR); 113499653d4eSeschrock } 113599653d4eSeschrock 113699653d4eSeschrock if (strcmp(type, "spare") == 0) { 113799653d4eSeschrock if (mindev != NULL) 113899653d4eSeschrock *mindev = 1; 113999653d4eSeschrock return (VDEV_TYPE_SPARE); 114099653d4eSeschrock } 114199653d4eSeschrock 11428654d025Sperrin if (strcmp(type, "log") == 0) { 11438654d025Sperrin if (mindev != NULL) 11448654d025Sperrin *mindev = 1; 11458654d025Sperrin return (VDEV_TYPE_LOG); 11468654d025Sperrin } 11478654d025Sperrin 1148fa94a07fSbrendan if (strcmp(type, "cache") == 0) { 1149fa94a07fSbrendan if (mindev != NULL) 1150fa94a07fSbrendan *mindev = 1; 1151fa94a07fSbrendan return (VDEV_TYPE_L2CACHE); 1152fa94a07fSbrendan } 1153fa94a07fSbrendan 115499653d4eSeschrock return (NULL); 115599653d4eSeschrock } 115699653d4eSeschrock 1157fa9e4066Sahrens /* 1158fa9e4066Sahrens * Construct a syntactically valid vdev specification, 1159fa9e4066Sahrens * and ensure that all devices and files exist and can be opened. 1160fa9e4066Sahrens * Note: we don't bother freeing anything in the error paths 1161fa9e4066Sahrens * because the program is just going to exit anyway. 1162fa9e4066Sahrens */ 1163fa9e4066Sahrens nvlist_t * 1164fa9e4066Sahrens construct_spec(int argc, char **argv) 1165fa9e4066Sahrens { 1166fa94a07fSbrendan nvlist_t *nvroot, *nv, **top, **spares, **l2cache; 1167f94275ceSAdam Leventhal int t, toplevels, mindev, maxdev, nspares, nlogs, nl2cache; 116899653d4eSeschrock const char *type; 11698654d025Sperrin uint64_t is_log; 11708654d025Sperrin boolean_t seen_logs; 1171fa9e4066Sahrens 1172fa9e4066Sahrens top = NULL; 1173fa9e4066Sahrens toplevels = 0; 117499653d4eSeschrock spares = NULL; 1175fa94a07fSbrendan l2cache = NULL; 117699653d4eSeschrock nspares = 0; 11778654d025Sperrin nlogs = 0; 1178fa94a07fSbrendan nl2cache = 0; 11798654d025Sperrin is_log = B_FALSE; 11808654d025Sperrin seen_logs = B_FALSE; 1181fa9e4066Sahrens 1182fa9e4066Sahrens while (argc > 0) { 1183fa9e4066Sahrens nv = NULL; 1184fa9e4066Sahrens 1185fa9e4066Sahrens /* 1186fa9e4066Sahrens * If it's a mirror or raidz, the subsequent arguments are 1187fa9e4066Sahrens * its leaves -- until we encounter the next mirror or raidz. 1188fa9e4066Sahrens */ 1189f94275ceSAdam Leventhal if ((type = is_grouping(argv[0], &mindev, &maxdev)) != NULL) { 1190fa9e4066Sahrens nvlist_t **child = NULL; 119199653d4eSeschrock int c, children = 0; 119299653d4eSeschrock 11938654d025Sperrin if (strcmp(type, VDEV_TYPE_SPARE) == 0) { 11948654d025Sperrin if (spares != NULL) { 11958654d025Sperrin (void) fprintf(stderr, 11968654d025Sperrin gettext("invalid vdev " 119799653d4eSeschrock "specification: 'spare' can be " 119899653d4eSeschrock "specified only once\n")); 119999653d4eSeschrock return (NULL); 120099653d4eSeschrock } 12018654d025Sperrin is_log = B_FALSE; 12028654d025Sperrin } 12038654d025Sperrin 12048654d025Sperrin if (strcmp(type, VDEV_TYPE_LOG) == 0) { 12058654d025Sperrin if (seen_logs) { 12068654d025Sperrin (void) fprintf(stderr, 12078654d025Sperrin gettext("invalid vdev " 12088654d025Sperrin "specification: 'log' can be " 12098654d025Sperrin "specified only once\n")); 12108654d025Sperrin return (NULL); 12118654d025Sperrin } 12128654d025Sperrin seen_logs = B_TRUE; 12138654d025Sperrin is_log = B_TRUE; 12148654d025Sperrin argc--; 12158654d025Sperrin argv++; 12168654d025Sperrin /* 12178654d025Sperrin * A log is not a real grouping device. 12188654d025Sperrin * We just set is_log and continue. 12198654d025Sperrin */ 12208654d025Sperrin continue; 12218654d025Sperrin } 12228654d025Sperrin 1223fa94a07fSbrendan if (strcmp(type, VDEV_TYPE_L2CACHE) == 0) { 1224fa94a07fSbrendan if (l2cache != NULL) { 1225fa94a07fSbrendan (void) fprintf(stderr, 1226fa94a07fSbrendan gettext("invalid vdev " 1227fa94a07fSbrendan "specification: 'cache' can be " 1228fa94a07fSbrendan "specified only once\n")); 1229fa94a07fSbrendan return (NULL); 1230fa94a07fSbrendan } 1231fa94a07fSbrendan is_log = B_FALSE; 1232fa94a07fSbrendan } 1233fa94a07fSbrendan 12348654d025Sperrin if (is_log) { 12358654d025Sperrin if (strcmp(type, VDEV_TYPE_MIRROR) != 0) { 12368654d025Sperrin (void) fprintf(stderr, 12378654d025Sperrin gettext("invalid vdev " 12388654d025Sperrin "specification: unsupported 'log' " 12398654d025Sperrin "device: %s\n"), type); 12408654d025Sperrin return (NULL); 12418654d025Sperrin } 12428654d025Sperrin nlogs++; 12438654d025Sperrin } 1244fa9e4066Sahrens 1245fa9e4066Sahrens for (c = 1; c < argc; c++) { 1246f94275ceSAdam Leventhal if (is_grouping(argv[c], NULL, NULL) != NULL) 1247fa9e4066Sahrens break; 1248fa9e4066Sahrens children++; 1249fa9e4066Sahrens child = realloc(child, 1250fa9e4066Sahrens children * sizeof (nvlist_t *)); 1251fa9e4066Sahrens if (child == NULL) 12525ad82045Snd150628 zpool_no_memory(); 12538654d025Sperrin if ((nv = make_leaf_vdev(argv[c], B_FALSE)) 12548654d025Sperrin == NULL) 1255fa9e4066Sahrens return (NULL); 1256fa9e4066Sahrens child[children - 1] = nv; 1257fa9e4066Sahrens } 1258fa9e4066Sahrens 125999653d4eSeschrock if (children < mindev) { 126099653d4eSeschrock (void) fprintf(stderr, gettext("invalid vdev " 126199653d4eSeschrock "specification: %s requires at least %d " 126299653d4eSeschrock "devices\n"), argv[0], mindev); 1263fa9e4066Sahrens return (NULL); 1264fa9e4066Sahrens } 1265fa9e4066Sahrens 1266f94275ceSAdam Leventhal if (children > maxdev) { 1267f94275ceSAdam Leventhal (void) fprintf(stderr, gettext("invalid vdev " 1268f94275ceSAdam Leventhal "specification: %s supports no more than " 1269f94275ceSAdam Leventhal "%d devices\n"), argv[0], maxdev); 1270f94275ceSAdam Leventhal return (NULL); 1271f94275ceSAdam Leventhal } 1272f94275ceSAdam Leventhal 127399653d4eSeschrock argc -= c; 127499653d4eSeschrock argv += c; 127599653d4eSeschrock 127699653d4eSeschrock if (strcmp(type, VDEV_TYPE_SPARE) == 0) { 127799653d4eSeschrock spares = child; 127899653d4eSeschrock nspares = children; 127999653d4eSeschrock continue; 1280fa94a07fSbrendan } else if (strcmp(type, VDEV_TYPE_L2CACHE) == 0) { 1281fa94a07fSbrendan l2cache = child; 1282fa94a07fSbrendan nl2cache = children; 1283fa94a07fSbrendan continue; 128499653d4eSeschrock } else { 128599653d4eSeschrock verify(nvlist_alloc(&nv, NV_UNIQUE_NAME, 128699653d4eSeschrock 0) == 0); 1287fa9e4066Sahrens verify(nvlist_add_string(nv, ZPOOL_CONFIG_TYPE, 1288fa9e4066Sahrens type) == 0); 12898654d025Sperrin verify(nvlist_add_uint64(nv, 12908654d025Sperrin ZPOOL_CONFIG_IS_LOG, is_log) == 0); 129199653d4eSeschrock if (strcmp(type, VDEV_TYPE_RAIDZ) == 0) { 129299653d4eSeschrock verify(nvlist_add_uint64(nv, 129399653d4eSeschrock ZPOOL_CONFIG_NPARITY, 129499653d4eSeschrock mindev - 1) == 0); 129599653d4eSeschrock } 1296fa9e4066Sahrens verify(nvlist_add_nvlist_array(nv, 129799653d4eSeschrock ZPOOL_CONFIG_CHILDREN, child, 129899653d4eSeschrock children) == 0); 1299fa9e4066Sahrens 1300fa9e4066Sahrens for (c = 0; c < children; c++) 1301fa9e4066Sahrens nvlist_free(child[c]); 1302fa9e4066Sahrens free(child); 130399653d4eSeschrock } 1304fa9e4066Sahrens } else { 1305fa9e4066Sahrens /* 1306fa9e4066Sahrens * We have a device. Pass off to make_leaf_vdev() to 1307fa9e4066Sahrens * construct the appropriate nvlist describing the vdev. 1308fa9e4066Sahrens */ 13098654d025Sperrin if ((nv = make_leaf_vdev(argv[0], is_log)) == NULL) 1310fa9e4066Sahrens return (NULL); 13118654d025Sperrin if (is_log) 13128654d025Sperrin nlogs++; 1313fa9e4066Sahrens argc--; 1314fa9e4066Sahrens argv++; 1315fa9e4066Sahrens } 1316fa9e4066Sahrens 1317fa9e4066Sahrens toplevels++; 1318fa9e4066Sahrens top = realloc(top, toplevels * sizeof (nvlist_t *)); 1319fa9e4066Sahrens if (top == NULL) 13205ad82045Snd150628 zpool_no_memory(); 1321fa9e4066Sahrens top[toplevels - 1] = nv; 1322fa9e4066Sahrens } 1323fa9e4066Sahrens 1324fa94a07fSbrendan if (toplevels == 0 && nspares == 0 && nl2cache == 0) { 132599653d4eSeschrock (void) fprintf(stderr, gettext("invalid vdev " 132699653d4eSeschrock "specification: at least one toplevel vdev must be " 132799653d4eSeschrock "specified\n")); 132899653d4eSeschrock return (NULL); 132999653d4eSeschrock } 133099653d4eSeschrock 13318654d025Sperrin if (seen_logs && nlogs == 0) { 13328654d025Sperrin (void) fprintf(stderr, gettext("invalid vdev specification: " 13338654d025Sperrin "log requires at least 1 device\n")); 13348654d025Sperrin return (NULL); 13358654d025Sperrin } 13368654d025Sperrin 1337fa9e4066Sahrens /* 1338fa9e4066Sahrens * Finally, create nvroot and add all top-level vdevs to it. 1339fa9e4066Sahrens */ 1340fa9e4066Sahrens verify(nvlist_alloc(&nvroot, NV_UNIQUE_NAME, 0) == 0); 1341fa9e4066Sahrens verify(nvlist_add_string(nvroot, ZPOOL_CONFIG_TYPE, 1342fa9e4066Sahrens VDEV_TYPE_ROOT) == 0); 1343fa9e4066Sahrens verify(nvlist_add_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN, 1344fa9e4066Sahrens top, toplevels) == 0); 134599653d4eSeschrock if (nspares != 0) 134699653d4eSeschrock verify(nvlist_add_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES, 134799653d4eSeschrock spares, nspares) == 0); 1348fa94a07fSbrendan if (nl2cache != 0) 1349fa94a07fSbrendan verify(nvlist_add_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE, 1350fa94a07fSbrendan l2cache, nl2cache) == 0); 1351fa9e4066Sahrens 1352fa9e4066Sahrens for (t = 0; t < toplevels; t++) 1353fa9e4066Sahrens nvlist_free(top[t]); 135499653d4eSeschrock for (t = 0; t < nspares; t++) 135599653d4eSeschrock nvlist_free(spares[t]); 1356fa94a07fSbrendan for (t = 0; t < nl2cache; t++) 1357fa94a07fSbrendan nvlist_free(l2cache[t]); 135899653d4eSeschrock if (spares) 135999653d4eSeschrock free(spares); 1360fa94a07fSbrendan if (l2cache) 1361fa94a07fSbrendan free(l2cache); 1362fa9e4066Sahrens free(top); 1363fa9e4066Sahrens 1364fa9e4066Sahrens return (nvroot); 1365fa9e4066Sahrens } 1366fa9e4066Sahrens 13671195e687SMark J Musante nvlist_t * 13681195e687SMark J Musante split_mirror_vdev(zpool_handle_t *zhp, char *newname, nvlist_t *props, 13691195e687SMark J Musante splitflags_t flags, int argc, char **argv) 13701195e687SMark J Musante { 13711195e687SMark J Musante nvlist_t *newroot = NULL, **child; 13721195e687SMark J Musante uint_t c, children; 13731195e687SMark J Musante 13741195e687SMark J Musante if (argc > 0) { 13751195e687SMark J Musante if ((newroot = construct_spec(argc, argv)) == NULL) { 13761195e687SMark J Musante (void) fprintf(stderr, gettext("Unable to build a " 13771195e687SMark J Musante "pool from the specified devices\n")); 13781195e687SMark J Musante return (NULL); 13791195e687SMark J Musante } 13801195e687SMark J Musante 13811195e687SMark J Musante if (!flags.dryrun && make_disks(zhp, newroot) != 0) { 13821195e687SMark J Musante nvlist_free(newroot); 13831195e687SMark J Musante return (NULL); 13841195e687SMark J Musante } 13851195e687SMark J Musante 13861195e687SMark J Musante /* avoid any tricks in the spec */ 13871195e687SMark J Musante verify(nvlist_lookup_nvlist_array(newroot, 13881195e687SMark J Musante ZPOOL_CONFIG_CHILDREN, &child, &children) == 0); 13891195e687SMark J Musante for (c = 0; c < children; c++) { 13901195e687SMark J Musante char *path; 13911195e687SMark J Musante const char *type; 13921195e687SMark J Musante int min, max; 13931195e687SMark J Musante 13941195e687SMark J Musante verify(nvlist_lookup_string(child[c], 13951195e687SMark J Musante ZPOOL_CONFIG_PATH, &path) == 0); 13961195e687SMark J Musante if ((type = is_grouping(path, &min, &max)) != NULL) { 13971195e687SMark J Musante (void) fprintf(stderr, gettext("Cannot use " 13981195e687SMark J Musante "'%s' as a device for splitting\n"), type); 13991195e687SMark J Musante nvlist_free(newroot); 14001195e687SMark J Musante return (NULL); 14011195e687SMark J Musante } 14021195e687SMark J Musante } 14031195e687SMark J Musante } 14041195e687SMark J Musante 14051195e687SMark J Musante if (zpool_vdev_split(zhp, newname, &newroot, props, flags) != 0) { 14061195e687SMark J Musante nvlist_free(newroot); 14071195e687SMark J Musante return (NULL); 14081195e687SMark J Musante } 14091195e687SMark J Musante 14101195e687SMark J Musante return (newroot); 14111195e687SMark J Musante } 14128488aeb5Staylor 1413fa9e4066Sahrens /* 1414fa9e4066Sahrens * Get and validate the contents of the given vdev specification. This ensures 1415fa9e4066Sahrens * that the nvlist returned is well-formed, that all the devices exist, and that 1416fa9e4066Sahrens * they are not currently in use by any other known consumer. The 'poolconfig' 1417fa9e4066Sahrens * parameter is the current configuration of the pool when adding devices 1418fa9e4066Sahrens * existing pool, and is used to perform additional checks, such as changing the 1419fa9e4066Sahrens * replication level of the pool. It can be 'NULL' to indicate that this is a 1420fa9e4066Sahrens * new pool. The 'force' flag controls whether devices should be forcefully 1421fa9e4066Sahrens * added, even if they appear in use. 1422fa9e4066Sahrens */ 1423fa9e4066Sahrens nvlist_t * 14248488aeb5Staylor make_root_vdev(zpool_handle_t *zhp, int force, int check_rep, 14253f9d6ad7SLin Ling boolean_t replacing, boolean_t dryrun, int argc, char **argv) 1426fa9e4066Sahrens { 1427fa9e4066Sahrens nvlist_t *newroot; 14288488aeb5Staylor nvlist_t *poolconfig = NULL; 1429fa9e4066Sahrens is_force = force; 1430fa9e4066Sahrens 1431fa9e4066Sahrens /* 1432fa9e4066Sahrens * Construct the vdev specification. If this is successful, we know 1433fa9e4066Sahrens * that we have a valid specification, and that all devices can be 1434fa9e4066Sahrens * opened. 1435fa9e4066Sahrens */ 1436fa9e4066Sahrens if ((newroot = construct_spec(argc, argv)) == NULL) 1437fa9e4066Sahrens return (NULL); 1438fa9e4066Sahrens 14398488aeb5Staylor if (zhp && ((poolconfig = zpool_get_config(zhp, NULL)) == NULL)) 14408488aeb5Staylor return (NULL); 14418488aeb5Staylor 1442fa9e4066Sahrens /* 1443fa9e4066Sahrens * Validate each device to make sure that its not shared with another 1444fa9e4066Sahrens * subsystem. We do this even if 'force' is set, because there are some 1445fa9e4066Sahrens * uses (such as a dedicated dump device) that even '-f' cannot 1446fa9e4066Sahrens * override. 1447fa9e4066Sahrens */ 144875fbdf9bSBasil Crow if (is_device_in_use(poolconfig, newroot, force, replacing, B_FALSE)) { 1449fa9e4066Sahrens nvlist_free(newroot); 1450fa9e4066Sahrens return (NULL); 1451fa9e4066Sahrens } 1452fa9e4066Sahrens 1453fa9e4066Sahrens /* 1454fa9e4066Sahrens * Check the replication level of the given vdevs and report any errors 1455fa9e4066Sahrens * found. We include the existing pool spec, if any, as we need to 1456fa9e4066Sahrens * catch changes against the existing replication level. 1457fa9e4066Sahrens */ 1458fa9e4066Sahrens if (check_rep && check_replication(poolconfig, newroot) != 0) { 1459fa9e4066Sahrens nvlist_free(newroot); 1460fa9e4066Sahrens return (NULL); 1461fa9e4066Sahrens } 1462fa9e4066Sahrens 1463fa9e4066Sahrens /* 1464fa9e4066Sahrens * Run through the vdev specification and label any whole disks found. 1465fa9e4066Sahrens */ 1466705040edSEric Taylor if (!dryrun && make_disks(zhp, newroot) != 0) { 1467fa9e4066Sahrens nvlist_free(newroot); 1468fa9e4066Sahrens return (NULL); 1469fa9e4066Sahrens } 1470fa9e4066Sahrens 1471fa9e4066Sahrens return (newroot); 1472fa9e4066Sahrens } 1473