From a9d5ac84026cd13c39427d55285ec92506088f8f Mon Sep 17 00:00:00 2001 From: imp Date: Thu, 15 Nov 2018 16:02:45 +0000 Subject: [PATCH] Add cam_iosched_set_latfcn to set a latency callback for high latency. It's often useful to have a callback when an I/O takes more than a threshold amount of time. This adds the infrastructure for periph devices to register one. One use-case is as a debugging aide when you need a semi-realtime indication of an I/O outlier so you can trigger bus capture gear for vendor analysis. Sponsored by: Netflix, Inc --- sys/cam/cam_iosched.c | 35 ++++++++++++++++++++++++++++++++--- sys/cam/cam_iosched.h | 3 +++ 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/sys/cam/cam_iosched.c b/sys/cam/cam_iosched.c index 6e1f6d52d0eb..1818870436db 100644 --- a/sys/cam/cam_iosched.c +++ b/sys/cam/cam_iosched.c @@ -294,6 +294,9 @@ struct cam_iosched_softc { uint32_t this_frac; /* Fraction of a second (1024ths) for this tick */ sbintime_t last_time; /* Last time we ticked */ struct control_loop cl; + sbintime_t max_lat; /* when != 0, if iop latency > max_lat, call max_lat_fcn */ + cam_iosched_latfcn_t latfcn; + void *latarg; #endif }; @@ -1171,6 +1174,21 @@ void cam_iosched_sysctl_init(struct cam_iosched_softc *isc, OID_AUTO, "load", CTLFLAG_RD, &isc->load, 0, "scaled load average / 100"); + + SYSCTL_ADD_U64(ctx, n, + OID_AUTO, "latency_trigger", CTLFLAG_RW, + &isc->max_lat, 0, + "Latency treshold to trigger callbacks"); +#endif +} + +void +cam_iosched_set_latfcn(struct cam_iosched_softc *isc, + cam_iosched_latfcn_t fnp, void *argp) +{ +#ifdef CAM_IOSCHED_DYNAMIC + isc->latfcn = fnp; + isc->latarg = argp; #endif } @@ -1510,10 +1528,21 @@ cam_iosched_bio_complete(struct cam_iosched_softc *isc, struct bio *bp, printf("Completing command with bio_cmd == %#x\n", bp->bio_cmd); } - if (!(bp->bio_flags & BIO_ERROR) && done_ccb != NULL) - cam_iosched_io_metric_update(isc, - cam_iosched_sbintime_t(done_ccb->ccb_h.qos.periph_data), + if (!(bp->bio_flags & BIO_ERROR) && done_ccb != NULL) { + sbintime_t sim_latency; + + sim_latency = cam_iosched_sbintime_t(done_ccb->ccb_h.qos.periph_data); + + cam_iosched_io_metric_update(isc, sim_latency, bp->bio_cmd, bp->bio_bcount); + /* + * Debugging code: allow callbacks to the periph driver when latency max + * is exceeded. This can be useful for triggering external debugging actions. + */ + if (isc->latfcn && isc->max_lat != 0 && sim_latency > isc->max_lat) + isc->latfcn(isc->latarg, sim_latency, bp); + } + #endif return retval; } diff --git a/sys/cam/cam_iosched.h b/sys/cam/cam_iosched.h index 8c575a5ad0de..4fa7fe3b915e 100644 --- a/sys/cam/cam_iosched.h +++ b/sys/cam/cam_iosched.h @@ -80,6 +80,8 @@ cam_iosched_sbintime_t(uintptr_t delta) return (sbintime_t)((uint64_t)delta << CAM_IOSCHED_TIME_SHIFT); } +typedef void (*cam_iosched_latfcn_t)(void *, sbintime_t, struct bio *); + int cam_iosched_init(struct cam_iosched_softc **, struct cam_periph *periph); void cam_iosched_fini(struct cam_iosched_softc *); void cam_iosched_sysctl_init(struct cam_iosched_softc *, struct sysctl_ctx_list *, struct sysctl_oid *); @@ -98,6 +100,7 @@ void cam_iosched_set_work_flags(struct cam_iosched_softc *isc, uint32_t flags); void cam_iosched_clr_work_flags(struct cam_iosched_softc *isc, uint32_t flags); void cam_iosched_trim_done(struct cam_iosched_softc *isc); int cam_iosched_bio_complete(struct cam_iosched_softc *isc, struct bio *bp, union ccb *done_ccb); +void cam_iosched_set_latfcn(struct cam_iosched_softc *isc, cam_iosched_latfcn_t, void *); #endif #endif