summaryrefslogtreecommitdiff
path: root/usr/src/lib/libzfs/common
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/libzfs/common')
-rw-r--r--usr/src/lib/libzfs/common/libzfs.h23
-rw-r--r--usr/src/lib/libzfs/common/libzfs_dataset.c7
-rw-r--r--usr/src/lib/libzfs/common/libzfs_pool.c181
-rw-r--r--usr/src/lib/libzfs/common/libzfs_status.c46
-rw-r--r--usr/src/lib/libzfs/common/libzfs_util.c5
-rw-r--r--usr/src/lib/libzfs/common/mapfile-vers4
6 files changed, 206 insertions, 60 deletions
diff --git a/usr/src/lib/libzfs/common/libzfs.h b/usr/src/lib/libzfs/common/libzfs.h
index 4550e4a320..b23cfd239a 100644
--- a/usr/src/lib/libzfs/common/libzfs.h
+++ b/usr/src/lib/libzfs/common/libzfs.h
@@ -158,14 +158,20 @@ extern int zpool_add(zpool_handle_t *, nvlist_t *);
* Functions to manipulate pool and vdev state
*/
extern int zpool_scrub(zpool_handle_t *, pool_scrub_type_t);
+extern int zpool_clear(zpool_handle_t *, const char *);
-extern int zpool_vdev_online(zpool_handle_t *, const char *);
-extern int zpool_vdev_offline(zpool_handle_t *, const char *, int);
-extern int zpool_vdev_attach(zpool_handle_t *, const char *, const char *,
- nvlist_t *, int);
+extern int zpool_vdev_online(zpool_handle_t *, const char *, int,
+ vdev_state_t *);
+extern int zpool_vdev_offline(zpool_handle_t *, const char *, boolean_t);
+extern int zpool_vdev_attach(zpool_handle_t *, const char *,
+ const char *, nvlist_t *, int);
extern int zpool_vdev_detach(zpool_handle_t *, const char *);
extern int zpool_vdev_remove(zpool_handle_t *, const char *);
-extern int zpool_clear(zpool_handle_t *, const char *);
+
+extern int zpool_vdev_fault(zpool_handle_t *, uint64_t);
+extern int zpool_vdev_degrade(zpool_handle_t *, uint64_t);
+extern int zpool_vdev_clear(zpool_handle_t *, uint64_t);
+
extern nvlist_t *zpool_find_vdev(zpool_handle_t *, const char *, boolean_t *);
extern int zpool_label_disk(libzfs_handle_t *, zpool_handle_t *, char *);
@@ -173,8 +179,9 @@ extern int zpool_label_disk(libzfs_handle_t *, zpool_handle_t *, char *);
* Functions to manage pool properties
*/
extern int zpool_set_prop(zpool_handle_t *, const char *, const char *);
-extern int zpool_get_prop(zpool_handle_t *, zfs_prop_t, char *,
+extern int zpool_get_prop(zpool_handle_t *, zpool_prop_t, char *,
size_t proplen, zfs_source_t *);
+extern uint64_t zpool_get_prop_int(zpool_handle_t *, zpool_prop_t);
extern const char *zpool_prop_to_name(zpool_prop_t);
extern const char *zpool_prop_values(zpool_prop_t);
@@ -197,6 +204,8 @@ typedef enum {
ZPOOL_STATUS_FAILING_DEV, /* device experiencing errors */
ZPOOL_STATUS_VERSION_NEWER, /* newer on-disk version */
ZPOOL_STATUS_HOSTID_MISMATCH, /* last accessed by another system */
+ ZPOOL_STATUS_FAULTED_DEV_R, /* faulted device with replicas */
+ ZPOOL_STATUS_FAULTED_DEV_NR, /* faulted device with no replicas */
/*
* The following are not faults per se, but still an error possibly
@@ -372,7 +381,7 @@ extern int zfs_share(zfs_handle_t *);
extern int zfs_unshare(zfs_handle_t *);
/*
- * Protocol-specifc share support functions.
+ * Protocol-specific share support functions.
*/
extern boolean_t zfs_is_shared_nfs(zfs_handle_t *, char **);
extern int zfs_share_nfs(zfs_handle_t *);
diff --git a/usr/src/lib/libzfs/common/libzfs_dataset.c b/usr/src/lib/libzfs/common/libzfs_dataset.c
index de438079c6..3f8a377eff 100644
--- a/usr/src/lib/libzfs/common/libzfs_dataset.c
+++ b/usr/src/lib/libzfs/common/libzfs_dataset.c
@@ -1020,7 +1020,7 @@ zfs_validate_properties(libzfs_handle_t *hdl, zfs_type_t type, char *pool_name,
break;
- case ZFS_PROP_BOOTFS:
+ case ZPOOL_PROP_BOOTFS:
/*
* bootfs property value has to be a dataset name and
* the dataset has to be in the same pool as it sets to.
@@ -3568,7 +3568,7 @@ zfs_get_user_props(zfs_handle_t *zhp)
}
/*
- * Given a comma-separated list of properties, contruct a property list
+ * Given a comma-separated list of properties, construct a property list
* containing both user-defined and native properties. This function will
* return a NULL list if 'all' is specified, which can later be expanded on a
* per-dataset basis by zfs_expand_proplist().
@@ -3631,7 +3631,8 @@ zfs_get_proplist_common(libzfs_handle_t *hdl, char *fields,
*/
c = s[len];
s[len] = '\0';
- prop = zfs_name_to_prop_common(s, type);
+ prop = type == ZFS_TYPE_POOL ? zpool_name_to_prop(s) :
+ zfs_name_to_prop(s);
if (prop != ZFS_PROP_INVAL &&
!zfs_prop_valid_for_type(prop, type))
diff --git a/usr/src/lib/libzfs/common/libzfs_pool.c b/usr/src/lib/libzfs/common/libzfs_pool.c
index a5e469c007..fa6cb1a8d6 100644
--- a/usr/src/lib/libzfs/common/libzfs_pool.c
+++ b/usr/src/lib/libzfs/common/libzfs_pool.c
@@ -862,10 +862,12 @@ is_spare(zpool_handle_t *zhp, uint64_t guid)
}
/*
- * Bring the specified vdev online
+ * Bring the specified vdev online. The 'flags' parameter is a set of the
+ * ZFS_ONLINE_* flags.
*/
int
-zpool_vdev_online(zpool_handle_t *zhp, const char *path)
+zpool_vdev_online(zpool_handle_t *zhp, const char *path, int flags,
+ vdev_state_t *newstate)
{
zfs_cmd_t zc = { 0 };
char msg[1024];
@@ -885,17 +887,22 @@ zpool_vdev_online(zpool_handle_t *zhp, const char *path)
if (avail_spare || is_spare(zhp, zc.zc_guid) == B_TRUE)
return (zfs_error(hdl, EZFS_ISSPARE, msg));
- if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_ONLINE, &zc) == 0)
- return (0);
+ zc.zc_cookie = VDEV_STATE_ONLINE;
+ zc.zc_obj = flags;
- return (zpool_standard_error(hdl, errno, msg));
+
+ if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_SET_STATE, &zc) != 0)
+ return (zpool_standard_error(hdl, errno, msg));
+
+ *newstate = zc.zc_cookie;
+ return (0);
}
/*
* Take the specified vdev offline
*/
int
-zpool_vdev_offline(zpool_handle_t *zhp, const char *path, int istmp)
+zpool_vdev_offline(zpool_handle_t *zhp, const char *path, boolean_t istmp)
{
zfs_cmd_t zc = { 0 };
char msg[1024];
@@ -915,9 +922,43 @@ zpool_vdev_offline(zpool_handle_t *zhp, const char *path, int istmp)
if (avail_spare || is_spare(zhp, zc.zc_guid) == B_TRUE)
return (zfs_error(hdl, EZFS_ISSPARE, msg));
- zc.zc_cookie = istmp;
+ zc.zc_cookie = VDEV_STATE_OFFLINE;
+ zc.zc_obj = istmp ? ZFS_OFFLINE_TEMPORARY : 0;
+
+ if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_SET_STATE, &zc) == 0)
+ return (0);
+
+ switch (errno) {
+ case EBUSY:
+
+ /*
+ * There are no other replicas of this device.
+ */
+ return (zfs_error(hdl, EZFS_NOREPLICAS, msg));
+
+ default:
+ return (zpool_standard_error(hdl, errno, msg));
+ }
+}
+
+/*
+ * Mark the given vdev faulted.
+ */
+int
+zpool_vdev_fault(zpool_handle_t *zhp, uint64_t guid)
+{
+ 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"), guid);
- if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_OFFLINE, &zc) == 0)
+ (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
+ zc.zc_guid = guid;
+ zc.zc_cookie = VDEV_STATE_FAULTED;
+
+ if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_SET_STATE, &zc) == 0)
return (0);
switch (errno) {
@@ -931,6 +972,30 @@ zpool_vdev_offline(zpool_handle_t *zhp, const char *path, int istmp)
default:
return (zpool_standard_error(hdl, errno, msg));
}
+
+}
+
+/*
+ * Mark the given vdev degraded.
+ */
+int
+zpool_vdev_degrade(zpool_handle_t *zhp, uint64_t guid)
+{
+ 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"), guid);
+
+ (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
+ zc.zc_guid = guid;
+ zc.zc_cookie = VDEV_STATE_DEGRADED;
+
+ if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_SET_STATE, &zc) == 0)
+ return (0);
+
+ return (zpool_standard_error(hdl, errno, msg));
}
/*
@@ -1232,6 +1297,29 @@ zpool_clear(zpool_handle_t *zhp, const char *path)
}
/*
+ * Similar to zpool_clear(), but takes a GUID (used by fmd).
+ */
+int
+zpool_vdev_clear(zpool_handle_t *zhp, uint64_t guid)
+{
+ 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"),
+ guid);
+
+ (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
+ zc.zc_guid = guid;
+
+ if (ioctl(hdl->libzfs_fd, ZFS_IOC_CLEAR, &zc) == 0)
+ return (0);
+
+ return (zpool_standard_error(hdl, errno, msg));
+}
+
+/*
* Iterate over all zvols in a given pool by walking the /dev/zvol/dsk/<pool>
* hierarchy.
*/
@@ -1492,6 +1580,8 @@ zpool_vdev_name(libzfs_handle_t *hdl, zpool_handle_t *zhp, nvlist_t *nv)
char *path, *devid;
uint64_t value;
char buf[64];
+ vdev_stat_t *vs;
+ uint_t vsc;
if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT,
&value) == 0) {
@@ -1502,7 +1592,16 @@ zpool_vdev_name(libzfs_handle_t *hdl, zpool_handle_t *zhp, nvlist_t *nv)
path = buf;
} else if (nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0) {
- if (zhp != NULL &&
+ /*
+ * If the device is dead (faulted, offline, etc) then don't
+ * bother opening it. Otherwise we may be forcing the user to
+ * open a misbehaving device, which can have undesirable
+ * effects.
+ */
+ if ((nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS,
+ (uint64_t **)&vs, &vsc) != 0 ||
+ vs->vs_state >= VDEV_STATE_DEGRADED) &&
+ zhp != NULL &&
nvlist_lookup_string(nv, ZPOOL_CONFIG_DEVID, &devid) == 0) {
/*
* Determine if the current path is correct.
@@ -1684,7 +1783,7 @@ zpool_upgrade(zpool_handle_t *zhp)
*
* 'pool' is B_TRUE if we are logging a command for 'zpool'; B_FALSE
* otherwise ('zfs'). 'pool_create' is B_TRUE if we are logging the creation
- * of the pool; B_FALSE otherwise. 'path' is the pathanme containing the
+ * of the pool; B_FALSE otherwise. 'path' is the pathname containing the
* poolname. 'argc' and 'argv' are used to construct the command string.
*/
void
@@ -2121,6 +2220,37 @@ zpool_set_prop(zpool_handle_t *zhp, const char *propname, const char *propval)
return (ret);
}
+uint64_t
+zpool_get_prop_int(zpool_handle_t *zhp, zpool_prop_t prop)
+{
+ uint64_t value;
+ nvlist_t *nvp;
+
+ if (zpool_get_version(zhp) < ZFS_VERSION_BOOTFS)
+ return (0);
+
+ if (zhp->zpool_props == NULL && zpool_get_all_props(zhp))
+ return (zpool_prop_default_numeric(prop));
+
+ switch (prop) {
+ case ZPOOL_PROP_AUTOREPLACE:
+ if (nvlist_lookup_nvlist(zhp->zpool_props,
+ zpool_prop_to_name(prop), &nvp) != 0) {
+ value = zpool_prop_default_numeric(prop);
+ } else {
+ VERIFY(nvlist_lookup_uint64(nvp, ZFS_PROP_VALUE,
+ &value) == 0);
+ }
+ return (value);
+ break;
+
+ default:
+ assert(0);
+ }
+
+ return (0);
+}
+
int
zpool_get_prop(zpool_handle_t *zhp, zpool_prop_t prop, char *propbuf,
size_t proplen, zfs_source_t *srctype)
@@ -2140,22 +2270,16 @@ zpool_get_prop(zpool_handle_t *zhp, zpool_prop_t prop, char *propbuf,
return (zfs_error(zhp->zpool_hdl, EZFS_BADVERSION, msg));
}
- if (zhp->zpool_props == NULL && zpool_get_all_props(zhp))
+ if (zhp->zpool_props == NULL && zpool_get_all_props(zhp) &&
+ prop != ZPOOL_PROP_NAME)
return (zfs_error(zhp->zpool_hdl, EZFS_POOLPROPS, msg));
- /*
- * the "name" property is special cased
- */
- if (!zfs_prop_valid_for_type(prop, ZFS_TYPE_POOL) &&
- prop != ZFS_PROP_NAME)
- return (-1);
-
switch (prop) {
- case ZFS_PROP_NAME:
+ case ZPOOL_PROP_NAME:
(void) strlcpy(propbuf, zhp->zpool_name, proplen);
break;
- case ZFS_PROP_BOOTFS:
+ case ZPOOL_PROP_BOOTFS:
if (nvlist_lookup_nvlist(zhp->zpool_props,
zpool_prop_to_name(prop), &nvp) != 0) {
strvalue = (char *)zfs_prop_default_string(prop);
@@ -2171,7 +2295,22 @@ zpool_get_prop(zpool_handle_t *zhp, zpool_prop_t prop, char *propbuf,
if (strlen(strvalue) >= proplen)
return (-1);
}
- (void) strcpy(propbuf, strvalue);
+ (void) strlcpy(propbuf, strvalue, proplen);
+ break;
+
+ case ZPOOL_PROP_AUTOREPLACE:
+ if (nvlist_lookup_nvlist(zhp->zpool_props,
+ zpool_prop_to_name(prop), &nvp) != 0) {
+ value = zpool_prop_default_numeric(prop);
+ src = ZFS_SRC_DEFAULT;
+ } else {
+ VERIFY(nvlist_lookup_uint64(nvp,
+ ZFS_PROP_SOURCE, &value) == 0);
+ src = value;
+ VERIFY(nvlist_lookup_uint64(nvp, ZFS_PROP_VALUE,
+ &value) == 0);
+ }
+ (void) strlcpy(propbuf, value ? "on" : "off", proplen);
break;
default:
diff --git a/usr/src/lib/libzfs/common/libzfs_status.c b/usr/src/lib/libzfs/common/libzfs_status.c
index 3eba97a431..97a81c35bb 100644
--- a/usr/src/lib/libzfs/common/libzfs_status.c
+++ b/usr/src/lib/libzfs/common/libzfs_status.c
@@ -30,7 +30,7 @@
* include both the status of an active pool, as well as the status exported
* pools. Returns one of the ZPOOL_STATUS_* defines describing the status of
* the pool. This status is independent (to a certain degree) from the state of
- * the pool. A pool's state descsribes only whether or not it is capable of
+ * the pool. A pool's state describes only whether or not it is capable of
* providing the necessary fault tolerance for data. The status describes the
* overall status of devices. A pool that is online can still have a device
* that is experiencing errors.
@@ -47,7 +47,7 @@
#include "libzfs_impl.h"
/*
- * Message ID table. This must be kep in sync with the ZPOOL_STATUS_* defines
+ * Message ID table. This must be kept in sync with the ZPOOL_STATUS_* defines
* in libzfs.h. Note that there are some status results which go past the end
* of this table, and hence have no associated message ID.
*/
@@ -65,25 +65,6 @@ static char *zfs_msgid_table[] = {
"ZFS-8000-EY"
};
-/*
- * If the pool is active, a certain class of static errors is overridden by the
- * faults as analayzed by FMA. These faults have separate knowledge articles,
- * and the article referred to by 'zpool status' must match that indicated by
- * the syslog error message. We override missing data as well as corrupt pool.
- */
-static char *zfs_msgid_table_active[] = {
- "ZFS-8000-14",
- "ZFS-8000-D3", /* overridden */
- "ZFS-8000-D3", /* overridden */
- "ZFS-8000-4J",
- "ZFS-8000-5E",
- "ZFS-8000-6X",
- "ZFS-8000-CS", /* overridden */
- "ZFS-8000-8A",
- "ZFS-8000-9P",
- "ZFS-8000-CS", /* overridden */
-};
-
#define NMSGID (sizeof (zfs_msgid_table) / sizeof (zfs_msgid_table[0]))
/* ARGSUSED */
@@ -96,9 +77,16 @@ vdev_missing(uint64_t state, uint64_t aux, uint64_t errs)
/* ARGSUSED */
static int
+vdev_faulted(uint64_t state, uint64_t aux, uint64_t errs)
+{
+ return (state == VDEV_STATE_FAULTED);
+}
+
+/* ARGSUSED */
+static int
vdev_errors(uint64_t state, uint64_t aux, uint64_t errs)
{
- return (errs != 0);
+ return (state == VDEV_STATE_DEGRADED || errs != 0);
}
/* ARGSUSED */
@@ -163,9 +151,9 @@ find_vdev_problem(nvlist_t *vdev, int (*func)(uint64_t, uint64_t, uint64_t))
* following:
*
* - Check for a complete and valid configuration
- * - Look for any missing devices in a non-replicated config
+ * - Look for any faulted or missing devices in a non-replicated config
* - Check for any data errors
- * - Check for any missing devices in a replicated config
+ * - Check for any faulted or missing devices in a replicated config
* - Look for any devices showing errors
* - Check for any resilvering devices
*
@@ -215,9 +203,13 @@ check_status(nvlist_t *config, boolean_t isimport)
return (ZPOOL_STATUS_BAD_GUID_SUM);
/*
- * Missing devices in non-replicated config.
+ * Bad devices in non-replicated config.
*/
if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
+ find_vdev_problem(nvroot, vdev_faulted))
+ return (ZPOOL_STATUS_FAULTED_DEV_NR);
+
+ if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
find_vdev_problem(nvroot, vdev_missing))
return (ZPOOL_STATUS_MISSING_DEV_NR);
@@ -244,6 +236,8 @@ check_status(nvlist_t *config, boolean_t isimport)
/*
* Missing devices in a replicated config.
*/
+ if (find_vdev_problem(nvroot, vdev_faulted))
+ return (ZPOOL_STATUS_FAULTED_DEV_R);
if (find_vdev_problem(nvroot, vdev_missing))
return (ZPOOL_STATUS_MISSING_DEV_R);
if (find_vdev_problem(nvroot, vdev_broken))
@@ -284,7 +278,7 @@ zpool_get_status(zpool_handle_t *zhp, char **msgid)
if (ret >= NMSGID)
*msgid = NULL;
else
- *msgid = zfs_msgid_table_active[ret];
+ *msgid = zfs_msgid_table[ret];
return (ret);
}
diff --git a/usr/src/lib/libzfs/common/libzfs_util.c b/usr/src/lib/libzfs/common/libzfs_util.c
index 6b5a6de945..2ae3e2e6ce 100644
--- a/usr/src/lib/libzfs/common/libzfs_util.c
+++ b/usr/src/lib/libzfs/common/libzfs_util.c
@@ -490,9 +490,8 @@ zfs_nicenum(uint64_t num, char *buf, size_t buflen)
*/
int i;
for (i = 2; i >= 0; i--) {
- (void) snprintf(buf, buflen, "%.*f%c", i,
- (double)num / (1ULL << 10 * index), u);
- if (strlen(buf) <= 5)
+ if (snprintf(buf, buflen, "%.*f%c", i,
+ (double)num / (1ULL << 10 * index), u) <= 5)
break;
}
}
diff --git a/usr/src/lib/libzfs/common/mapfile-vers b/usr/src/lib/libzfs/common/mapfile-vers
index bd4d915a36..e182f14eed 100644
--- a/usr/src/lib/libzfs/common/mapfile-vers
+++ b/usr/src/lib/libzfs/common/mapfile-vers
@@ -116,6 +116,7 @@ SUNWprivate_1.1 {
zpool_get_history;
zpool_get_name;
zpool_get_prop;
+ zpool_get_prop_int;
zpool_get_proplist;
zpool_get_root;
zpool_get_space_total;
@@ -144,7 +145,10 @@ SUNWprivate_1.1 {
zpool_unmount_datasets;
zpool_upgrade;
zpool_vdev_attach;
+ zpool_vdev_clear;
+ zpool_vdev_degrade;
zpool_vdev_detach;
+ zpool_vdev_fault;
zpool_vdev_name;
zpool_vdev_offline;
zpool_vdev_online;