/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2011 Nexenta Systems, Inc. All rights reserved.
- * Copyright (c) 2011 by Delphix. All rights reserved.
+ * Copyright (c) 2012 by Delphix. All rights reserved.
*/
#include <ctype.h>
#include <stdlib.h>
#include <strings.h>
#include <unistd.h>
+#include <libgen.h>
#include <zone.h>
#include <sys/stat.h>
#include <sys/efi_partition.h>
#include "zfs_prop.h"
#include "libzfs_impl.h"
#include "zfs_comutil.h"
+#include "zfeature_common.h"
static int read_efi_label(nvlist_t *config, diskaddr_t *sb);
static int
zpool_get_all_props(zpool_handle_t *zhp)
{
- zfs_cmd_t zc = { "\0", "\0", "\0", "\0", 0 };
+ zfs_cmd_t zc = {"\0"};
libzfs_handle_t *hdl = zhp->zpool_hdl;
(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
}
/*
- * Get a zpool property value for 'prop' and return the value in
- * a pre-allocated buffer.
+ * Map POOL STATE to printed strings.
+ */
+const char *
+zpool_pool_state_to_name(pool_state_t state)
+{
+ switch (state) {
+ default:
+ break;
+ case POOL_STATE_ACTIVE:
+ return (gettext("ACTIVE"));
+ case POOL_STATE_EXPORTED:
+ return (gettext("EXPORTED"));
+ case POOL_STATE_DESTROYED:
+ return (gettext("DESTROYED"));
+ case POOL_STATE_SPARE:
+ return (gettext("SPARE"));
+ case POOL_STATE_L2CACHE:
+ return (gettext("L2CACHE"));
+ case POOL_STATE_UNINITIALIZED:
+ return (gettext("UNINITIALIZED"));
+ case POOL_STATE_UNAVAIL:
+ return (gettext("UNAVAIL"));
+ case POOL_STATE_POTENTIALLY_ACTIVE:
+ return (gettext("POTENTIALLY_ACTIVE"));
+ }
+
+ return (gettext("UNKNOWN"));
+}
+
+/*
+ * API compatibility wrapper around zpool_get_prop_literal
*/
int
zpool_get_prop(zpool_handle_t *zhp, zpool_prop_t prop, char *buf, size_t len,
zprop_source_t *srctype)
+{
+ return (zpool_get_prop_literal(zhp, prop, buf, len, srctype, B_FALSE));
+}
+
+/*
+ * Get a zpool property value for 'prop' and return the value in
+ * a pre-allocated buffer.
+ */
+int
+zpool_get_prop_literal(zpool_handle_t *zhp, zpool_prop_t prop, char *buf,
+ size_t len, zprop_source_t *srctype, boolean_t literal)
{
uint64_t intval;
const char *strval;
case ZPOOL_PROP_ALTROOT:
case ZPOOL_PROP_CACHEFILE:
+ case ZPOOL_PROP_COMMENT:
if (zhp->zpool_props != NULL ||
zpool_get_all_props(zhp) == 0) {
(void) strlcpy(buf,
case ZPOOL_PROP_SIZE:
case ZPOOL_PROP_ALLOCATED:
case ZPOOL_PROP_FREE:
+ case ZPOOL_PROP_FREEING:
+ case ZPOOL_PROP_EXPANDSZ:
case ZPOOL_PROP_ASHIFT:
- (void) zfs_nicenum(intval, buf, len);
+ if (literal)
+ (void) snprintf(buf, len, "%llu",
+ (u_longlong_t)intval);
+ else
+ (void) zfs_nicenum(intval, buf, len);
break;
case ZPOOL_PROP_CAPACITY:
(void) strlcpy(buf, zpool_state_to_name(intval,
vs->vs_aux), len);
break;
+ case ZPOOL_PROP_VERSION:
+ if (intval >= SPA_VERSION_FEATURES) {
+ (void) snprintf(buf, len, "-");
+ break;
+ }
+ /* FALLTHROUGH */
default:
(void) snprintf(buf, len, "%llu", (u_longlong_t)intval);
}
return (B_FALSE);
}
+#if defined(__sun__) || defined(__sun)
/*
* Inspect the configuration to determine if any of the devices contain
* an EFI label.
}
return (B_FALSE);
}
+#endif
-static boolean_t
-pool_is_bootable(zpool_handle_t *zhp)
+boolean_t
+zpool_is_bootable(zpool_handle_t *zhp)
{
char bootfs[ZPOOL_MAXNAMELEN];
zpool_prop_t prop;
char *strval;
uint64_t intval;
- char *slash;
+ char *slash, *check;
struct stat64 statbuf;
zpool_handle_t *zhp;
nvlist_t *nvroot;
while ((elem = nvlist_next_nvpair(props, elem)) != NULL) {
const char *propname = nvpair_name(elem);
+ prop = zpool_name_to_prop(propname);
+ if (prop == ZPROP_INVAL && zpool_prop_feature(propname)) {
+ int err;
+ zfeature_info_t *feature;
+ char *fname = strchr(propname, '@') + 1;
+
+ err = zfeature_lookup_name(fname, &feature);
+ if (err != 0) {
+ ASSERT3U(err, ==, ENOENT);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "invalid feature '%s'"), fname);
+ (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+ goto error;
+ }
+
+ if (nvpair_type(elem) != DATA_TYPE_STRING) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "'%s' must be a string"), propname);
+ (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+ goto error;
+ }
+
+ (void) nvpair_value_string(elem, &strval);
+ if (strcmp(strval, ZFS_FEATURE_ENABLED) != 0) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "property '%s' can only be set to "
+ "'enabled'"), propname);
+ (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+ goto error;
+ }
+
+ if (nvlist_add_uint64(retprops, propname, 0) != 0) {
+ (void) no_memory(hdl);
+ goto error;
+ }
+ continue;
+ }
+
/*
* Make sure this property is valid and applies to this type.
*/
- if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL) {
+ if (prop == ZPROP_INVAL) {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"invalid property '%s'"), propname);
(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
default:
break;
case ZPOOL_PROP_VERSION:
- if (intval < version || intval > SPA_VERSION) {
+ if (intval < version ||
+ !SPA_VERSION_IS_SUPPORTED(intval)) {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"property '%s' number %d is invalid."),
propname, intval);
*slash = '/';
break;
+ case ZPOOL_PROP_COMMENT:
+ for (check = strval; *check != '\0'; check++) {
+ if (!isprint(*check)) {
+ zfs_error_aux(hdl,
+ dgettext(TEXT_DOMAIN,
+ "comment may only have printable "
+ "characters"));
+ (void) zfs_error(hdl, EZFS_BADPROP,
+ errbuf);
+ goto error;
+ }
+ }
+ if (strlen(strval) > ZPROP_MAX_COMMENT) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "comment must not exceed %d characters"),
+ ZPROP_MAX_COMMENT);
+ (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+ goto error;
+ }
+ break;
case ZPOOL_PROP_READONLY:
if (!flags.import) {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
int
zpool_set_prop(zpool_handle_t *zhp, const char *propname, const char *propval)
{
- zfs_cmd_t zc = { "\0", "\0", "\0", "\0", 0 };
+ zfs_cmd_t zc = {"\0"};
int ret = -1;
char errbuf[1024];
nvlist_t *nvl = NULL;
libzfs_handle_t *hdl = zhp->zpool_hdl;
zprop_list_t *entry;
char buf[ZFS_MAXPROPLEN];
+ nvlist_t *features = NULL;
+ nvpair_t *nvp;
+ zprop_list_t **last;
+ boolean_t firstexpand = (NULL == *plp);
+ int i;
if (zprop_expand_list(hdl, plp, ZFS_TYPE_POOL) != 0)
return (-1);
+ last = plp;
+ while (*last != NULL)
+ last = &(*last)->pl_next;
+
+ if ((*plp)->pl_all)
+ features = zpool_get_features(zhp);
+
+ if ((*plp)->pl_all && firstexpand) {
+ for (i = 0; i < SPA_FEATURES; i++) {
+ zprop_list_t *entry = zfs_alloc(hdl,
+ sizeof (zprop_list_t));
+ entry->pl_prop = ZPROP_INVAL;
+ entry->pl_user_prop = zfs_asprintf(hdl, "feature@%s",
+ spa_feature_table[i].fi_uname);
+ entry->pl_width = strlen(entry->pl_user_prop);
+ entry->pl_all = B_TRUE;
+
+ *last = entry;
+ last = &entry->pl_next;
+ }
+ }
+
+ /* add any unsupported features */
+ for (nvp = nvlist_next_nvpair(features, NULL);
+ nvp != NULL; nvp = nvlist_next_nvpair(features, nvp)) {
+ char *propname;
+ boolean_t found;
+ zprop_list_t *entry;
+
+ if (zfeature_is_supported(nvpair_name(nvp)))
+ continue;
+
+ propname = zfs_asprintf(hdl, "unsupported@%s",
+ nvpair_name(nvp));
+
+ /*
+ * Before adding the property to the list make sure that no
+ * other pool already added the same property.
+ */
+ found = B_FALSE;
+ entry = *plp;
+ while (entry != NULL) {
+ if (entry->pl_user_prop != NULL &&
+ strcmp(propname, entry->pl_user_prop) == 0) {
+ found = B_TRUE;
+ break;
+ }
+ entry = entry->pl_next;
+ }
+ if (found) {
+ free(propname);
+ continue;
+ }
+
+ entry = zfs_alloc(hdl, sizeof (zprop_list_t));
+ entry->pl_prop = ZPROP_INVAL;
+ entry->pl_user_prop = propname;
+ entry->pl_width = strlen(entry->pl_user_prop);
+ entry->pl_all = B_TRUE;
+
+ *last = entry;
+ last = &entry->pl_next;
+ }
+
for (entry = *plp; entry != NULL; entry = entry->pl_next) {
if (entry->pl_fixed)
return (0);
}
+/*
+ * Get the state for the given feature on the given ZFS pool.
+ */
+int
+zpool_prop_get_feature(zpool_handle_t *zhp, const char *propname, char *buf,
+ size_t len)
+{
+ uint64_t refcount;
+ boolean_t found = B_FALSE;
+ nvlist_t *features = zpool_get_features(zhp);
+ boolean_t supported;
+ const char *feature = strchr(propname, '@') + 1;
+
+ supported = zpool_prop_feature(propname);
+ ASSERT(supported || zpool_prop_unsupported(propname));
+
+ /*
+ * Convert from feature name to feature guid. This conversion is
+ * unecessary for unsupported@... properties because they already
+ * use guids.
+ */
+ if (supported) {
+ int ret;
+ zfeature_info_t *fi;
+
+ ret = zfeature_lookup_name(feature, &fi);
+ if (ret != 0) {
+ (void) strlcpy(buf, "-", len);
+ return (ENOTSUP);
+ }
+ feature = fi->fi_guid;
+ }
+
+ if (nvlist_lookup_uint64(features, feature, &refcount) == 0)
+ found = B_TRUE;
+
+ if (supported) {
+ if (!found) {
+ (void) strlcpy(buf, ZFS_FEATURE_DISABLED, len);
+ } else {
+ if (refcount == 0)
+ (void) strlcpy(buf, ZFS_FEATURE_ENABLED, len);
+ else
+ (void) strlcpy(buf, ZFS_FEATURE_ACTIVE, len);
+ }
+ } else {
+ if (found) {
+ if (refcount == 0) {
+ (void) strcpy(buf, ZFS_UNSUPPORTED_INACTIVE);
+ } else {
+ (void) strcpy(buf, ZFS_UNSUPPORTED_READONLY);
+ }
+ } else {
+ (void) strlcpy(buf, "-", len);
+ return (ENOTSUP);
+ }
+ }
+
+ return (0);
+}
/*
* Don't start the slice at the default block of 34; many storage
zpool_create(libzfs_handle_t *hdl, const char *pool, nvlist_t *nvroot,
nvlist_t *props, nvlist_t *fsprops)
{
- zfs_cmd_t zc = { "\0", "\0", "\0", "\0", 0 };
+ zfs_cmd_t zc = {"\0"};
nvlist_t *zc_fsprops = NULL;
nvlist_t *zc_props = NULL;
char msg[1024];
- char *altroot;
int ret = -1;
(void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
* part of an active md or lvm device.
*/
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "one or more vdevs refer to the same device, or one of\n"
- "the devices is part of an active md or lvm device"));
+ "one or more vdevs refer to the same device, or "
+ "one of\nthe devices is part of an active md or "
+ "lvm device"));
return (zfs_error(hdl, EZFS_BADDEV, msg));
case EOVERFLOW:
}
}
- /*
- * If this is an alternate root pool, then we automatically set the
- * mountpoint of the root dataset to be '/'.
- */
- if (nvlist_lookup_string(props, zpool_prop_to_name(ZPOOL_PROP_ALTROOT),
- &altroot) == 0) {
- zfs_handle_t *zhp;
-
- verify((zhp = zfs_open(hdl, pool, ZFS_TYPE_DATASET)) != NULL);
- verify(zfs_prop_set(zhp, zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
- "/") == 0);
-
- zfs_close(zhp);
- }
-
create_failed:
zcmd_free_nvlists(&zc);
nvlist_free(zc_props);
* datasets left in the pool.
*/
int
-zpool_destroy(zpool_handle_t *zhp)
+zpool_destroy(zpool_handle_t *zhp, const char *log_str)
{
- zfs_cmd_t zc = { "\0", "\0", "\0", "\0", 0 };
+ zfs_cmd_t zc = {"\0"};
zfs_handle_t *zfp = NULL;
libzfs_handle_t *hdl = zhp->zpool_hdl;
char msg[1024];
return (-1);
(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
+ zc.zc_history = (uint64_t)(uintptr_t)log_str;
if (zfs_ioctl(hdl, ZFS_IOC_POOL_DESTROY, &zc) != 0) {
(void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
int
zpool_add(zpool_handle_t *zhp, nvlist_t *nvroot)
{
- zfs_cmd_t zc = { "\0", "\0", "\0", "\0", 0 };
+ zfs_cmd_t zc = {"\0"};
int ret;
libzfs_handle_t *hdl = zhp->zpool_hdl;
char msg[1024];
return (zfs_error(hdl, EZFS_BADVERSION, msg));
}
- if (pool_is_bootable(zhp) && nvlist_lookup_nvlist_array(nvroot,
+#if defined(__sun__) || defined(__sun)
+ if (zpool_is_bootable(zhp) && nvlist_lookup_nvlist_array(nvroot,
ZPOOL_CONFIG_SPARES, &spares, &nspares) == 0) {
uint64_t s;
}
}
}
+#endif
if (zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL) <
SPA_VERSION_L2CACHE &&
(void) zfs_error(hdl, EZFS_BADVERSION, msg);
break;
- case EDOM:
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "root pool can not have multiple vdevs"
- " or separate logs"));
- (void) zfs_error(hdl, EZFS_POOL_NOTSUP, msg);
- break;
-
case ENOTBLK:
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"cache device must be a disk or disk slice"));
* Exports the pool from the system. The caller must ensure that there are no
* mounted datasets in the pool.
*/
-int
-zpool_export_common(zpool_handle_t *zhp, boolean_t force, boolean_t hardforce)
+static int
+zpool_export_common(zpool_handle_t *zhp, boolean_t force, boolean_t hardforce,
+ const char *log_str)
{
- zfs_cmd_t zc = { "\0", "\0", "\0", "\0", 0 };
+ zfs_cmd_t zc = {"\0"};
char msg[1024];
(void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
zc.zc_cookie = force;
zc.zc_guid = hardforce;
+ zc.zc_history = (uint64_t)(uintptr_t)log_str;
if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_EXPORT, &zc) != 0) {
switch (errno) {
}
int
-zpool_export(zpool_handle_t *zhp, boolean_t force)
+zpool_export(zpool_handle_t *zhp, boolean_t force, const char *log_str)
{
- return (zpool_export_common(zhp, force, B_FALSE));
+ return (zpool_export_common(zhp, force, B_FALSE, log_str));
}
int
-zpool_export_force(zpool_handle_t *zhp)
+zpool_export_force(zpool_handle_t *zhp, const char *log_str)
{
- return (zpool_export_common(zhp, B_TRUE, B_TRUE));
+ return (zpool_export_common(zhp, B_TRUE, B_TRUE, log_str));
}
static void
if (!hdl->libzfs_printerr || config == NULL)
return;
- if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_LOAD_INFO, &nv) != 0)
+ if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_LOAD_INFO, &nv) != 0 ||
+ nvlist_lookup_nvlist(nv, ZPOOL_CONFIG_REWIND_INFO, &nv) != 0) {
return;
+ }
if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_LOAD_TIME, &rewindto) != 0)
return;
/* All attempted rewinds failed if ZPOOL_CONFIG_LOAD_TIME missing */
if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_LOAD_INFO, &nv) != 0 ||
+ nvlist_lookup_nvlist(nv, ZPOOL_CONFIG_REWIND_INFO, &nv) != 0 ||
nvlist_lookup_uint64(nv, ZPOOL_CONFIG_LOAD_TIME, &rewindto) != 0)
goto no_info;
}
}
+void
+zpool_print_unsup_feat(nvlist_t *config)
+{
+ nvlist_t *nvinfo, *unsup_feat;
+ nvpair_t *nvp;
+
+ verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_LOAD_INFO, &nvinfo) ==
+ 0);
+ verify(nvlist_lookup_nvlist(nvinfo, ZPOOL_CONFIG_UNSUP_FEAT,
+ &unsup_feat) == 0);
+
+ for (nvp = nvlist_next_nvpair(unsup_feat, NULL); nvp != NULL;
+ nvp = nvlist_next_nvpair(unsup_feat, nvp)) {
+ char *desc;
+
+ verify(nvpair_type(nvp) == DATA_TYPE_STRING);
+ verify(nvpair_value_string(nvp, &desc) == 0);
+
+ if (strlen(desc) > 0)
+ (void) printf("\t%s (%s)\n", nvpair_name(nvp), desc);
+ else
+ (void) printf("\t%s\n", nvpair_name(nvp));
+ }
+}
+
/*
* Import the given pool using the known configuration and a list of
* properties to be set. The configuration should have come from
zpool_import_props(libzfs_handle_t *hdl, nvlist_t *config, const char *newname,
nvlist_t *props, int flags)
{
- zfs_cmd_t zc = { "\0", "\0", "\0", "\0", 0 };
+ zfs_cmd_t zc = {"\0"};
zpool_rewind_policy_t policy;
nvlist_t *nv = NULL;
nvlist_t *nvinfo = NULL;
switch (error) {
case ENOTSUP:
+ if (nv != NULL && nvlist_lookup_nvlist(nv,
+ ZPOOL_CONFIG_LOAD_INFO, &nvinfo) == 0 &&
+ nvlist_exists(nvinfo, ZPOOL_CONFIG_UNSUP_FEAT)) {
+ (void) printf(dgettext(TEXT_DOMAIN, "This "
+ "pool uses the following feature(s) not "
+ "supported by this system:\n"));
+ zpool_print_unsup_feat(nv);
+ if (nvlist_exists(nvinfo,
+ ZPOOL_CONFIG_CAN_RDONLY)) {
+ (void) printf(dgettext(TEXT_DOMAIN,
+ "All unsupported features are only "
+ "required for writing to the pool."
+ "\nThe pool can be imported using "
+ "'-o readonly=on'.\n"));
+ }
+ }
/*
* Unsupported version.
*/
int
zpool_scan(zpool_handle_t *zhp, pool_scan_func_t func)
{
- zfs_cmd_t zc = { "\0", "\0", "\0", "\0", 0 };
+ zfs_cmd_t zc = {"\0"};
char msg[1024];
libzfs_handle_t *hdl = zhp->zpool_hdl;
/*
* Search for the requested value. Special cases:
*
- * - ZPOOL_CONFIG_PATH for whole disk entries. These end in with a
- * partition suffix "1", "-part1", or "p1". The suffix is hidden
- * from the user, but included in the string, so this matches around
- * it.
+ * - ZPOOL_CONFIG_PATH for whole disk entries. These end in
+ * "-part1", or "p1". The suffix is hidden from the user,
+ * but included in the string, so this matches around it.
+ * - ZPOOL_CONFIG_PATH for short names zfs_strcmp_shortname()
+ * is used to check all possible expanded paths.
* - looking for a top-level vdev name (i.e. ZPOOL_CONFIG_TYPE).
*
* Otherwise, all other searches are simple string compares.
(void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK,
&wholedisk);
- if (wholedisk) {
- char buf[MAXPATHLEN];
-
- zfs_append_partition(srchval, buf, sizeof (buf));
- if (strcmp(val, buf) == 0)
- return (nv);
+ if (zfs_strcmp_pathname(srchval, val, wholedisk) == 0)
+ return (nv);
- break;
- }
} else if (strcmp(srchkey, ZPOOL_CONFIG_TYPE) == 0 && val) {
char *type, *idx, *end, *p;
uint64_t id, vdev_id;
zpool_find_vdev(zpool_handle_t *zhp, const char *path, boolean_t *avail_spare,
boolean_t *l2cache, boolean_t *log)
{
- char buf[MAXPATHLEN];
char *end;
nvlist_t *nvroot, *search, *ret;
uint64_t guid;
verify(nvlist_add_uint64(search, ZPOOL_CONFIG_GUID, guid) == 0);
} else if (zpool_vdev_is_interior(path)) {
verify(nvlist_add_string(search, ZPOOL_CONFIG_TYPE, path) == 0);
- } else if (path[0] != '/') {
- if (zfs_resolve_shortname(path, buf, sizeof (buf)) < 0) {
- nvlist_free(search);
- return (NULL);
- }
- verify(nvlist_add_string(search, ZPOOL_CONFIG_PATH, buf) == 0);
} else {
verify(nvlist_add_string(search, ZPOOL_CONFIG_PATH, path) == 0);
}
&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.
if (strcmp(type, VDEV_TYPE_ROOT) != 0 || count != 1 ||
pool_uses_efi(vdev_root))
return (EZFS_POOL_INVALARG);
+#endif
(void) vdev_get_physpaths(child[0], physpath, phypath_size, &rsz,
B_FALSE);
* It's possible that we might encounter an error if the device
* does not have any unallocated space left. If so, we simply
* ignore that error and continue on.
+ *
+ * Also, we don't call efi_rescan() - that would just return EBUSY.
+ * The module will do it for us in vdev_disk_open().
*/
error = efi_use_whole_disk(fd);
(void) close(fd);
zpool_vdev_online(zpool_handle_t *zhp, const char *path, int flags,
vdev_state_t *newstate)
{
- zfs_cmd_t zc = { "\0", "\0", "\0", "\0", 0 };
+ zfs_cmd_t zc = {"\0"};
char msg[1024];
nvlist_t *tgt;
boolean_t avail_spare, l2cache, islog;
if (path[0] != '/') {
error = zfs_resolve_shortname(path, buf,
- sizeof(buf));
+ sizeof (buf));
if (error != 0)
return (zfs_error(hdl, EZFS_NODEVICE,
msg));
int
zpool_vdev_offline(zpool_handle_t *zhp, const char *path, boolean_t istmp)
{
- zfs_cmd_t zc = { "\0", "\0", "\0", "\0", 0 };
+ zfs_cmd_t zc = {"\0"};
char msg[1024];
nvlist_t *tgt;
boolean_t avail_spare, l2cache;
int
zpool_vdev_fault(zpool_handle_t *zhp, uint64_t guid, vdev_aux_t aux)
{
- zfs_cmd_t zc = { "\0", "\0", "\0", "\0", 0 };
+ zfs_cmd_t zc = {"\0"};
char msg[1024];
libzfs_handle_t *hdl = zhp->zpool_hdl;
(void) snprintf(msg, sizeof (msg),
- dgettext(TEXT_DOMAIN, "cannot fault %llu"), (u_longlong_t)guid);
+ dgettext(TEXT_DOMAIN, "cannot fault %llu"), (u_longlong_t)guid);
(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
zc.zc_guid = guid;
int
zpool_vdev_degrade(zpool_handle_t *zhp, uint64_t guid, vdev_aux_t aux)
{
- zfs_cmd_t zc = { "\0", "\0", "\0", "\0", 0 };
+ zfs_cmd_t zc = {"\0"};
char msg[1024];
libzfs_handle_t *hdl = zhp->zpool_hdl;
(void) snprintf(msg, sizeof (msg),
- dgettext(TEXT_DOMAIN, "cannot degrade %llu"), (u_longlong_t)guid);
+ dgettext(TEXT_DOMAIN, "cannot degrade %llu"), (u_longlong_t)guid);
(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
zc.zc_guid = guid;
zpool_vdev_attach(zpool_handle_t *zhp,
const char *old_disk, const char *new_disk, nvlist_t *nvroot, int replacing)
{
- zfs_cmd_t zc = { "\0", "\0", "\0", "\0", 0 };
+ zfs_cmd_t zc = {"\0"};
char msg[1024];
int ret;
nvlist_t *tgt;
uint_t children;
nvlist_t *config_root;
libzfs_handle_t *hdl = zhp->zpool_hdl;
- boolean_t rootpool = pool_is_bootable(zhp);
+ boolean_t rootpool = zpool_is_bootable(zhp);
if (replacing)
(void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
(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.
"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,
int
zpool_vdev_detach(zpool_handle_t *zhp, const char *path)
{
- zfs_cmd_t zc = { "\0", "\0", "\0", "\0", 0 };
+ zfs_cmd_t zc = {"\0"};
char msg[1024];
nvlist_t *tgt;
boolean_t avail_spare, l2cache;
zpool_vdev_split(zpool_handle_t *zhp, char *newname, nvlist_t **newroot,
nvlist_t *props, splitflags_t flags)
{
- zfs_cmd_t zc = { "\0", "\0", "\0", "\0", 0 };
+ zfs_cmd_t zc = {"\0"};
char msg[1024];
nvlist_t *tree, *config, **child, **newchild, *newconfig = NULL;
nvlist_t **varray = NULL, *zc_props = NULL;
int
zpool_vdev_remove(zpool_handle_t *zhp, const char *path)
{
- zfs_cmd_t zc = { "\0", "\0", "\0", "\0", 0 };
+ zfs_cmd_t zc = {"\0"};
char msg[1024];
nvlist_t *tgt;
boolean_t avail_spare, l2cache, islog;
int
zpool_clear(zpool_handle_t *zhp, const char *path, nvlist_t *rewindnvl)
{
- zfs_cmd_t zc = { "\0", "\0", "\0", "\0", 0 };
+ zfs_cmd_t zc = {"\0"};
char msg[1024];
nvlist_t *tgt;
zpool_rewind_policy_t policy;
int
zpool_vdev_clear(zpool_handle_t *zhp, uint64_t guid)
{
- zfs_cmd_t zc = { "\0", "\0", "\0", "\0", 0 };
+ zfs_cmd_t zc = {"\0"};
char msg[1024];
libzfs_handle_t *hdl = zhp->zpool_hdl;
(void) snprintf(msg, sizeof (msg),
dgettext(TEXT_DOMAIN, "cannot clear errors for %llx"),
- (u_longlong_t)guid);
+ (u_longlong_t)guid);
(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
zc.zc_guid = guid;
{
char msg[1024];
libzfs_handle_t *hdl = zhp->zpool_hdl;
- zfs_cmd_t zc = { "\0", "\0", "\0", "\0", 0 };
+ zfs_cmd_t zc = {"\0"};
(void) snprintf(msg, sizeof (msg),
dgettext(TEXT_DOMAIN, "cannot reguid '%s'"), zhp->zpool_name);
return (zpool_standard_error(hdl, errno, msg));
}
+/*
+ * Reopen the pool.
+ */
+int
+zpool_reopen(zpool_handle_t *zhp)
+{
+ zfs_cmd_t zc = {"\0"};
+ char msg[1024];
+ libzfs_handle_t *hdl = zhp->zpool_hdl;
+
+ (void) snprintf(msg, sizeof (msg),
+ dgettext(TEXT_DOMAIN, "cannot reopen '%s'"),
+ zhp->zpool_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));
+}
+
/*
* Convert from a devid string to a path.
*/
static void
set_path(zpool_handle_t *zhp, nvlist_t *nv, const char *path)
{
- zfs_cmd_t zc = { "\0", "\0", "\0", "\0", 0 };
+ zfs_cmd_t zc = {"\0"};
(void) strncpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
(void) strncpy(zc.zc_value, path, sizeof (zc.zc_value));
char *path, *devid, *type;
uint64_t value;
char buf[PATH_BUF_LEN];
+ char tmpbuf[PATH_BUF_LEN];
vdev_stat_t *vs;
uint_t vsc;
*/
if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK,
&value) == 0 && value) {
- return strip_partition(hdl, path);
+ return (strip_partition(hdl, path));
}
} else {
verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &path) == 0);
* If it's a raidz device, we need to stick in the parity level.
*/
if (strcmp(path, VDEV_TYPE_RAIDZ) == 0) {
- char tmpbuf[PATH_BUF_LEN];
verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NPARITY,
&value) == 0);
- (void) snprintf(tmpbuf, sizeof (tmpbuf), "%s%llu", path,
+ (void) snprintf(buf, sizeof (buf), "%s%llu", path,
(u_longlong_t)value);
- path = tmpbuf;
+ path = buf;
}
/*
verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_ID,
&id) == 0);
- (void) snprintf(buf, sizeof (buf), "%s-%llu", path,
- (u_longlong_t)id);
- path = buf;
+ (void) snprintf(tmpbuf, sizeof (tmpbuf), "%s-%llu",
+ path, (u_longlong_t)id);
+ path = tmpbuf;
}
}
int
zpool_get_errlog(zpool_handle_t *zhp, nvlist_t **nverrlistp)
{
- zfs_cmd_t zc = { "\0", "\0", "\0", "\0", 0 };
+ zfs_cmd_t zc = {"\0"};
uint64_t count;
zbookmark_t *zb = NULL;
int i;
int
zpool_upgrade(zpool_handle_t *zhp, uint64_t new_version)
{
- zfs_cmd_t zc = { "\0", "\0", "\0", "\0", 0 };
+ zfs_cmd_t zc = {"\0"};
libzfs_handle_t *hdl = zhp->zpool_hdl;
(void) strcpy(zc.zc_name, zhp->zpool_name);
}
void
-zpool_set_history_str(const char *subcommand, int argc, char **argv,
- char *history_str)
+zfs_save_arguments(int argc, char **argv, char *string, int len)
{
int i;
- (void) strlcpy(history_str, subcommand, HIS_MAX_RECORD_LEN);
+ (void) strlcpy(string, basename(argv[0]), len);
for (i = 1; i < argc; i++) {
- if (strlen(history_str) + 1 + strlen(argv[i]) >
- HIS_MAX_RECORD_LEN)
- break;
- (void) strlcat(history_str, " ", HIS_MAX_RECORD_LEN);
- (void) strlcat(history_str, argv[i], HIS_MAX_RECORD_LEN);
+ (void) strlcat(string, " ", len);
+ (void) strlcat(string, argv[i], len);
}
}
-/*
- * Stage command history for logging.
- */
int
-zpool_stage_history(libzfs_handle_t *hdl, const char *history_str)
+zpool_log_history(libzfs_handle_t *hdl, const char *message)
{
- if (history_str == NULL)
- return (EINVAL);
-
- if (strlen(history_str) > HIS_MAX_RECORD_LEN)
- return (EINVAL);
-
- if (hdl->libzfs_log_str != NULL)
- free(hdl->libzfs_log_str);
-
- if ((hdl->libzfs_log_str = strdup(history_str)) == NULL)
- return (no_memory(hdl));
-
- return (0);
+ zfs_cmd_t zc = {"\0"};
+ nvlist_t *args;
+ int err;
+
+ args = fnvlist_alloc();
+ fnvlist_add_string(args, "message", message);
+ err = zcmd_write_src_nvlist(hdl, &zc, args);
+ if (err == 0)
+ err = ioctl(hdl->libzfs_fd, ZFS_IOC_LOG_HISTORY, &zc);
+ nvlist_free(args);
+ zcmd_free_nvlists(&zc);
+ return (err);
}
/*
static int
get_history(zpool_handle_t *zhp, char *buf, uint64_t *off, uint64_t *len)
{
- zfs_cmd_t zc = { "\0", "\0", "\0", "\0", 0 };
+ zfs_cmd_t zc = {"\0"};
libzfs_handle_t *hdl = zhp->zpool_hdl;
(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
zpool_events_next(libzfs_handle_t *hdl, nvlist_t **nvp,
int *dropped, int block, int cleanup_fd)
{
- zfs_cmd_t zc = { "\0", "\0", "\0", "\0", 0 };
+ zfs_cmd_t zc = {"\0"};
int error = 0;
*nvp = NULL;
int
zpool_events_clear(libzfs_handle_t *hdl, int *count)
{
- zfs_cmd_t zc = { "\0", "\0", "\0", "\0", 0 };
+ zfs_cmd_t zc = {"\0"};
char msg[1024];
(void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
zpool_obj_to_path(zpool_handle_t *zhp, uint64_t dsobj, uint64_t obj,
char *pathname, size_t len)
{
- zfs_cmd_t zc = { "\0", "\0", "\0", "\0", 0 };
+ zfs_cmd_t zc = {"\0"};
boolean_t mounted = B_FALSE;
char *mntpnt = NULL;
char dsname[MAXNAMELEN];
if (dsobj == 0) {
/* special case for the MOS */
- (void) snprintf(pathname, len, "<metadata>:<0x%llx>", (longlong_t)obj);
+ (void) snprintf(pathname, len, "<metadata>:<0x%llx>",
+ (longlong_t)obj);
return;
}
dsname, zc.zc_value);
}
} else {
- (void) snprintf(pathname, len, "%s:<0x%llx>", dsname, (longlong_t)obj);
+ (void) snprintf(pathname, len, "%s:<0x%llx>", dsname,
+ (longlong_t)obj);
}
free(mntpnt);
}
if (nvlist_lookup_string(config, ZPOOL_CONFIG_PATH, &path) != 0)
return (err);
- (void) snprintf(diskname, sizeof (diskname), "%s%s", RDISK_ROOT,
+ (void) snprintf(diskname, sizeof (diskname), "%s%s", DISK_ROOT,
strrchr(path, '/'));
if ((fd = open(diskname, O_RDWR|O_DIRECT)) >= 0) {
struct dk_gpt *vtoc;
int fd, err;
if ((fd = open(path, O_RDWR|O_DIRECT)) < 0)
- return errno;
+ return (errno);
if ((err = efi_alloc_and_read(fd, &vtoc)) != 0) {
(void) close(fd);
- return err;
+ return (err);
}
if (vtoc->efi_flags & EFI_GPT_PRIMARY_CORRUPT) {
efi_free(vtoc);
(void) close(fd);
- return EIDRM;
+ return (EIDRM);
}
efi_free(vtoc);
(void) close(fd);
- return 0;
+ return (0);
}
/*
if (zhp) {
nvlist_t *nvroot;
- if (pool_is_bootable(zhp)) {
+#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);
start_block = NEW_START_BLOCK;
}
- (void) snprintf(path, sizeof (path), "%s/%s%s", RDISK_ROOT, name,
- BACKUP_SLICE);
+ (void) snprintf(path, sizeof (path), "%s/%s", DISK_ROOT, name);
if ((fd = open(path, O_RDWR|O_DIRECT)) < 0) {
/*
vtoc->efi_parts[8].p_size = resv;
vtoc->efi_parts[8].p_tag = V_RESERVED;
- if ((rval = efi_write(fd, vtoc)) != 0) {
+ 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-
(void) close(fd);
efi_free(vtoc);
- /* Wait for the first expected slice to appear. */
- (void) snprintf(path, sizeof (path), "%s/%s%s%s", DISK_ROOT, name,
- isdigit(name[strlen(name)-1]) ? "p" : "", FIRST_SLICE);
+ /* Wait for the first expected partition to appear. */
+
+ (void) snprintf(path, sizeof (path), "%s/%s", DISK_ROOT, name);
+ (void) zfs_append_partition(path, MAXPATHLEN);
+
rval = zpool_label_disk_wait(path, 3000);
if (rval) {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "failed to "
return (zfs_error(hdl, EZFS_LABELFAILED, errbuf));
}
- return 0;
+ return (0);
}