DESC antsched: commentary and block/as-iosched.c | 150 ++++++++++++++++++++++++++++++++++------------------- 1 files changed, 98 insertions(+), 52 deletions(-) diff -puN drivers/block/as-iosched.c~as-comments-and-tweaks drivers/block/as-iosched.c --- 25/drivers/block/as-iosched.c~as-comments-and-tweaks 2003-02-20 23:20:20.000000000 -0800 +++ 25-akpm/drivers/block/as-iosched.c 2003-02-20 23:20:20.000000000 -0800 @@ -89,13 +89,10 @@ static const int as_hash_shift = 10; (dd)->hash_valid_count = 1; \ } while (0) -/* - * Nick! These need descriptions - */ -#define ANTIC_OFF 0 -#define ANTIC_WAIT 1 -#define ANTIC_TIMEOUT 2 -#define ANTIC_FOUND 3 +#define ANTIC_OFF 0 /* Not anticipating (normal operation) */ +#define ANTIC_WAIT 1 /* Currently anticipating a request */ +#define ANTIC_FINISHED 2 /* Anticipating but have found a candidate + or timed out */ struct as_data { /* @@ -592,6 +589,19 @@ static int as_fifo_expired(struct as_dat return time_after(jiffies, drq->expires); } +static int as_antic_expired(struct as_data *dd) +{ + long delta_jif; + + delta_jif = jiffies - dd->antic_start; + if (unlikely(delta_jif < 0)) + delta_jif = -delta_jif; + if (delta_jif < dd->antic_expire) + return 0; + + return 1; +} + /* * as_batch_expired returns true if the current batch has expired. */ @@ -638,8 +648,7 @@ static void as_anticipate_timeout(unsign spin_lock_irqsave(q->queue_lock, flags); - if (dd->antic_status != ANTIC_FOUND) - dd->antic_status = ANTIC_TIMEOUT; + dd->antic_status = ANTIC_FINISHED; blk_remove_plug(q); schedule_work(&dd->antic_work); @@ -662,10 +671,10 @@ as_close_req(struct as_data *dd, struct sector_t delta; /* acceptable close offset (in sectors) */ - if (dd->antic_status == ANTIC_OFF || delay <= 2) - delta = 64; - else if (delay <= dd->antic_expire / 2) - delta = 64 << ((delay - 2)*2); + if (dd->antic_status == ANTIC_OFF || delay <= 1) + delta = 32; + else if (delay <= 20 && delay <= dd->antic_expire / 2) + delta = 32 << (delay-1); else return 1; @@ -695,43 +704,30 @@ as_choose_req(struct as_data *dd, BUG_ON(data_dir != rq_data_dir(drq2->request)); /* - * Nick: boggle. What algorithm is this implementing? - */ - if (data_dir == READ) { - if (s1 >= last) - d1 = s1 - last; - else { - /* count large back seeks as a forward seek */ - if (dd->current_id == drq1->request_id && s1+maxback >= last) + * Strict one way elevator _except_ in the case where we allow + * short backward seeks which are biased as twice the cost of a + * similar forward seek. Only for reads and only between reads + * from the same process! + */ + if (s1 >= last) + d1 = s1 - last; + else if (data_dir == READ + && dd->current_id == drq1->request_id + && s1+maxback >= last) d1 = (last - s1)*2; - else - d1 = (last - s1)*8; - } + else + goto elevator_wrap; - if (s2 >= last) - d2 = s2 - last; - else { - if (dd->current_id == drq2->request_id && s2+maxback >= last) + if (s2 >= last) + d2 = s2 - last; + else if (data_dir == READ + && dd->current_id == drq2->request_id + && s2+maxback >= last) d2 = (last - s2)*2; - else - d2 = (last - s2)*8; - } - } else { /* data_dir == WRITE */ - if (s1 >= last && s2 >= last) { - d1 = s1 - last; - d2 = s2 - last; - } else if (s1 >= last && s2 < last) { - d1 = s1 - last; - d2 = d1+1; - } else if (s2 >= last && s1 < last) { - d2 = s2 - last; - d1 = d2+1; - } else { - d1 = s1; - d2 = s2; - } - } + else + goto elevator_wrap; + /* Found the deltas */ if (d1 < d2) return drq1; else if (d2 < d1) @@ -742,6 +738,25 @@ as_choose_req(struct as_data *dd, else return drq2; } + +elevator_wrap: + /* + * a request is behind the disk head, in most + * cases this is treated as the elevator wrapping + * to the start, so a lower valued request (further away) + * is favourable + */ + if (s1 >= last && s2 < last) + return drq1; + else if (s2 >= last && s1 < last) + return drq2; + else { + /* both behind the head */ + if (s1 <= s2) + return drq1; + else + return drq2; + } } /* @@ -810,25 +825,46 @@ as_update_drq(struct as_data *dd, struct ant_stats.lba_forward_offsets[log2]++; del_timer(&dd->antic_timer); - dd->antic_status = ANTIC_FOUND; + dd->antic_status = ANTIC_FINISHED; blk_remove_plug(drq->request->q); schedule_work(&dd->antic_work); } } /* - * argh. Nick, can you please comment every clause in this function? + * can_start_anticipation indicates weather we should either run drq + * or keep anticipating a better request. */ static int can_start_anticipation(struct as_data *dd, struct as_rq *drq) { - if (dd->antic_status == ANTIC_FOUND) + if (dd->antic_status == ANTIC_FINISHED) + /* + * Don't restart if we have just finished. Run the next request + */ return 0; - if (!(dd->antic_status == ANTIC_OFF || - time_before(jiffies, dd->antic_start + dd->antic_expire))) + + if (dd->antic_status == ANTIC_WAIT && as_antic_expired(dd)) + /* + * In this situation status should really be FINISHED, however + * the timer hasn't had the chance to run yet. + */ return 0; + if (drq && as_antic_req(dd, drq)) + /* + * This request is a good candidate. Don't keep anticipating, + * run it. + */ return 0; + + /* + * OK from here, we haven't finished, haven't timed out, and don't + * have a decent request! + * status is either ANTIC_WAIT or ANTIC_OFF. So we'll either keep + * waiting or start waiting respectively. + */ + return 1; } @@ -843,6 +879,8 @@ static int as_dispatch_request(struct re struct as_rq *drq; const int reads = !list_empty(&dd->fifo_list[READ]); const int writes = !list_empty(&dd->fifo_list[WRITE]); + static unsigned long last_read_id; + static unsigned long last_finished; if (!(reads || writes)) return 0; @@ -956,6 +994,14 @@ fifo_expired: */ dd->antic_status = ANTIC_OFF; as_move_request(dd, drq); + + if (dd->batch_data_dir == READ) { + if (last_read_id != drq->request_id) { + last_read_id = drq->request_id; + } + last_finished = drq->request->sector + drq->request->nr_sectors; + } + return 1; } @@ -992,7 +1038,7 @@ as_insert_request(request_queue_t *q, st if (rq_data_dir(rq) == READ && dd->antic_status != ANTIC_OFF) { del_timer(&dd->antic_timer); - dd->antic_status = ANTIC_FOUND; + dd->antic_status = ANTIC_FINISHED; blk_remove_plug(q); schedule_work(&dd->antic_work); } _