summaryrefslogtreecommitdiffstats
path: root/module/zfs
diff options
context:
space:
mode:
Diffstat (limited to 'module/zfs')
-rw-r--r--module/zfs/vdev.c27
-rw-r--r--module/zfs/zfs_fm.c42
2 files changed, 50 insertions, 19 deletions
diff --git a/module/zfs/vdev.c b/module/zfs/vdev.c
index 75f6e5ce1..dcf56d8df 100644
--- a/module/zfs/vdev.c
+++ b/module/zfs/vdev.c
@@ -3373,19 +3373,6 @@ vdev_set_state(vdev_t *vd, boolean_t isopen, vdev_state_t state, vdev_aux_t aux)
vd->vdev_ops->vdev_op_leaf)
vd->vdev_ops->vdev_op_close(vd);
- /*
- * If we have brought this vdev back into service, we need
- * to notify fmd so that it can gracefully repair any outstanding
- * cases due to a missing device. We do this in all cases, even those
- * that probably don't correlate to a repaired fault. This is sure to
- * catch all cases, and we let the zfs-retire agent sort it out. If
- * this is a transient state it's OK, as the retire agent will
- * double-check the state of the vdev before repairing it.
- */
- if (state == VDEV_STATE_HEALTHY && vd->vdev_ops->vdev_op_leaf &&
- vd->vdev_prevstate != state)
- zfs_post_state_change(spa, vd);
-
if (vd->vdev_removed &&
state == VDEV_STATE_CANT_OPEN &&
(aux == VDEV_AUX_OPEN_FAILED || vd->vdev_checkremove)) {
@@ -3466,6 +3453,20 @@ vdev_set_state(vdev_t *vd, boolean_t isopen, vdev_state_t state, vdev_aux_t aux)
vd->vdev_removed = B_FALSE;
}
+ /*
+ * Notify ZED of any significant state-change on a leaf vdev.
+ *
+ * We ignore transitions from a closed state to healthy unless
+ * the parent was degraded.
+ */
+ if (vd->vdev_ops->vdev_op_leaf &&
+ ((save_state > VDEV_STATE_CLOSED) ||
+ (vd->vdev_state < VDEV_STATE_HEALTHY) ||
+ (vd->vdev_parent != NULL &&
+ vd->vdev_parent->vdev_prevstate == VDEV_STATE_DEGRADED))) {
+ zfs_post_state_change(spa, vd, save_state);
+ }
+
if (!isopen && vd->vdev_parent)
vdev_propagate_state(vd->vdev_parent);
}
diff --git a/module/zfs/zfs_fm.c b/module/zfs/zfs_fm.c
index 0871fa95b..0d508c0b8 100644
--- a/module/zfs/zfs_fm.c
+++ b/module/zfs/zfs_fm.c
@@ -848,7 +848,8 @@ zfs_ereport_post_checksum(spa_t *spa, vdev_t *vd,
}
static void
-zfs_post_common(spa_t *spa, vdev_t *vd, const char *type, const char *name)
+zfs_post_common(spa_t *spa, vdev_t *vd, const char *type, const char *name,
+ nvlist_t *aux)
{
#ifdef _KERNEL
nvlist_t *resource;
@@ -883,6 +884,13 @@ zfs_post_common(spa_t *spa, vdev_t *vd, const char *type, const char *name)
if (vd->vdev_fru != NULL)
VERIFY0(nvlist_add_string(resource,
FM_EREPORT_PAYLOAD_ZFS_VDEV_FRU, vd->vdev_fru));
+ /* also copy any optional payload data */
+ if (aux) {
+ nvpair_t *elem = NULL;
+
+ while ((elem = nvlist_next_nvpair(aux, elem)) != NULL)
+ (void) nvlist_add_nvpair(resource, elem);
+ }
}
zfs_zevent_post(resource, NULL, zfs_zevent_post_cb);
@@ -898,7 +906,7 @@ zfs_post_common(spa_t *spa, vdev_t *vd, const char *type, const char *name)
void
zfs_post_remove(spa_t *spa, vdev_t *vd)
{
- zfs_post_common(spa, vd, FM_RSRC_CLASS, FM_RESOURCE_REMOVED);
+ zfs_post_common(spa, vd, FM_RSRC_CLASS, FM_RESOURCE_REMOVED, NULL);
}
/*
@@ -909,7 +917,7 @@ zfs_post_remove(spa_t *spa, vdev_t *vd)
void
zfs_post_autoreplace(spa_t *spa, vdev_t *vd)
{
- zfs_post_common(spa, vd, FM_RSRC_CLASS, FM_RESOURCE_AUTOREPLACE);
+ zfs_post_common(spa, vd, FM_RSRC_CLASS, FM_RESOURCE_AUTOREPLACE, NULL);
}
/*
@@ -919,9 +927,31 @@ zfs_post_autoreplace(spa_t *spa, vdev_t *vd)
* open because the device was not found (fault.fs.zfs.device).
*/
void
-zfs_post_state_change(spa_t *spa, vdev_t *vd)
+zfs_post_state_change(spa_t *spa, vdev_t *vd, uint64_t laststate)
{
- zfs_post_common(spa, vd, FM_RSRC_CLASS, FM_RESOURCE_STATECHANGE);
+#ifdef _KERNEL
+ nvlist_t *aux;
+
+ /*
+ * Add optional supplemental keys to payload
+ */
+ aux = fm_nvlist_create(NULL);
+ if (vd && aux) {
+ if (vd->vdev_physpath) {
+ (void) nvlist_add_string(aux,
+ FM_EREPORT_PAYLOAD_ZFS_VDEV_PHYSPATH,
+ vd->vdev_physpath);
+ }
+ (void) nvlist_add_uint64(aux,
+ FM_EREPORT_PAYLOAD_ZFS_VDEV_LASTSTATE, laststate);
+ }
+
+ zfs_post_common(spa, vd, FM_RSRC_CLASS, FM_RESOURCE_STATECHANGE,
+ aux);
+
+ if (aux)
+ fm_nvlist_destroy(aux, FM_NVA_FREE);
+#endif
}
/*
@@ -933,7 +963,7 @@ zfs_post_state_change(spa_t *spa, vdev_t *vd)
void
zfs_post_sysevent(spa_t *spa, vdev_t *vd, const char *name)
{
- zfs_post_common(spa, vd, FM_SYSEVENT_CLASS, name);
+ zfs_post_common(spa, vd, FM_SYSEVENT_CLASS, name, NULL);
}
#if defined(_KERNEL) && defined(HAVE_SPL)