Add -p switch to "zpool get"
[zfs.git] / module / zfs / zfs_fm.c
index 0b48126..af2030a 100644 (file)
  * Use is subject to license terms.
  */
 
+/*
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ */
+
 #include <sys/spa.h>
 #include <sys/spa_impl.h>
 #include <sys/vdev.h>
  */
 #ifdef _KERNEL
 static void
+zfs_zevent_post_cb(nvlist_t *nvl, nvlist_t *detector)
+{
+       if (nvl)
+               fm_nvlist_destroy(nvl, FM_NVA_FREE);
+
+       if (detector)
+               fm_nvlist_destroy(detector, FM_NVA_FREE);
+}
+
+static void
 zfs_ereport_start(nvlist_t **ereport_out, nvlist_t **detector_out,
     const char *subclass, spa_t *spa, vdev_t *vd, zio_t *zio,
     uint64_t stateoroffset, uint64_t size)
@@ -134,22 +148,6 @@ zfs_ereport_start(nvlist_t **ereport_out, nvlist_t **detector_out,
                    zio->io_type != ZIO_TYPE_WRITE)
                        return;
 
-               /*
-                * Ignore any errors from speculative I/Os, as failure is an
-                * expected result.
-                */
-               if (zio->io_flags & ZIO_FLAG_SPECULATIVE)
-                       return;
-
-               /*
-                * If this I/O is not a retry I/O, don't post an ereport.
-                * Otherwise, we risk making bad diagnoses based on B_FAILFAST
-                * I/Os.
-                */
-               if (zio->io_error == EIO &&
-                   !(zio->io_flags & ZIO_FLAG_IO_RETRY))
-                       return;
-
                if (vd != NULL) {
                        /*
                         * If the vdev has already been marked as failing due
@@ -252,6 +250,7 @@ zfs_ereport_start(nvlist_t **ereport_out, nvlist_t **detector_out,
 
        if (vd != NULL) {
                vdev_t *pvd = vd->vdev_parent;
+               vdev_queue_t *vq = &vd->vdev_queue;
 
                fm_payload_set(ereport, FM_EREPORT_PAYLOAD_ZFS_VDEV_GUID,
                    DATA_TYPE_UINT64, vd->vdev_guid,
@@ -269,6 +268,19 @@ zfs_ereport_start(nvlist_t **ereport_out, nvlist_t **detector_out,
                        fm_payload_set(ereport,
                            FM_EREPORT_PAYLOAD_ZFS_VDEV_FRU,
                            DATA_TYPE_STRING, vd->vdev_fru, NULL);
+               if (vd->vdev_ashift)
+                       fm_payload_set(ereport,
+                           FM_EREPORT_PAYLOAD_ZFS_VDEV_ASHIFT,
+                           DATA_TYPE_UINT64, vd->vdev_ashift, NULL);
+
+               if (vq != NULL) {
+                       fm_payload_set(ereport,
+                           FM_EREPORT_PAYLOAD_ZFS_VDEV_COMP_TS,
+                           DATA_TYPE_UINT64, vq->vq_io_complete_ts, NULL);
+                       fm_payload_set(ereport,
+                           FM_EREPORT_PAYLOAD_ZFS_VDEV_DELTA_TS,
+                           DATA_TYPE_UINT64, vq->vq_io_delta_ts, NULL);
+               }
 
                if (pvd != NULL) {
                        fm_payload_set(ereport,
@@ -294,6 +306,20 @@ zfs_ereport_start(nvlist_t **ereport_out, nvlist_t **detector_out,
                 */
                fm_payload_set(ereport, FM_EREPORT_PAYLOAD_ZFS_ZIO_ERR,
                    DATA_TYPE_INT32, zio->io_error, NULL);
+               fm_payload_set(ereport, FM_EREPORT_PAYLOAD_ZFS_ZIO_FLAGS,
+                   DATA_TYPE_INT32, zio->io_flags, NULL);
+               fm_payload_set(ereport, FM_EREPORT_PAYLOAD_ZFS_ZIO_STAGE,
+                   DATA_TYPE_UINT32, zio->io_stage, NULL);
+               fm_payload_set(ereport, FM_EREPORT_PAYLOAD_ZFS_ZIO_PIPELINE,
+                   DATA_TYPE_UINT32, zio->io_pipeline, NULL);
+               fm_payload_set(ereport, FM_EREPORT_PAYLOAD_ZFS_ZIO_DELAY,
+                   DATA_TYPE_UINT64, zio->io_delay, NULL);
+               fm_payload_set(ereport, FM_EREPORT_PAYLOAD_ZFS_ZIO_TIMESTAMP,
+                   DATA_TYPE_UINT64, zio->io_timestamp, NULL);
+               fm_payload_set(ereport, FM_EREPORT_PAYLOAD_ZFS_ZIO_DEADLINE,
+                   DATA_TYPE_UINT64, zio->io_deadline, NULL);
+               fm_payload_set(ereport, FM_EREPORT_PAYLOAD_ZFS_ZIO_DELTA,
+                   DATA_TYPE_UINT64, zio->io_delta, NULL);
 
                /*
                 * If the 'size' parameter is non-zero, it indicates this is a
@@ -410,7 +436,7 @@ update_histogram(uint64_t value_arg, uint16_t *hist, uint32_t *count)
  * to the new smallest gap, to prepare for our next invocation.
  */
 static void
-shrink_ranges(zfs_ecksum_info_t *eip)
+zei_shrink_ranges(zfs_ecksum_info_t *eip)
 {
        uint32_t mingap = UINT32_MAX;
        uint32_t new_allowed_gap = eip->zei_mingap + 1;
@@ -429,12 +455,13 @@ shrink_ranges(zfs_ecksum_info_t *eip)
                uint32_t end = r[idx].zr_end;
 
                while (idx < max - 1) {
-                       idx++;
+                       uint32_t nstart, nend, gap;
 
-                       uint32_t nstart = r[idx].zr_start;
-                       uint32_t nend = r[idx].zr_end;
+                       idx++;
+                       nstart = r[idx].zr_start;
+                       nend = r[idx].zr_end;
 
-                       uint32_t gap = nstart - end;
+                       gap = nstart - end;
                        if (gap < new_allowed_gap) {
                                end = nend;
                                continue;
@@ -454,13 +481,13 @@ shrink_ranges(zfs_ecksum_info_t *eip)
 }
 
 static void
-add_range(zfs_ecksum_info_t *eip, int start, int end)
+zei_add_range(zfs_ecksum_info_t *eip, int start, int end)
 {
        struct zei_ranges *r = eip->zei_ranges;
        size_t count = eip->zei_range_count;
 
        if (count >= MAX_RANGES) {
-               shrink_ranges(eip);
+               zei_shrink_ranges(eip);
                count = eip->zei_range_count;
        }
        if (count == 0) {
@@ -482,7 +509,7 @@ add_range(zfs_ecksum_info_t *eip, int start, int end)
 }
 
 static size_t
-range_total_size(zfs_ecksum_info_t *eip)
+zei_range_total_size(zfs_ecksum_info_t *eip)
 {
        struct zei_ranges *r = eip->zei_ranges;
        size_t count = eip->zei_range_count;
@@ -516,7 +543,7 @@ annotate_ecksum(nvlist_t *ereport, zio_bad_cksum_t *info,
        size_t offset = 0;
        ssize_t start = -1;
 
-       zfs_ecksum_info_t *eip = kmem_zalloc(sizeof (*eip), KM_SLEEP);
+       zfs_ecksum_info_t *eip = kmem_zalloc(sizeof (*eip), KM_PUSHPAGE);
 
        /* don't do any annotation for injected checksum errors */
        if (info != NULL && info->zbc_injected)
@@ -559,7 +586,7 @@ annotate_ecksum(nvlist_t *ereport, zio_bad_cksum_t *info,
                        if (start == -1)
                                continue;
 
-                       add_range(eip, start, idx);
+                       zei_add_range(eip, start, idx);
                        start = -1;
                } else {
                        if (start != -1)
@@ -569,10 +596,10 @@ annotate_ecksum(nvlist_t *ereport, zio_bad_cksum_t *info,
                }
        }
        if (start != -1)
-               add_range(eip, start, idx);
+               zei_add_range(eip, start, idx);
 
        /* See if it will fit in our inline buffers */
-       inline_size = range_total_size(eip);
+       inline_size = zei_range_total_size(eip);
        if (inline_size > ZFM_MAX_INLINE)
                no_inline = 1;
 
@@ -675,10 +702,8 @@ zfs_ereport_post(const char *subclass, spa_t *spa, vdev_t *vd, zio_t *zio,
        if (ereport == NULL)
                return;
 
-       fm_ereport_post(ereport, EVCH_SLEEP);
-
-       fm_nvlist_destroy(ereport, FM_NVA_FREE);
-       fm_nvlist_destroy(detector, FM_NVA_FREE);
+       /* Cleanup is handled by the callback function */
+       zfs_zevent_post(ereport, detector, zfs_zevent_post_cb);
 #endif
 }
 
@@ -687,7 +712,7 @@ zfs_ereport_start_checksum(spa_t *spa, vdev_t *vd,
     struct zio *zio, uint64_t offset, uint64_t length, void *arg,
     zio_bad_cksum_t *info)
 {
-       zio_cksum_report_t *report = kmem_zalloc(sizeof (*report), KM_SLEEP);
+       zio_cksum_report_t *report = kmem_zalloc(sizeof (*report), KM_PUSHPAGE);
 
        if (zio->io_vsd != NULL)
                zio->io_vsd_ops->vsd_cksum_report(zio, report, arg);
@@ -696,7 +721,7 @@ zfs_ereport_start_checksum(spa_t *spa, vdev_t *vd,
 
        /* copy the checksum failure information if it was provided */
        if (info != NULL) {
-               report->zcr_ckinfo = kmem_zalloc(sizeof (*info), KM_SLEEP);
+               report->zcr_ckinfo = kmem_zalloc(sizeof (*info), KM_PUSHPAGE);
                bcopy(info, report->zcr_ckinfo, sizeof (*info));
        }
 
@@ -709,6 +734,10 @@ zfs_ereport_start_checksum(spa_t *spa, vdev_t *vd,
 
        if (report->zcr_ereport == NULL) {
                report->zcr_free(report->zcr_cbdata, report->zcr_cbinfo);
+               if (report->zcr_ckinfo != NULL) {
+                       kmem_free(report->zcr_ckinfo,
+                           sizeof (*report->zcr_ckinfo));
+               }
                kmem_free(report, sizeof (*report));
                return;
        }
@@ -730,12 +759,10 @@ zfs_ereport_finish_checksum(zio_cksum_report_t *report,
            good_data, bad_data, report->zcr_length, drop_if_identical);
 
        if (info != NULL)
-               fm_ereport_post(report->zcr_ereport, EVCH_SLEEP);
+               zfs_zevent_post(report->zcr_ereport,
+                   report->zcr_detector, zfs_zevent_post_cb);
 
-       fm_nvlist_destroy(report->zcr_ereport, FM_NVA_FREE);
-       fm_nvlist_destroy(report->zcr_detector, FM_NVA_FREE);
        report->zcr_ereport = report->zcr_detector = NULL;
-
        if (info != NULL)
                kmem_free(info, sizeof (*info));
 #endif
@@ -764,7 +791,7 @@ void
 zfs_ereport_send_interim_checksum(zio_cksum_report_t *report)
 {
 #ifdef _KERNEL
-       fm_ereport_post(report->zcr_ereport, EVCH_SLEEP);
+       zfs_zevent_post(report->zcr_ereport, report->zcr_detector, NULL);
 #endif
 }
 
@@ -787,14 +814,10 @@ zfs_ereport_post_checksum(spa_t *spa, vdev_t *vd,
        info = annotate_ecksum(ereport, zbc, good_data, bad_data, length,
            B_FALSE);
 
-       if (info != NULL)
-               fm_ereport_post(ereport, EVCH_SLEEP);
-
-       fm_nvlist_destroy(ereport, FM_NVA_FREE);
-       fm_nvlist_destroy(detector, FM_NVA_FREE);
-
-       if (info != NULL)
+       if (info != NULL) {
+               zfs_zevent_post(ereport, detector, zfs_zevent_post_cb);
                kmem_free(info, sizeof (*info));
+       }
 #endif
 }
 
@@ -817,13 +840,14 @@ zfs_post_common(spa_t *spa, vdev_t *vd, const char *name)
        VERIFY(nvlist_add_string(resource, FM_CLASS, class) == 0);
        VERIFY(nvlist_add_uint64(resource,
            FM_EREPORT_PAYLOAD_ZFS_POOL_GUID, spa_guid(spa)) == 0);
-       if (vd)
+       if (vd) {
                VERIFY(nvlist_add_uint64(resource,
                    FM_EREPORT_PAYLOAD_ZFS_VDEV_GUID, vd->vdev_guid) == 0);
+               VERIFY(nvlist_add_uint64(resource,
+                   FM_EREPORT_PAYLOAD_ZFS_VDEV_STATE, vd->vdev_state) == 0);
+       }
 
-       fm_ereport_post(resource, EVCH_SLEEP);
-
-       fm_nvlist_destroy(resource, FM_NVA_FREE);
+       zfs_zevent_post(resource, NULL, zfs_zevent_post_cb);
 #endif
 }
 
@@ -836,7 +860,7 @@ zfs_post_common(spa_t *spa, vdev_t *vd, const char *name)
 void
 zfs_post_remove(spa_t *spa, vdev_t *vd)
 {
-       zfs_post_common(spa, vd, FM_RESOURCE_REMOVED);
+       zfs_post_common(spa, vd, FM_EREPORT_RESOURCE_REMOVED);
 }
 
 /*
@@ -847,7 +871,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_RESOURCE_AUTOREPLACE);
+       zfs_post_common(spa, vd, FM_EREPORT_RESOURCE_AUTOREPLACE);
 }
 
 /*
@@ -859,5 +883,13 @@ zfs_post_autoreplace(spa_t *spa, vdev_t *vd)
 void
 zfs_post_state_change(spa_t *spa, vdev_t *vd)
 {
-       zfs_post_common(spa, vd, FM_RESOURCE_STATECHANGE);
+       zfs_post_common(spa, vd, FM_EREPORT_RESOURCE_STATECHANGE);
 }
+
+#if defined(_KERNEL) && defined(HAVE_SPL)
+EXPORT_SYMBOL(zfs_ereport_post);
+EXPORT_SYMBOL(zfs_ereport_post_checksum);
+EXPORT_SYMBOL(zfs_post_remove);
+EXPORT_SYMBOL(zfs_post_autoreplace);
+EXPORT_SYMBOL(zfs_post_state_change);
+#endif /* _KERNEL */