Commit ab8df828 authored by Tejun Heo's avatar Tejun Heo Committed by Jens Axboe
Browse files

iocost: factor out ioc_forgive_debts()



Debt reduction logic is going to be improved and expanded. Factor it out
into ioc_forgive_debts() and generalize the comment a bit. No functional
change.

Signed-off-by: default avatarTejun Heo <tj@kernel.org>
Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent 6abc4946
Loading
Loading
Loading
Loading
+35 −31
Original line number Diff line number Diff line
@@ -1979,6 +1979,40 @@ static void transfer_surpluses(struct list_head *surpluses, struct ioc_now *now)
		list_del_init(&iocg->walk_list);
}

/*
 * A low weight iocg can amass a large amount of debt, for example, when
 * anonymous memory gets reclaimed aggressively. If the system has a lot of
 * memory paired with a slow IO device, the debt can span multiple seconds or
 * more. If there are no other subsequent IO issuers, the in-debt iocg may end
 * up blocked paying its debt while the IO device is idle.
 *
 * The following protects against such cases. If the device has been
 * sufficiently idle for a while, the debts are halved.
 */
static void ioc_forgive_debts(struct ioc *ioc, u64 usage_us_sum, int nr_debtors,
			      int nr_shortages, struct ioc_now *now)
{
	if (nr_shortages ||
	    div64_u64(100 * usage_us_sum, now->now - ioc->period_at) >=
	    DEBT_BUSY_USAGE_PCT)
		ioc->debt_busy_at = now->now;

	if (nr_debtors &&
	    now->now - ioc->debt_busy_at >= DEBT_REDUCTION_IDLE_DUR) {
		struct ioc_gq *iocg;

		list_for_each_entry(iocg, &ioc->active_iocgs, active_list) {
			if (iocg->abs_vdebt) {
				spin_lock(&iocg->waitq.lock);
				iocg->abs_vdebt /= 2;
				iocg_kick_waitq(iocg, true, now);
				spin_unlock(&iocg->waitq.lock);
			}
		}
		ioc->debt_busy_at = now->now;
	}
}

static void ioc_timer_fn(struct timer_list *timer)
{
	struct ioc *ioc = container_of(timer, struct ioc, timer);
@@ -2171,37 +2205,7 @@ static void ioc_timer_fn(struct timer_list *timer)
	list_for_each_entry_safe(iocg, tiocg, &surpluses, surplus_list)
		list_del_init(&iocg->surplus_list);

	/*
	 * A low weight iocg can amass a large amount of debt, for example, when
	 * anonymous memory gets reclaimed aggressively. If the system has a lot
	 * of memory paired with a slow IO device, the debt can span multiple
	 * seconds or more. If there are no other subsequent IO issuers, the
	 * in-debt iocg may end up blocked paying its debt while the IO device
	 * is idle.
	 *
	 * The following protects against such pathological cases. If the device
	 * has been sufficiently idle for a substantial amount of time, the
	 * debts are halved. The criteria are on the conservative side as we
	 * want to resolve the rare extreme cases without impacting regular
	 * operation by forgiving debts too readily.
	 */
	if (nr_shortages ||
	    div64_u64(100 * usage_us_sum, now.now - ioc->period_at) >=
	    DEBT_BUSY_USAGE_PCT)
		ioc->debt_busy_at = now.now;

	if (nr_debtors &&
	    now.now - ioc->debt_busy_at >= DEBT_REDUCTION_IDLE_DUR) {
		list_for_each_entry(iocg, &ioc->active_iocgs, active_list) {
			if (iocg->abs_vdebt) {
				spin_lock(&iocg->waitq.lock);
				iocg->abs_vdebt /= 2;
				iocg_kick_waitq(iocg, true, &now);
				spin_unlock(&iocg->waitq.lock);
			}
		}
		ioc->debt_busy_at = now.now;
	}
	ioc_forgive_debts(ioc, usage_us_sum, nr_debtors, nr_shortages, &now);

	/*
	 * If q is getting clogged or we're missing too much, we're issuing