mirror of
https://github.com/S3NEO/android_kernel_samsung_msm8226.git
synced 2024-11-07 03:47:13 +00:00
block: row: Prevent starvation of regular priority by high priority
At the moment all REGULAR and LOW priority requests are starved as long as there are HIGH priority requests to dispatch. This patch prevents the above starvation by setting a starvation limit the REGULAR\LOW priority requests can tolerate. Change-Id: Ibe24207982c2c55d75c0b0230f67e013d1106017 Signed-off-by: Tatyana Brokhman <tlinder@codeaurora.org>
This commit is contained in:
parent
e334e072f2
commit
eec494769a
1 changed files with 107 additions and 6 deletions
|
@ -157,6 +157,20 @@ struct idling_data {
|
|||
enum row_queue_prio idling_queue_idx;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct starvation_data - data for starvation management
|
||||
* @starvation_limit: number of times this priority class
|
||||
* can tolerate being starved
|
||||
* @starvation_counter: number of requests from higher
|
||||
* priority classes that were dispatched while this
|
||||
* priority request were pending
|
||||
*
|
||||
*/
|
||||
struct starvation_data {
|
||||
int starvation_limit;
|
||||
int starvation_counter;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct row_queue - Per block device rqueue structure
|
||||
* @dispatch_queue: dispatch rqueue
|
||||
|
@ -170,6 +184,8 @@ struct idling_data {
|
|||
* complete.
|
||||
* @pending_urgent_rq: pointer to the pending urgent request
|
||||
* @last_served_ioprio_class: I/O priority class that was last dispatched from
|
||||
* @reg_prio_starvation: starvation data for REGULAR priority queues
|
||||
* @low_prio_starvation: starvation data for LOW priority queues
|
||||
* @cycle_flags: used for marking unserved queueus
|
||||
*
|
||||
*/
|
||||
|
@ -183,6 +199,12 @@ struct row_data {
|
|||
bool urgent_in_flight;
|
||||
struct request *pending_urgent_rq;
|
||||
int last_served_ioprio_class;
|
||||
|
||||
#define ROW_REG_STARVATION_TOLLERANCE 50
|
||||
struct starvation_data reg_prio_starvation;
|
||||
#define ROW_LOW_STARVATION_TOLLERANCE 1000
|
||||
struct starvation_data low_prio_starvation;
|
||||
|
||||
unsigned int cycle_flags;
|
||||
};
|
||||
|
||||
|
@ -258,6 +280,42 @@ static enum hrtimer_restart row_idle_hrtimer_fn(struct hrtimer *hr_timer)
|
|||
return HRTIMER_NORESTART;
|
||||
}
|
||||
|
||||
/*
|
||||
* row_regular_req_pending() - Check if there are REGULAR priority requests
|
||||
* Pending in scheduler
|
||||
* @rd: pointer to struct row_data
|
||||
*
|
||||
* Returns True if there are REGULAR priority requests in scheduler queues.
|
||||
* False, otherwise.
|
||||
*/
|
||||
static inline bool row_regular_req_pending(struct row_data *rd)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = ROWQ_REG_PRIO_IDX; i < ROWQ_LOW_PRIO_IDX; i++)
|
||||
if (!list_empty(&rd->row_queues[i].fifo))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* row_low_req_pending() - Check if there are LOW priority requests
|
||||
* Pending in scheduler
|
||||
* @rd: pointer to struct row_data
|
||||
*
|
||||
* Returns True if there are LOW priority requests in scheduler queues.
|
||||
* False, otherwise.
|
||||
*/
|
||||
static inline bool row_low_req_pending(struct row_data *rd)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = ROWQ_LOW_PRIO_IDX; i < ROWQ_MAX_PRIO; i++)
|
||||
if (!list_empty(&rd->row_queues[i].fifo))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/******************* Elevator callback functions *********************/
|
||||
|
||||
/*
|
||||
|
@ -272,6 +330,7 @@ static void row_add_request(struct request_queue *q,
|
|||
struct row_data *rd = (struct row_data *)q->elevator->elevator_data;
|
||||
struct row_queue *rqueue = RQ_ROWQ(rq);
|
||||
s64 diff_ms;
|
||||
bool queue_was_empty = list_empty(&rqueue->fifo);
|
||||
|
||||
list_add_tail(&rq->queuelist, &rqueue->fifo);
|
||||
rd->nr_reqs[rq_data_dir(rq)]++;
|
||||
|
@ -316,7 +375,8 @@ static void row_add_request(struct request_queue *q,
|
|||
!rd->pending_urgent_rq && !rd->urgent_in_flight) {
|
||||
/* Handle High Priority queues */
|
||||
if (rqueue->prio < ROWQ_REG_PRIO_IDX &&
|
||||
rd->last_served_ioprio_class != IOPRIO_CLASS_RT) {
|
||||
rd->last_served_ioprio_class != IOPRIO_CLASS_RT &&
|
||||
queue_was_empty) {
|
||||
row_log_rowq(rd, rqueue->prio,
|
||||
"added (high prio) urgent request");
|
||||
rq->cmd_flags |= REQ_URGENT;
|
||||
|
@ -472,12 +532,21 @@ static void row_dispatch_insert(struct row_data *rd, struct request *rq)
|
|||
row_log_rowq(rd, rqueue->prio,
|
||||
" Dispatched request %p nr_disp = %d", rq,
|
||||
rqueue->nr_dispatched);
|
||||
if (rqueue->prio < ROWQ_REG_PRIO_IDX)
|
||||
if (rqueue->prio < ROWQ_REG_PRIO_IDX) {
|
||||
rd->last_served_ioprio_class = IOPRIO_CLASS_RT;
|
||||
else if (rqueue->prio < ROWQ_LOW_PRIO_IDX)
|
||||
if (row_regular_req_pending(rd))
|
||||
rd->reg_prio_starvation.starvation_counter++;
|
||||
if (row_low_req_pending(rd))
|
||||
rd->low_prio_starvation.starvation_counter++;
|
||||
} else if (rqueue->prio < ROWQ_LOW_PRIO_IDX) {
|
||||
rd->last_served_ioprio_class = IOPRIO_CLASS_BE;
|
||||
else
|
||||
rd->reg_prio_starvation.starvation_counter = 0;
|
||||
if (row_low_req_pending(rd))
|
||||
rd->low_prio_starvation.starvation_counter++;
|
||||
} else {
|
||||
rd->last_served_ioprio_class = IOPRIO_CLASS_IDLE;
|
||||
rd->low_prio_starvation.starvation_counter = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -517,7 +586,18 @@ static int row_get_ioprio_class_to_serve(struct row_data *rd, int force)
|
|||
rd->rd_idle_data.idling_queue_idx =
|
||||
ROWQ_MAX_PRIO;
|
||||
}
|
||||
ret = IOPRIO_CLASS_RT;
|
||||
|
||||
if (row_regular_req_pending(rd) &&
|
||||
(rd->reg_prio_starvation.starvation_counter >=
|
||||
rd->reg_prio_starvation.starvation_limit))
|
||||
ret = IOPRIO_CLASS_BE;
|
||||
else if (row_low_req_pending(rd) &&
|
||||
(rd->low_prio_starvation.starvation_counter >=
|
||||
rd->low_prio_starvation.starvation_limit))
|
||||
ret = IOPRIO_CLASS_IDLE;
|
||||
else
|
||||
ret = IOPRIO_CLASS_RT;
|
||||
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
@ -546,7 +626,12 @@ check_idling:
|
|||
!force && row_queues_def[i].idling_enabled)
|
||||
goto initiate_idling;
|
||||
} else {
|
||||
ret = IOPRIO_CLASS_BE;
|
||||
if (row_low_req_pending(rd) &&
|
||||
(rd->low_prio_starvation.starvation_counter >=
|
||||
rd->low_prio_starvation.starvation_limit))
|
||||
ret = IOPRIO_CLASS_IDLE;
|
||||
else
|
||||
ret = IOPRIO_CLASS_BE;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
@ -716,6 +801,10 @@ static void *row_init_queue(struct request_queue *q)
|
|||
ktime_set(0, 0);
|
||||
}
|
||||
|
||||
rdata->reg_prio_starvation.starvation_limit =
|
||||
ROW_REG_STARVATION_TOLLERANCE;
|
||||
rdata->low_prio_starvation.starvation_limit =
|
||||
ROW_LOW_STARVATION_TOLLERANCE;
|
||||
/*
|
||||
* Currently idling is enabled only for READ queues. If we want to
|
||||
* enable it for write queues also, note that idling frequency will
|
||||
|
@ -890,6 +979,10 @@ SHOW_FUNCTION(row_lp_swrite_quantum_show,
|
|||
rowd->row_queues[ROWQ_PRIO_LOW_SWRITE].disp_quantum, 0);
|
||||
SHOW_FUNCTION(row_rd_idle_data_show, rowd->rd_idle_data.idle_time_ms, 0);
|
||||
SHOW_FUNCTION(row_rd_idle_data_freq_show, rowd->rd_idle_data.freq_ms, 0);
|
||||
SHOW_FUNCTION(row_reg_starv_limit_show,
|
||||
rowd->reg_prio_starvation.starvation_limit, 0);
|
||||
SHOW_FUNCTION(row_low_starv_limit_show,
|
||||
rowd->low_prio_starvation.starvation_limit, 0);
|
||||
#undef SHOW_FUNCTION
|
||||
|
||||
#define STORE_FUNCTION(__FUNC, __PTR, MIN, MAX, __CONV) \
|
||||
|
@ -932,6 +1025,12 @@ STORE_FUNCTION(row_rd_idle_data_store, &rowd->rd_idle_data.idle_time_ms,
|
|||
1, INT_MAX, 0);
|
||||
STORE_FUNCTION(row_rd_idle_data_freq_store, &rowd->rd_idle_data.freq_ms,
|
||||
1, INT_MAX, 0);
|
||||
STORE_FUNCTION(row_reg_starv_limit_store,
|
||||
&rowd->reg_prio_starvation.starvation_limit,
|
||||
1, INT_MAX, 0);
|
||||
STORE_FUNCTION(row_low_starv_limit_store,
|
||||
&rowd->low_prio_starvation.starvation_limit,
|
||||
1, INT_MAX, 0);
|
||||
|
||||
#undef STORE_FUNCTION
|
||||
|
||||
|
@ -949,6 +1048,8 @@ static struct elv_fs_entry row_attrs[] = {
|
|||
ROW_ATTR(lp_swrite_quantum),
|
||||
ROW_ATTR(rd_idle_data),
|
||||
ROW_ATTR(rd_idle_data_freq),
|
||||
ROW_ATTR(reg_starv_limit),
|
||||
ROW_ATTR(low_starv_limit),
|
||||
__ATTR_NULL
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue