Commit bba7c645 authored by Jens Axboe's avatar Jens Axboe Committed by Jens Axboe

[PATCH] misc elevator/block updates

I've got a new i/o scheduler in testing, some changes where needed in
the block layer to accomodate it. Basically because right now
assumptions are made about q->queue_head being the sort list. The
changes in detail:

o elevator_merge_requests_fn takes queue argument as well

o __make_request() inits insert_here to NULL instead of
  q->queue_head.prev, which means that the i/o schedulers must
  explicitly check for this condition now.

o incorporate elv_queue_empty(), it was just a place holder before

o add elv_get_sort_head(). it returns the sort head of the elevator for
  a given request. attempt_{back,front}_merge uses it to determine
  whether a request is valid or not. Maybe attempt_{back,front}_merge
  should just be killed, I doubt they have much relevance with the wake
  up batching.

o call the merge_cleanup functions of the elevator _after_ the merge has
  been done, not before. This way the elevator functions get the new
  state of the request, which is the most interesting.

o Kill extra nr_sectors check in ll_merge_requests_fn()

o bi->bi_bdev is always set in __make_request(), so kill check.
parent f04d3972
......@@ -220,7 +220,8 @@ void elevator_linus_merge_cleanup(request_queue_t *q, struct request *req, int c
}
}
void elevator_linus_merge_req(struct request *req, struct request *next)
void elevator_linus_merge_req(request_queue_t *q, struct request *req,
struct request *next)
{
if (elv_linus_sequence(next) < elv_linus_sequence(req))
elv_linus_sequence(req) = elv_linus_sequence(next);
......@@ -232,6 +233,9 @@ void elevator_linus_add_request(request_queue_t *q, struct request *rq,
elevator_t *e = &q->elevator;
int lat = 0, *latency = e->elevator_data;
if (!insert_here)
insert_here = q->queue_head.prev;
if (!(rq->flags & REQ_BARRIER))
lat = latency[rq_data_dir(rq)];
......@@ -318,7 +322,7 @@ void elevator_noop_add_request(request_queue_t *q, struct request *rq,
struct request *elevator_noop_next_request(request_queue_t *q)
{
if (!blk_queue_empty(q))
if (!list_empty(&q->queue_head))
return list_entry_rq(q->queue_head.next);
return NULL;
......@@ -376,7 +380,7 @@ void elv_merge_requests(request_queue_t *q, struct request *rq,
elevator_t *e = &q->elevator;
if (e->elevator_merge_req_fn)
e->elevator_merge_req_fn(rq, next);
e->elevator_merge_req_fn(q, rq, next);
}
/*
......@@ -433,6 +437,27 @@ void elv_remove_request(request_queue_t *q, struct request *rq)
e->elevator_remove_req_fn(q, rq);
}
int elv_queue_empty(request_queue_t *q)
{
elevator_t *e = &q->elevator;
if (e->elevator_queue_empty_fn)
return e->elevator_queue_empty_fn(q);
return list_empty(&q->queue_head);
}
inline struct list_head *elv_get_sort_head(request_queue_t *q,
struct request *rq)
{
elevator_t *e = &q->elevator;
if (e->elevator_get_sort_head_fn)
return e->elevator_get_sort_head_fn(q, rq);
return &q->queue_head;
}
elevator_t elevator_linus = {
elevator_merge_fn: elevator_linus_merge,
elevator_merge_cleanup_fn: elevator_linus_merge_cleanup,
......
......@@ -1391,7 +1391,6 @@ static void attempt_merge(request_queue_t *q, struct request *req,
if (rq_data_dir(req) != rq_data_dir(next)
|| !kdev_same(req->rq_dev, next->rq_dev)
|| req->nr_sectors + next->nr_sectors > q->max_sectors
|| next->waiting || next->special)
return;
......@@ -1402,15 +1401,14 @@ static void attempt_merge(request_queue_t *q, struct request *req,
* counts here.
*/
if (q->merge_requests_fn(q, req, next)) {
elv_merge_requests(q, req, next);
blkdev_dequeue_request(next);
req->biotail->bi_next = next->bio;
req->biotail = next->biotail;
req->nr_sectors = req->hard_nr_sectors += next->hard_nr_sectors;
elv_merge_requests(q, req, next);
blkdev_dequeue_request(next);
blk_put_request(next);
}
}
......@@ -1418,16 +1416,18 @@ static void attempt_merge(request_queue_t *q, struct request *req,
static inline void attempt_back_merge(request_queue_t *q, struct request *rq)
{
struct list_head *next = rq->queuelist.next;
struct list_head *sort_head = elv_get_sort_head(q, rq);
if (next != &q->queue_head)
if (next != sort_head)
attempt_merge(q, rq, list_entry_rq(next));
}
static inline void attempt_front_merge(request_queue_t *q, struct request *rq)
{
struct list_head *prev = rq->queuelist.prev;
struct list_head *sort_head = elv_get_sort_head(q, rq);
if (prev != &q->queue_head)
if (prev != sort_head)
attempt_merge(q, list_entry_rq(prev), rq);
}
......@@ -1487,7 +1487,7 @@ static int __make_request(request_queue_t *q, struct bio *bio)
spin_lock_irq(q->queue_lock);
again:
req = NULL;
insert_here = q->queue_head.prev;
insert_here = NULL;
if (blk_queue_empty(q)) {
blk_plug_device(q);
......@@ -1505,11 +1505,10 @@ static int __make_request(request_queue_t *q, struct bio *bio)
break;
}
elv_merge_cleanup(q, req, nr_sectors);
req->biotail->bi_next = bio;
req->biotail = bio;
req->nr_sectors = req->hard_nr_sectors += nr_sectors;
elv_merge_cleanup(q, req, nr_sectors);
drive_stat_acct(req, nr_sectors, 0);
attempt_back_merge(q, req);
goto out;
......@@ -1521,8 +1520,6 @@ static int __make_request(request_queue_t *q, struct bio *bio)
break;
}
elv_merge_cleanup(q, req, nr_sectors);
bio->bi_next = req->bio;
req->bio = bio;
/*
......@@ -1535,6 +1532,7 @@ static int __make_request(request_queue_t *q, struct bio *bio)
req->hard_cur_sectors = cur_nr_sectors;
req->sector = req->hard_sector = sector;
req->nr_sectors = req->hard_nr_sectors += nr_sectors;
elv_merge_cleanup(q, req, nr_sectors);
drive_stat_acct(req, nr_sectors, 0);
attempt_front_merge(q, req);
goto out;
......@@ -1603,9 +1601,7 @@ static int __make_request(request_queue_t *q, struct bio *bio)
req->buffer = bio_data(bio); /* see ->buffer comment above */
req->waiting = NULL;
req->bio = req->biotail = bio;
if (bio->bi_bdev)
req->rq_dev = to_kdev_t(bio->bi_bdev->bd_dev);
else req->rq_dev = NODEV;
req->rq_dev = to_kdev_t(bio->bi_bdev->bd_dev);
add_request(q, req, insert_here);
out:
if (freereq)
......
......@@ -6,13 +6,14 @@ typedef int (elevator_merge_fn) (request_queue_t *, struct request **,
typedef void (elevator_merge_cleanup_fn) (request_queue_t *, struct request *, int);
typedef void (elevator_merge_req_fn) (struct request *, struct request *);
typedef void (elevator_merge_req_fn) (request_queue_t *, struct request *, struct request *);
typedef struct request *(elevator_next_req_fn) (request_queue_t *);
typedef void (elevator_add_req_fn) (request_queue_t *, struct request *, struct list_head *);
typedef int (elevator_queue_empty_fn) (request_queue_t *);
typedef void (elevator_remove_req_fn) (request_queue_t *, struct request *);
typedef struct list_head *(elevator_get_sort_head_fn) (request_queue_t *, struct request *);
typedef int (elevator_init_fn) (request_queue_t *, elevator_t *);
typedef void (elevator_exit_fn) (request_queue_t *, elevator_t *);
......@@ -28,6 +29,7 @@ struct elevator_s
elevator_remove_req_fn *elevator_remove_req_fn;
elevator_queue_empty_fn *elevator_queue_empty_fn;
elevator_get_sort_head_fn *elevator_get_sort_head_fn;
elevator_init_fn *elevator_init_fn;
elevator_exit_fn *elevator_exit_fn;
......@@ -45,6 +47,8 @@ extern int elv_merge(request_queue_t *, struct request **, struct bio *);
extern void elv_merge_requests(request_queue_t *, struct request *,
struct request *);
extern void elv_remove_request(request_queue_t *, struct request *);
extern int elv_queue_empty(request_queue_t *);
extern inline struct list_head *elv_get_sort_head(request_queue_t *, struct request *);
/*
* noop I/O scheduler. always merges, always inserts new request at tail
......@@ -72,6 +76,10 @@ typedef struct blkelv_ioctl_arg_s {
extern int elevator_init(request_queue_t *, elevator_t *, elevator_t);
extern void elevator_exit(request_queue_t *, elevator_t *);
extern inline int bio_rq_in_between(struct bio *, struct request *, struct list_head *);
extern inline int elv_rq_merge_ok(struct request *, struct bio *);
extern inline int elv_try_merge(struct request *, struct bio *);
extern inline int elv_try_last_merge(request_queue_t *, struct request **, struct bio *);
/*
* Return values from elevator merger
......@@ -80,10 +88,4 @@ extern void elevator_exit(request_queue_t *, elevator_t *);
#define ELEVATOR_FRONT_MERGE 1
#define ELEVATOR_BACK_MERGE 2
/*
* will change once we move to a more complex data structure than a simple
* list for pending requests
*/
#define elv_queue_empty(q) list_empty(&(q)->queue_head)
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment