* Copyright 2015 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2014 by Delphix. All rights reserved.
+ * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>
+ * Copyright (c) 2017 Datto Inc.
+ * Copyright (c) 2017 Open-E, Inc. All Rights Reserved.
*/
#include <ctype.h>
#include <zone.h>
#include <sys/stat.h>
#include <sys/efi_partition.h>
+#include <sys/systeminfo.h>
#include <sys/vtoc.h>
#include <sys/zfs_ioctl.h>
#include <dlfcn.h>
#include "zfeature_common.h"
static int read_efi_label(nvlist_t *config, diskaddr_t *sb);
+static boolean_t zpool_vdev_is_interior(const char *name);
typedef struct prop_flags {
int create:1; /* Validate property on creation */
return (0);
}
-static char *
+static const char *
zpool_get_prop_string(zpool_handle_t *zhp, zpool_prop_t prop,
zprop_source_t *src)
{
/*
* Map VDEV STATE to printed strings.
*/
-char *
+const char *
zpool_state_to_name(vdev_state_t state, vdev_aux_t aux)
{
switch (state) {
- default:
- break;
case VDEV_STATE_CLOSED:
case VDEV_STATE_OFFLINE:
return (gettext("OFFLINE"));
return (gettext("DEGRADED"));
case VDEV_STATE_HEALTHY:
return (gettext("ONLINE"));
+
+ default:
+ break;
}
return (gettext("UNKNOWN"));
(void) snprintf(buf, len, "%llu",
(u_longlong_t)intval);
} else {
- (void) zfs_nicenum(intval, buf, len);
+ (void) zfs_nicebytes(intval, buf, len);
}
break;
bootfs_name_valid(const char *pool, char *bootfs)
{
int len = strlen(pool);
+ if (bootfs[0] == '\0')
+ return (B_TRUE);
if (!zfs_name_valid(bootfs, ZFS_TYPE_FILESYSTEM|ZFS_TYPE_SNAPSHOT))
return (B_FALSE);
return (B_FALSE);
}
-#if defined(__sun__) || defined(__sun)
-/*
- * Inspect the configuration to determine if any of the devices contain
- * an EFI label.
- */
-static boolean_t
-pool_uses_efi(nvlist_t *config)
-{
- nvlist_t **child;
- uint_t c, children;
-
- if (nvlist_lookup_nvlist_array(config, ZPOOL_CONFIG_CHILDREN,
- &child, &children) != 0)
- return (read_efi_label(config, NULL) >= 0);
-
- for (c = 0; c < children; c++) {
- if (pool_uses_efi(child[c]))
- return (B_TRUE);
- }
- return (B_FALSE);
-}
-#endif
-
boolean_t
zpool_is_bootable(zpool_handle_t *zhp)
{
char *slash, *check;
struct stat64 statbuf;
zpool_handle_t *zhp;
- nvlist_t *nvroot;
if (nvlist_alloc(&retprops, NV_UNIQUE_NAME, 0) != 0) {
(void) no_memory(hdl);
const char *propname = nvpair_name(elem);
prop = zpool_name_to_prop(propname);
- if (prop == ZPROP_INVAL && zpool_prop_feature(propname)) {
+ if (prop == ZPOOL_PROP_INVAL && zpool_prop_feature(propname)) {
int err;
char *fname = strchr(propname, '@') + 1;
goto error;
}
+ if (!flags.create &&
+ strcmp(strval, ZFS_FEATURE_DISABLED) == 0) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "property '%s' can only be set to "
+ "'disabled' at creation time"), propname);
+ (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+ goto error;
+ }
+
if (nvlist_add_uint64(retprops, propname, 0) != 0) {
(void) no_memory(hdl);
goto error;
/*
* Make sure this property is valid and applies to this type.
*/
- if (prop == ZPROP_INVAL) {
+ if (prop == ZPOOL_PROP_INVAL) {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"invalid property '%s'"), propname);
(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
* Perform additional checking for specific properties.
*/
switch (prop) {
- default:
- break;
case ZPOOL_PROP_VERSION:
if (intval < version ||
!SPA_VERSION_IS_SUPPORTED(intval)) {
break;
case ZPOOL_PROP_ASHIFT:
- if (!flags.create) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "property '%s' can only be set at "
- "creation time"), propname);
- (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
- goto error;
- }
-
- if (intval != 0 && (intval < 9 || intval > 13)) {
+ if (intval != 0 &&
+ (intval < ASHIFT_MIN || intval > ASHIFT_MAX)) {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "property '%s' number %d is invalid."),
- propname, intval);
+ "invalid '%s=%d' property: only values "
+ "between %" PRId32 " and %" PRId32 " "
+ "are allowed.\n"),
+ propname, intval, ASHIFT_MIN, ASHIFT_MAX);
(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
goto error;
}
* bootfs property value has to be a dataset name and
* the dataset has to be in the same pool as it sets to.
*/
- if (strval[0] != '\0' && !bootfs_name_valid(poolname,
- strval)) {
+ if (!bootfs_name_valid(poolname, strval)) {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' "
"is an invalid name"), strval);
(void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf);
(void) zfs_error(hdl, EZFS_OPENFAILED, errbuf);
goto error;
}
- verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL),
- ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0);
-
-#if defined(__sun__) || defined(__sun)
- /*
- * bootfs property cannot be set on a disk which has
- * been EFI labeled.
- */
- if (pool_uses_efi(nvroot)) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "property '%s' not supported on "
- "EFI labeled devices"), propname);
- (void) zfs_error(hdl, EZFS_POOL_NOTSUP, errbuf);
- zpool_close(zhp);
- goto error;
- }
-#endif
zpool_close(zhp);
break;
goto error;
}
break;
+ case ZPOOL_PROP_MULTIHOST:
+ if (get_system_hostid() == 0) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "requires a non-zero system hostid"));
+ (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+ goto error;
+ }
+ break;
+ default:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "property '%s'(%d) not defined"), propname, prop);
+ break;
}
}
"trailing slash in name"));
break;
- case NAME_ERR_MULTIPLE_AT:
+ case NAME_ERR_MULTIPLE_DELIMITERS:
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "multiple '@' delimiters in name"));
+ "multiple '@' and/or '#' delimiters in "
+ "name"));
break;
+
case NAME_ERR_NO_AT:
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"permission set is missing '@'"));
break;
+
+ default:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "(%d) not defined"), why);
+ break;
}
}
return (B_FALSE);
zfs_cmd_t zc = {"\0"};
nvlist_t *zc_fsprops = NULL;
nvlist_t *zc_props = NULL;
+ nvlist_t *hidden_args = NULL;
+ uint8_t *wkeydata = NULL;
+ uint_t wkeylen = 0;
char msg[1024];
int ret = -1;
strcmp(zonestr, "on") == 0);
if ((zc_fsprops = zfs_valid_proplist(hdl, ZFS_TYPE_FILESYSTEM,
- fsprops, zoned, NULL, NULL, msg)) == NULL) {
+ fsprops, zoned, NULL, NULL, B_TRUE, msg)) == NULL) {
goto create_failed;
}
if (!zc_props &&
(nvlist_alloc(&zc_props, NV_UNIQUE_NAME, 0) != 0)) {
goto create_failed;
}
+ if (zfs_crypto_create(hdl, NULL, zc_fsprops, props,
+ &wkeydata, &wkeylen) != 0) {
+ zfs_error(hdl, EZFS_CRYPTOFAILED, msg);
+ goto create_failed;
+ }
if (nvlist_add_nvlist(zc_props,
ZPOOL_ROOTFS_PROPS, zc_fsprops) != 0) {
goto create_failed;
}
+ if (wkeydata != NULL) {
+ if (nvlist_alloc(&hidden_args, NV_UNIQUE_NAME, 0) != 0)
+ goto create_failed;
+
+ if (nvlist_add_uint8_array(hidden_args, "wkeydata",
+ wkeydata, wkeylen) != 0)
+ goto create_failed;
+
+ if (nvlist_add_nvlist(zc_props, ZPOOL_HIDDEN_ARGS,
+ hidden_args) != 0)
+ goto create_failed;
+ }
}
if (zc_props && zcmd_write_src_nvlist(hdl, &zc, zc_props) != 0)
zcmd_free_nvlists(&zc);
nvlist_free(zc_props);
nvlist_free(zc_fsprops);
+ nvlist_free(hidden_args);
+ if (wkeydata != NULL)
+ free(wkeydata);
switch (errno) {
case EBUSY:
{
char buf[64];
- zfs_nicenum(SPA_MINDEVSIZE, buf, sizeof (buf));
+ zfs_nicebytes(SPA_MINDEVSIZE, buf,
+ sizeof (buf));
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"one or more devices is less than the "
zcmd_free_nvlists(&zc);
nvlist_free(zc_props);
nvlist_free(zc_fsprops);
+ nvlist_free(hidden_args);
+ if (wkeydata != NULL)
+ free(wkeydata);
return (ret);
}
return (zfs_error(hdl, EZFS_BADVERSION, msg));
}
-#if defined(__sun__) || defined(__sun)
- if (zpool_is_bootable(zhp) && nvlist_lookup_nvlist_array(nvroot,
- ZPOOL_CONFIG_SPARES, &spares, &nspares) == 0) {
- uint64_t s;
-
- for (s = 0; s < nspares; s++) {
- char *path;
-
- if (nvlist_lookup_string(spares[s], ZPOOL_CONFIG_PATH,
- &path) == 0 && pool_uses_efi(spares[s])) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "device '%s' contains an EFI label and "
- "cannot be used on root pools."),
- zpool_vdev_name(hdl, NULL, spares[s], 0));
- return (zfs_error(hdl, EZFS_POOL_NOTSUP, msg));
- }
- }
- }
-#endif
-
if (zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL) <
SPA_VERSION_L2CACHE &&
nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE,
{
char buf[64];
- zfs_nicenum(SPA_MINDEVSIZE, buf, sizeof (buf));
+ zfs_nicebytes(SPA_MINDEVSIZE, buf,
+ sizeof (buf));
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"device is less than the minimum "
if (error) {
char desc[1024];
+ char aux[256];
/*
* Dry-run failed, but we print out what success
(void) zfs_error(hdl, EZFS_BADVERSION, desc);
break;
+ case EREMOTEIO:
+ if (nv != NULL && nvlist_lookup_nvlist(nv,
+ ZPOOL_CONFIG_LOAD_INFO, &nvinfo) == 0) {
+ char *hostname = "<unknown>";
+ uint64_t hostid = 0;
+ mmp_state_t mmp_state;
+
+ mmp_state = fnvlist_lookup_uint64(nvinfo,
+ ZPOOL_CONFIG_MMP_STATE);
+
+ if (nvlist_exists(nvinfo,
+ ZPOOL_CONFIG_MMP_HOSTNAME))
+ hostname = fnvlist_lookup_string(nvinfo,
+ ZPOOL_CONFIG_MMP_HOSTNAME);
+
+ if (nvlist_exists(nvinfo,
+ ZPOOL_CONFIG_MMP_HOSTID))
+ hostid = fnvlist_lookup_uint64(nvinfo,
+ ZPOOL_CONFIG_MMP_HOSTID);
+
+ if (mmp_state == MMP_STATE_ACTIVE) {
+ (void) snprintf(aux, sizeof (aux),
+ dgettext(TEXT_DOMAIN, "pool is imp"
+ "orted on host '%s' (hostid=%lx).\n"
+ "Export the pool on the other "
+ "system, then run 'zpool import'."),
+ hostname, (unsigned long) hostid);
+ } else if (mmp_state == MMP_STATE_NO_HOSTID) {
+ (void) snprintf(aux, sizeof (aux),
+ dgettext(TEXT_DOMAIN, "pool has "
+ "the multihost property on and "
+ "the\nsystem's hostid is not set. "
+ "Set a unique system hostid with "
+ "the zgenhostid(8) command.\n"));
+ }
+
+ (void) zfs_error_aux(hdl, aux);
+ }
+ (void) zfs_error(hdl, EZFS_ACTIVE_POOL, desc);
+ break;
+
case EINVAL:
(void) zfs_error(hdl, EZFS_INVALCONFIG, desc);
break;
* Scan the pool.
*/
int
-zpool_scan(zpool_handle_t *zhp, pool_scan_func_t func)
+zpool_scan(zpool_handle_t *zhp, pool_scan_func_t func, pool_scrub_cmd_t cmd)
{
zfs_cmd_t zc = {"\0"};
char msg[1024];
+ int err;
libzfs_handle_t *hdl = zhp->zpool_hdl;
(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
zc.zc_cookie = func;
+ zc.zc_flags = cmd;
+
+ if (zfs_ioctl(hdl, ZFS_IOC_POOL_SCAN, &zc) == 0)
+ return (0);
+
+ err = errno;
- if (zfs_ioctl(hdl, ZFS_IOC_POOL_SCAN, &zc) == 0 ||
- (errno == ENOENT && func != POOL_SCAN_NONE))
+ /* ECANCELED on a scrub means we resumed a paused scrub */
+ if (err == ECANCELED && func == POOL_SCAN_SCRUB &&
+ cmd == POOL_SCRUB_NORMAL)
+ return (0);
+
+ if (err == ENOENT && func != POOL_SCAN_NONE && cmd == POOL_SCRUB_NORMAL)
return (0);
if (func == POOL_SCAN_SCRUB) {
- (void) snprintf(msg, sizeof (msg),
- dgettext(TEXT_DOMAIN, "cannot scrub %s"), zc.zc_name);
+ if (cmd == POOL_SCRUB_PAUSE) {
+ (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
+ "cannot pause scrubbing %s"), zc.zc_name);
+ } else {
+ assert(cmd == POOL_SCRUB_NORMAL);
+ (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
+ "cannot scrub %s"), zc.zc_name);
+ }
} else if (func == POOL_SCAN_NONE) {
(void) snprintf(msg, sizeof (msg),
dgettext(TEXT_DOMAIN, "cannot cancel scrubbing %s"),
assert(!"unexpected result");
}
- if (errno == EBUSY) {
+ if (err == EBUSY) {
nvlist_t *nvroot;
pool_scan_stat_t *ps = NULL;
uint_t psc;
ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0);
(void) nvlist_lookup_uint64_array(nvroot,
ZPOOL_CONFIG_SCAN_STATS, (uint64_t **)&ps, &psc);
- if (ps && ps->pss_func == POOL_SCAN_SCRUB)
- return (zfs_error(hdl, EZFS_SCRUBBING, msg));
- else
+ if (ps && ps->pss_func == POOL_SCAN_SCRUB) {
+ if (cmd == POOL_SCRUB_PAUSE)
+ return (zfs_error(hdl, EZFS_SCRUB_PAUSED, msg));
+ else
+ return (zfs_error(hdl, EZFS_SCRUBBING, msg));
+ } else {
return (zfs_error(hdl, EZFS_RESILVERING, msg));
- } else if (errno == ENOENT) {
+ }
+ } else if (err == ENOENT) {
return (zfs_error(hdl, EZFS_NO_SCRUB, msg));
} else {
- return (zpool_standard_error(hdl, errno, msg));
+ return (zpool_standard_error(hdl, err, msg));
}
}
break;
}
- verify(strncmp(type, VDEV_TYPE_RAIDZ,
- strlen(VDEV_TYPE_RAIDZ)) == 0 ||
- strncmp(type, VDEV_TYPE_MIRROR,
- strlen(VDEV_TYPE_MIRROR)) == 0);
+ verify(zpool_vdev_is_interior(type));
verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_ID,
&id) == 0);
/*
* Determine if we have an "interior" top-level vdev (i.e mirror/raidz).
*/
-boolean_t
+static boolean_t
zpool_vdev_is_interior(const char *name)
{
if (strncmp(name, VDEV_TYPE_RAIDZ, strlen(VDEV_TYPE_RAIDZ)) == 0 ||
+ strncmp(name, VDEV_TYPE_SPARE, strlen(VDEV_TYPE_SPARE)) == 0 ||
+ strncmp(name,
+ VDEV_TYPE_REPLACING, strlen(VDEV_TYPE_REPLACING)) == 0 ||
strncmp(name, VDEV_TYPE_MIRROR, strlen(VDEV_TYPE_MIRROR)) == 0)
return (B_TRUE);
return (B_FALSE);
}
static int
-vdev_online(nvlist_t *nv)
+vdev_is_online(nvlist_t *nv)
{
uint64_t ival;
return (EZFS_INVALCONFIG);
}
- if (vdev_online(nv)) {
+ if (vdev_is_online(nv)) {
if ((ret = vdev_get_one_physpath(nv, physpath,
phypath_size, rsz)) != 0)
return (ret);
}
} else if (strcmp(type, VDEV_TYPE_MIRROR) == 0 ||
+ strcmp(type, VDEV_TYPE_RAIDZ) == 0 ||
strcmp(type, VDEV_TYPE_REPLACING) == 0 ||
(is_spare = (strcmp(type, VDEV_TYPE_SPARE) == 0))) {
nvlist_t **child;
&child, &count) != 0)
return (EZFS_INVALCONFIG);
-#if defined(__sun__) || defined(__sun)
/*
- * root pool can not have EFI labeled disks and can only have
- * a single top-level vdev.
+ * root pool can only have a single top-level vdev.
*/
- if (strcmp(type, VDEV_TYPE_ROOT) != 0 || count != 1 ||
- pool_uses_efi(vdev_root))
+ if (strcmp(type, VDEV_TYPE_ROOT) != 0 || count != 1)
return (EZFS_POOL_INVALARG);
-#endif
(void) vdev_get_physpaths(child[0], physpath, phypath_size, &rsz,
B_FALSE);
* The module will do it for us in vdev_disk_open().
*/
error = efi_use_whole_disk(fd);
+
+ /* Flush the buffers to disk and invalidate the page cache. */
+ (void) fsync(fd);
+ (void) ioctl(fd, BLKFLSBUF);
+
(void) close(fd);
if (error && error != VT_ENOSPC) {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "cannot "
"relabel '%s': unable to read disk capacity"), path);
return (zfs_error(hdl, EZFS_NOCAP, msg));
}
+
return (0);
}
+/*
+ * Convert a vdev path to a GUID. Returns GUID or 0 on error.
+ *
+ * If is_spare, is_l2cache, or is_log is non-NULL, then store within it
+ * if the VDEV is a spare, l2cache, or log device. If they're NULL then
+ * ignore them.
+ */
+static uint64_t
+zpool_vdev_path_to_guid_impl(zpool_handle_t *zhp, const char *path,
+ boolean_t *is_spare, boolean_t *is_l2cache, boolean_t *is_log)
+{
+ uint64_t guid;
+ boolean_t spare = B_FALSE, l2cache = B_FALSE, log = B_FALSE;
+ nvlist_t *tgt;
+
+ if ((tgt = zpool_find_vdev(zhp, path, &spare, &l2cache,
+ &log)) == NULL)
+ return (0);
+
+ verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &guid) == 0);
+ if (is_spare != NULL)
+ *is_spare = spare;
+ if (is_l2cache != NULL)
+ *is_l2cache = l2cache;
+ if (is_log != NULL)
+ *is_log = log;
+
+ return (guid);
+}
+
+/* Convert a vdev path to a GUID. Returns GUID or 0 on error. */
+uint64_t
+zpool_vdev_path_to_guid(zpool_handle_t *zhp, const char *path)
+{
+ return (zpool_vdev_path_to_guid_impl(zhp, path, NULL, NULL, NULL));
+}
+
/*
* Bring the specified vdev online. The 'flags' parameter is a set of the
* ZFS_ONLINE_* flags.
{
zfs_cmd_t zc = {"\0"};
char msg[1024];
+ char *pathname;
nvlist_t *tgt;
boolean_t avail_spare, l2cache, islog;
libzfs_handle_t *hdl = zhp->zpool_hdl;
if (avail_spare)
return (zfs_error(hdl, EZFS_ISSPARE, msg));
- if (flags & ZFS_ONLINE_EXPAND ||
- zpool_get_prop_int(zhp, ZPOOL_PROP_AUTOEXPAND, NULL)) {
+ if ((flags & ZFS_ONLINE_EXPAND ||
+ zpool_get_prop_int(zhp, ZPOOL_PROP_AUTOEXPAND, NULL)) &&
+ nvlist_lookup_string(tgt, ZPOOL_CONFIG_PATH, &pathname) == 0) {
uint64_t wholedisk = 0;
(void) nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_WHOLE_DISK,
(void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
"cannot attach %s to %s"), new_disk, old_disk);
-#if defined(__sun__) || defined(__sun)
- /*
- * If this is a root pool, make sure that we're not attaching an
- * EFI labeled device.
- */
- if (rootpool && pool_uses_efi(nvroot)) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "EFI labeled devices are not supported on root pools."));
- return (zfs_error(hdl, EZFS_POOL_NOTSUP, msg));
- }
-#endif
-
(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
if ((tgt = zpool_find_vdev(zhp, old_disk, &avail_spare, &l2cache,
&islog)) == 0)
nvlist_t **varray = NULL, *zc_props = NULL;
uint_t c, children, newchildren, lastlog = 0, vcount, found = 0;
libzfs_handle_t *hdl = zhp->zpool_hdl;
- uint64_t vers;
+ uint64_t vers, readonly = B_FALSE;
boolean_t freelist = B_FALSE, memory_err = B_TRUE;
int retval = 0;
if ((zc_props = zpool_valid_proplist(hdl, zhp->zpool_name,
props, vers, flags, msg)) == NULL)
return (-1);
+ (void) nvlist_lookup_uint64(zc_props,
+ zpool_prop_to_name(ZPOOL_PROP_READONLY), &readonly);
+ if (readonly) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "property %s can only be set at import time"),
+ zpool_prop_to_name(ZPOOL_PROP_READONLY));
+ return (-1);
+ }
}
if (nvlist_lookup_nvlist_array(tree, ZPOOL_CONFIG_CHILDREN, &child,
* Reopen the pool.
*/
int
-zpool_reopen(zpool_handle_t *zhp)
+zpool_reopen_one(zpool_handle_t *zhp, void *data)
{
- zfs_cmd_t zc = {"\0"};
- char msg[1024];
- libzfs_handle_t *hdl = zhp->zpool_hdl;
+ libzfs_handle_t *hdl = zpool_get_handle(zhp);
+ const char *pool_name = zpool_get_name(zhp);
+ boolean_t *scrub_restart = data;
+ int error;
- (void) snprintf(msg, sizeof (msg),
- dgettext(TEXT_DOMAIN, "cannot reopen '%s'"),
- zhp->zpool_name);
+ error = lzc_reopen(pool_name, *scrub_restart);
+ if (error) {
+ return (zpool_standard_error_fmt(hdl, error,
+ dgettext(TEXT_DOMAIN, "cannot reopen '%s'"), pool_name));
+ }
- (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
- if (zfs_ioctl(hdl, ZFS_IOC_POOL_REOPEN, &zc) == 0)
- return (0);
- return (zpool_standard_error(hdl, errno, msg));
+ return (0);
+}
+
+/* call into libzfs_core to execute the sync IOCTL per pool */
+int
+zpool_sync_one(zpool_handle_t *zhp, void *data)
+{
+ int ret;
+ libzfs_handle_t *hdl = zpool_get_handle(zhp);
+ const char *pool_name = zpool_get_name(zhp);
+ boolean_t *force = data;
+ nvlist_t *innvl = fnvlist_alloc();
+
+ fnvlist_add_boolean_value(innvl, "force", *force);
+ if ((ret = lzc_sync(pool_name, innvl, NULL)) != 0) {
+ nvlist_free(innvl);
+ return (zpool_standard_error_fmt(hdl, ret,
+ dgettext(TEXT_DOMAIN, "sync '%s' failed"), pool_name));
+ }
+ nvlist_free(innvl);
+
+ return (0);
}
#if defined(__sun__) || defined(__sun)
char buf[PATH_BUF_LEN];
char tmpbuf[PATH_BUF_LEN];
+ /*
+ * vdev_name will be "root"/"root-0" for the root vdev, but it is the
+ * zpool name that will be displayed to the user.
+ */
+ verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0);
+ if (zhp != NULL && strcmp(type, "root") == 0)
+ return (zfs_strdup(hdl, zpool_get_name(zhp)));
+
env = getenv("ZPOOL_VDEV_NAME_PATH");
if (env && (strtoul(env, NULL, 0) > 0 ||
!strncasecmp(env, "YES", 3) || !strncasecmp(env, "ON", 2)))
/*
* For a block device only use the name.
*/
- verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0);
if ((strcmp(type, VDEV_TYPE_DISK) == 0) &&
!(name_flags & VDEV_NAME_PATH)) {
path = strrchr(path, '/');
return (zfs_strip_partition(path));
}
} else {
- verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &path) == 0);
+ path = type;
/*
* If it's a raidz device, we need to stick in the parity level.
zpool_get_errlog(zpool_handle_t *zhp, nvlist_t **nverrlistp)
{
zfs_cmd_t zc = {"\0"};
+ libzfs_handle_t *hdl = zhp->zpool_hdl;
uint64_t count;
zbookmark_phys_t *zb = NULL;
int i;
&count) == 0);
if (count == 0)
return (0);
- if ((zc.zc_nvlist_dst = (uintptr_t)zfs_alloc(zhp->zpool_hdl,
- count * sizeof (zbookmark_phys_t))) == (uintptr_t)NULL)
- return (-1);
+ zc.zc_nvlist_dst = (uintptr_t)zfs_alloc(zhp->zpool_hdl,
+ count * sizeof (zbookmark_phys_t));
zc.zc_nvlist_dst_size = count;
(void) strcpy(zc.zc_name, zhp->zpool_name);
for (;;) {
count = zc.zc_nvlist_dst_size;
dst = zfs_alloc(zhp->zpool_hdl, count *
sizeof (zbookmark_phys_t));
- if (dst == NULL)
- return (-1);
zc.zc_nvlist_dst = (uintptr_t)dst;
} else {
- return (-1);
+ return (zpool_standard_error_fmt(hdl, errno,
+ dgettext(TEXT_DOMAIN, "errors: List of "
+ "errors unavailable")));
}
} else {
break;
uint64_t reclen;
nvlist_t *nv;
int i;
+ void *tmp;
while (bytes_read > sizeof (reclen)) {
/* add record to nvlist array */
(*numrecords)++;
if (ISP2(*numrecords + 1)) {
- *records = realloc(*records,
+ tmp = realloc(*records,
*numrecords * 2 * sizeof (nvlist_t *));
+ if (tmp == NULL) {
+ nvlist_free(nv);
+ (*numrecords)--;
+ return (ENOMEM);
+ }
+ *records = tmp;
}
(*records)[*numrecords - 1] = nv;
}
(void) snprintf(diskname, sizeof (diskname), "%s%s", DISK_ROOT,
strrchr(path, '/'));
- if ((fd = open(diskname, O_RDWR|O_DIRECT)) >= 0) {
+ if ((fd = open(diskname, O_RDONLY|O_DIRECT)) >= 0) {
struct dk_gpt *vtoc;
if ((err = efi_alloc_and_read(fd, &vtoc)) >= 0) {
struct dk_gpt *vtoc;
int fd, err;
- if ((fd = open(path, O_RDWR|O_DIRECT)) < 0)
+ if ((fd = open(path, O_RDONLY|O_DIRECT)) < 0)
return (errno);
if ((err = efi_alloc_and_read(fd, &vtoc)) != 0) {
if (zhp) {
nvlist_t *nvroot;
-#if defined(__sun__) || defined(__sun)
- if (zpool_is_bootable(zhp)) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "EFI labeled devices are not supported on root "
- "pools."));
- return (zfs_error(hdl, EZFS_POOL_NOTSUP, errbuf));
- }
-#endif
-
verify(nvlist_lookup_nvlist(zhp->zpool_config,
ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0);
vtoc->efi_parts[8].p_size = resv;
vtoc->efi_parts[8].p_tag = V_RESERVED;
- if ((rval = efi_write(fd, vtoc)) != 0 || (rval = efi_rescan(fd)) != 0) {
- /*
- * Some block drivers (like pcata) may not support EFI
- * GPT labels. Print out a helpful error message dir-
- * ecting the user to manually label the disk and give
- * a specific slice.
- */
+ rval = efi_write(fd, vtoc);
+
+ /* Flush the buffers to disk and invalidate the page cache. */
+ (void) fsync(fd);
+ (void) ioctl(fd, BLKFLSBUF);
+
+ if (rval == 0)
+ rval = efi_rescan(fd);
+
+ /*
+ * Some block drivers (like pcata) may not support EFI GPT labels.
+ * Print out a helpful error message directing the user to manually
+ * label the disk and give a specific slice.
+ */
+ if (rval != 0) {
(void) close(fd);
efi_free(vtoc);
return (1);
}
+/*
+ * By "whole disk" we mean an entire physical disk (something we can
+ * label, toggle the write cache on, etc.) as opposed to the full
+ * capacity of a pseudo-device such as lofi or did. We act as if we
+ * are labeling the disk, which should be a pretty good test of whether
+ * it's a viable device or not. Returns B_TRUE if it is and B_FALSE if
+ * it isn't.
+ */
+int
+zfs_dev_is_whole_disk(char *dev_name)
+{
+ struct dk_gpt *label;
+ int fd;
+
+ if ((fd = open(dev_name, O_RDONLY | O_DIRECT)) < 0)
+ return (0);
+
+ if (efi_alloc_and_init(fd, EFI_NUMPAR, &label) != 0) {
+ (void) close(fd);
+ return (0);
+ }
+
+ efi_free(label);
+ (void) close(fd);
+
+ return (1);
+}
+
/*
* Lookup the underlying device for a device name
*