]> git.proxmox.com Git - mirror_zfs.git/blobdiff - zfs/zcmd/zpool/zpool_main.c
Rebase to OpenSolaris b103, in the process we are removing any code which did not...
[mirror_zfs.git] / zfs / zcmd / zpool / zpool_main.c
index 83c7e72e7c17998b3bd7134fe4552110d2f435f1..54bba8645c669e5eaa4a13de63ed6519479f057f 100644 (file)
@@ -24,8 +24,6 @@
  * Use is subject to license terms.
  */
 
-#pragma ident  "@(#)zpool_main.c       1.54    08/02/13 SMI"
-
 #include <assert.h>
 #include <ctype.h>
 #include <dirent.h>
@@ -86,6 +84,8 @@ static int zpool_do_set(int, char **);
  * These libumem hooks provide a reasonable set of defaults for the allocator's
  * debugging facilities.
  */
+
+#ifdef DEBUG
 const char *
 _umem_debug_init(void)
 {
@@ -97,6 +97,7 @@ _umem_logging_init(void)
 {
        return ("fail,contents"); /* $UMEM_LOGGING setting */
 }
+#endif
 
 typedef enum {
        HELP_ADD,
@@ -184,6 +185,7 @@ get_usage(zpool_help_t idx) {
                return (gettext("\tclear <pool> [device]\n"));
        case HELP_CREATE:
                return (gettext("\tcreate [-fn] [-o property=value] ... \n"
+                   "\t    [-O file-system-property=value] ... \n"
                    "\t    [-m mountpoint] [-R root] <pool> <vdev> ...\n"));
        case HELP_DESTROY:
                return (gettext("\tdestroy [-f] <pool>\n"));
@@ -348,11 +350,14 @@ print_vdev_tree(zpool_handle_t *zhp, const char *name, nvlist_t *nv, int indent,
  * Add a property pair (name, string-value) into a property nvlist.
  */
 static int
-add_prop_list(const char *propname, char *propval, nvlist_t **props)
+add_prop_list(const char *propname, char *propval, nvlist_t **props,
+    boolean_t poolprop)
 {
-       char *strval;
+       zpool_prop_t prop = ZPROP_INVAL;
+       zfs_prop_t fprop;
        nvlist_t *proplist;
-       zpool_prop_t prop;
+       const char *normnm;
+       char *strval;
 
        if (*props == NULL &&
            nvlist_alloc(props, NV_UNIQUE_NAME, 0) != 0) {
@@ -363,22 +368,30 @@ add_prop_list(const char *propname, char *propval, nvlist_t **props)
 
        proplist = *props;
 
-       if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL) {
-               (void) fprintf(stderr, gettext("property '%s' is "
-                   "not a valid pool property\n"), propname);
-               return (2);
+       if (poolprop) {
+               if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL) {
+                       (void) fprintf(stderr, gettext("property '%s' is "
+                           "not a valid pool property\n"), propname);
+                       return (2);
+               }
+               normnm = zpool_prop_to_name(prop);
+       } else {
+               if ((fprop = zfs_name_to_prop(propname)) == ZPROP_INVAL) {
+                       (void) fprintf(stderr, gettext("property '%s' is "
+                           "not a valid file system property\n"), propname);
+                       return (2);
+               }
+               normnm = zfs_prop_to_name(fprop);
        }
 
-       /* Use normalized property name for nvlist operations */
-       if (nvlist_lookup_string(proplist, zpool_prop_to_name(prop),
-           &strval) == 0 && prop != ZPOOL_PROP_CACHEFILE) {
+       if (nvlist_lookup_string(proplist, normnm, &strval) == 0 &&
+           prop != ZPOOL_PROP_CACHEFILE) {
                (void) fprintf(stderr, gettext("property '%s' "
                    "specified multiple times\n"), propname);
                return (2);
        }
 
-       if (nvlist_add_string(proplist, zpool_prop_to_name(prop),
-           propval) != 0) {
+       if (nvlist_add_string(proplist, normnm, propval) != 0) {
                (void) fprintf(stderr, gettext("internal "
                    "error: out of memory\n"));
                return (1);
@@ -455,7 +468,8 @@ zpool_do_add(int argc, char **argv)
        }
 
        /* pass off to get_vdev_spec for processing */
-       nvroot = make_root_vdev(zhp, force, !force, B_FALSE, argc, argv);
+       nvroot = make_root_vdev(zhp, force, !force, B_FALSE, dryrun,
+           argc, argv);
        if (nvroot == NULL) {
                zpool_close(zhp);
                return (1);
@@ -534,8 +548,9 @@ zpool_do_remove(int argc, char **argv)
 }
 
 /*
- * zpool create [-fn] [-o property=value] ... [-R root] [-m mountpoint]
- *             <pool> <dev> ...
+ * zpool create [-fn] [-o property=value] ...
+ *             [-O file-system-property=value] ...
+ *             [-R root] [-m mountpoint] <pool> <dev> ...
  *
  *     -f      Force creation, even if devices appear in use
  *     -n      Do not create the pool, but display the resulting layout if it
@@ -544,6 +559,7 @@ zpool_do_remove(int argc, char **argv)
  *      -m     Set default mountpoint for the root dataset.  By default it's
  *             '/<pool>'
  *     -o      Set property=value.
+ *     -O      Set fsproperty=value in the pool's root file system
  *
  * Creates the named pool according to the given vdev specification.  The
  * bulk of the vdev processing is done in get_vdev_spec() in zpool_vdev.c.  Once
@@ -561,11 +577,12 @@ zpool_do_create(int argc, char **argv)
        int ret = 1;
        char *altroot = NULL;
        char *mountpoint = NULL;
+       nvlist_t *fsprops = NULL;
        nvlist_t *props = NULL;
        char *propval;
 
        /* check options */
-       while ((c = getopt(argc, argv, ":fnR:m:o:")) != -1) {
+       while ((c = getopt(argc, argv, ":fnR:m:o:O:")) != -1) {
                switch (c) {
                case 'f':
                        force = B_TRUE;
@@ -576,14 +593,14 @@ zpool_do_create(int argc, char **argv)
                case 'R':
                        altroot = optarg;
                        if (add_prop_list(zpool_prop_to_name(
-                           ZPOOL_PROP_ALTROOT), optarg, &props))
+                           ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE))
                                goto errout;
                        if (nvlist_lookup_string(props,
                            zpool_prop_to_name(ZPOOL_PROP_CACHEFILE),
                            &propval) == 0)
                                break;
                        if (add_prop_list(zpool_prop_to_name(
-                           ZPOOL_PROP_CACHEFILE), "none", &props))
+                           ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE))
                                goto errout;
                        break;
                case 'm':
@@ -598,7 +615,19 @@ zpool_do_create(int argc, char **argv)
                        *propval = '\0';
                        propval++;
 
-                       if (add_prop_list(optarg, propval, &props))
+                       if (add_prop_list(optarg, propval, &props, B_TRUE))
+                               goto errout;
+                       break;
+               case 'O':
+                       if ((propval = strchr(optarg, '=')) == NULL) {
+                               (void) fprintf(stderr, gettext("missing "
+                                   "'=' for -O option\n"));
+                               goto errout;
+                       }
+                       *propval = '\0';
+                       propval++;
+
+                       if (add_prop_list(optarg, propval, &fsprops, B_FALSE))
                                goto errout;
                        break;
                case ':':
@@ -640,10 +669,10 @@ zpool_do_create(int argc, char **argv)
        }
 
        /* pass off to get_vdev_spec for bulk processing */
-       nvroot = make_root_vdev(NULL, force, !force, B_FALSE, argc - 1,
-           argv + 1);
+       nvroot = make_root_vdev(NULL, force, !force, B_FALSE, dryrun,
+           argc - 1, argv + 1);
        if (nvroot == NULL)
-               return (1);
+               goto errout;
 
        /* make_root_vdev() allows 0 toplevel children if there are spares */
        if (!zfs_allocatable_devs(nvroot)) {
@@ -735,7 +764,8 @@ zpool_do_create(int argc, char **argv)
                /*
                 * Hand off to libzfs.
                 */
-               if (zpool_create(g_zfs, poolname, nvroot, props) == 0) {
+               if (zpool_create(g_zfs, poolname,
+                   nvroot, props, fsprops) == 0) {
                        zfs_handle_t *pool = zfs_open(g_zfs, poolname,
                            ZFS_TYPE_FILESYSTEM);
                        if (pool != NULL) {
@@ -756,9 +786,11 @@ zpool_do_create(int argc, char **argv)
 
 errout:
        nvlist_free(nvroot);
+       nvlist_free(fsprops);
        nvlist_free(props);
        return (ret);
 badusage:
+       nvlist_free(fsprops);
        nvlist_free(props);
        usage(B_FALSE);
        return (2);
@@ -885,7 +917,7 @@ zpool_do_export(int argc, char **argv)
                        continue;
                }
 
-               if (zpool_export(zhp) != 0)
+               if (zpool_export(zhp, force) != 0)
                        ret = 1;
 
                zpool_close(zhp);
@@ -1109,16 +1141,23 @@ show_import(nvlist_t *config)
                (void) printf(gettext("status: The pool is formatted using an "
                    "incompatible version.\n"));
                break;
+
        case ZPOOL_STATUS_HOSTID_MISMATCH:
                (void) printf(gettext("status: The pool was last accessed by "
                    "another system.\n"));
                break;
+
        case ZPOOL_STATUS_FAULTED_DEV_R:
        case ZPOOL_STATUS_FAULTED_DEV_NR:
                (void) printf(gettext("status: One or more devices are "
                    "faulted.\n"));
                break;
 
+       case ZPOOL_STATUS_BAD_LOG:
+               (void) printf(gettext("status: An intent log record cannot be "
+                   "read.\n"));
+               break;
+
        default:
                /*
                 * No other status can be seen when importing pools.
@@ -1214,7 +1253,7 @@ show_import(nvlist_t *config)
  */
 static int
 do_import(nvlist_t *config, const char *newname, const char *mntopts,
-    int force, nvlist_t *props)
+    int force, nvlist_t *props, boolean_t allowfaulted)
 {
        zpool_handle_t *zhp;
        char *name;
@@ -1267,13 +1306,14 @@ do_import(nvlist_t *config, const char *newname, const char *mntopts,
                }
        }
 
-       if (zpool_import_props(g_zfs, config, newname, props) != 0)
+       if (zpool_import_props(g_zfs, config, newname, props,
+           allowfaulted) != 0)
                return (1);
 
        if (newname != NULL)
                name = (char *)newname;
 
-       verify((zhp = zpool_open(g_zfs, name)) != NULL);
+       verify((zhp = zpool_open_canfail(g_zfs, name)) != NULL);
 
        if (zpool_enable_datasets(zhp, mntopts, 0) != 0) {
                zpool_close(zhp);
@@ -1306,6 +1346,11 @@ do_import(nvlist_t *config, const char *newname, const char *mntopts,
  *
  *       -f    Force import, even if it appears that the pool is active.
  *
+ *       -F    Import even in the presence of faulted vdevs.  This is an
+ *             intentionally undocumented option for testing purposes, and
+ *             treats the pool configuration as complete, leaving any bad
+ *             vdevs in the FAULTED state.
+ *
  *       -a    Import all pools found.
  *
  *       -o    Set property=value and/or temporary mount options (without '=').
@@ -1327,17 +1372,18 @@ zpool_do_import(int argc, char **argv)
        boolean_t do_force = B_FALSE;
        nvpair_t *elem;
        nvlist_t *config;
-       uint64_t searchguid;
-       char *searchname;
+       uint64_t searchguid = 0;
+       char *searchname = NULL;
        char *propval;
        nvlist_t *found_config;
        nvlist_t *props = NULL;
        boolean_t first;
+       boolean_t allow_faulted = B_FALSE;
        uint64_t pool_state;
        char *cachefile = NULL;
 
        /* check options */
-       while ((c = getopt(argc, argv, ":afc:d:Do:p:R:")) != -1) {
+       while ((c = getopt(argc, argv, ":ac:d:DfFo:p:R:")) != -1) {
                switch (c) {
                case 'a':
                        do_all = B_TRUE;
@@ -1364,11 +1410,15 @@ zpool_do_import(int argc, char **argv)
                case 'f':
                        do_force = B_TRUE;
                        break;
+               case 'F':
+                       allow_faulted = B_TRUE;
+                       break;
                case 'o':
                        if ((propval = strchr(optarg, '=')) != NULL) {
                                *propval = '\0';
                                propval++;
-                               if (add_prop_list(optarg, propval, &props))
+                               if (add_prop_list(optarg, propval,
+                                   &props, B_TRUE))
                                        goto error;
                        } else {
                                mntopts = optarg;
@@ -1376,14 +1426,14 @@ zpool_do_import(int argc, char **argv)
                        break;
                case 'R':
                        if (add_prop_list(zpool_prop_to_name(
-                           ZPOOL_PROP_ALTROOT), optarg, &props))
+                           ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE))
                                goto error;
                        if (nvlist_lookup_string(props,
                            zpool_prop_to_name(ZPOOL_PROP_CACHEFILE),
                            &propval) == 0)
                                break;
                        if (add_prop_list(zpool_prop_to_name(
-                           ZPOOL_PROP_CACHEFILE), "none", &props))
+                           ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE))
                                goto error;
                        break;
                case ':':
@@ -1437,18 +1487,7 @@ zpool_do_import(int argc, char **argv)
                }
        }
 
-       if (cachefile)
-               pools = zpool_find_import_cached(g_zfs, cachefile, B_FALSE);
-       else
-               pools = zpool_find_import(g_zfs, nsearch, searchdirs, B_FALSE);
-
-       if (pools == NULL) {
-               free(searchdirs);
-               return (1);
-       }
-
        /*
-        * We now have a list of all available pools in the given directories.
         * Depending on the arguments given, we do one of the following:
         *
         *      <none>  Iterate through all pools and display information about
@@ -1468,11 +1507,38 @@ zpool_do_import(int argc, char **argv)
                searchguid = strtoull(argv[0], &endptr, 10);
                if (errno != 0 || *endptr != '\0')
                        searchname = argv[0];
-               else
-                       searchname = NULL;
                found_config = NULL;
        }
 
+       if (cachefile) {
+               pools = zpool_find_import_cached(g_zfs, cachefile, searchname,
+                   searchguid);
+       } else if (searchname != NULL) {
+               pools = zpool_find_import_byname(g_zfs, nsearch, searchdirs,
+                   searchname);
+       } else {
+               /*
+                * It's OK to search by guid even if searchguid is 0.
+                */
+               pools = zpool_find_import_byguid(g_zfs, nsearch, searchdirs,
+                   searchguid);
+       }
+
+       if (pools == NULL) {
+               if (argc != 0) {
+                       (void) fprintf(stderr, gettext("cannot import '%s': "
+                           "no such pool available\n"), argv[0]);
+               }
+               free(searchdirs);
+               return (1);
+       }
+
+       /*
+        * At this point we have a list of import candidate configs. Even if
+        * we were searching by pool name or guid, we still need to
+        * post-process the list to deal with pool state and possible
+        * duplicate names.
+        */
        err = 0;
        elem = NULL;
        first = B_TRUE;
@@ -1495,7 +1561,7 @@ zpool_do_import(int argc, char **argv)
 
                        if (do_all)
                                err |= do_import(config, NULL, mntopts,
-                                   do_force, props);
+                                   do_force, props, allow_faulted);
                        else
                                show_import(config);
                } else if (searchname != NULL) {
@@ -1543,7 +1609,7 @@ zpool_do_import(int argc, char **argv)
                        err = B_TRUE;
                } else {
                        err |= do_import(found_config, argc == 1 ? NULL :
-                           argv[1], mntopts, do_force, props);
+                           argv[1], mntopts, do_force, props, allow_faulted);
                }
        }
 
@@ -2238,7 +2304,8 @@ zpool_do_attach_or_replace(int argc, char **argv, int replacing)
                return (1);
        }
 
-       nvroot = make_root_vdev(zhp, force, B_FALSE, replacing, argc, argv);
+       nvroot = make_root_vdev(zhp, force, B_FALSE, replacing, B_FALSE,
+           argc, argv);
        if (nvroot == NULL) {
                zpool_close(zhp);
                return (1);
@@ -2493,7 +2560,7 @@ zpool_do_clear(int argc, char **argv)
        pool = argv[1];
        device = argc == 3 ? argv[2] : NULL;
 
-       if ((zhp = zpool_open(g_zfs, pool)) == NULL)
+       if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL)
                return (1);
 
        if (zpool_clear(zhp, device) != 0)
@@ -2776,6 +2843,14 @@ print_status_config(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
                        (void) printf(gettext("too many errors"));
                        break;
 
+               case VDEV_AUX_IO_FAILURE:
+                       (void) printf(gettext("experienced I/O failures"));
+                       break;
+
+               case VDEV_AUX_BAD_LOG:
+                       (void) printf(gettext("bad intent log"));
+                       break;
+
                default:
                        (void) printf(gettext("corrupted data"));
                        break;
@@ -3058,6 +3133,25 @@ status_callback(zpool_handle_t *zhp, void *data)
                    "to be recovered.\n"));
                break;
 
+       case ZPOOL_STATUS_IO_FAILURE_WAIT:
+       case ZPOOL_STATUS_IO_FAILURE_CONTINUE:
+               (void) printf(gettext("status: One or more devices are "
+                   "faulted in response to IO failures.\n"));
+               (void) printf(gettext("action: Make sure the affected devices "
+                   "are connected, then run 'zpool clear'.\n"));
+               break;
+
+       case ZPOOL_STATUS_BAD_LOG:
+               (void) printf(gettext("status: An intent log record "
+                   "could not be read.\n"
+                   "\tWaiting for adminstrator intervention to fix the "
+                   "faulted pool.\n"));
+               (void) printf(gettext("action: Either restore the affected "
+                   "device(s) and run 'zpool online',\n"
+                   "\tor ignore the intent log records by running "
+                   "'zpool clear'.\n"));
+               break;
+
        default:
                /*
                 * The remaining errors can't actually be generated, yet.
@@ -3389,6 +3483,11 @@ zpool_do_upgrade(int argc, char **argv)
                (void) printf(gettext(" 9   refquota and refreservation "
                    "properties\n"));
                (void) printf(gettext(" 10  Cache devices\n"));
+               (void) printf(gettext(" 11  Improved scrub performance\n"));
+               (void) printf(gettext(" 12  Snapshot properties\n"));
+               (void) printf(gettext(" 13  snapused property\n"));
+               (void) printf(gettext(" 14  passthrough-x aclinherit "
+                   "support\n"));
                (void) printf(gettext("For more information on a particular "
                    "version, including supported releases, see:\n\n"));
                (void) printf("http://www.opensolaris.org/os/community/zfs/"
@@ -3473,6 +3572,7 @@ char *hist_event_table[LOG_END] = {
        "filesystem version upgrade",
        "refquota set",
        "refreservation set",
+       "pool scrub done",
 };
 
 /*
@@ -3527,7 +3627,7 @@ get_history_one(zpool_handle_t *zhp, void *data)
                            ZPOOL_HIST_TXG, &txg) == 0);
                        verify(nvlist_lookup_string(records[i],
                            ZPOOL_HIST_INT_STR, &pathstr) == 0);
-                       if (ievent > LOG_END)
+                       if (ievent >= LOG_END)
                                continue;
                        (void) snprintf(internalstr,
                            sizeof (internalstr),