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 ...@@ -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)) if (elv_linus_sequence(next) < elv_linus_sequence(req))
elv_linus_sequence(req) = elv_linus_sequence(next); elv_linus_sequence(req) = elv_linus_sequence(next);
...@@ -232,6 +233,9 @@ void elevator_linus_add_request(request_queue_t *q, struct request *rq, ...@@ -232,6 +233,9 @@ void elevator_linus_add_request(request_queue_t *q, struct request *rq,
elevator_t *e = &q->elevator; elevator_t *e = &q->elevator;
int lat = 0, *latency = e->elevator_data; int lat = 0, *latency = e->elevator_data;
if (!insert_here)
insert_here = q->queue_head.prev;
if (!(rq->flags & REQ_BARRIER)) if (!(rq->flags & REQ_BARRIER))
lat = latency[rq_data_dir(rq)]; lat = latency[rq_data_dir(rq)];
...@@ -318,7 +322,7 @@ void elevator_noop_add_request(request_queue_t *q, struct request *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) 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 list_entry_rq(q->queue_head.next);
return NULL; return NULL;
...@@ -376,7 +380,7 @@ void elv_merge_requests(request_queue_t *q, struct request *rq, ...@@ -376,7 +380,7 @@ void elv_merge_requests(request_queue_t *q, struct request *rq,
elevator_t *e = &q->elevator; elevator_t *e = &q->elevator;
if (e->elevator_merge_req_fn) 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) ...@@ -433,6 +437,27 @@ void elv_remove_request(request_queue_t *q, struct request *rq)
e->elevator_remove_req_fn(q, 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_t elevator_linus = {
elevator_merge_fn: elevator_linus_merge, elevator_merge_fn: elevator_linus_merge,
elevator_merge_cleanup_fn: elevator_linus_merge_cleanup, elevator_merge_cleanup_fn: elevator_linus_merge_cleanup,
......
...@@ -1391,7 +1391,6 @@ static void attempt_merge(request_queue_t *q, struct request *req, ...@@ -1391,7 +1391,6 @@ static void attempt_merge(request_queue_t *q, struct request *req,
if (rq_data_dir(req) != rq_data_dir(next) if (rq_data_dir(req) != rq_data_dir(next)
|| !kdev_same(req->rq_dev, next->rq_dev) || !kdev_same(req->rq_dev, next->rq_dev)
|| req->nr_sectors + next->nr_sectors > q->max_sectors
|| next->waiting || next->special) || next->waiting || next->special)
return; return;
...@@ -1402,15 +1401,14 @@ static void attempt_merge(request_queue_t *q, struct request *req, ...@@ -1402,15 +1401,14 @@ static void attempt_merge(request_queue_t *q, struct request *req,
* counts here. * counts here.
*/ */
if (q->merge_requests_fn(q, req, next)) { 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->bi_next = next->bio;
req->biotail = next->biotail; req->biotail = next->biotail;
req->nr_sectors = req->hard_nr_sectors += next->hard_nr_sectors; 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); blk_put_request(next);
} }
} }
...@@ -1418,16 +1416,18 @@ static void attempt_merge(request_queue_t *q, struct request *req, ...@@ -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) static inline void attempt_back_merge(request_queue_t *q, struct request *rq)
{ {
struct list_head *next = rq->queuelist.next; 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)); attempt_merge(q, rq, list_entry_rq(next));
} }
static inline void attempt_front_merge(request_queue_t *q, struct request *rq) static inline void attempt_front_merge(request_queue_t *q, struct request *rq)
{ {
struct list_head *prev = rq->queuelist.prev; 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); attempt_merge(q, list_entry_rq(prev), rq);
} }
...@@ -1487,7 +1487,7 @@ static int __make_request(request_queue_t *q, struct bio *bio) ...@@ -1487,7 +1487,7 @@ static int __make_request(request_queue_t *q, struct bio *bio)
spin_lock_irq(q->queue_lock); spin_lock_irq(q->queue_lock);
again: again:
req = NULL; req = NULL;
insert_here = q->queue_head.prev; insert_here = NULL;
if (blk_queue_empty(q)) { if (blk_queue_empty(q)) {
blk_plug_device(q); blk_plug_device(q);
...@@ -1505,11 +1505,10 @@ static int __make_request(request_queue_t *q, struct bio *bio) ...@@ -1505,11 +1505,10 @@ static int __make_request(request_queue_t *q, struct bio *bio)
break; break;
} }
elv_merge_cleanup(q, req, nr_sectors);
req->biotail->bi_next = bio; req->biotail->bi_next = bio;
req->biotail = bio; req->biotail = bio;
req->nr_sectors = req->hard_nr_sectors += nr_sectors; req->nr_sectors = req->hard_nr_sectors += nr_sectors;
elv_merge_cleanup(q, req, nr_sectors);
drive_stat_acct(req, nr_sectors, 0); drive_stat_acct(req, nr_sectors, 0);
attempt_back_merge(q, req); attempt_back_merge(q, req);
goto out; goto out;
...@@ -1521,8 +1520,6 @@ static int __make_request(request_queue_t *q, struct bio *bio) ...@@ -1521,8 +1520,6 @@ static int __make_request(request_queue_t *q, struct bio *bio)
break; break;
} }
elv_merge_cleanup(q, req, nr_sectors);
bio->bi_next = req->bio; bio->bi_next = req->bio;
req->bio = bio; req->bio = bio;
/* /*
...@@ -1535,6 +1532,7 @@ static int __make_request(request_queue_t *q, struct 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->hard_cur_sectors = cur_nr_sectors;
req->sector = req->hard_sector = sector; req->sector = req->hard_sector = sector;
req->nr_sectors = req->hard_nr_sectors += nr_sectors; req->nr_sectors = req->hard_nr_sectors += nr_sectors;
elv_merge_cleanup(q, req, nr_sectors);
drive_stat_acct(req, nr_sectors, 0); drive_stat_acct(req, nr_sectors, 0);
attempt_front_merge(q, req); attempt_front_merge(q, req);
goto out; goto out;
...@@ -1603,9 +1601,7 @@ static int __make_request(request_queue_t *q, struct bio *bio) ...@@ -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->buffer = bio_data(bio); /* see ->buffer comment above */
req->waiting = NULL; req->waiting = NULL;
req->bio = req->biotail = bio; req->bio = req->biotail = bio;
if (bio->bi_bdev)
req->rq_dev = to_kdev_t(bio->bi_bdev->bd_dev); req->rq_dev = to_kdev_t(bio->bi_bdev->bd_dev);
else req->rq_dev = NODEV;
add_request(q, req, insert_here); add_request(q, req, insert_here);
out: out:
if (freereq) if (freereq)
......
...@@ -6,13 +6,14 @@ typedef int (elevator_merge_fn) (request_queue_t *, struct request **, ...@@ -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_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 struct request *(elevator_next_req_fn) (request_queue_t *);
typedef void (elevator_add_req_fn) (request_queue_t *, struct request *, struct list_head *); typedef void (elevator_add_req_fn) (request_queue_t *, struct request *, struct list_head *);
typedef int (elevator_queue_empty_fn) (request_queue_t *); typedef int (elevator_queue_empty_fn) (request_queue_t *);
typedef void (elevator_remove_req_fn) (request_queue_t *, struct request *); 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 int (elevator_init_fn) (request_queue_t *, elevator_t *);
typedef void (elevator_exit_fn) (request_queue_t *, elevator_t *); typedef void (elevator_exit_fn) (request_queue_t *, elevator_t *);
...@@ -28,6 +29,7 @@ struct elevator_s ...@@ -28,6 +29,7 @@ struct elevator_s
elevator_remove_req_fn *elevator_remove_req_fn; elevator_remove_req_fn *elevator_remove_req_fn;
elevator_queue_empty_fn *elevator_queue_empty_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_init_fn *elevator_init_fn;
elevator_exit_fn *elevator_exit_fn; elevator_exit_fn *elevator_exit_fn;
...@@ -45,6 +47,8 @@ extern int elv_merge(request_queue_t *, struct request **, struct bio *); ...@@ -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 *, extern void elv_merge_requests(request_queue_t *, struct request *,
struct request *); struct request *);
extern void elv_remove_request(request_queue_t *, 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 * noop I/O scheduler. always merges, always inserts new request at tail
...@@ -72,6 +76,10 @@ typedef struct blkelv_ioctl_arg_s { ...@@ -72,6 +76,10 @@ typedef struct blkelv_ioctl_arg_s {
extern int elevator_init(request_queue_t *, elevator_t *, elevator_t); extern int elevator_init(request_queue_t *, elevator_t *, elevator_t);
extern void elevator_exit(request_queue_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 * Return values from elevator merger
...@@ -80,10 +88,4 @@ extern void elevator_exit(request_queue_t *, elevator_t *); ...@@ -80,10 +88,4 @@ extern void elevator_exit(request_queue_t *, elevator_t *);
#define ELEVATOR_FRONT_MERGE 1 #define ELEVATOR_FRONT_MERGE 1
#define ELEVATOR_BACK_MERGE 2 #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 #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