diff options
Diffstat (limited to 'sys')
-rw-r--r-- | sys/cam/cam_iosched.c | 3 | ||||
-rw-r--r-- | sys/cam/cam_iosched.h | 38 | ||||
-rw-r--r-- | sys/cam/cam_xpt.c | 7 |
3 files changed, 44 insertions, 4 deletions
diff --git a/sys/cam/cam_iosched.c b/sys/cam/cam_iosched.c index 98d0dc7d0829..8b77b7d6c44f 100644 --- a/sys/cam/cam_iosched.c +++ b/sys/cam/cam_iosched.c @@ -1428,7 +1428,8 @@ cam_iosched_bio_complete(struct cam_iosched_softc *isc, struct bio *bp, } if (!(bp->bio_flags & BIO_ERROR)) - cam_iosched_io_metric_update(isc, done_ccb->ccb_h.qos.sim_data, + cam_iosched_io_metric_update(isc, + cam_iosched_sbintime_t(done_ccb->ccb_h.qos.periph_data), bp->bio_cmd, bp->bio_bcount); #endif return retval; diff --git a/sys/cam/cam_iosched.h b/sys/cam/cam_iosched.h index 544c9006544e..150b8e90fb41 100644 --- a/sys/cam/cam_iosched.h +++ b/sys/cam/cam_iosched.h @@ -41,6 +41,44 @@ struct sysctl_oid; union ccb; struct bio; +/* + * For 64-bit platforms, we know that uintptr_t is the same size as sbintime_t + * so we can store values in it. For 32-bit systems, however, uintptr_t is only + * 32-bits, so it won't fit. For those systems, store 24 bits of fraction and 8 + * bits of seconds. This allows us to measure an interval of up to ~256s, which + * is ~200x what our current uses require. Provide some convenience functions to + * get the time, subtract two times and convert back to sbintime_t in a safe way + * that can be centralized. + */ +#ifdef __LP64__ +#define CAM_IOSCHED_TIME_SHIFT 0 +#else +#define CAM_IOSCHED_TIME_SHIFT 8 +#endif +static inline uintptr_t +cam_iosched_now(void) +{ + + /* Cast here is to avoid right shifting a signed value */ + return (uintptr_t)((uint64_t)sbinuptime() >> CAM_IOSCHED_TIME_SHIFT); +} + +static inline uintptr_t +cam_iosched_delta_t(uintptr_t then) +{ + + /* Since the types are identical, wrapping works correctly */ + return (cam_iosched_now() - then); +} + +static inline sbintime_t +cam_iosched_sbintime_t(uintptr_t delta) +{ + + /* Cast here is to widen the type so the left shift doesn't lose precision */ + return (sbintime_t)((uint64_t)delta << CAM_IOSCHED_TIME_SHIFT); +} + 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 *); diff --git a/sys/cam/cam_xpt.c b/sys/cam/cam_xpt.c index b29c0aa7079f..ec7169dd7b15 100644 --- a/sys/cam/cam_xpt.c +++ b/sys/cam/cam_xpt.c @@ -55,6 +55,7 @@ __FBSDID("$FreeBSD$"); #include <cam/cam.h> #include <cam/cam_ccb.h> +#include <cam/cam_iosched.h> #include <cam/cam_periph.h> #include <cam/cam_queue.h> #include <cam/cam_sim.h> @@ -3494,7 +3495,7 @@ xpt_run_devq(struct cam_devq *devq) mtx_lock(mtx); else mtx = NULL; - work_ccb->ccb_h.qos.sim_data = sbinuptime(); // xxx uintprt_t too small 32bit platforms + work_ccb->ccb_h.qos.periph_data = cam_iosched_now(); (*(sim->sim_action))(sim, work_ccb); if (mtx) mtx_unlock(mtx); @@ -4641,7 +4642,7 @@ xpt_done(union ccb *done_ccb) return; /* Store the time the ccb was in the sim */ - done_ccb->ccb_h.qos.sim_data = sbinuptime() - done_ccb->ccb_h.qos.sim_data; + done_ccb->ccb_h.qos.periph_data = cam_iosched_delta_t(done_ccb->ccb_h.qos.periph_data); hash = (done_ccb->ccb_h.path_id + done_ccb->ccb_h.target_id + done_ccb->ccb_h.target_lun) % cam_num_doneqs; queue = &cam_doneqs[hash]; @@ -4664,7 +4665,7 @@ xpt_done_direct(union ccb *done_ccb) return; /* Store the time the ccb was in the sim */ - done_ccb->ccb_h.qos.sim_data = sbinuptime() - done_ccb->ccb_h.qos.sim_data; + done_ccb->ccb_h.qos.periph_data = cam_iosched_delta_t(done_ccb->ccb_h.qos.periph_data); xpt_done_process(&done_ccb->ccb_h); } |