1fa9e4066Sahrens /* 2fa9e4066Sahrens * CDDL HEADER START 3fa9e4066Sahrens * 4fa9e4066Sahrens * The contents of this file are subject to the terms of the 5fa9e4066Sahrens * Common Development and Distribution License, Version 1.0 only 6fa9e4066Sahrens * (the "License"). You may not use this file except in compliance 7fa9e4066Sahrens * with the License. 8fa9e4066Sahrens * 9fa9e4066Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10fa9e4066Sahrens * or http://www.opensolaris.org/os/licensing. 11fa9e4066Sahrens * See the License for the specific language governing permissions 12fa9e4066Sahrens * and limitations under the License. 13fa9e4066Sahrens * 14fa9e4066Sahrens * When distributing Covered Code, include this CDDL HEADER in each 15fa9e4066Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16fa9e4066Sahrens * If applicable, add the following below this CDDL HEADER, with the 17fa9e4066Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 18fa9e4066Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 19fa9e4066Sahrens * 20fa9e4066Sahrens * CDDL HEADER END 21fa9e4066Sahrens */ 22fa9e4066Sahrens /* 23fa9e4066Sahrens * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24fa9e4066Sahrens * Use is subject to license terms. 25fa9e4066Sahrens */ 26fa9e4066Sahrens 27fa9e4066Sahrens #pragma ident "%Z%%M% %I% %E% SMI" 28fa9e4066Sahrens 29fa9e4066Sahrens /* 30fa9e4066Sahrens * Functions to convert between a list of vdevs and an nvlist representing the 31fa9e4066Sahrens * configuration. Each entry in the list can be one of: 32fa9e4066Sahrens * 33fa9e4066Sahrens * Device vdevs 34fa9e4066Sahrens * disk=(path=..., devid=...) 35fa9e4066Sahrens * file=(path=...) 36fa9e4066Sahrens * 37fa9e4066Sahrens * Group vdevs 38fa9e4066Sahrens * raidz=(...) 39fa9e4066Sahrens * mirror=(...) 40fa9e4066Sahrens * 41fa9e4066Sahrens * While the underlying implementation supports it, group vdevs cannot contain 42fa9e4066Sahrens * other group vdevs. All userland verification of devices is contained within 43fa9e4066Sahrens * this file. If successful, the nvlist returned can be passed directly to the 44fa9e4066Sahrens * kernel; we've done as much verification as possible in userland. 45fa9e4066Sahrens * 46fa9e4066Sahrens * The only function exported by this file is 'get_vdev_spec'. The function 47fa9e4066Sahrens * performs several passes: 48fa9e4066Sahrens * 49fa9e4066Sahrens * 1. Construct the vdev specification. Performs syntax validation and 50fa9e4066Sahrens * makes sure each device is valid. 51fa9e4066Sahrens * 2. Check for devices in use. Using libdiskmgt, makes sure that no 52fa9e4066Sahrens * devices are also in use. Some can be overridden using the 'force' 53fa9e4066Sahrens * flag, others cannot. 54fa9e4066Sahrens * 3. Check for replication errors if the 'force' flag is not specified. 55fa9e4066Sahrens * validates that the replication level is consistent across the 56fa9e4066Sahrens * entire pool. 57fa9e4066Sahrens * 4. Label any whole disks with an EFI label. 58fa9e4066Sahrens */ 59fa9e4066Sahrens 60fa9e4066Sahrens #include <assert.h> 61fa9e4066Sahrens #include <devid.h> 62fa9e4066Sahrens #include <errno.h> 63fa9e4066Sahrens #include <fcntl.h> 64fa9e4066Sahrens #include <libdiskmgt.h> 65fa9e4066Sahrens #include <libintl.h> 66fa9e4066Sahrens #include <libnvpair.h> 67fa9e4066Sahrens #include <stdio.h> 68fa9e4066Sahrens #include <string.h> 69fa9e4066Sahrens #include <unistd.h> 70fa9e4066Sahrens #include <sys/efi_partition.h> 71fa9e4066Sahrens #include <sys/stat.h> 72fa9e4066Sahrens #include <sys/vtoc.h> 73fa9e4066Sahrens #include <sys/mntent.h> 74fa9e4066Sahrens 75fa9e4066Sahrens #include <libzfs.h> 76fa9e4066Sahrens 77fa9e4066Sahrens #include "zpool_util.h" 78fa9e4066Sahrens 79fa9e4066Sahrens #define DISK_ROOT "/dev/dsk" 80fa9e4066Sahrens #define RDISK_ROOT "/dev/rdsk" 81fa9e4066Sahrens #define BACKUP_SLICE "s2" 82fa9e4066Sahrens 83fa9e4066Sahrens /* 84fa9e4066Sahrens * For any given vdev specification, we can have multiple errors. The 85fa9e4066Sahrens * vdev_error() function keeps track of whether we have seen an error yet, and 86fa9e4066Sahrens * prints out a header if its the first error we've seen. 87fa9e4066Sahrens */ 88fa9e4066Sahrens int error_seen; 89fa9e4066Sahrens int is_force; 90fa9e4066Sahrens 91fa9e4066Sahrens void 92fa9e4066Sahrens vdev_error(const char *fmt, ...) 93fa9e4066Sahrens { 94fa9e4066Sahrens va_list ap; 95fa9e4066Sahrens 96fa9e4066Sahrens if (!error_seen) { 97fa9e4066Sahrens (void) fprintf(stderr, gettext("invalid vdev specification\n")); 98fa9e4066Sahrens if (!is_force) 99fa9e4066Sahrens (void) fprintf(stderr, gettext("use '-f' to override " 100fa9e4066Sahrens "the following errors:\n")); 101fa9e4066Sahrens else 102fa9e4066Sahrens (void) fprintf(stderr, gettext("the following errors " 103fa9e4066Sahrens "must be manually repaired:\n")); 104fa9e4066Sahrens error_seen = TRUE; 105fa9e4066Sahrens } 106fa9e4066Sahrens 107fa9e4066Sahrens va_start(ap, fmt); 108fa9e4066Sahrens (void) vfprintf(stderr, fmt, ap); 109fa9e4066Sahrens va_end(ap); 110fa9e4066Sahrens } 111fa9e4066Sahrens 112fa9e4066Sahrens void 113fa9e4066Sahrens _libdskmgt_error(int err, const char *file, int line) 114fa9e4066Sahrens { 115fa9e4066Sahrens if (err == 0) 116fa9e4066Sahrens no_memory(); 117fa9e4066Sahrens 118fa9e4066Sahrens /* 119fa9e4066Sahrens * Some of the libdiskmgt stuff requires root privileges in order to 120fa9e4066Sahrens * examine devices. Bail out gracefully in this case. 121fa9e4066Sahrens */ 122fa9e4066Sahrens if (err == EACCES) { 123fa9e4066Sahrens (void) fprintf(stderr, gettext("cannot determine disk " 124fa9e4066Sahrens "configuration: permission denied\n")); 125fa9e4066Sahrens exit(1); 126fa9e4066Sahrens } 127fa9e4066Sahrens 128fa9e4066Sahrens (void) fprintf(stderr, gettext("internal error: disk configuration " 129fa9e4066Sahrens "error %d at line %d of file %s\n"), err, line, file); 130fa9e4066Sahrens abort(); 131fa9e4066Sahrens } 132fa9e4066Sahrens 133fa9e4066Sahrens #define libdskmgt_error(err) (_libdskmgt_error((err), __FILE__, __LINE__)) 134fa9e4066Sahrens 135fa9e4066Sahrens /* 136fa9e4066Sahrens * Checks whether a single slice overlaps with any of the slices in the provided 137fa9e4066Sahrens * list. Called by check_overlapping(). 138fa9e4066Sahrens */ 139fa9e4066Sahrens int 140fa9e4066Sahrens is_overlapping(dm_descriptor_t slice, dm_descriptor_t media, 141fa9e4066Sahrens dm_descriptor_t *slice_list, int *error, char **overlaps_with) 142fa9e4066Sahrens { 143fa9e4066Sahrens int i = 0; 144fa9e4066Sahrens uint32_t in_snum; 145fa9e4066Sahrens uint64_t start_block = 0; 146fa9e4066Sahrens uint64_t end_block = 0; 147fa9e4066Sahrens uint64_t media_size = 0; 148fa9e4066Sahrens uint64_t size = 0; 149fa9e4066Sahrens nvlist_t *media_attrs; 150fa9e4066Sahrens nvlist_t *slice_attrs; 151fa9e4066Sahrens 152fa9e4066Sahrens media_attrs = dm_get_attributes(media, error); 153fa9e4066Sahrens if (*error != 0) { 154fa9e4066Sahrens return (-1); 155fa9e4066Sahrens } 156fa9e4066Sahrens 157fa9e4066Sahrens if (media_attrs == NULL) { 158fa9e4066Sahrens return (0); 159fa9e4066Sahrens } 160fa9e4066Sahrens 161fa9e4066Sahrens *error = nvlist_lookup_uint64(media_attrs, DM_NACCESSIBLE, &media_size); 162fa9e4066Sahrens if (*error != 0) { 163fa9e4066Sahrens nvlist_free(media_attrs); 164fa9e4066Sahrens return (-1); 165fa9e4066Sahrens } 166fa9e4066Sahrens 167fa9e4066Sahrens slice_attrs = dm_get_attributes(slice, error); 168fa9e4066Sahrens if (*error != 0) { 169fa9e4066Sahrens nvlist_free(media_attrs); 170fa9e4066Sahrens return (-1); 171fa9e4066Sahrens } 172fa9e4066Sahrens /* 173fa9e4066Sahrens * Not really possible, but the error above would catch any system 174fa9e4066Sahrens * errors. 175fa9e4066Sahrens */ 176fa9e4066Sahrens if (slice_attrs == NULL) { 177fa9e4066Sahrens nvlist_free(media_attrs); 178fa9e4066Sahrens return (0); 179fa9e4066Sahrens } 180fa9e4066Sahrens 181fa9e4066Sahrens *error = nvlist_lookup_uint64(slice_attrs, DM_START, &start_block); 182fa9e4066Sahrens if (*error != 0) { 183fa9e4066Sahrens nvlist_free(media_attrs); 184fa9e4066Sahrens nvlist_free(slice_attrs); 185fa9e4066Sahrens return (-1); 186fa9e4066Sahrens } 187fa9e4066Sahrens 188fa9e4066Sahrens *error = nvlist_lookup_uint64(slice_attrs, DM_SIZE, &size); 189fa9e4066Sahrens if (*error != 0) { 190fa9e4066Sahrens nvlist_free(media_attrs); 191fa9e4066Sahrens nvlist_free(slice_attrs); 192fa9e4066Sahrens return (-1); 193fa9e4066Sahrens } 194fa9e4066Sahrens *error = nvlist_lookup_uint32(slice_attrs, DM_INDEX, &in_snum); 195fa9e4066Sahrens if (*error != 0) { 196fa9e4066Sahrens nvlist_free(media_attrs); 197fa9e4066Sahrens nvlist_free(slice_attrs); 198fa9e4066Sahrens return (-1); 199fa9e4066Sahrens } 200fa9e4066Sahrens 201fa9e4066Sahrens end_block = (start_block + size) - 1; 202fa9e4066Sahrens 203fa9e4066Sahrens for (i = 0; slice_list[i]; i ++) { 204fa9e4066Sahrens uint64_t other_start; 205fa9e4066Sahrens uint64_t other_end; 206fa9e4066Sahrens uint64_t other_size; 207fa9e4066Sahrens uint32_t snum; 208fa9e4066Sahrens 209fa9e4066Sahrens nvlist_t *other_attrs = dm_get_attributes(slice_list[i], error); 210fa9e4066Sahrens if (*error != 0) { 211fa9e4066Sahrens return (-1); 212fa9e4066Sahrens } 213fa9e4066Sahrens 214fa9e4066Sahrens if (other_attrs == NULL) 215fa9e4066Sahrens continue; 216fa9e4066Sahrens 217fa9e4066Sahrens *error = nvlist_lookup_uint64(other_attrs, DM_START, 218fa9e4066Sahrens &other_start); 219fa9e4066Sahrens if (*error) { 220fa9e4066Sahrens nvlist_free(media_attrs); 221fa9e4066Sahrens nvlist_free(slice_attrs); 222fa9e4066Sahrens nvlist_free(other_attrs); 223fa9e4066Sahrens return (-1); 224fa9e4066Sahrens } 225fa9e4066Sahrens 226fa9e4066Sahrens *error = nvlist_lookup_uint64(other_attrs, DM_SIZE, 227fa9e4066Sahrens &other_size); 228fa9e4066Sahrens 229fa9e4066Sahrens if (*error) { 230fa9e4066Sahrens nvlist_free(media_attrs); 231fa9e4066Sahrens nvlist_free(slice_attrs); 232fa9e4066Sahrens nvlist_free(other_attrs); 233fa9e4066Sahrens return (-1); 234fa9e4066Sahrens } 235fa9e4066Sahrens 236fa9e4066Sahrens other_end = (other_size + other_start) - 1; 237fa9e4066Sahrens 238fa9e4066Sahrens *error = nvlist_lookup_uint32(other_attrs, DM_INDEX, 239fa9e4066Sahrens &snum); 240fa9e4066Sahrens 241fa9e4066Sahrens if (*error) { 242fa9e4066Sahrens nvlist_free(media_attrs); 243fa9e4066Sahrens nvlist_free(slice_attrs); 244fa9e4066Sahrens nvlist_free(other_attrs); 245fa9e4066Sahrens return (-1); 246fa9e4066Sahrens } 247fa9e4066Sahrens 248fa9e4066Sahrens /* 249fa9e4066Sahrens * Check to see if there are > 2 overlapping regions 250fa9e4066Sahrens * on this media in the same region as this slice. 251fa9e4066Sahrens * This is done by assuming the following: 252fa9e4066Sahrens * Slice 2 is the backup slice if it is the size 253fa9e4066Sahrens * of the whole disk 254fa9e4066Sahrens * If slice 2 is the overlap and slice 2 is the size of 255fa9e4066Sahrens * the whole disk, continue. If another slice is found 256fa9e4066Sahrens * that overlaps with our slice, return it. 257fa9e4066Sahrens * There is the potential that there is more than one slice 258fa9e4066Sahrens * that our slice overlaps with, however, we only return 259fa9e4066Sahrens * the first overlapping slice we find. 260fa9e4066Sahrens * 261fa9e4066Sahrens */ 262fa9e4066Sahrens 263fa9e4066Sahrens if (start_block >= other_start && start_block <= other_end) { 264fa9e4066Sahrens if ((snum == 2 && (other_size == media_size)) || 265fa9e4066Sahrens snum == in_snum) { 266fa9e4066Sahrens continue; 267fa9e4066Sahrens } else { 268fa9e4066Sahrens char *str = dm_get_name(slice_list[i], error); 269fa9e4066Sahrens if (*error != 0) { 270fa9e4066Sahrens nvlist_free(media_attrs); 271fa9e4066Sahrens nvlist_free(slice_attrs); 272fa9e4066Sahrens nvlist_free(other_attrs); 273fa9e4066Sahrens return (-1); 274fa9e4066Sahrens } 275fa9e4066Sahrens *overlaps_with = strdup(str); 276fa9e4066Sahrens dm_free_name(str); 277fa9e4066Sahrens nvlist_free(media_attrs); 278fa9e4066Sahrens nvlist_free(slice_attrs); 279fa9e4066Sahrens nvlist_free(other_attrs); 280fa9e4066Sahrens return (1); 281fa9e4066Sahrens } 282fa9e4066Sahrens } else if (other_start >= start_block && 283fa9e4066Sahrens other_start <= end_block) { 284fa9e4066Sahrens if ((snum == 2 && (other_size == media_size)) || 285fa9e4066Sahrens snum == in_snum) { 286fa9e4066Sahrens continue; 287fa9e4066Sahrens } else { 288fa9e4066Sahrens char *str = dm_get_name(slice_list[i], error); 289fa9e4066Sahrens if (*error != 0) { 290fa9e4066Sahrens nvlist_free(media_attrs); 291fa9e4066Sahrens nvlist_free(slice_attrs); 292fa9e4066Sahrens nvlist_free(other_attrs); 293fa9e4066Sahrens return (-1); 294fa9e4066Sahrens } 295fa9e4066Sahrens *overlaps_with = strdup(str); 296fa9e4066Sahrens dm_free_name(str); 297fa9e4066Sahrens nvlist_free(media_attrs); 298fa9e4066Sahrens nvlist_free(slice_attrs); 299fa9e4066Sahrens nvlist_free(other_attrs); 300fa9e4066Sahrens return (1); 301fa9e4066Sahrens } 302fa9e4066Sahrens } 303fa9e4066Sahrens nvlist_free(other_attrs); 304fa9e4066Sahrens } 305fa9e4066Sahrens nvlist_free(media_attrs); 306fa9e4066Sahrens nvlist_free(slice_attrs); 307fa9e4066Sahrens return (0); 308fa9e4066Sahrens } 309fa9e4066Sahrens 310fa9e4066Sahrens /* 311fa9e4066Sahrens * Check to see whether the given slice overlaps with any other slices. Get the 312fa9e4066Sahrens * associated slice information and pass on to is_overlapping(). 313fa9e4066Sahrens */ 314fa9e4066Sahrens int 315fa9e4066Sahrens check_overlapping(const char *slicename, dm_descriptor_t slice) 316fa9e4066Sahrens { 317fa9e4066Sahrens dm_descriptor_t *media; 318fa9e4066Sahrens dm_descriptor_t *slices; 319fa9e4066Sahrens int error; 320fa9e4066Sahrens char *overlaps; 321fa9e4066Sahrens int ret = 0; 322fa9e4066Sahrens 323fa9e4066Sahrens /* 324fa9e4066Sahrens * Get the list of slices be fetching the associated media, and then all 325fa9e4066Sahrens * associated slices. 326fa9e4066Sahrens */ 327fa9e4066Sahrens media = dm_get_associated_descriptors(slice, DM_MEDIA, &error); 328fa9e4066Sahrens if (media == NULL || *media == NULL || error != 0) 329fa9e4066Sahrens libdskmgt_error(error); 330fa9e4066Sahrens 331fa9e4066Sahrens slices = dm_get_associated_descriptors(*media, DM_SLICE, &error); 332fa9e4066Sahrens if (slices == NULL || *slices == NULL || error != 0) 333fa9e4066Sahrens libdskmgt_error(error); 334fa9e4066Sahrens 335fa9e4066Sahrens 336fa9e4066Sahrens overlaps = NULL; 337fa9e4066Sahrens if (is_overlapping(slice, *media, slices, &error, &overlaps)) { 338fa9e4066Sahrens vdev_error(gettext("device '%s' overlaps with '%s'\n"), 339fa9e4066Sahrens slicename, overlaps); 340fa9e4066Sahrens ret = -1; 341fa9e4066Sahrens } 342fa9e4066Sahrens 343fa9e4066Sahrens if (overlaps != NULL) 344fa9e4066Sahrens free(overlaps); 345fa9e4066Sahrens dm_free_descriptors(slices); 346fa9e4066Sahrens dm_free_descriptors(media); 347fa9e4066Sahrens 348fa9e4066Sahrens return (ret); 349fa9e4066Sahrens } 350fa9e4066Sahrens 351fa9e4066Sahrens /* 352fa9e4066Sahrens * Validate the given slice. If 'diskname' is non-NULL, then this is a single 353fa9e4066Sahrens * slice on a complete disk. If 'force' is set, then the user specified '-f' 354fa9e4066Sahrens * and we only want to report error for completely forbidden uses. 355fa9e4066Sahrens */ 356fa9e4066Sahrens int 357fa9e4066Sahrens check_slice(const char *slicename, dm_descriptor_t slice, int force, 358fa9e4066Sahrens int overlap) 359fa9e4066Sahrens { 360fa9e4066Sahrens nvlist_t *stats; 361fa9e4066Sahrens int err; 362fa9e4066Sahrens nvpair_t *nvwhat, *nvdesc; 363fa9e4066Sahrens char *what, *desc, *name; 364fa9e4066Sahrens int found = FALSE; 365fa9e4066Sahrens int found_zfs = FALSE; 366fa9e4066Sahrens int fd; 367fa9e4066Sahrens 368fa9e4066Sahrens if ((stats = dm_get_stats(slice, DM_SLICE_STAT_USE, &err)) == NULL) 369fa9e4066Sahrens libdskmgt_error(err); 370fa9e4066Sahrens 371fa9e4066Sahrens /* 372fa9e4066Sahrens * Always check to see if this is used by an active ZFS pool. 373fa9e4066Sahrens */ 374fa9e4066Sahrens if ((fd = open(slicename, O_RDONLY)) > 0) { 375fa9e4066Sahrens if (zpool_in_use(fd, &desc, &name)) { 376fa9e4066Sahrens 377fa9e4066Sahrens if (!force) { 378fa9e4066Sahrens vdev_error(gettext("%s is part of %s pool " 379fa9e4066Sahrens "'%s'\n"), slicename, desc, name); 380fa9e4066Sahrens found = found_zfs = TRUE; 381fa9e4066Sahrens } 382fa9e4066Sahrens 383fa9e4066Sahrens free(desc); 384fa9e4066Sahrens free(name); 385fa9e4066Sahrens } 386fa9e4066Sahrens 387fa9e4066Sahrens (void) close(fd); 388fa9e4066Sahrens } 389fa9e4066Sahrens 390fa9e4066Sahrens /* 391fa9e4066Sahrens * This slice is in use. Print out a descriptive message describing who 392fa9e4066Sahrens * is using it. The 'used_by' nvlist is formatted as: 393fa9e4066Sahrens * 394fa9e4066Sahrens * (used_by=what, used_name=desc, ...) 395fa9e4066Sahrens * 396fa9e4066Sahrens * Each 'used_by' must be accompanied by a 'used_name'. 397fa9e4066Sahrens */ 398fa9e4066Sahrens nvdesc = NULL; 399fa9e4066Sahrens for (;;) { 400fa9e4066Sahrens nvwhat = nvlist_next_nvpair(stats, nvdesc); 401fa9e4066Sahrens nvdesc = nvlist_next_nvpair(stats, nvwhat); 402fa9e4066Sahrens 403fa9e4066Sahrens if (nvwhat == NULL || nvdesc == NULL) 404fa9e4066Sahrens break; 405fa9e4066Sahrens 406fa9e4066Sahrens assert(strcmp(nvpair_name(nvwhat), DM_USED_BY) == 0); 407fa9e4066Sahrens assert(strcmp(nvpair_name(nvdesc), DM_USED_NAME) == 0); 408fa9e4066Sahrens 409fa9e4066Sahrens verify(nvpair_value_string(nvwhat, &what) == 0); 410fa9e4066Sahrens verify(nvpair_value_string(nvdesc, &desc) == 0); 411fa9e4066Sahrens 412fa9e4066Sahrens /* 413fa9e4066Sahrens * For currently mounted filesystems, filesystems in 414fa9e4066Sahrens * /etc/vfstab, or dedicated dump devices, we can never use 415fa9e4066Sahrens * them, even if '-f' is specified. The rest of the errors 416fa9e4066Sahrens * indicate that a filesystem was detected on disk, which can be 417fa9e4066Sahrens * overridden with '-f'. 418fa9e4066Sahrens */ 419fa9e4066Sahrens if (strcmp(what, DM_USE_MOUNT) == 0 || 420fa9e4066Sahrens strcmp(what, DM_USE_VFSTAB) == 0 || 421fa9e4066Sahrens strcmp(what, DM_USE_DUMP) == 0) { 422fa9e4066Sahrens found = TRUE; 423fa9e4066Sahrens if (strcmp(what, DM_USE_MOUNT) == 0) { 424fa9e4066Sahrens vdev_error(gettext("%s is " 425fa9e4066Sahrens "currently mounted on %s\n"), 426fa9e4066Sahrens slicename, desc); 427fa9e4066Sahrens } else if (strcmp(what, DM_USE_VFSTAB) == 0) { 428fa9e4066Sahrens vdev_error(gettext("%s is usually " 429fa9e4066Sahrens "mounted at %s in /etc/vfstab\n"), 430fa9e4066Sahrens slicename, desc); 431fa9e4066Sahrens } else if (strcmp(what, DM_USE_DUMP) == 0) { 432fa9e4066Sahrens vdev_error(gettext("%s is the " 433fa9e4066Sahrens "dedicated dump device\n"), slicename); 434fa9e4066Sahrens } 435fa9e4066Sahrens } else if (!force) { 436fa9e4066Sahrens found = TRUE; 437fa9e4066Sahrens if (strcmp(what, DM_USE_SVM) == 0) { 438fa9e4066Sahrens vdev_error(gettext("%s is part of " 439fa9e4066Sahrens "SVM volume %s\n"), slicename, desc); 440fa9e4066Sahrens } else if (strcmp(what, DM_USE_LU) == 0) { 441fa9e4066Sahrens vdev_error(gettext("%s is in use " 442fa9e4066Sahrens "for live upgrade %s\n"), slicename, desc); 443fa9e4066Sahrens } else if (strcmp(what, DM_USE_VXVM) == 0) { 444fa9e4066Sahrens vdev_error(gettext("%s is part of " 445fa9e4066Sahrens "VxVM volume %s\n"), slicename, desc); 446fa9e4066Sahrens } else if (strcmp(what, DM_USE_FS) == 0) { 447fa9e4066Sahrens /* 448fa9e4066Sahrens * We should have already caught ZFS in-use 449fa9e4066Sahrens * filesystems above. If the ZFS version is 450fa9e4066Sahrens * different, or there was some other critical 451fa9e4066Sahrens * failure, it's possible for fstyp to report it 452fa9e4066Sahrens * as in-use, but zpool_open_by_dev() to fail. 453fa9e4066Sahrens */ 454fa9e4066Sahrens if (strcmp(desc, MNTTYPE_ZFS) != 0) 455fa9e4066Sahrens vdev_error(gettext("%s contains a %s " 456fa9e4066Sahrens "filesystem\n"), slicename, desc); 457fa9e4066Sahrens else if (!found_zfs) 458fa9e4066Sahrens vdev_error(gettext("%s is part of an " 459fa9e4066Sahrens "outdated or damaged ZFS " 460fa9e4066Sahrens "pool\n"), slicename); 461fa9e4066Sahrens } else { 462fa9e4066Sahrens vdev_error(gettext("is used by %s as %s\n"), 463fa9e4066Sahrens slicename, what, desc); 464fa9e4066Sahrens } 465fa9e4066Sahrens } else { 466fa9e4066Sahrens found = FALSE; 467fa9e4066Sahrens } 468fa9e4066Sahrens } 469fa9e4066Sahrens 470fa9e4066Sahrens /* 471fa9e4066Sahrens * Perform any overlap checking if requested to do so. 472fa9e4066Sahrens */ 473fa9e4066Sahrens if (overlap && !force) 474fa9e4066Sahrens found |= (check_overlapping(slicename, slice) != 0); 475fa9e4066Sahrens 476fa9e4066Sahrens return (found ? -1 : 0); 477fa9e4066Sahrens } 478fa9e4066Sahrens 479fa9e4066Sahrens /* 480fa9e4066Sahrens * Validate a whole disk. Iterate over all slices on the disk and make sure 481fa9e4066Sahrens * that none is in use by calling check_slice(). 482fa9e4066Sahrens */ 483fa9e4066Sahrens /* ARGSUSED */ 484fa9e4066Sahrens int 485fa9e4066Sahrens check_disk(const char *name, dm_descriptor_t disk, int force) 486fa9e4066Sahrens { 487fa9e4066Sahrens dm_descriptor_t *drive, *media, *slice; 488fa9e4066Sahrens int err = 0; 489fa9e4066Sahrens int i; 490fa9e4066Sahrens int ret; 491fa9e4066Sahrens 492fa9e4066Sahrens /* 493fa9e4066Sahrens * Get the drive associated with this disk. This should never fail, 494fa9e4066Sahrens * because we already have an alias handle open for the device. 495fa9e4066Sahrens */ 496fa9e4066Sahrens if ((drive = dm_get_associated_descriptors(disk, DM_DRIVE, 497fa9e4066Sahrens &err)) == NULL || *drive == NULL) 498fa9e4066Sahrens libdskmgt_error(err); 499fa9e4066Sahrens 500fa9e4066Sahrens if ((media = dm_get_associated_descriptors(*drive, DM_MEDIA, 501fa9e4066Sahrens &err)) == NULL) 502fa9e4066Sahrens libdskmgt_error(err); 503fa9e4066Sahrens 504fa9e4066Sahrens dm_free_descriptors(drive); 505fa9e4066Sahrens 506fa9e4066Sahrens /* 507fa9e4066Sahrens * It is possible that the user has specified a removable media drive, 508fa9e4066Sahrens * and the media is not present. 509fa9e4066Sahrens */ 510fa9e4066Sahrens if (*media == NULL) { 511fa9e4066Sahrens vdev_error(gettext("'%s' has no media in drive\n"), name); 512fa9e4066Sahrens dm_free_descriptors(media); 513fa9e4066Sahrens return (-1); 514fa9e4066Sahrens } 515fa9e4066Sahrens 516fa9e4066Sahrens if ((slice = dm_get_associated_descriptors(*media, DM_SLICE, 517fa9e4066Sahrens &err)) == NULL) 518fa9e4066Sahrens libdskmgt_error(err); 519fa9e4066Sahrens 520fa9e4066Sahrens dm_free_descriptors(media); 521fa9e4066Sahrens 522fa9e4066Sahrens ret = 0; 523fa9e4066Sahrens 524fa9e4066Sahrens /* 525fa9e4066Sahrens * Iterate over all slices and report any errors. We don't care about 526fa9e4066Sahrens * overlapping slices because we are using the whole disk. 527fa9e4066Sahrens */ 528fa9e4066Sahrens for (i = 0; slice[i] != NULL; i++) { 529fa9e4066Sahrens if (check_slice(dm_get_name(slice[i], &err), slice[i], 530fa9e4066Sahrens force, FALSE) != 0) 531fa9e4066Sahrens ret = -1; 532fa9e4066Sahrens } 533fa9e4066Sahrens 534fa9e4066Sahrens dm_free_descriptors(slice); 535fa9e4066Sahrens return (ret); 536fa9e4066Sahrens } 537fa9e4066Sahrens 538fa9e4066Sahrens 539fa9e4066Sahrens /* 540fa9e4066Sahrens * Validate a device. Determines whether the device is a disk, slice, or 541fa9e4066Sahrens * partition, and passes it off to an appropriate function. 542fa9e4066Sahrens */ 543fa9e4066Sahrens int 544fa9e4066Sahrens check_device(const char *path, int force) 545fa9e4066Sahrens { 546fa9e4066Sahrens dm_descriptor_t desc; 547fa9e4066Sahrens int err; 548fa9e4066Sahrens char *dev, rpath[MAXPATHLEN]; 549fa9e4066Sahrens 550fa9e4066Sahrens /* 551fa9e4066Sahrens * For whole disks, libdiskmgt does not include the leading dev path. 552fa9e4066Sahrens */ 553fa9e4066Sahrens dev = strrchr(path, '/'); 554fa9e4066Sahrens assert(dev != NULL); 555fa9e4066Sahrens dev++; 556fa9e4066Sahrens if ((desc = dm_get_descriptor_by_name(DM_ALIAS, dev, &err)) != NULL) 557fa9e4066Sahrens return (check_disk(path, desc, force)); 558fa9e4066Sahrens 559fa9e4066Sahrens /* 560fa9e4066Sahrens * If 'err' is not ENODEV, then we've had an unexpected error from 561fa9e4066Sahrens * libdiskmgt. The only explanation is that we ran out of memory. 562fa9e4066Sahrens */ 563fa9e4066Sahrens if (err != ENODEV) 564fa9e4066Sahrens libdskmgt_error(err); 565fa9e4066Sahrens 566fa9e4066Sahrens /* 567fa9e4066Sahrens * Determine if this is a slice. 568fa9e4066Sahrens */ 569fa9e4066Sahrens if ((desc = dm_get_descriptor_by_name(DM_SLICE, (char *)path, &err)) 570fa9e4066Sahrens != NULL) 571fa9e4066Sahrens return (check_slice(path, desc, force, TRUE)); 572fa9e4066Sahrens 573fa9e4066Sahrens if (err != ENODEV) 574fa9e4066Sahrens libdskmgt_error(err); 575fa9e4066Sahrens 576fa9e4066Sahrens /* 577fa9e4066Sahrens * Check for a partition. libdiskmgt expects path of /dev/rdsk when 578fa9e4066Sahrens * dealing with partitions, so convert it. 579fa9e4066Sahrens */ 580fa9e4066Sahrens (void) snprintf(rpath, sizeof (rpath), "/dev/rdsk/%s", dev); 581fa9e4066Sahrens if ((desc = dm_get_descriptor_by_name(DM_PARTITION, rpath, &err)) 582fa9e4066Sahrens != NULL) { 583fa9e4066Sahrens /* XXZFS perform checking on partitions */ 584fa9e4066Sahrens return (0); 585fa9e4066Sahrens } 586fa9e4066Sahrens 587fa9e4066Sahrens if (err != ENODEV) 588fa9e4066Sahrens libdskmgt_error(err); 589fa9e4066Sahrens 590fa9e4066Sahrens /* 591fa9e4066Sahrens * At this point, libdiskmgt failed to find the device as either a whole 592fa9e4066Sahrens * disk or a slice. Ignore these errors, as we know that it at least a 593fa9e4066Sahrens * block device. The user may have provided us with some unknown device 594fa9e4066Sahrens * that libdiskmgt doesn't know about. 595fa9e4066Sahrens */ 596fa9e4066Sahrens return (0); 597fa9e4066Sahrens } 598fa9e4066Sahrens 599fa9e4066Sahrens /* 600fa9e4066Sahrens * Check that a file is valid. All we can do in this case is check that it's 601fa9e4066Sahrens * not in use by another pool. 602fa9e4066Sahrens */ 603fa9e4066Sahrens int 604fa9e4066Sahrens check_file(const char *file, int force) 605fa9e4066Sahrens { 606fa9e4066Sahrens char *desc, *name; 607fa9e4066Sahrens int fd; 608fa9e4066Sahrens int ret = 0; 609fa9e4066Sahrens 610fa9e4066Sahrens if ((fd = open(file, O_RDONLY)) < 0) 611fa9e4066Sahrens return (0); 612fa9e4066Sahrens 613fa9e4066Sahrens if (zpool_in_use(fd, &desc, &name)) { 614fa9e4066Sahrens if (strcmp(desc, gettext("active")) == 0 || 615fa9e4066Sahrens !force) { 616fa9e4066Sahrens vdev_error(gettext("%s is part of %s pool '%s'\n"), 617fa9e4066Sahrens file, desc, name); 618fa9e4066Sahrens ret = -1; 619fa9e4066Sahrens } 620fa9e4066Sahrens 621fa9e4066Sahrens free(desc); 622fa9e4066Sahrens free(name); 623fa9e4066Sahrens } 624fa9e4066Sahrens 625fa9e4066Sahrens (void) close(fd); 626fa9e4066Sahrens return (ret); 627fa9e4066Sahrens } 628fa9e4066Sahrens 629fa9e4066Sahrens static int 630fa9e4066Sahrens is_whole_disk(const char *arg, struct stat64 *statbuf) 631fa9e4066Sahrens { 632fa9e4066Sahrens char path[MAXPATHLEN]; 633fa9e4066Sahrens 634fa9e4066Sahrens (void) snprintf(path, sizeof (path), "%s%s", arg, BACKUP_SLICE); 635fa9e4066Sahrens if (stat64(path, statbuf) == 0) 636fa9e4066Sahrens return (TRUE); 637fa9e4066Sahrens 638fa9e4066Sahrens return (FALSE); 639fa9e4066Sahrens } 640fa9e4066Sahrens 641fa9e4066Sahrens /* 642fa9e4066Sahrens * Create a leaf vdev. Determine if this is a file or a device. If it's a 643fa9e4066Sahrens * device, fill in the device id to make a complete nvlist. Valid forms for a 644fa9e4066Sahrens * leaf vdev are: 645fa9e4066Sahrens * 646fa9e4066Sahrens * /dev/dsk/xxx Complete disk path 647fa9e4066Sahrens * /xxx Full path to file 648fa9e4066Sahrens * xxx Shorthand for /dev/dsk/xxx 649fa9e4066Sahrens */ 650fa9e4066Sahrens nvlist_t * 651fa9e4066Sahrens make_leaf_vdev(const char *arg) 652fa9e4066Sahrens { 653fa9e4066Sahrens char path[MAXPATHLEN]; 654fa9e4066Sahrens struct stat64 statbuf; 655fa9e4066Sahrens nvlist_t *vdev = NULL; 656fa9e4066Sahrens char *type = NULL; 657fa9e4066Sahrens int wholedisk = FALSE; 658fa9e4066Sahrens 659fa9e4066Sahrens /* 660fa9e4066Sahrens * Determine what type of vdev this is, and put the full path into 661fa9e4066Sahrens * 'path'. We detect whether this is a device of file afterwards by 662fa9e4066Sahrens * checking the st_mode of the file. 663fa9e4066Sahrens */ 664fa9e4066Sahrens if (arg[0] == '/') { 665fa9e4066Sahrens /* 666fa9e4066Sahrens * Complete device or file path. Exact type is determined by 667fa9e4066Sahrens * examining the file descriptor afterwards. 668fa9e4066Sahrens */ 669fa9e4066Sahrens if (is_whole_disk(arg, &statbuf)) { 670fa9e4066Sahrens wholedisk = TRUE; 671fa9e4066Sahrens } else if (stat64(arg, &statbuf) != 0) { 672fa9e4066Sahrens (void) fprintf(stderr, 673fa9e4066Sahrens gettext("cannot open '%s': %s\n"), 674fa9e4066Sahrens arg, strerror(errno)); 675fa9e4066Sahrens return (NULL); 676fa9e4066Sahrens } 677fa9e4066Sahrens 678fa9e4066Sahrens (void) strlcpy(path, arg, sizeof (path)); 679fa9e4066Sahrens } else { 680fa9e4066Sahrens /* 681fa9e4066Sahrens * This may be a short path for a device, or it could be total 682fa9e4066Sahrens * gibberish. Check to see if it's a known device in 683fa9e4066Sahrens * /dev/dsk/. As part of this check, see if we've been given a 684fa9e4066Sahrens * an entire disk (minus the slice number). 685fa9e4066Sahrens */ 686fa9e4066Sahrens (void) snprintf(path, sizeof (path), "%s/%s", DISK_ROOT, 687fa9e4066Sahrens arg); 688fa9e4066Sahrens if (is_whole_disk(path, &statbuf)) { 689fa9e4066Sahrens wholedisk = TRUE; 690fa9e4066Sahrens } else if (stat64(path, &statbuf) != 0) { 691fa9e4066Sahrens /* 692fa9e4066Sahrens * If we got ENOENT, then the user gave us 693fa9e4066Sahrens * gibberish, so try to direct them with a 694fa9e4066Sahrens * reasonable error message. Otherwise, 695fa9e4066Sahrens * regurgitate strerror() since it's the best we 696fa9e4066Sahrens * can do. 697fa9e4066Sahrens */ 698fa9e4066Sahrens if (errno == ENOENT) { 699fa9e4066Sahrens (void) fprintf(stderr, 700fa9e4066Sahrens gettext("cannot open '%s': no such " 701fa9e4066Sahrens "device in %s\n"), arg, DISK_ROOT); 702fa9e4066Sahrens (void) fprintf(stderr, 703fa9e4066Sahrens gettext("must be a full path or " 704fa9e4066Sahrens "shorthand device name\n")); 705fa9e4066Sahrens return (NULL); 706fa9e4066Sahrens } else { 707fa9e4066Sahrens (void) fprintf(stderr, 708fa9e4066Sahrens gettext("cannot open '%s': %s\n"), 709fa9e4066Sahrens path, strerror(errno)); 710fa9e4066Sahrens return (NULL); 711fa9e4066Sahrens } 712fa9e4066Sahrens } 713fa9e4066Sahrens } 714fa9e4066Sahrens 715fa9e4066Sahrens /* 716fa9e4066Sahrens * Determine whether this is a device or a file. 717fa9e4066Sahrens */ 718fa9e4066Sahrens if (S_ISBLK(statbuf.st_mode)) { 719fa9e4066Sahrens type = VDEV_TYPE_DISK; 720fa9e4066Sahrens } else if (S_ISREG(statbuf.st_mode)) { 721fa9e4066Sahrens type = VDEV_TYPE_FILE; 722fa9e4066Sahrens } else { 723fa9e4066Sahrens (void) fprintf(stderr, gettext("cannot use '%s': must be a " 724fa9e4066Sahrens "block device or regular file\n"), path); 725fa9e4066Sahrens return (NULL); 726fa9e4066Sahrens } 727fa9e4066Sahrens 728fa9e4066Sahrens /* 729fa9e4066Sahrens * Finally, we have the complete device or file, and we know that it is 730fa9e4066Sahrens * acceptable to use. Construct the nvlist to describe this vdev. All 731fa9e4066Sahrens * vdevs have a 'path' element, and devices also have a 'devid' element. 732fa9e4066Sahrens */ 733fa9e4066Sahrens verify(nvlist_alloc(&vdev, NV_UNIQUE_NAME, 0) == 0); 734fa9e4066Sahrens verify(nvlist_add_string(vdev, ZPOOL_CONFIG_PATH, path) == 0); 735fa9e4066Sahrens verify(nvlist_add_string(vdev, ZPOOL_CONFIG_TYPE, type) == 0); 736*afefbcddSeschrock if (strcmp(type, VDEV_TYPE_DISK) == 0) 737*afefbcddSeschrock verify(nvlist_add_uint64(vdev, ZPOOL_CONFIG_WHOLE_DISK, 738*afefbcddSeschrock (uint64_t)wholedisk) == 0); 739fa9e4066Sahrens 740fa9e4066Sahrens /* 741fa9e4066Sahrens * For a whole disk, defer getting its devid until after labeling it. 742fa9e4066Sahrens */ 743fa9e4066Sahrens if (S_ISBLK(statbuf.st_mode) && !wholedisk) { 744fa9e4066Sahrens /* 745fa9e4066Sahrens * Get the devid for the device. 746fa9e4066Sahrens */ 747fa9e4066Sahrens int fd; 748fa9e4066Sahrens ddi_devid_t devid; 749fa9e4066Sahrens char *minor = NULL, *devid_str = NULL; 750fa9e4066Sahrens 751fa9e4066Sahrens if ((fd = open(path, O_RDONLY)) < 0) { 752fa9e4066Sahrens (void) fprintf(stderr, gettext("cannot open '%s': " 753fa9e4066Sahrens "%s\n"), path, strerror(errno)); 754fa9e4066Sahrens nvlist_free(vdev); 755fa9e4066Sahrens return (NULL); 756fa9e4066Sahrens } 757fa9e4066Sahrens 758fa9e4066Sahrens if (devid_get(fd, &devid) == 0) { 759fa9e4066Sahrens if (devid_get_minor_name(fd, &minor) == 0 && 760fa9e4066Sahrens (devid_str = devid_str_encode(devid, minor)) != 761fa9e4066Sahrens NULL) { 762fa9e4066Sahrens verify(nvlist_add_string(vdev, 763fa9e4066Sahrens ZPOOL_CONFIG_DEVID, devid_str) == 0); 764fa9e4066Sahrens } 765fa9e4066Sahrens if (devid_str != NULL) 766fa9e4066Sahrens devid_str_free(devid_str); 767fa9e4066Sahrens if (minor != NULL) 768fa9e4066Sahrens devid_str_free(minor); 769fa9e4066Sahrens devid_free(devid); 770fa9e4066Sahrens } 771fa9e4066Sahrens 772fa9e4066Sahrens (void) close(fd); 773fa9e4066Sahrens } 774fa9e4066Sahrens 775fa9e4066Sahrens return (vdev); 776fa9e4066Sahrens } 777fa9e4066Sahrens 778fa9e4066Sahrens /* 779fa9e4066Sahrens * Go through and verify the replication level of the pool is consistent. 780fa9e4066Sahrens * Performs the following checks: 781fa9e4066Sahrens * 782fa9e4066Sahrens * For the new spec, verifies that devices in mirrors and raidz are the 783fa9e4066Sahrens * same size. 784fa9e4066Sahrens * 785fa9e4066Sahrens * If the current configuration already has inconsistent replication 786fa9e4066Sahrens * levels, ignore any other potential problems in the new spec. 787fa9e4066Sahrens * 788fa9e4066Sahrens * Otherwise, make sure that the current spec (if there is one) and the new 789fa9e4066Sahrens * spec have consistent replication levels. 790fa9e4066Sahrens */ 791fa9e4066Sahrens typedef struct replication_level { 792fa9e4066Sahrens char *type; 793fa9e4066Sahrens int level; 794fa9e4066Sahrens } replication_level_t; 795fa9e4066Sahrens 796fa9e4066Sahrens /* 797fa9e4066Sahrens * Given a list of toplevel vdevs, return the current replication level. If 798fa9e4066Sahrens * the config is inconsistent, then NULL is returned. If 'fatal' is set, then 799fa9e4066Sahrens * an error message will be displayed for each self-inconsistent vdev. 800fa9e4066Sahrens */ 801fa9e4066Sahrens replication_level_t * 802fa9e4066Sahrens get_replication(nvlist_t *nvroot, int fatal) 803fa9e4066Sahrens { 804fa9e4066Sahrens nvlist_t **top; 805fa9e4066Sahrens uint_t t, toplevels; 806fa9e4066Sahrens nvlist_t **child; 807fa9e4066Sahrens uint_t c, children; 808fa9e4066Sahrens nvlist_t *nv; 809fa9e4066Sahrens char *type; 810fa9e4066Sahrens replication_level_t lastrep, rep, *ret; 811fa9e4066Sahrens int dontreport; 812fa9e4066Sahrens 813fa9e4066Sahrens ret = safe_malloc(sizeof (replication_level_t)); 814fa9e4066Sahrens 815fa9e4066Sahrens verify(nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN, 816fa9e4066Sahrens &top, &toplevels) == 0); 817fa9e4066Sahrens 818fa9e4066Sahrens lastrep.type = NULL; 819fa9e4066Sahrens for (t = 0; t < toplevels; t++) { 820fa9e4066Sahrens nv = top[t]; 821fa9e4066Sahrens 822fa9e4066Sahrens verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0); 823fa9e4066Sahrens 824fa9e4066Sahrens if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 825fa9e4066Sahrens &child, &children) != 0) { 826fa9e4066Sahrens /* 827fa9e4066Sahrens * This is a 'file' or 'disk' vdev. 828fa9e4066Sahrens */ 829fa9e4066Sahrens rep.type = type; 830fa9e4066Sahrens rep.level = 1; 831fa9e4066Sahrens } else { 832fa9e4066Sahrens uint64_t vdev_size; 833fa9e4066Sahrens 834fa9e4066Sahrens /* 835fa9e4066Sahrens * This is a mirror or RAID-Z vdev. Go through and make 836fa9e4066Sahrens * sure the contents are all the same (files vs. disks), 837fa9e4066Sahrens * keeping track of the number of elements in the 838fa9e4066Sahrens * process. 839fa9e4066Sahrens * 840fa9e4066Sahrens * We also check that the size of each vdev (if it can 841fa9e4066Sahrens * be determined) is the same. 842fa9e4066Sahrens */ 843fa9e4066Sahrens rep.type = type; 844fa9e4066Sahrens rep.level = 0; 845fa9e4066Sahrens 846fa9e4066Sahrens /* 847fa9e4066Sahrens * The 'dontreport' variable indicatest that we've 848fa9e4066Sahrens * already reported an error for this spec, so don't 849fa9e4066Sahrens * bother doing it again. 850fa9e4066Sahrens */ 851fa9e4066Sahrens type = NULL; 852fa9e4066Sahrens dontreport = 0; 853fa9e4066Sahrens vdev_size = -1ULL; 854fa9e4066Sahrens for (c = 0; c < children; c++) { 855fa9e4066Sahrens nvlist_t *cnv = child[c]; 856fa9e4066Sahrens char *path; 857fa9e4066Sahrens struct stat64 statbuf; 858fa9e4066Sahrens uint64_t size = -1ULL; 859fa9e4066Sahrens char *childtype; 860fa9e4066Sahrens int fd, err; 861fa9e4066Sahrens 862fa9e4066Sahrens rep.level++; 863fa9e4066Sahrens 864fa9e4066Sahrens verify(nvlist_lookup_string(cnv, 865fa9e4066Sahrens ZPOOL_CONFIG_TYPE, &childtype) == 0); 866fa9e4066Sahrens verify(nvlist_lookup_string(cnv, 867fa9e4066Sahrens ZPOOL_CONFIG_PATH, &path) == 0); 868fa9e4066Sahrens 869fa9e4066Sahrens /* 870fa9e4066Sahrens * If we have a raidz/mirror that combines disks 871fa9e4066Sahrens * with files, report it as an error. 872fa9e4066Sahrens */ 873fa9e4066Sahrens if (!dontreport && type != NULL && 874fa9e4066Sahrens strcmp(type, childtype) != 0) { 875fa9e4066Sahrens if (ret != NULL) 876fa9e4066Sahrens free(ret); 877fa9e4066Sahrens ret = NULL; 878fa9e4066Sahrens if (fatal) 879fa9e4066Sahrens vdev_error(gettext( 880fa9e4066Sahrens "mismatched replication " 881fa9e4066Sahrens "level: %s contains both " 882fa9e4066Sahrens "files and devices\n"), 883fa9e4066Sahrens rep.type); 884fa9e4066Sahrens else 885fa9e4066Sahrens return (NULL); 886fa9e4066Sahrens dontreport = TRUE; 887fa9e4066Sahrens } 888fa9e4066Sahrens 889fa9e4066Sahrens /* 890fa9e4066Sahrens * According to stat(2), the value of 'st_size' 891fa9e4066Sahrens * is undefined for block devices and character 892fa9e4066Sahrens * devices. But there is no effective way to 893fa9e4066Sahrens * determine the real size in userland. 894fa9e4066Sahrens * 895fa9e4066Sahrens * Instead, we'll take advantage of an 896fa9e4066Sahrens * implementation detail of spec_size(). If the 897fa9e4066Sahrens * device is currently open, then we (should) 898fa9e4066Sahrens * return a valid size. 899fa9e4066Sahrens * 900fa9e4066Sahrens * If we still don't get a valid size (indicated 901fa9e4066Sahrens * by a size of 0 or MAXOFFSET_T), then ignore 902fa9e4066Sahrens * this device altogether. 903fa9e4066Sahrens */ 904fa9e4066Sahrens if ((fd = open(path, O_RDONLY)) >= 0) { 905fa9e4066Sahrens err = fstat64(fd, &statbuf); 906fa9e4066Sahrens (void) close(fd); 907fa9e4066Sahrens } else { 908fa9e4066Sahrens err = stat64(path, &statbuf); 909fa9e4066Sahrens } 910fa9e4066Sahrens 911fa9e4066Sahrens if (err != 0 || 912fa9e4066Sahrens statbuf.st_size == 0 || 913fa9e4066Sahrens statbuf.st_size == MAXOFFSET_T) 914fa9e4066Sahrens continue; 915fa9e4066Sahrens 916fa9e4066Sahrens size = statbuf.st_size; 917fa9e4066Sahrens 918fa9e4066Sahrens /* 919fa9e4066Sahrens * Also check the size of each device. If they 920fa9e4066Sahrens * differ, then report an error. 921fa9e4066Sahrens */ 922fa9e4066Sahrens if (!dontreport && vdev_size != -1ULL && 923fa9e4066Sahrens size != vdev_size) { 924fa9e4066Sahrens if (ret != NULL) 925fa9e4066Sahrens free(ret); 926fa9e4066Sahrens ret = NULL; 927fa9e4066Sahrens if (fatal) 928fa9e4066Sahrens vdev_error(gettext( 929fa9e4066Sahrens "%s contains devices of " 930fa9e4066Sahrens "different sizes\n"), 931fa9e4066Sahrens rep.type); 932fa9e4066Sahrens else 933fa9e4066Sahrens return (NULL); 934fa9e4066Sahrens dontreport = TRUE; 935fa9e4066Sahrens } 936fa9e4066Sahrens 937fa9e4066Sahrens type = childtype; 938fa9e4066Sahrens vdev_size = size; 939fa9e4066Sahrens } 940fa9e4066Sahrens } 941fa9e4066Sahrens 942fa9e4066Sahrens /* 943fa9e4066Sahrens * At this point, we have the replication of the last toplevel 944fa9e4066Sahrens * vdev in 'rep'. Compare it to 'lastrep' to see if its 945fa9e4066Sahrens * different. 946fa9e4066Sahrens */ 947fa9e4066Sahrens if (lastrep.type != NULL) { 948fa9e4066Sahrens if (strcmp(lastrep.type, rep.type) != 0) { 949fa9e4066Sahrens if (ret != NULL) 950fa9e4066Sahrens free(ret); 951fa9e4066Sahrens ret = NULL; 952fa9e4066Sahrens if (fatal) 953fa9e4066Sahrens vdev_error(gettext( 954fa9e4066Sahrens "mismatched replication " 955fa9e4066Sahrens "level: both %s and %s vdevs are " 956fa9e4066Sahrens "present\n"), 957fa9e4066Sahrens lastrep.type, rep.type); 958fa9e4066Sahrens else 959fa9e4066Sahrens return (NULL); 960fa9e4066Sahrens } else if (lastrep.level != rep.level) { 961fa9e4066Sahrens if (ret) 962fa9e4066Sahrens free(ret); 963fa9e4066Sahrens ret = NULL; 964fa9e4066Sahrens if (fatal) 965fa9e4066Sahrens vdev_error(gettext( 966fa9e4066Sahrens "mismatched replication " 967fa9e4066Sahrens "level: %d-way %s and %d-way %s " 968fa9e4066Sahrens "vdevs are present\n"), 969fa9e4066Sahrens lastrep.level, lastrep.type, 970fa9e4066Sahrens rep.level, rep.type); 971fa9e4066Sahrens else 972fa9e4066Sahrens return (NULL); 973fa9e4066Sahrens } 974fa9e4066Sahrens } 975fa9e4066Sahrens lastrep = rep; 976fa9e4066Sahrens } 977fa9e4066Sahrens 978fa9e4066Sahrens if (ret != NULL) { 979fa9e4066Sahrens ret->type = rep.type; 980fa9e4066Sahrens ret->level = rep.level; 981fa9e4066Sahrens } 982fa9e4066Sahrens 983fa9e4066Sahrens return (ret); 984fa9e4066Sahrens } 985fa9e4066Sahrens 986fa9e4066Sahrens /* 987fa9e4066Sahrens * Check the replication level of the vdev spec against the current pool. Calls 988fa9e4066Sahrens * get_replication() to make sure the new spec is self-consistent. If the pool 989fa9e4066Sahrens * has a consistent replication level, then we ignore any errors. Otherwise, 990fa9e4066Sahrens * report any difference between the two. 991fa9e4066Sahrens */ 992fa9e4066Sahrens int 993fa9e4066Sahrens check_replication(nvlist_t *config, nvlist_t *newroot) 994fa9e4066Sahrens { 995fa9e4066Sahrens replication_level_t *current = NULL, *new; 996fa9e4066Sahrens int ret; 997fa9e4066Sahrens 998fa9e4066Sahrens /* 999fa9e4066Sahrens * If we have a current pool configuration, check to see if it's 1000fa9e4066Sahrens * self-consistent. If not, simply return success. 1001fa9e4066Sahrens */ 1002fa9e4066Sahrens if (config != NULL) { 1003fa9e4066Sahrens nvlist_t *nvroot; 1004fa9e4066Sahrens 1005fa9e4066Sahrens verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 1006fa9e4066Sahrens &nvroot) == 0); 1007fa9e4066Sahrens if ((current = get_replication(nvroot, FALSE)) == NULL) 1008fa9e4066Sahrens return (0); 1009fa9e4066Sahrens } 1010fa9e4066Sahrens 1011fa9e4066Sahrens /* 1012fa9e4066Sahrens * Get the replication level of the new vdev spec, reporting any 1013fa9e4066Sahrens * inconsistencies found. 1014fa9e4066Sahrens */ 1015fa9e4066Sahrens if ((new = get_replication(newroot, TRUE)) == NULL) { 1016fa9e4066Sahrens free(current); 1017fa9e4066Sahrens return (-1); 1018fa9e4066Sahrens } 1019fa9e4066Sahrens 1020fa9e4066Sahrens /* 1021fa9e4066Sahrens * Check to see if the new vdev spec matches the replication level of 1022fa9e4066Sahrens * the current pool. 1023fa9e4066Sahrens */ 1024fa9e4066Sahrens ret = 0; 1025fa9e4066Sahrens if (current != NULL) { 1026fa9e4066Sahrens if (strcmp(current->type, new->type) != 0 || 1027fa9e4066Sahrens current->level != new->level) { 1028fa9e4066Sahrens vdev_error(gettext( 1029fa9e4066Sahrens "mismatched replication level: pool uses %d-way %s " 1030fa9e4066Sahrens "and new vdev uses %d-way %s\n"), 1031fa9e4066Sahrens current->level, current->type, new->level, 1032fa9e4066Sahrens new->type); 1033fa9e4066Sahrens ret = -1; 1034fa9e4066Sahrens } 1035fa9e4066Sahrens } 1036fa9e4066Sahrens 1037fa9e4066Sahrens free(new); 1038fa9e4066Sahrens if (current != NULL) 1039fa9e4066Sahrens free(current); 1040fa9e4066Sahrens 1041fa9e4066Sahrens return (ret); 1042fa9e4066Sahrens } 1043fa9e4066Sahrens 1044fa9e4066Sahrens /* 1045fa9e4066Sahrens * Label an individual disk. The name provided is the short name, stripped of 1046fa9e4066Sahrens * any leading /dev path. 1047fa9e4066Sahrens */ 1048fa9e4066Sahrens int 1049fa9e4066Sahrens label_disk(char *name) 1050fa9e4066Sahrens { 1051fa9e4066Sahrens char path[MAXPATHLEN]; 1052fa9e4066Sahrens struct dk_gpt *vtoc; 1053fa9e4066Sahrens int fd; 1054fa9e4066Sahrens size_t resv = 16384; 1055fa9e4066Sahrens 1056fa9e4066Sahrens (void) snprintf(path, sizeof (path), "%s/%s%s", RDISK_ROOT, name, 1057fa9e4066Sahrens BACKUP_SLICE); 1058fa9e4066Sahrens 1059fa9e4066Sahrens if ((fd = open(path, O_RDWR | O_NDELAY)) < 0) { 1060fa9e4066Sahrens /* 1061fa9e4066Sahrens * This shouldn't happen. We've long since verified that this 1062fa9e4066Sahrens * is a valid device. 1063fa9e4066Sahrens */ 1064fa9e4066Sahrens (void) fprintf(stderr, gettext("cannot open '%s': %s\n"), 1065fa9e4066Sahrens path, strerror(errno)); 1066fa9e4066Sahrens return (-1); 1067fa9e4066Sahrens } 1068fa9e4066Sahrens 1069fa9e4066Sahrens 1070fa9e4066Sahrens if (efi_alloc_and_init(fd, 9, &vtoc) != 0) { 1071fa9e4066Sahrens /* 1072fa9e4066Sahrens * The only way this can fail is if we run out of memory, or we 1073fa9e4066Sahrens * were unable to read the disk geometry. 1074fa9e4066Sahrens */ 1075fa9e4066Sahrens if (errno == ENOMEM) 1076fa9e4066Sahrens no_memory(); 1077fa9e4066Sahrens 1078fa9e4066Sahrens (void) fprintf(stderr, gettext("cannot label '%s': unable to " 1079fa9e4066Sahrens "read disk geometry\n"), name); 1080fa9e4066Sahrens (void) close(fd); 1081fa9e4066Sahrens return (-1); 1082fa9e4066Sahrens } 1083fa9e4066Sahrens 1084fa9e4066Sahrens vtoc->efi_parts[0].p_start = vtoc->efi_first_u_lba; 1085fa9e4066Sahrens vtoc->efi_parts[0].p_size = vtoc->efi_last_u_lba + 1 - 1086fa9e4066Sahrens vtoc->efi_first_u_lba - resv; 1087fa9e4066Sahrens 1088fa9e4066Sahrens /* 1089fa9e4066Sahrens * Why we use V_USR: V_BACKUP confuses users, and is considered 1090fa9e4066Sahrens * disposable by some EFI utilities (since EFI doesn't have a backup 1091fa9e4066Sahrens * slice). V_UNASSIGNED is supposed to be used only for zero size 1092fa9e4066Sahrens * partitions, and efi_write() will fail if we use it. V_ROOT, V_BOOT, 1093fa9e4066Sahrens * etc. were all pretty specific. V_USR is as close to reality as we 1094fa9e4066Sahrens * can get, in the absence of V_OTHER. 1095fa9e4066Sahrens */ 1096fa9e4066Sahrens vtoc->efi_parts[0].p_tag = V_USR; 1097fa9e4066Sahrens (void) strcpy(vtoc->efi_parts[0].p_name, "zfs"); 1098fa9e4066Sahrens 1099fa9e4066Sahrens vtoc->efi_parts[8].p_start = vtoc->efi_last_u_lba + 1 - resv; 1100fa9e4066Sahrens vtoc->efi_parts[8].p_size = resv; 1101fa9e4066Sahrens vtoc->efi_parts[8].p_tag = V_RESERVED; 1102fa9e4066Sahrens 1103fa9e4066Sahrens if (efi_write(fd, vtoc) != 0) { 1104fa9e4066Sahrens /* 1105fa9e4066Sahrens * Currently, EFI labels are not supported for IDE disks, and it 1106fa9e4066Sahrens * is likely that they will not be supported on other drives for 1107fa9e4066Sahrens * some time. Print out a helpful error message directing the 1108fa9e4066Sahrens * user to manually label the disk and give a specific slice. 1109fa9e4066Sahrens */ 1110fa9e4066Sahrens (void) fprintf(stderr, gettext("cannot label '%s': failed to " 1111fa9e4066Sahrens "write EFI label\n"), name); 1112fa9e4066Sahrens (void) fprintf(stderr, gettext("use fdisk(1M) to partition " 1113fa9e4066Sahrens "the disk, and provide a specific slice\n")); 1114fa9e4066Sahrens (void) close(fd); 1115fa9e4066Sahrens return (-1); 1116fa9e4066Sahrens } 1117fa9e4066Sahrens 1118fa9e4066Sahrens (void) close(fd); 1119fa9e4066Sahrens return (0); 1120fa9e4066Sahrens } 1121fa9e4066Sahrens 1122fa9e4066Sahrens /* 1123fa9e4066Sahrens * Go through and find any whole disks in the vdev specification, labelling them 1124fa9e4066Sahrens * as appropriate. When constructing the vdev spec, we were unable to open this 1125fa9e4066Sahrens * device in order to provide a devid. Now that we have labelled the disk and 1126fa9e4066Sahrens * know that slice 0 is valid, we can construct the devid now. 1127fa9e4066Sahrens * 1128fa9e4066Sahrens * If the disk was already labelled with an EFI label, we will have gotten the 1129fa9e4066Sahrens * devid already (because we were able to open the whole disk). Otherwise, we 1130fa9e4066Sahrens * need to get the devid after we label the disk. 1131fa9e4066Sahrens */ 1132fa9e4066Sahrens int 1133fa9e4066Sahrens make_disks(nvlist_t *nv) 1134fa9e4066Sahrens { 1135fa9e4066Sahrens nvlist_t **child; 1136fa9e4066Sahrens uint_t c, children; 1137fa9e4066Sahrens char *type, *path, *diskname; 1138fa9e4066Sahrens char buf[MAXPATHLEN]; 1139*afefbcddSeschrock uint64_t wholedisk; 1140fa9e4066Sahrens int fd; 1141fa9e4066Sahrens int ret; 1142fa9e4066Sahrens ddi_devid_t devid; 1143fa9e4066Sahrens char *minor = NULL, *devid_str = NULL; 1144fa9e4066Sahrens 1145fa9e4066Sahrens verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0); 1146fa9e4066Sahrens 1147fa9e4066Sahrens if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 1148fa9e4066Sahrens &child, &children) != 0) { 1149fa9e4066Sahrens 1150fa9e4066Sahrens if (strcmp(type, VDEV_TYPE_DISK) != 0) 1151fa9e4066Sahrens return (0); 1152fa9e4066Sahrens 1153fa9e4066Sahrens /* 1154fa9e4066Sahrens * We have a disk device. Get the path to the device 1155fa9e4066Sahrens * and see if its a whole disk by appending the backup 1156fa9e4066Sahrens * slice and stat()ing the device. 1157fa9e4066Sahrens */ 1158fa9e4066Sahrens verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0); 1159fa9e4066Sahrens 1160*afefbcddSeschrock if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK, 1161*afefbcddSeschrock &wholedisk) != 0 || !wholedisk) 1162fa9e4066Sahrens return (0); 1163fa9e4066Sahrens 1164fa9e4066Sahrens diskname = strrchr(path, '/'); 1165fa9e4066Sahrens assert(diskname != NULL); 1166fa9e4066Sahrens diskname++; 1167fa9e4066Sahrens if (label_disk(diskname) != 0) 1168fa9e4066Sahrens return (-1); 1169fa9e4066Sahrens 1170fa9e4066Sahrens /* 1171fa9e4066Sahrens * Fill in the devid, now that we've labeled the disk. 1172fa9e4066Sahrens */ 1173fa9e4066Sahrens (void) snprintf(buf, sizeof (buf), "%ss0", path); 1174fa9e4066Sahrens if ((fd = open(buf, O_RDONLY)) < 0) { 1175fa9e4066Sahrens (void) fprintf(stderr, 1176fa9e4066Sahrens gettext("cannot open '%s': %s\n"), 1177fa9e4066Sahrens buf, strerror(errno)); 1178fa9e4066Sahrens return (-1); 1179fa9e4066Sahrens } 1180fa9e4066Sahrens 1181fa9e4066Sahrens if (devid_get(fd, &devid) == 0) { 1182fa9e4066Sahrens if (devid_get_minor_name(fd, &minor) == 0 && 1183fa9e4066Sahrens (devid_str = devid_str_encode(devid, minor)) != 1184fa9e4066Sahrens NULL) { 1185fa9e4066Sahrens verify(nvlist_add_string(nv, 1186fa9e4066Sahrens ZPOOL_CONFIG_DEVID, devid_str) == 0); 1187fa9e4066Sahrens } 1188fa9e4066Sahrens if (devid_str != NULL) 1189fa9e4066Sahrens devid_str_free(devid_str); 1190fa9e4066Sahrens if (minor != NULL) 1191fa9e4066Sahrens devid_str_free(minor); 1192fa9e4066Sahrens devid_free(devid); 1193fa9e4066Sahrens } 1194fa9e4066Sahrens 1195*afefbcddSeschrock /* 1196*afefbcddSeschrock * Update the path to refer to the 's0' slice. The presence of 1197*afefbcddSeschrock * the 'whole_disk' field indicates to the CLI that we should 1198*afefbcddSeschrock * chop off the slice number when displaying the device in 1199*afefbcddSeschrock * future output. 1200*afefbcddSeschrock */ 1201*afefbcddSeschrock verify(nvlist_add_string(nv, ZPOOL_CONFIG_PATH, buf) == 0); 1202*afefbcddSeschrock 1203fa9e4066Sahrens (void) close(fd); 1204fa9e4066Sahrens 1205fa9e4066Sahrens return (0); 1206fa9e4066Sahrens } 1207fa9e4066Sahrens 1208fa9e4066Sahrens for (c = 0; c < children; c++) 1209fa9e4066Sahrens if ((ret = make_disks(child[c])) != 0) 1210fa9e4066Sahrens return (ret); 1211fa9e4066Sahrens 1212fa9e4066Sahrens return (0); 1213fa9e4066Sahrens } 1214fa9e4066Sahrens 1215fa9e4066Sahrens /* 1216fa9e4066Sahrens * Go through and find any devices that are in use. We rely on libdiskmgt for 1217fa9e4066Sahrens * the majority of this task. 1218fa9e4066Sahrens */ 1219fa9e4066Sahrens int 1220fa9e4066Sahrens check_in_use(nvlist_t *nv, int force) 1221fa9e4066Sahrens { 1222fa9e4066Sahrens nvlist_t **child; 1223fa9e4066Sahrens uint_t c, children; 1224fa9e4066Sahrens char *type, *path; 1225fa9e4066Sahrens int ret; 1226fa9e4066Sahrens 1227fa9e4066Sahrens verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0); 1228fa9e4066Sahrens 1229fa9e4066Sahrens if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 1230fa9e4066Sahrens &child, &children) != 0) { 1231fa9e4066Sahrens 1232fa9e4066Sahrens verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0); 1233fa9e4066Sahrens 1234fa9e4066Sahrens if (strcmp(type, VDEV_TYPE_DISK) == 0) 1235fa9e4066Sahrens ret = check_device(path, force); 1236fa9e4066Sahrens 1237fa9e4066Sahrens if (strcmp(type, VDEV_TYPE_FILE) == 0) 1238fa9e4066Sahrens ret = check_file(path, force); 1239fa9e4066Sahrens 1240fa9e4066Sahrens return (ret); 1241fa9e4066Sahrens } 1242fa9e4066Sahrens 1243fa9e4066Sahrens for (c = 0; c < children; c++) 1244fa9e4066Sahrens if ((ret = check_in_use(child[c], force)) != 0) 1245fa9e4066Sahrens return (ret); 1246fa9e4066Sahrens 1247fa9e4066Sahrens return (0); 1248fa9e4066Sahrens } 1249fa9e4066Sahrens 1250fa9e4066Sahrens /* 1251fa9e4066Sahrens * Construct a syntactically valid vdev specification, 1252fa9e4066Sahrens * and ensure that all devices and files exist and can be opened. 1253fa9e4066Sahrens * Note: we don't bother freeing anything in the error paths 1254fa9e4066Sahrens * because the program is just going to exit anyway. 1255fa9e4066Sahrens */ 1256fa9e4066Sahrens nvlist_t * 1257fa9e4066Sahrens construct_spec(int argc, char **argv) 1258fa9e4066Sahrens { 1259fa9e4066Sahrens nvlist_t *nvroot, *nv, **top; 1260fa9e4066Sahrens int t, toplevels; 1261fa9e4066Sahrens 1262fa9e4066Sahrens top = NULL; 1263fa9e4066Sahrens toplevels = 0; 1264fa9e4066Sahrens 1265fa9e4066Sahrens while (argc > 0) { 1266fa9e4066Sahrens nv = NULL; 1267fa9e4066Sahrens 1268fa9e4066Sahrens /* 1269fa9e4066Sahrens * If it's a mirror or raidz, the subsequent arguments are 1270fa9e4066Sahrens * its leaves -- until we encounter the next mirror or raidz. 1271fa9e4066Sahrens */ 1272fa9e4066Sahrens if (strcmp(argv[0], VDEV_TYPE_MIRROR) == 0 || 1273fa9e4066Sahrens strcmp(argv[0], VDEV_TYPE_RAIDZ) == 0) { 1274fa9e4066Sahrens 1275fa9e4066Sahrens char *type = argv[0]; 1276fa9e4066Sahrens nvlist_t **child = NULL; 1277fa9e4066Sahrens int children = 0; 1278fa9e4066Sahrens int c; 1279fa9e4066Sahrens 1280fa9e4066Sahrens for (c = 1; c < argc; c++) { 1281fa9e4066Sahrens if (strcmp(argv[c], VDEV_TYPE_MIRROR) == 0 || 1282fa9e4066Sahrens strcmp(argv[c], VDEV_TYPE_RAIDZ) == 0) 1283fa9e4066Sahrens break; 1284fa9e4066Sahrens children++; 1285fa9e4066Sahrens child = realloc(child, 1286fa9e4066Sahrens children * sizeof (nvlist_t *)); 1287fa9e4066Sahrens if (child == NULL) 1288fa9e4066Sahrens no_memory(); 1289fa9e4066Sahrens if ((nv = make_leaf_vdev(argv[c])) == NULL) 1290fa9e4066Sahrens return (NULL); 1291fa9e4066Sahrens child[children - 1] = nv; 1292fa9e4066Sahrens } 1293fa9e4066Sahrens 1294fa9e4066Sahrens argc -= c; 1295fa9e4066Sahrens argv += c; 1296fa9e4066Sahrens 1297fa9e4066Sahrens /* 1298fa9e4066Sahrens * Mirrors and RAID-Z devices require at least 1299fa9e4066Sahrens * two components. 1300fa9e4066Sahrens */ 1301fa9e4066Sahrens if (children < 2) { 1302fa9e4066Sahrens (void) fprintf(stderr, 1303fa9e4066Sahrens gettext("invalid vdev specification: " 1304fa9e4066Sahrens "%s requires at least 2 devices\n"), type); 1305fa9e4066Sahrens return (NULL); 1306fa9e4066Sahrens } 1307fa9e4066Sahrens 1308fa9e4066Sahrens verify(nvlist_alloc(&nv, NV_UNIQUE_NAME, 0) == 0); 1309fa9e4066Sahrens verify(nvlist_add_string(nv, ZPOOL_CONFIG_TYPE, 1310fa9e4066Sahrens type) == 0); 1311fa9e4066Sahrens verify(nvlist_add_nvlist_array(nv, 1312fa9e4066Sahrens ZPOOL_CONFIG_CHILDREN, child, children) == 0); 1313fa9e4066Sahrens 1314fa9e4066Sahrens for (c = 0; c < children; c++) 1315fa9e4066Sahrens nvlist_free(child[c]); 1316fa9e4066Sahrens free(child); 1317fa9e4066Sahrens } else { 1318fa9e4066Sahrens /* 1319fa9e4066Sahrens * We have a device. Pass off to make_leaf_vdev() to 1320fa9e4066Sahrens * construct the appropriate nvlist describing the vdev. 1321fa9e4066Sahrens */ 1322fa9e4066Sahrens if ((nv = make_leaf_vdev(argv[0])) == NULL) 1323fa9e4066Sahrens return (NULL); 1324fa9e4066Sahrens argc--; 1325fa9e4066Sahrens argv++; 1326fa9e4066Sahrens } 1327fa9e4066Sahrens 1328fa9e4066Sahrens toplevels++; 1329fa9e4066Sahrens top = realloc(top, toplevels * sizeof (nvlist_t *)); 1330fa9e4066Sahrens if (top == NULL) 1331fa9e4066Sahrens no_memory(); 1332fa9e4066Sahrens top[toplevels - 1] = nv; 1333fa9e4066Sahrens } 1334fa9e4066Sahrens 1335fa9e4066Sahrens /* 1336fa9e4066Sahrens * Finally, create nvroot and add all top-level vdevs to it. 1337fa9e4066Sahrens */ 1338fa9e4066Sahrens verify(nvlist_alloc(&nvroot, NV_UNIQUE_NAME, 0) == 0); 1339fa9e4066Sahrens verify(nvlist_add_string(nvroot, ZPOOL_CONFIG_TYPE, 1340fa9e4066Sahrens VDEV_TYPE_ROOT) == 0); 1341fa9e4066Sahrens verify(nvlist_add_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN, 1342fa9e4066Sahrens top, toplevels) == 0); 1343fa9e4066Sahrens 1344fa9e4066Sahrens for (t = 0; t < toplevels; t++) 1345fa9e4066Sahrens nvlist_free(top[t]); 1346fa9e4066Sahrens free(top); 1347fa9e4066Sahrens 1348fa9e4066Sahrens return (nvroot); 1349fa9e4066Sahrens } 1350fa9e4066Sahrens 1351fa9e4066Sahrens /* 1352fa9e4066Sahrens * Get and validate the contents of the given vdev specification. This ensures 1353fa9e4066Sahrens * that the nvlist returned is well-formed, that all the devices exist, and that 1354fa9e4066Sahrens * they are not currently in use by any other known consumer. The 'poolconfig' 1355fa9e4066Sahrens * parameter is the current configuration of the pool when adding devices 1356fa9e4066Sahrens * existing pool, and is used to perform additional checks, such as changing the 1357fa9e4066Sahrens * replication level of the pool. It can be 'NULL' to indicate that this is a 1358fa9e4066Sahrens * new pool. The 'force' flag controls whether devices should be forcefully 1359fa9e4066Sahrens * added, even if they appear in use. 1360fa9e4066Sahrens */ 1361fa9e4066Sahrens nvlist_t * 1362fa9e4066Sahrens make_root_vdev(nvlist_t *poolconfig, int force, int check_rep, 1363fa9e4066Sahrens int argc, char **argv) 1364fa9e4066Sahrens { 1365fa9e4066Sahrens nvlist_t *newroot; 1366fa9e4066Sahrens 1367fa9e4066Sahrens is_force = force; 1368fa9e4066Sahrens 1369fa9e4066Sahrens /* 1370fa9e4066Sahrens * Construct the vdev specification. If this is successful, we know 1371fa9e4066Sahrens * that we have a valid specification, and that all devices can be 1372fa9e4066Sahrens * opened. 1373fa9e4066Sahrens */ 1374fa9e4066Sahrens if ((newroot = construct_spec(argc, argv)) == NULL) 1375fa9e4066Sahrens return (NULL); 1376fa9e4066Sahrens 1377fa9e4066Sahrens /* 1378fa9e4066Sahrens * Validate each device to make sure that its not shared with another 1379fa9e4066Sahrens * subsystem. We do this even if 'force' is set, because there are some 1380fa9e4066Sahrens * uses (such as a dedicated dump device) that even '-f' cannot 1381fa9e4066Sahrens * override. 1382fa9e4066Sahrens */ 1383fa9e4066Sahrens if (check_in_use(newroot, force) != 0) { 1384fa9e4066Sahrens nvlist_free(newroot); 1385fa9e4066Sahrens return (NULL); 1386fa9e4066Sahrens } 1387fa9e4066Sahrens 1388fa9e4066Sahrens /* 1389fa9e4066Sahrens * Check the replication level of the given vdevs and report any errors 1390fa9e4066Sahrens * found. We include the existing pool spec, if any, as we need to 1391fa9e4066Sahrens * catch changes against the existing replication level. 1392fa9e4066Sahrens */ 1393fa9e4066Sahrens if (check_rep && check_replication(poolconfig, newroot) != 0) { 1394fa9e4066Sahrens nvlist_free(newroot); 1395fa9e4066Sahrens return (NULL); 1396fa9e4066Sahrens } 1397fa9e4066Sahrens 1398fa9e4066Sahrens /* 1399fa9e4066Sahrens * Run through the vdev specification and label any whole disks found. 1400fa9e4066Sahrens */ 1401fa9e4066Sahrens if (make_disks(newroot) != 0) { 1402fa9e4066Sahrens nvlist_free(newroot); 1403fa9e4066Sahrens return (NULL); 1404fa9e4066Sahrens } 1405fa9e4066Sahrens 1406fa9e4066Sahrens return (newroot); 1407fa9e4066Sahrens } 1408