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
        
@@ -19,10 +19,11 @@
  * CDDL HEADER END
  */
 
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
  * Copyright (c) 2013, 2015 by Delphix. All rights reserved.
  * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>.
  */
 
 /*
@@ -385,11 +386,11 @@
  *      /dev/dsk/xxx    Complete disk path
  *      /xxx            Full path to file
  *      xxx             Shorthand for /dev/dsk/xxx
  */
 static nvlist_t *
-make_leaf_vdev(const char *arg, uint64_t is_log)
+make_leaf_vdev(const char *arg, uint64_t is_log, uint64_t is_special)
 {
         char path[MAXPATHLEN];
         struct stat64 statbuf;
         nvlist_t *vdev = NULL;
         char *type = NULL;
@@ -469,10 +470,12 @@
          */
         verify(nvlist_alloc(&vdev, NV_UNIQUE_NAME, 0) == 0);
         verify(nvlist_add_string(vdev, ZPOOL_CONFIG_PATH, path) == 0);
         verify(nvlist_add_string(vdev, ZPOOL_CONFIG_TYPE, type) == 0);
         verify(nvlist_add_uint64(vdev, ZPOOL_CONFIG_IS_LOG, is_log) == 0);
+        verify(nvlist_add_uint64(vdev, ZPOOL_CONFIG_IS_SPECIAL,
+            is_special) == 0);
         if (strcmp(type, VDEV_TYPE_DISK) == 0)
                 verify(nvlist_add_uint64(vdev, ZPOOL_CONFIG_WHOLE_DISK,
                     (uint64_t)wholedisk) == 0);
 
         /*
@@ -626,15 +629,13 @@
                                 verify(nvlist_lookup_string(cnv,
                                     ZPOOL_CONFIG_TYPE, &childtype) == 0);
 
                                 /*
                                  * If this is a replacing or spare vdev, then
-                                 * get the real first child of the vdev: do this
-                                 * in a loop because replacing and spare vdevs
-                                 * can be nested.
+                                 * get the real first child of the vdev.
                                  */
-                                while (strcmp(childtype,
+                                if (strcmp(childtype,
                                     VDEV_TYPE_REPLACING) == 0 ||
                                     strcmp(childtype, VDEV_TYPE_SPARE) == 0) {
                                         nvlist_t **rchild;
                                         uint_t rchildren;
 
@@ -1181,10 +1182,16 @@
                 if (mindev != NULL)
                         *mindev = 1;
                 return (VDEV_TYPE_L2CACHE);
         }
 
+        if (strcmp(type, "special") == 0) {
+                if (mindev != NULL)
+                        *mindev = 1;
+                return (VDEV_TYPE_SPECIAL);
+        }
+
         return (NULL);
 }
 
 /*
  * Construct a syntactically valid vdev specification,
@@ -1195,13 +1202,14 @@
 nvlist_t *
 construct_spec(int argc, char **argv)
 {
         nvlist_t *nvroot, *nv, **top, **spares, **l2cache;
         int t, toplevels, mindev, maxdev, nspares, nlogs, nl2cache;
+        int nspecial = 0;
         const char *type;
-        uint64_t is_log;
-        boolean_t seen_logs;
+        boolean_t is_log, seen_logs;
+        boolean_t is_special, seen_special;
 
         top = NULL;
         toplevels = 0;
         spares = NULL;
         l2cache = NULL;
@@ -1208,10 +1216,12 @@
         nspares = 0;
         nlogs = 0;
         nl2cache = 0;
         is_log = B_FALSE;
         seen_logs = B_FALSE;
+        is_special = B_FALSE;
+        seen_special = B_FALSE;
 
         while (argc > 0) {
                 nv = NULL;
 
                 /*
@@ -1229,10 +1239,11 @@
                                             "specification: 'spare' can be "
                                             "specified only once\n"));
                                         return (NULL);
                                 }
                                 is_log = B_FALSE;
+                                is_special = B_FALSE;
                         }
 
                         if (strcmp(type, VDEV_TYPE_LOG) == 0) {
                                 if (seen_logs) {
                                         (void) fprintf(stderr,
@@ -1241,10 +1252,11 @@
                                             "specified only once\n"));
                                         return (NULL);
                                 }
                                 seen_logs = B_TRUE;
                                 is_log = B_TRUE;
+                                is_special = B_FALSE;
                                 argc--;
                                 argv++;
                                 /*
                                  * A log is not a real grouping device.
                                  * We just set is_log and continue.
@@ -1259,12 +1271,33 @@
                                             "specification: 'cache' can be "
                                             "specified only once\n"));
                                         return (NULL);
                                 }
                                 is_log = B_FALSE;
+                                is_special = B_FALSE;
                         }
 
+                        if (strcmp(type, VDEV_TYPE_SPECIAL) == 0) {
+                                if (seen_special) {
+                                        (void) fprintf(stderr,
+                                            gettext("invalid vdev "
+                                            "specification: 'special' can be "
+                                            "specified only once\n"));
+                                        return (NULL);
+                                }
+                                seen_special = B_TRUE;
+                                is_log = B_FALSE;
+                                is_special = B_TRUE;
+                                argc--;
+                                argv++;
+                                /*
+                                 * A special is not a real grouping device.
+                                 * We just set is_special and continue.
+                                 */
+                                continue;
+                        }
+
                         if (is_log) {
                                 if (strcmp(type, VDEV_TYPE_MIRROR) != 0) {
                                         (void) fprintf(stderr,
                                             gettext("invalid vdev "
                                             "specification: unsupported 'log' "
@@ -1272,20 +1305,32 @@
                                         return (NULL);
                                 }
                                 nlogs++;
                         }
 
+                        if (is_special) {
+                                if (strcmp(type, VDEV_TYPE_MIRROR) != 0) {
+                                        (void) fprintf(stderr,
+                                            gettext("invalid vdev "
+                                            "specification: unsupported "
+                                            "'special' device: %s\n"), type);
+                                        return (NULL);
+                                }
+                                nspecial++;
+                        }
+
                         for (c = 1; c < argc; c++) {
                                 if (is_grouping(argv[c], NULL, NULL) != NULL)
                                         break;
                                 children++;
                                 child = realloc(child,
                                     children * sizeof (nvlist_t *));
                                 if (child == NULL)
                                         zpool_no_memory();
-                                if ((nv = make_leaf_vdev(argv[c], B_FALSE))
-                                    == NULL)
+                                if ((nv = make_leaf_vdev(argv[c],
+                                    (uint64_t)B_FALSE,
+                                    (uint64_t)B_FALSE)) == NULL)
                                         return (NULL);
                                 child[children - 1] = nv;
                         }
 
                         if (children < mindev) {
@@ -1317,11 +1362,15 @@
                                 verify(nvlist_alloc(&nv, NV_UNIQUE_NAME,
                                     0) == 0);
                                 verify(nvlist_add_string(nv, ZPOOL_CONFIG_TYPE,
                                     type) == 0);
                                 verify(nvlist_add_uint64(nv,
-                                    ZPOOL_CONFIG_IS_LOG, is_log) == 0);
+                                    ZPOOL_CONFIG_IS_LOG,
+                                    (uint64_t)is_log) == 0);
+                                verify(nvlist_add_uint64(nv,
+                                    ZPOOL_CONFIG_IS_SPECIAL,
+                                    (uint64_t)is_special) == 0);
                                 if (strcmp(type, VDEV_TYPE_RAIDZ) == 0) {
                                         verify(nvlist_add_uint64(nv,
                                             ZPOOL_CONFIG_NPARITY,
                                             mindev - 1) == 0);
                                 }
@@ -1336,14 +1385,17 @@
                 } else {
                         /*
                          * We have a device.  Pass off to make_leaf_vdev() to
                          * construct the appropriate nvlist describing the vdev.
                          */
-                        if ((nv = make_leaf_vdev(argv[0], is_log)) == NULL)
+                        if ((nv = make_leaf_vdev(argv[0], (uint64_t)is_log,
+                            (uint64_t)is_special)) == NULL)
                                 return (NULL);
                         if (is_log)
                                 nlogs++;
+                        if (is_special)
+                                nspecial++;
                         argc--;
                         argv++;
                 }
 
                 toplevels++;
@@ -1357,10 +1409,16 @@
                 (void) fprintf(stderr, gettext("invalid vdev "
                     "specification: at least one toplevel vdev must be "
                     "specified\n"));
                 return (NULL);
         }
+
+        if (seen_special && nspecial == 0) {
+                (void) fprintf(stderr, gettext("invalid vdev specification: "
+                    "special requires at least 1 device\n"));
+                return (NULL);
+        }
 
         if (seen_logs && nlogs == 0) {
                 (void) fprintf(stderr, gettext("invalid vdev specification: "
                     "log requires at least 1 device\n"));
                 return (NULL);