diff options
author | eschrock <none@none> | 2007-06-12 13:18:17 -0700 |
---|---|---|
committer | eschrock <none@none> | 2007-06-12 13:18:17 -0700 |
commit | 3d7072f8bd27709dba14f6fe336f149d25d9e207 (patch) | |
tree | d325ae63ce74901b55494e8a0dc011b9e2e13d43 /usr/src/lib/libzfs/common | |
parent | a5b881a79e40ec2c21d682e676b130a1ee3d2a73 (diff) | |
download | illumos-joyent-3d7072f8bd27709dba14f6fe336f149d25d9e207.tar.gz |
PSARC 2007/197 ZFS hotplug
PSARC 2007/283 FMA for ZFS Phase 2
6401126 ZFS DE should verify that diagnosis is still valid before solving cases
6500545 ZFS does not handle changes in devids
6508521 zpool online should warn when it is being used incorrectly
6509807 ZFS checksum ereports are not being posted
6514712 zfs_nicenum() doesn't work with perfectly-sized buffers
6520510 media state doesn't get updated properly on device removal
6520513 ZFS should have better support for device removal
6520514 vdev state should be controlled through a single ioctl()
6520519 ZFS should diagnose faulty devices
6520947 ZFS DE should close cases which no longer apply
6521393 ZFS case timeout should be FMD_TYPE_TIME
6521624 fmd_hash_walk() can dump core when given a bad address
6521946 ZFS DE needlessly subscribes to faults
6522085 ZFS dictionary files contain spelling errors
6523185 vdev_reopen() doesn't correctly propagate state
6523555 'zpool online' should be less chatty unless something goes wrong
6527379 zpool(1M) should not try to open faulted devices
6527700 ZFS should post a sysevent when topology changes
6528194 lofi should support force unmap and DKIO_DEV_GONE
6528732 ZFS should store physical device path in addition to /dev path
6532635 ZFS keeps devices open unnecessarily
6532979 bad argument to ZFS_IOC_VDEV_ATTACH can panic system
6567983 deadlock with spa_scrub_thread() and spa_namespace_lock
Diffstat (limited to 'usr/src/lib/libzfs/common')
-rw-r--r-- | usr/src/lib/libzfs/common/libzfs.h | 23 | ||||
-rw-r--r-- | usr/src/lib/libzfs/common/libzfs_dataset.c | 7 | ||||
-rw-r--r-- | usr/src/lib/libzfs/common/libzfs_pool.c | 181 | ||||
-rw-r--r-- | usr/src/lib/libzfs/common/libzfs_status.c | 46 | ||||
-rw-r--r-- | usr/src/lib/libzfs/common/libzfs_util.c | 5 | ||||
-rw-r--r-- | usr/src/lib/libzfs/common/mapfile-vers | 4 |
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; |