Print this page
NEX-3558 KRRP Integration
OS-195 itadm needs an easily parsable output mode
OS-207 SUP-817 causes lint warnings in zpool_main.c
Reviewed by: Alek Pinchuk <alek.pinchuk@nexena.com>
Reviewed by: Saso Kiselkov <saso.kiselkov@nexenta.com>
Reviewed by: Albert Lee <albert.lee@nexenta.com>
re #12585 rb4049 ZFS++ work port - refactoring to improve separation of open/closed code, bug fixes, performance improvements - open code
Bug 11205: add missing libzfs_closed_stubs.c to fix opensource-only build.
ZFS plus work: special vdevs, cos, cos/vdev properties


   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.

  24  * Copyright (c) 2013, 2015 by Delphix. All rights reserved.
  25  * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>.
  26  */
  27 
  28 /*
  29  * Functions to convert between a list of vdevs and an nvlist representing the
  30  * configuration.  Each entry in the list can be one of:
  31  *
  32  *      Device vdevs
  33  *              disk=(path=..., devid=...)
  34  *              file=(path=...)
  35  *
  36  *      Group vdevs
  37  *              raidz[1|2]=(...)
  38  *              mirror=(...)
  39  *
  40  *      Hot spares
  41  *
  42  * While the underlying implementation supports it, group vdevs cannot contain
  43  * other group vdevs.  All userland verification of devices is contained within


 370                 return (B_FALSE);
 371         if (efi_alloc_and_init(fd, EFI_NUMPAR, &label) != 0) {
 372                 (void) close(fd);
 373                 return (B_FALSE);
 374         }
 375         efi_free(label);
 376         (void) close(fd);
 377         return (B_TRUE);
 378 }
 379 
 380 /*
 381  * Create a leaf vdev.  Determine if this is a file or a device.  If it's a
 382  * device, fill in the device id to make a complete nvlist.  Valid forms for a
 383  * leaf vdev are:
 384  *
 385  *      /dev/dsk/xxx    Complete disk path
 386  *      /xxx            Full path to file
 387  *      xxx             Shorthand for /dev/dsk/xxx
 388  */
 389 static nvlist_t *
 390 make_leaf_vdev(const char *arg, uint64_t is_log)
 391 {
 392         char path[MAXPATHLEN];
 393         struct stat64 statbuf;
 394         nvlist_t *vdev = NULL;
 395         char *type = NULL;
 396         boolean_t wholedisk = B_FALSE;
 397 
 398         /*
 399          * Determine what type of vdev this is, and put the full path into
 400          * 'path'.  We detect whether this is a device of file afterwards by
 401          * checking the st_mode of the file.
 402          */
 403         if (arg[0] == '/') {
 404                 /*
 405                  * Complete device or file path.  Exact type is determined by
 406                  * examining the file descriptor afterwards.
 407                  */
 408                 wholedisk = is_whole_disk(arg);
 409                 if (!wholedisk && (stat64(arg, &statbuf) != 0)) {
 410                         (void) fprintf(stderr,


 454          */
 455         if (wholedisk || S_ISBLK(statbuf.st_mode)) {
 456                 type = VDEV_TYPE_DISK;
 457         } else if (S_ISREG(statbuf.st_mode)) {
 458                 type = VDEV_TYPE_FILE;
 459         } else {
 460                 (void) fprintf(stderr, gettext("cannot use '%s': must be a "
 461                     "block device or regular file\n"), path);
 462                 return (NULL);
 463         }
 464 
 465         /*
 466          * Finally, we have the complete device or file, and we know that it is
 467          * acceptable to use.  Construct the nvlist to describe this vdev.  All
 468          * vdevs have a 'path' element, and devices also have a 'devid' element.
 469          */
 470         verify(nvlist_alloc(&vdev, NV_UNIQUE_NAME, 0) == 0);
 471         verify(nvlist_add_string(vdev, ZPOOL_CONFIG_PATH, path) == 0);
 472         verify(nvlist_add_string(vdev, ZPOOL_CONFIG_TYPE, type) == 0);
 473         verify(nvlist_add_uint64(vdev, ZPOOL_CONFIG_IS_LOG, is_log) == 0);


 474         if (strcmp(type, VDEV_TYPE_DISK) == 0)
 475                 verify(nvlist_add_uint64(vdev, ZPOOL_CONFIG_WHOLE_DISK,
 476                     (uint64_t)wholedisk) == 0);
 477 
 478         /*
 479          * For a whole disk, defer getting its devid until after labeling it.
 480          */
 481         if (S_ISBLK(statbuf.st_mode) && !wholedisk) {
 482                 /*
 483                  * Get the devid for the device.
 484                  */
 485                 int fd;
 486                 ddi_devid_t devid;
 487                 char *minor = NULL, *devid_str = NULL;
 488 
 489                 if ((fd = open(path, O_RDONLY)) < 0) {
 490                         (void) fprintf(stderr, gettext("cannot open '%s': "
 491                             "%s\n"), path, strerror(errno));
 492                         nvlist_free(vdev);
 493                         return (NULL);


 611                          * bother doing it again.
 612                          */
 613                         type = NULL;
 614                         dontreport = 0;
 615                         vdev_size = -1ULL;
 616                         for (c = 0; c < children; c++) {
 617                                 nvlist_t *cnv = child[c];
 618                                 char *path;
 619                                 struct stat64 statbuf;
 620                                 uint64_t size = -1ULL;
 621                                 char *childtype;
 622                                 int fd, err;
 623 
 624                                 rep.zprl_children++;
 625 
 626                                 verify(nvlist_lookup_string(cnv,
 627                                     ZPOOL_CONFIG_TYPE, &childtype) == 0);
 628 
 629                                 /*
 630                                  * If this is a replacing or spare vdev, then
 631                                  * get the real first child of the vdev: do this
 632                                  * in a loop because replacing and spare vdevs
 633                                  * can be nested.
 634                                  */
 635                                 while (strcmp(childtype,
 636                                     VDEV_TYPE_REPLACING) == 0 ||
 637                                     strcmp(childtype, VDEV_TYPE_SPARE) == 0) {
 638                                         nvlist_t **rchild;
 639                                         uint_t rchildren;
 640 
 641                                         verify(nvlist_lookup_nvlist_array(cnv,
 642                                             ZPOOL_CONFIG_CHILDREN, &rchild,
 643                                             &rchildren) == 0);
 644                                         assert(rchildren == 2);
 645                                         cnv = rchild[0];
 646 
 647                                         verify(nvlist_lookup_string(cnv,
 648                                             ZPOOL_CONFIG_TYPE,
 649                                             &childtype) == 0);
 650                                 }
 651 
 652                                 verify(nvlist_lookup_string(cnv,
 653                                     ZPOOL_CONFIG_PATH, &path) == 0);
 654 
 655                                 /*


1166         }
1167 
1168         if (strcmp(type, "spare") == 0) {
1169                 if (mindev != NULL)
1170                         *mindev = 1;
1171                 return (VDEV_TYPE_SPARE);
1172         }
1173 
1174         if (strcmp(type, "log") == 0) {
1175                 if (mindev != NULL)
1176                         *mindev = 1;
1177                 return (VDEV_TYPE_LOG);
1178         }
1179 
1180         if (strcmp(type, "cache") == 0) {
1181                 if (mindev != NULL)
1182                         *mindev = 1;
1183                 return (VDEV_TYPE_L2CACHE);
1184         }
1185 






1186         return (NULL);
1187 }
1188 
1189 /*
1190  * Construct a syntactically valid vdev specification,
1191  * and ensure that all devices and files exist and can be opened.
1192  * Note: we don't bother freeing anything in the error paths
1193  * because the program is just going to exit anyway.
1194  */
1195 nvlist_t *
1196 construct_spec(int argc, char **argv)
1197 {
1198         nvlist_t *nvroot, *nv, **top, **spares, **l2cache;
1199         int t, toplevels, mindev, maxdev, nspares, nlogs, nl2cache;

1200         const char *type;
1201         uint64_t is_log;
1202         boolean_t seen_logs;
1203 
1204         top = NULL;
1205         toplevels = 0;
1206         spares = NULL;
1207         l2cache = NULL;
1208         nspares = 0;
1209         nlogs = 0;
1210         nl2cache = 0;
1211         is_log = B_FALSE;
1212         seen_logs = B_FALSE;


1213 
1214         while (argc > 0) {
1215                 nv = NULL;
1216 
1217                 /*
1218                  * If it's a mirror or raidz, the subsequent arguments are
1219                  * its leaves -- until we encounter the next mirror or raidz.
1220                  */
1221                 if ((type = is_grouping(argv[0], &mindev, &maxdev)) != NULL) {
1222                         nvlist_t **child = NULL;
1223                         int c, children = 0;
1224 
1225                         if (strcmp(type, VDEV_TYPE_SPARE) == 0) {
1226                                 if (spares != NULL) {
1227                                         (void) fprintf(stderr,
1228                                             gettext("invalid vdev "
1229                                             "specification: 'spare' can be "
1230                                             "specified only once\n"));
1231                                         return (NULL);
1232                                 }
1233                                 is_log = B_FALSE;

1234                         }
1235 
1236                         if (strcmp(type, VDEV_TYPE_LOG) == 0) {
1237                                 if (seen_logs) {
1238                                         (void) fprintf(stderr,
1239                                             gettext("invalid vdev "
1240                                             "specification: 'log' can be "
1241                                             "specified only once\n"));
1242                                         return (NULL);
1243                                 }
1244                                 seen_logs = B_TRUE;
1245                                 is_log = B_TRUE;

1246                                 argc--;
1247                                 argv++;
1248                                 /*
1249                                  * A log is not a real grouping device.
1250                                  * We just set is_log and continue.
1251                                  */
1252                                 continue;
1253                         }
1254 
1255                         if (strcmp(type, VDEV_TYPE_L2CACHE) == 0) {
1256                                 if (l2cache != NULL) {
1257                                         (void) fprintf(stderr,
1258                                             gettext("invalid vdev "
1259                                             "specification: 'cache' can be "
1260                                             "specified only once\n"));
1261                                         return (NULL);
1262                                 }
1263                                 is_log = B_FALSE;

1264                         }
1265 




















1266                         if (is_log) {
1267                                 if (strcmp(type, VDEV_TYPE_MIRROR) != 0) {
1268                                         (void) fprintf(stderr,
1269                                             gettext("invalid vdev "
1270                                             "specification: unsupported 'log' "
1271                                             "device: %s\n"), type);
1272                                         return (NULL);
1273                                 }
1274                                 nlogs++;
1275                         }
1276 











1277                         for (c = 1; c < argc; c++) {
1278                                 if (is_grouping(argv[c], NULL, NULL) != NULL)
1279                                         break;
1280                                 children++;
1281                                 child = realloc(child,
1282                                     children * sizeof (nvlist_t *));
1283                                 if (child == NULL)
1284                                         zpool_no_memory();
1285                                 if ((nv = make_leaf_vdev(argv[c], B_FALSE))
1286                                     == NULL)

1287                                         return (NULL);
1288                                 child[children - 1] = nv;
1289                         }
1290 
1291                         if (children < mindev) {
1292                                 (void) fprintf(stderr, gettext("invalid vdev "
1293                                     "specification: %s requires at least %d "
1294                                     "devices\n"), argv[0], mindev);
1295                                 return (NULL);
1296                         }
1297 
1298                         if (children > maxdev) {
1299                                 (void) fprintf(stderr, gettext("invalid vdev "
1300                                     "specification: %s supports no more than "
1301                                     "%d devices\n"), argv[0], maxdev);
1302                                 return (NULL);
1303                         }
1304 
1305                         argc -= c;
1306                         argv += c;
1307 
1308                         if (strcmp(type, VDEV_TYPE_SPARE) == 0) {
1309                                 spares = child;
1310                                 nspares = children;
1311                                 continue;
1312                         } else if (strcmp(type, VDEV_TYPE_L2CACHE) == 0) {
1313                                 l2cache = child;
1314                                 nl2cache = children;
1315                                 continue;
1316                         } else {
1317                                 verify(nvlist_alloc(&nv, NV_UNIQUE_NAME,
1318                                     0) == 0);
1319                                 verify(nvlist_add_string(nv, ZPOOL_CONFIG_TYPE,
1320                                     type) == 0);
1321                                 verify(nvlist_add_uint64(nv,
1322                                     ZPOOL_CONFIG_IS_LOG, is_log) == 0);




1323                                 if (strcmp(type, VDEV_TYPE_RAIDZ) == 0) {
1324                                         verify(nvlist_add_uint64(nv,
1325                                             ZPOOL_CONFIG_NPARITY,
1326                                             mindev - 1) == 0);
1327                                 }
1328                                 verify(nvlist_add_nvlist_array(nv,
1329                                     ZPOOL_CONFIG_CHILDREN, child,
1330                                     children) == 0);
1331 
1332                                 for (c = 0; c < children; c++)
1333                                         nvlist_free(child[c]);
1334                                 free(child);
1335                         }
1336                 } else {
1337                         /*
1338                          * We have a device.  Pass off to make_leaf_vdev() to
1339                          * construct the appropriate nvlist describing the vdev.
1340                          */
1341                         if ((nv = make_leaf_vdev(argv[0], is_log)) == NULL)

1342                                 return (NULL);
1343                         if (is_log)
1344                                 nlogs++;


1345                         argc--;
1346                         argv++;
1347                 }
1348 
1349                 toplevels++;
1350                 top = realloc(top, toplevels * sizeof (nvlist_t *));
1351                 if (top == NULL)
1352                         zpool_no_memory();
1353                 top[toplevels - 1] = nv;
1354         }
1355 
1356         if (toplevels == 0 && nspares == 0 && nl2cache == 0) {
1357                 (void) fprintf(stderr, gettext("invalid vdev "
1358                     "specification: at least one toplevel vdev must be "
1359                     "specified\n"));
1360                 return (NULL);
1361         }






1362 
1363         if (seen_logs && nlogs == 0) {
1364                 (void) fprintf(stderr, gettext("invalid vdev specification: "
1365                     "log requires at least 1 device\n"));
1366                 return (NULL);
1367         }
1368 
1369         /*
1370          * Finally, create nvroot and add all top-level vdevs to it.
1371          */
1372         verify(nvlist_alloc(&nvroot, NV_UNIQUE_NAME, 0) == 0);
1373         verify(nvlist_add_string(nvroot, ZPOOL_CONFIG_TYPE,
1374             VDEV_TYPE_ROOT) == 0);
1375         verify(nvlist_add_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN,
1376             top, toplevels) == 0);
1377         if (nspares != 0)
1378                 verify(nvlist_add_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES,
1379                     spares, nspares) == 0);
1380         if (nl2cache != 0)
1381                 verify(nvlist_add_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE,




   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
  25  * Copyright (c) 2013, 2015 by Delphix. All rights reserved.
  26  * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>.
  27  */
  28 
  29 /*
  30  * Functions to convert between a list of vdevs and an nvlist representing the
  31  * configuration.  Each entry in the list can be one of:
  32  *
  33  *      Device vdevs
  34  *              disk=(path=..., devid=...)
  35  *              file=(path=...)
  36  *
  37  *      Group vdevs
  38  *              raidz[1|2]=(...)
  39  *              mirror=(...)
  40  *
  41  *      Hot spares
  42  *
  43  * While the underlying implementation supports it, group vdevs cannot contain
  44  * other group vdevs.  All userland verification of devices is contained within


 371                 return (B_FALSE);
 372         if (efi_alloc_and_init(fd, EFI_NUMPAR, &label) != 0) {
 373                 (void) close(fd);
 374                 return (B_FALSE);
 375         }
 376         efi_free(label);
 377         (void) close(fd);
 378         return (B_TRUE);
 379 }
 380 
 381 /*
 382  * Create a leaf vdev.  Determine if this is a file or a device.  If it's a
 383  * device, fill in the device id to make a complete nvlist.  Valid forms for a
 384  * leaf vdev are:
 385  *
 386  *      /dev/dsk/xxx    Complete disk path
 387  *      /xxx            Full path to file
 388  *      xxx             Shorthand for /dev/dsk/xxx
 389  */
 390 static nvlist_t *
 391 make_leaf_vdev(const char *arg, uint64_t is_log, uint64_t is_special)
 392 {
 393         char path[MAXPATHLEN];
 394         struct stat64 statbuf;
 395         nvlist_t *vdev = NULL;
 396         char *type = NULL;
 397         boolean_t wholedisk = B_FALSE;
 398 
 399         /*
 400          * Determine what type of vdev this is, and put the full path into
 401          * 'path'.  We detect whether this is a device of file afterwards by
 402          * checking the st_mode of the file.
 403          */
 404         if (arg[0] == '/') {
 405                 /*
 406                  * Complete device or file path.  Exact type is determined by
 407                  * examining the file descriptor afterwards.
 408                  */
 409                 wholedisk = is_whole_disk(arg);
 410                 if (!wholedisk && (stat64(arg, &statbuf) != 0)) {
 411                         (void) fprintf(stderr,


 455          */
 456         if (wholedisk || S_ISBLK(statbuf.st_mode)) {
 457                 type = VDEV_TYPE_DISK;
 458         } else if (S_ISREG(statbuf.st_mode)) {
 459                 type = VDEV_TYPE_FILE;
 460         } else {
 461                 (void) fprintf(stderr, gettext("cannot use '%s': must be a "
 462                     "block device or regular file\n"), path);
 463                 return (NULL);
 464         }
 465 
 466         /*
 467          * Finally, we have the complete device or file, and we know that it is
 468          * acceptable to use.  Construct the nvlist to describe this vdev.  All
 469          * vdevs have a 'path' element, and devices also have a 'devid' element.
 470          */
 471         verify(nvlist_alloc(&vdev, NV_UNIQUE_NAME, 0) == 0);
 472         verify(nvlist_add_string(vdev, ZPOOL_CONFIG_PATH, path) == 0);
 473         verify(nvlist_add_string(vdev, ZPOOL_CONFIG_TYPE, type) == 0);
 474         verify(nvlist_add_uint64(vdev, ZPOOL_CONFIG_IS_LOG, is_log) == 0);
 475         verify(nvlist_add_uint64(vdev, ZPOOL_CONFIG_IS_SPECIAL,
 476             is_special) == 0);
 477         if (strcmp(type, VDEV_TYPE_DISK) == 0)
 478                 verify(nvlist_add_uint64(vdev, ZPOOL_CONFIG_WHOLE_DISK,
 479                     (uint64_t)wholedisk) == 0);
 480 
 481         /*
 482          * For a whole disk, defer getting its devid until after labeling it.
 483          */
 484         if (S_ISBLK(statbuf.st_mode) && !wholedisk) {
 485                 /*
 486                  * Get the devid for the device.
 487                  */
 488                 int fd;
 489                 ddi_devid_t devid;
 490                 char *minor = NULL, *devid_str = NULL;
 491 
 492                 if ((fd = open(path, O_RDONLY)) < 0) {
 493                         (void) fprintf(stderr, gettext("cannot open '%s': "
 494                             "%s\n"), path, strerror(errno));
 495                         nvlist_free(vdev);
 496                         return (NULL);


 614                          * bother doing it again.
 615                          */
 616                         type = NULL;
 617                         dontreport = 0;
 618                         vdev_size = -1ULL;
 619                         for (c = 0; c < children; c++) {
 620                                 nvlist_t *cnv = child[c];
 621                                 char *path;
 622                                 struct stat64 statbuf;
 623                                 uint64_t size = -1ULL;
 624                                 char *childtype;
 625                                 int fd, err;
 626 
 627                                 rep.zprl_children++;
 628 
 629                                 verify(nvlist_lookup_string(cnv,
 630                                     ZPOOL_CONFIG_TYPE, &childtype) == 0);
 631 
 632                                 /*
 633                                  * If this is a replacing or spare vdev, then
 634                                  * get the real first child of the vdev.


 635                                  */
 636                                 if (strcmp(childtype,
 637                                     VDEV_TYPE_REPLACING) == 0 ||
 638                                     strcmp(childtype, VDEV_TYPE_SPARE) == 0) {
 639                                         nvlist_t **rchild;
 640                                         uint_t rchildren;
 641 
 642                                         verify(nvlist_lookup_nvlist_array(cnv,
 643                                             ZPOOL_CONFIG_CHILDREN, &rchild,
 644                                             &rchildren) == 0);
 645                                         assert(rchildren == 2);
 646                                         cnv = rchild[0];
 647 
 648                                         verify(nvlist_lookup_string(cnv,
 649                                             ZPOOL_CONFIG_TYPE,
 650                                             &childtype) == 0);
 651                                 }
 652 
 653                                 verify(nvlist_lookup_string(cnv,
 654                                     ZPOOL_CONFIG_PATH, &path) == 0);
 655 
 656                                 /*


1167         }
1168 
1169         if (strcmp(type, "spare") == 0) {
1170                 if (mindev != NULL)
1171                         *mindev = 1;
1172                 return (VDEV_TYPE_SPARE);
1173         }
1174 
1175         if (strcmp(type, "log") == 0) {
1176                 if (mindev != NULL)
1177                         *mindev = 1;
1178                 return (VDEV_TYPE_LOG);
1179         }
1180 
1181         if (strcmp(type, "cache") == 0) {
1182                 if (mindev != NULL)
1183                         *mindev = 1;
1184                 return (VDEV_TYPE_L2CACHE);
1185         }
1186 
1187         if (strcmp(type, "special") == 0) {
1188                 if (mindev != NULL)
1189                         *mindev = 1;
1190                 return (VDEV_TYPE_SPECIAL);
1191         }
1192 
1193         return (NULL);
1194 }
1195 
1196 /*
1197  * Construct a syntactically valid vdev specification,
1198  * and ensure that all devices and files exist and can be opened.
1199  * Note: we don't bother freeing anything in the error paths
1200  * because the program is just going to exit anyway.
1201  */
1202 nvlist_t *
1203 construct_spec(int argc, char **argv)
1204 {
1205         nvlist_t *nvroot, *nv, **top, **spares, **l2cache;
1206         int t, toplevels, mindev, maxdev, nspares, nlogs, nl2cache;
1207         int nspecial = 0;
1208         const char *type;
1209         boolean_t is_log, seen_logs;
1210         boolean_t is_special, seen_special;
1211 
1212         top = NULL;
1213         toplevels = 0;
1214         spares = NULL;
1215         l2cache = NULL;
1216         nspares = 0;
1217         nlogs = 0;
1218         nl2cache = 0;
1219         is_log = B_FALSE;
1220         seen_logs = B_FALSE;
1221         is_special = B_FALSE;
1222         seen_special = B_FALSE;
1223 
1224         while (argc > 0) {
1225                 nv = NULL;
1226 
1227                 /*
1228                  * If it's a mirror or raidz, the subsequent arguments are
1229                  * its leaves -- until we encounter the next mirror or raidz.
1230                  */
1231                 if ((type = is_grouping(argv[0], &mindev, &maxdev)) != NULL) {
1232                         nvlist_t **child = NULL;
1233                         int c, children = 0;
1234 
1235                         if (strcmp(type, VDEV_TYPE_SPARE) == 0) {
1236                                 if (spares != NULL) {
1237                                         (void) fprintf(stderr,
1238                                             gettext("invalid vdev "
1239                                             "specification: 'spare' can be "
1240                                             "specified only once\n"));
1241                                         return (NULL);
1242                                 }
1243                                 is_log = B_FALSE;
1244                                 is_special = B_FALSE;
1245                         }
1246 
1247                         if (strcmp(type, VDEV_TYPE_LOG) == 0) {
1248                                 if (seen_logs) {
1249                                         (void) fprintf(stderr,
1250                                             gettext("invalid vdev "
1251                                             "specification: 'log' can be "
1252                                             "specified only once\n"));
1253                                         return (NULL);
1254                                 }
1255                                 seen_logs = B_TRUE;
1256                                 is_log = B_TRUE;
1257                                 is_special = B_FALSE;
1258                                 argc--;
1259                                 argv++;
1260                                 /*
1261                                  * A log is not a real grouping device.
1262                                  * We just set is_log and continue.
1263                                  */
1264                                 continue;
1265                         }
1266 
1267                         if (strcmp(type, VDEV_TYPE_L2CACHE) == 0) {
1268                                 if (l2cache != NULL) {
1269                                         (void) fprintf(stderr,
1270                                             gettext("invalid vdev "
1271                                             "specification: 'cache' can be "
1272                                             "specified only once\n"));
1273                                         return (NULL);
1274                                 }
1275                                 is_log = B_FALSE;
1276                                 is_special = B_FALSE;
1277                         }
1278 
1279                         if (strcmp(type, VDEV_TYPE_SPECIAL) == 0) {
1280                                 if (seen_special) {
1281                                         (void) fprintf(stderr,
1282                                             gettext("invalid vdev "
1283                                             "specification: 'special' can be "
1284                                             "specified only once\n"));
1285                                         return (NULL);
1286                                 }
1287                                 seen_special = B_TRUE;
1288                                 is_log = B_FALSE;
1289                                 is_special = B_TRUE;
1290                                 argc--;
1291                                 argv++;
1292                                 /*
1293                                  * A special is not a real grouping device.
1294                                  * We just set is_special and continue.
1295                                  */
1296                                 continue;
1297                         }
1298 
1299                         if (is_log) {
1300                                 if (strcmp(type, VDEV_TYPE_MIRROR) != 0) {
1301                                         (void) fprintf(stderr,
1302                                             gettext("invalid vdev "
1303                                             "specification: unsupported 'log' "
1304                                             "device: %s\n"), type);
1305                                         return (NULL);
1306                                 }
1307                                 nlogs++;
1308                         }
1309 
1310                         if (is_special) {
1311                                 if (strcmp(type, VDEV_TYPE_MIRROR) != 0) {
1312                                         (void) fprintf(stderr,
1313                                             gettext("invalid vdev "
1314                                             "specification: unsupported "
1315                                             "'special' device: %s\n"), type);
1316                                         return (NULL);
1317                                 }
1318                                 nspecial++;
1319                         }
1320 
1321                         for (c = 1; c < argc; c++) {
1322                                 if (is_grouping(argv[c], NULL, NULL) != NULL)
1323                                         break;
1324                                 children++;
1325                                 child = realloc(child,
1326                                     children * sizeof (nvlist_t *));
1327                                 if (child == NULL)
1328                                         zpool_no_memory();
1329                                 if ((nv = make_leaf_vdev(argv[c],
1330                                     (uint64_t)B_FALSE,
1331                                     (uint64_t)B_FALSE)) == NULL)
1332                                         return (NULL);
1333                                 child[children - 1] = nv;
1334                         }
1335 
1336                         if (children < mindev) {
1337                                 (void) fprintf(stderr, gettext("invalid vdev "
1338                                     "specification: %s requires at least %d "
1339                                     "devices\n"), argv[0], mindev);
1340                                 return (NULL);
1341                         }
1342 
1343                         if (children > maxdev) {
1344                                 (void) fprintf(stderr, gettext("invalid vdev "
1345                                     "specification: %s supports no more than "
1346                                     "%d devices\n"), argv[0], maxdev);
1347                                 return (NULL);
1348                         }
1349 
1350                         argc -= c;
1351                         argv += c;
1352 
1353                         if (strcmp(type, VDEV_TYPE_SPARE) == 0) {
1354                                 spares = child;
1355                                 nspares = children;
1356                                 continue;
1357                         } else if (strcmp(type, VDEV_TYPE_L2CACHE) == 0) {
1358                                 l2cache = child;
1359                                 nl2cache = children;
1360                                 continue;
1361                         } else {
1362                                 verify(nvlist_alloc(&nv, NV_UNIQUE_NAME,
1363                                     0) == 0);
1364                                 verify(nvlist_add_string(nv, ZPOOL_CONFIG_TYPE,
1365                                     type) == 0);
1366                                 verify(nvlist_add_uint64(nv,
1367                                     ZPOOL_CONFIG_IS_LOG,
1368                                     (uint64_t)is_log) == 0);
1369                                 verify(nvlist_add_uint64(nv,
1370                                     ZPOOL_CONFIG_IS_SPECIAL,
1371                                     (uint64_t)is_special) == 0);
1372                                 if (strcmp(type, VDEV_TYPE_RAIDZ) == 0) {
1373                                         verify(nvlist_add_uint64(nv,
1374                                             ZPOOL_CONFIG_NPARITY,
1375                                             mindev - 1) == 0);
1376                                 }
1377                                 verify(nvlist_add_nvlist_array(nv,
1378                                     ZPOOL_CONFIG_CHILDREN, child,
1379                                     children) == 0);
1380 
1381                                 for (c = 0; c < children; c++)
1382                                         nvlist_free(child[c]);
1383                                 free(child);
1384                         }
1385                 } else {
1386                         /*
1387                          * We have a device.  Pass off to make_leaf_vdev() to
1388                          * construct the appropriate nvlist describing the vdev.
1389                          */
1390                         if ((nv = make_leaf_vdev(argv[0], (uint64_t)is_log,
1391                             (uint64_t)is_special)) == NULL)
1392                                 return (NULL);
1393                         if (is_log)
1394                                 nlogs++;
1395                         if (is_special)
1396                                 nspecial++;
1397                         argc--;
1398                         argv++;
1399                 }
1400 
1401                 toplevels++;
1402                 top = realloc(top, toplevels * sizeof (nvlist_t *));
1403                 if (top == NULL)
1404                         zpool_no_memory();
1405                 top[toplevels - 1] = nv;
1406         }
1407 
1408         if (toplevels == 0 && nspares == 0 && nl2cache == 0) {
1409                 (void) fprintf(stderr, gettext("invalid vdev "
1410                     "specification: at least one toplevel vdev must be "
1411                     "specified\n"));
1412                 return (NULL);
1413         }
1414 
1415         if (seen_special && nspecial == 0) {
1416                 (void) fprintf(stderr, gettext("invalid vdev specification: "
1417                     "special requires at least 1 device\n"));
1418                 return (NULL);
1419         }
1420 
1421         if (seen_logs && nlogs == 0) {
1422                 (void) fprintf(stderr, gettext("invalid vdev specification: "
1423                     "log requires at least 1 device\n"));
1424                 return (NULL);
1425         }
1426 
1427         /*
1428          * Finally, create nvroot and add all top-level vdevs to it.
1429          */
1430         verify(nvlist_alloc(&nvroot, NV_UNIQUE_NAME, 0) == 0);
1431         verify(nvlist_add_string(nvroot, ZPOOL_CONFIG_TYPE,
1432             VDEV_TYPE_ROOT) == 0);
1433         verify(nvlist_add_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN,
1434             top, toplevels) == 0);
1435         if (nspares != 0)
1436                 verify(nvlist_add_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES,
1437                     spares, nspares) == 0);
1438         if (nl2cache != 0)
1439                 verify(nvlist_add_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE,