]> git.proxmox.com Git - mirror_zfs.git/blobdiff - lib/libzfs/libzfs_pool.c
OpenZFS 9102 - zfs should be able to initialize storage devices
[mirror_zfs.git] / lib / libzfs / libzfs_pool.c
index bc320e516752e844f7d7642fd46085bfa442f0ef..f799471e435128e43ba16cdcac07afa723df7ed1 100644 (file)
@@ -2092,6 +2092,100 @@ zpool_import_props(libzfs_handle_t *hdl, nvlist_t *config, const char *newname,
        return (ret);
 }
 
+static int
+xlate_init_err(int err)
+{
+       switch (err) {
+       case ENODEV:
+               return (EZFS_NODEVICE);
+       case EINVAL:
+       case EROFS:
+               return (EZFS_BADDEV);
+       case EBUSY:
+               return (EZFS_INITIALIZING);
+       case ESRCH:
+               return (EZFS_NO_INITIALIZE);
+       }
+       return (err);
+}
+
+/*
+ * Begin, suspend, or cancel the initialization (initializing of all free
+ * blocks) for the given vdevs in the given pool.
+ */
+int
+zpool_initialize(zpool_handle_t *zhp, pool_initialize_func_t cmd_type,
+    nvlist_t *vds)
+{
+       char msg[1024];
+       libzfs_handle_t *hdl = zhp->zpool_hdl;
+
+       nvlist_t *errlist;
+
+       /* translate vdev names to guids */
+       nvlist_t *vdev_guids = fnvlist_alloc();
+       nvlist_t *guids_to_paths = fnvlist_alloc();
+       boolean_t spare, cache;
+       nvlist_t *tgt;
+       nvpair_t *elem;
+
+       for (elem = nvlist_next_nvpair(vds, NULL); elem != NULL;
+           elem = nvlist_next_nvpair(vds, elem)) {
+               char *vd_path = nvpair_name(elem);
+               tgt = zpool_find_vdev(zhp, vd_path, &spare, &cache, NULL);
+
+               if ((tgt == NULL) || cache || spare) {
+                       (void) snprintf(msg, sizeof (msg),
+                           dgettext(TEXT_DOMAIN, "cannot initialize '%s'"),
+                           vd_path);
+                       int err = (tgt == NULL) ? EZFS_NODEVICE :
+                           (spare ? EZFS_ISSPARE : EZFS_ISL2CACHE);
+                       fnvlist_free(vdev_guids);
+                       fnvlist_free(guids_to_paths);
+                       return (zfs_error(hdl, err, msg));
+               }
+
+               uint64_t guid = fnvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID);
+               fnvlist_add_uint64(vdev_guids, vd_path, guid);
+
+               (void) snprintf(msg, sizeof (msg), "%llu", (u_longlong_t)guid);
+               fnvlist_add_string(guids_to_paths, msg, vd_path);
+       }
+
+       int err = lzc_initialize(zhp->zpool_name, cmd_type, vdev_guids,
+           &errlist);
+       fnvlist_free(vdev_guids);
+
+       if (err == 0) {
+               fnvlist_free(guids_to_paths);
+               return (0);
+       }
+
+       nvlist_t *vd_errlist = NULL;
+       if (errlist != NULL) {
+               vd_errlist = fnvlist_lookup_nvlist(errlist,
+                   ZPOOL_INITIALIZE_VDEVS);
+       }
+
+       (void) snprintf(msg, sizeof (msg),
+           dgettext(TEXT_DOMAIN, "operation failed"));
+
+       for (elem = nvlist_next_nvpair(vd_errlist, NULL); elem != NULL;
+           elem = nvlist_next_nvpair(vd_errlist, elem)) {
+               int64_t vd_error = xlate_init_err(fnvpair_value_int64(elem));
+               char *path = fnvlist_lookup_string(guids_to_paths,
+                   nvpair_name(elem));
+               (void) zfs_error_fmt(hdl, vd_error, "cannot initialize '%s'",
+                   path);
+       }
+
+       fnvlist_free(guids_to_paths);
+       if (vd_errlist != NULL)
+               return (-1);
+
+       return (zpool_standard_error(hdl, err, msg));
+}
+
 /*
  * Scan the pool.
  */