* `vtime_done` is the same but progressed on completion rather
         * than issue.  The delta behind `vtime` represents the cost of
         * currently in-flight IOs.
-        *
-        * `last_vtime` is used to remember `vtime` at the end of the last
-        * period to calculate utilization.
         */
        atomic64_t                      vtime;
        atomic64_t                      done_vtime;
        u64                             abs_vdebt;
-       u64                             last_vtime;
 
        /*
         * The period this iocg was last active in.  Used for deactivation
        struct hrtimer                  waitq_timer;
        struct hrtimer                  delay_timer;
 
+       /* timestamp at the latest activation */
+       u64                             activated_at;
+
        /* statistics */
        struct iocg_pcpu_stat __percpu  *pcpu_stat;
        struct iocg_stat                local_stat;
        u64                             last_stat_abs_vusage;
 
        /* usage is recorded as fractions of WEIGHT_ONE */
+       u32                             usage_delta_us;
        int                             usage_idx;
        u32                             usages[NR_USAGE_SLOTS];
 
        TRACE_IOCG_PATH(iocg_activate, iocg, now,
                        last_period, cur_period, vtime);
 
-       iocg->last_vtime = vtime;
+       iocg->activated_at = now->now;
 
        if (ioc->running == IOC_IDLE) {
                ioc->running = IOC_RUNNING;
        vusage_delta = abs_vusage - iocg->last_stat_abs_vusage;
        iocg->last_stat_abs_vusage = abs_vusage;
 
-       iocg->local_stat.usage_us += div64_u64(vusage_delta, now->vrate);
+       iocg->usage_delta_us = div64_u64(vusage_delta, now->vrate);
+       iocg->local_stat.usage_us += iocg->usage_delta_us;
 
        new_stat.usage_us =
                iocg->local_stat.usage_us + iocg->desc_stat.usage_us;
 
        /* calc usages and see whether some weights need to be moved around */
        list_for_each_entry(iocg, &ioc->active_iocgs, active_list) {
-               u64 vdone, vtime, vusage, vmin;
+               u64 vdone, vtime, usage_us, vmin;
                u32 hw_active, hw_inuse, usage;
+               int uidx;
 
                /*
                 * Collect unused and wind vtime closer to vnow to prevent
                    time_before64(vdone, now.vnow - period_vtime))
                        nr_lagging++;
 
-               if (waitqueue_active(&iocg->waitq))
-                       vusage = now.vnow - iocg->last_vtime;
-               else if (time_before64(iocg->last_vtime, vtime))
-                       vusage = vtime - iocg->last_vtime;
-               else
-                       vusage = 0;
-
-               iocg->last_vtime += vusage;
                /*
-                * Factor in in-flight vtime into vusage to avoid
-                * high-latency completions appearing as idle.  This should
-                * be done after the above ->last_time adjustment.
+                * Determine absolute usage factoring in pending and in-flight
+                * IOs to avoid stalls and high-latency completions appearing as
+                * idle.
                 */
-               vusage = max(vusage, vtime - vdone);
-
-               /* calculate hweight based usage ratio and record */
-               if (vusage) {
-                       usage = DIV64_U64_ROUND_UP(vusage * hw_inuse,
-                                                  period_vtime);
-                       iocg->usage_idx = (iocg->usage_idx + 1) % NR_USAGE_SLOTS;
-                       iocg->usages[iocg->usage_idx] = usage;
+               usage_us = iocg->usage_delta_us;
+               if (waitqueue_active(&iocg->waitq) && time_before64(vtime, now.vnow))
+                       usage_us += DIV64_U64_ROUND_UP(
+                               cost_to_abs_cost(now.vnow - vtime, hw_inuse),
+                               now.vrate);
+               if (vdone != vtime) {
+                       u64 inflight_us = DIV64_U64_ROUND_UP(
+                               cost_to_abs_cost(vtime - vdone, hw_inuse),
+                               now.vrate);
+                       usage_us = max(usage_us, inflight_us);
+               }
+
+               /* convert to hweight based usage ratio and record */
+               uidx = (iocg->usage_idx + 1) % NR_USAGE_SLOTS;
+
+               if (time_after64(vtime, now.vnow - ioc->margins.min)) {
+                       iocg->usage_idx = uidx;
+                       iocg->usages[uidx] = WEIGHT_ONE;
+               } else if (usage_us) {
+                       u64 started_at, dur;
+
+                       if (time_after64(iocg->activated_at, ioc->period_at))
+                               started_at = iocg->activated_at;
+                       else
+                               started_at = ioc->period_at;
+
+                       dur = max_t(u64, now.now - started_at, 1);
+                       usage = clamp_t(u32,
+                               DIV64_U64_ROUND_UP(usage_us * WEIGHT_ONE, dur),
+                               1, WEIGHT_ONE);
+
+                       iocg->usage_idx = uidx;
+                       iocg->usages[uidx] = usage;
                } else {
                        usage = 0;
                }
                        /* throw away surplus vtime */
                        atomic64_add(delta, &iocg->vtime);
                        atomic64_add(delta, &iocg->done_vtime);
-                       iocg->last_vtime += delta;
                        /* if usage is sufficiently low, maybe it can donate */
                        if (surplus_adjusted_hweight_inuse(usage, hw_inuse)) {
                                iocg->has_surplus = true;
 
                __field(u64, vrate)
                __field(u64, last_period)
                __field(u64, cur_period)
-               __field(u64, last_vtime)
                __field(u64, vtime)
                __field(u32, weight)
                __field(u32, inuse)
                __entry->vrate = now->vrate;
                __entry->last_period = last_period;
                __entry->cur_period = cur_period;
-               __entry->last_vtime = iocg->last_vtime;
                __entry->vtime = vtime;
                __entry->weight = iocg->weight;
                __entry->inuse = iocg->inuse;
        ),
 
        TP_printk("[%s:%s] now=%llu:%llu vrate=%llu "
-                 "period=%llu->%llu vtime=%llu->%llu "
+                 "period=%llu->%llu vtime=%llu "
                  "weight=%u/%u hweight=%llu/%llu",
                __get_str(devname), __get_str(cgroup),
                __entry->now, __entry->vnow, __entry->vrate,
                __entry->last_period, __entry->cur_period,
-               __entry->last_vtime, __entry->vtime,
-               __entry->inuse, __entry->weight,
+               __entry->vtime, __entry->inuse, __entry->weight,
                __entry->hweight_inuse, __entry->hweight_active
        )
 );