diff options
-rw-r--r-- | block/elevator.c | 123 | ||||
-rw-r--r-- | block/ll_rw_blk.c | 7 | ||||
-rw-r--r-- | include/linux/blkdev.h | 1 | ||||
-rw-r--r-- | include/linux/elevator.h | 18 |
4 files changed, 130 insertions, 19 deletions
diff --git a/block/elevator.c b/block/elevator.c index cff1102dac9d..cbbc36ba016a 100644 --- a/block/elevator.c +++ b/block/elevator.c | |||
@@ -239,6 +239,8 @@ int elevator_init(request_queue_t *q, char *name) | |||
239 | return ret; | 239 | return ret; |
240 | } | 240 | } |
241 | 241 | ||
242 | EXPORT_SYMBOL(elevator_init); | ||
243 | |||
242 | void elevator_exit(elevator_t *e) | 244 | void elevator_exit(elevator_t *e) |
243 | { | 245 | { |
244 | mutex_lock(&e->sysfs_lock); | 246 | mutex_lock(&e->sysfs_lock); |
@@ -250,6 +252,8 @@ void elevator_exit(elevator_t *e) | |||
250 | kobject_put(&e->kobj); | 252 | kobject_put(&e->kobj); |
251 | } | 253 | } |
252 | 254 | ||
255 | EXPORT_SYMBOL(elevator_exit); | ||
256 | |||
253 | static inline void __elv_rqhash_del(struct request *rq) | 257 | static inline void __elv_rqhash_del(struct request *rq) |
254 | { | 258 | { |
255 | hlist_del_init(&rq->hash); | 259 | hlist_del_init(&rq->hash); |
@@ -298,9 +302,68 @@ static struct request *elv_rqhash_find(request_queue_t *q, sector_t offset) | |||
298 | } | 302 | } |
299 | 303 | ||
300 | /* | 304 | /* |
305 | * RB-tree support functions for inserting/lookup/removal of requests | ||
306 | * in a sorted RB tree. | ||
307 | */ | ||
308 | struct request *elv_rb_add(struct rb_root *root, struct request *rq) | ||
309 | { | ||
310 | struct rb_node **p = &root->rb_node; | ||
311 | struct rb_node *parent = NULL; | ||
312 | struct request *__rq; | ||
313 | |||
314 | while (*p) { | ||
315 | parent = *p; | ||
316 | __rq = rb_entry(parent, struct request, rb_node); | ||
317 | |||
318 | if (rq->sector < __rq->sector) | ||
319 | p = &(*p)->rb_left; | ||
320 | else if (rq->sector > __rq->sector) | ||
321 | p = &(*p)->rb_right; | ||
322 | else | ||
323 | return __rq; | ||
324 | } | ||
325 | |||
326 | rb_link_node(&rq->rb_node, parent, p); | ||
327 | rb_insert_color(&rq->rb_node, root); | ||
328 | return NULL; | ||
329 | } | ||
330 | |||
331 | EXPORT_SYMBOL(elv_rb_add); | ||
332 | |||
333 | void elv_rb_del(struct rb_root *root, struct request *rq) | ||
334 | { | ||
335 | BUG_ON(RB_EMPTY_NODE(&rq->rb_node)); | ||
336 | rb_erase(&rq->rb_node, root); | ||
337 | RB_CLEAR_NODE(&rq->rb_node); | ||
338 | } | ||
339 | |||
340 | EXPORT_SYMBOL(elv_rb_del); | ||
341 | |||
342 | struct request *elv_rb_find(struct rb_root *root, sector_t sector) | ||
343 | { | ||
344 | struct rb_node *n = root->rb_node; | ||
345 | struct request *rq; | ||
346 | |||
347 | while (n) { | ||
348 | rq = rb_entry(n, struct request, rb_node); | ||
349 | |||
350 | if (sector < rq->sector) | ||
351 | n = n->rb_left; | ||
352 | else if (sector > rq->sector) | ||
353 | n = n->rb_right; | ||
354 | else | ||
355 | return rq; | ||
356 | } | ||
357 | |||
358 | return NULL; | ||
359 | } | ||
360 | |||
361 | EXPORT_SYMBOL(elv_rb_find); | ||
362 | |||
363 | /* | ||
301 | * Insert rq into dispatch queue of q. Queue lock must be held on | 364 | * Insert rq into dispatch queue of q. Queue lock must be held on |
302 | * entry. If sort != 0, rq is sort-inserted; otherwise, rq will be | 365 | * entry. rq is sort insted into the dispatch queue. To be used by |
303 | * appended to the dispatch queue. To be used by specific elevators. | 366 | * specific elevators. |
304 | */ | 367 | */ |
305 | void elv_dispatch_sort(request_queue_t *q, struct request *rq) | 368 | void elv_dispatch_sort(request_queue_t *q, struct request *rq) |
306 | { | 369 | { |
@@ -335,8 +398,12 @@ void elv_dispatch_sort(request_queue_t *q, struct request *rq) | |||
335 | list_add(&rq->queuelist, entry); | 398 | list_add(&rq->queuelist, entry); |
336 | } | 399 | } |
337 | 400 | ||
401 | EXPORT_SYMBOL(elv_dispatch_sort); | ||
402 | |||
338 | /* | 403 | /* |
339 | * This should be in elevator.h, but that requires pulling in rq and q | 404 | * Insert rq into dispatch queue of q. Queue lock must be held on |
405 | * entry. rq is added to the back of the dispatch queue. To be used by | ||
406 | * specific elevators. | ||
340 | */ | 407 | */ |
341 | void elv_dispatch_add_tail(struct request_queue *q, struct request *rq) | 408 | void elv_dispatch_add_tail(struct request_queue *q, struct request *rq) |
342 | { | 409 | { |
@@ -352,6 +419,8 @@ void elv_dispatch_add_tail(struct request_queue *q, struct request *rq) | |||
352 | list_add_tail(&rq->queuelist, &q->queue_head); | 419 | list_add_tail(&rq->queuelist, &q->queue_head); |
353 | } | 420 | } |
354 | 421 | ||
422 | EXPORT_SYMBOL(elv_dispatch_add_tail); | ||
423 | |||
355 | int elv_merge(request_queue_t *q, struct request **req, struct bio *bio) | 424 | int elv_merge(request_queue_t *q, struct request **req, struct bio *bio) |
356 | { | 425 | { |
357 | elevator_t *e = q->elevator; | 426 | elevator_t *e = q->elevator; |
@@ -384,14 +453,15 @@ int elv_merge(request_queue_t *q, struct request **req, struct bio *bio) | |||
384 | return ELEVATOR_NO_MERGE; | 453 | return ELEVATOR_NO_MERGE; |
385 | } | 454 | } |
386 | 455 | ||
387 | void elv_merged_request(request_queue_t *q, struct request *rq) | 456 | void elv_merged_request(request_queue_t *q, struct request *rq, int type) |
388 | { | 457 | { |
389 | elevator_t *e = q->elevator; | 458 | elevator_t *e = q->elevator; |
390 | 459 | ||
391 | if (e->ops->elevator_merged_fn) | 460 | if (e->ops->elevator_merged_fn) |
392 | e->ops->elevator_merged_fn(q, rq); | 461 | e->ops->elevator_merged_fn(q, rq, type); |
393 | 462 | ||
394 | elv_rqhash_reposition(q, rq); | 463 | if (type == ELEVATOR_BACK_MERGE) |
464 | elv_rqhash_reposition(q, rq); | ||
395 | 465 | ||
396 | q->last_merge = rq; | 466 | q->last_merge = rq; |
397 | } | 467 | } |
@@ -577,6 +647,8 @@ void __elv_add_request(request_queue_t *q, struct request *rq, int where, | |||
577 | elv_insert(q, rq, where); | 647 | elv_insert(q, rq, where); |
578 | } | 648 | } |
579 | 649 | ||
650 | EXPORT_SYMBOL(__elv_add_request); | ||
651 | |||
580 | void elv_add_request(request_queue_t *q, struct request *rq, int where, | 652 | void elv_add_request(request_queue_t *q, struct request *rq, int where, |
581 | int plug) | 653 | int plug) |
582 | { | 654 | { |
@@ -587,6 +659,8 @@ void elv_add_request(request_queue_t *q, struct request *rq, int where, | |||
587 | spin_unlock_irqrestore(q->queue_lock, flags); | 659 | spin_unlock_irqrestore(q->queue_lock, flags); |
588 | } | 660 | } |
589 | 661 | ||
662 | EXPORT_SYMBOL(elv_add_request); | ||
663 | |||
590 | static inline struct request *__elv_next_request(request_queue_t *q) | 664 | static inline struct request *__elv_next_request(request_queue_t *q) |
591 | { | 665 | { |
592 | struct request *rq; | 666 | struct request *rq; |
@@ -670,6 +744,8 @@ struct request *elv_next_request(request_queue_t *q) | |||
670 | return rq; | 744 | return rq; |
671 | } | 745 | } |
672 | 746 | ||
747 | EXPORT_SYMBOL(elv_next_request); | ||
748 | |||
673 | void elv_dequeue_request(request_queue_t *q, struct request *rq) | 749 | void elv_dequeue_request(request_queue_t *q, struct request *rq) |
674 | { | 750 | { |
675 | BUG_ON(list_empty(&rq->queuelist)); | 751 | BUG_ON(list_empty(&rq->queuelist)); |
@@ -686,6 +762,8 @@ void elv_dequeue_request(request_queue_t *q, struct request *rq) | |||
686 | q->in_flight++; | 762 | q->in_flight++; |
687 | } | 763 | } |
688 | 764 | ||
765 | EXPORT_SYMBOL(elv_dequeue_request); | ||
766 | |||
689 | int elv_queue_empty(request_queue_t *q) | 767 | int elv_queue_empty(request_queue_t *q) |
690 | { | 768 | { |
691 | elevator_t *e = q->elevator; | 769 | elevator_t *e = q->elevator; |
@@ -699,6 +777,8 @@ int elv_queue_empty(request_queue_t *q) | |||
699 | return 1; | 777 | return 1; |
700 | } | 778 | } |
701 | 779 | ||
780 | EXPORT_SYMBOL(elv_queue_empty); | ||
781 | |||
702 | struct request *elv_latter_request(request_queue_t *q, struct request *rq) | 782 | struct request *elv_latter_request(request_queue_t *q, struct request *rq) |
703 | { | 783 | { |
704 | elevator_t *e = q->elevator; | 784 | elevator_t *e = q->elevator; |
@@ -1025,11 +1105,26 @@ ssize_t elv_iosched_show(request_queue_t *q, char *name) | |||
1025 | return len; | 1105 | return len; |
1026 | } | 1106 | } |
1027 | 1107 | ||
1028 | EXPORT_SYMBOL(elv_dispatch_sort); | 1108 | struct request *elv_rb_former_request(request_queue_t *q, struct request *rq) |
1029 | EXPORT_SYMBOL(elv_add_request); | 1109 | { |
1030 | EXPORT_SYMBOL(__elv_add_request); | 1110 | struct rb_node *rbprev = rb_prev(&rq->rb_node); |
1031 | EXPORT_SYMBOL(elv_next_request); | 1111 | |
1032 | EXPORT_SYMBOL(elv_dequeue_request); | 1112 | if (rbprev) |
1033 | EXPORT_SYMBOL(elv_queue_empty); | 1113 | return rb_entry_rq(rbprev); |
1034 | EXPORT_SYMBOL(elevator_exit); | 1114 | |
1035 | EXPORT_SYMBOL(elevator_init); | 1115 | return NULL; |
1116 | } | ||
1117 | |||
1118 | EXPORT_SYMBOL(elv_rb_former_request); | ||
1119 | |||
1120 | struct request *elv_rb_latter_request(request_queue_t *q, struct request *rq) | ||
1121 | { | ||
1122 | struct rb_node *rbnext = rb_next(&rq->rb_node); | ||
1123 | |||
1124 | if (rbnext) | ||
1125 | return rb_entry_rq(rbnext); | ||
1126 | |||
1127 | return NULL; | ||
1128 | } | ||
1129 | |||
1130 | EXPORT_SYMBOL(elv_rb_latter_request); | ||
diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index 9cbf7b550c78..d388486e98bb 100644 --- a/block/ll_rw_blk.c +++ b/block/ll_rw_blk.c | |||
@@ -281,11 +281,12 @@ static inline void rq_init(request_queue_t *q, struct request *rq) | |||
281 | { | 281 | { |
282 | INIT_LIST_HEAD(&rq->queuelist); | 282 | INIT_LIST_HEAD(&rq->queuelist); |
283 | INIT_LIST_HEAD(&rq->donelist); | 283 | INIT_LIST_HEAD(&rq->donelist); |
284 | INIT_HLIST_NODE(&rq->hash); | ||
285 | 284 | ||
286 | rq->errors = 0; | 285 | rq->errors = 0; |
287 | rq->rq_status = RQ_ACTIVE; | 286 | rq->rq_status = RQ_ACTIVE; |
288 | rq->bio = rq->biotail = NULL; | 287 | rq->bio = rq->biotail = NULL; |
288 | INIT_HLIST_NODE(&rq->hash); | ||
289 | RB_CLEAR_NODE(&rq->rb_node); | ||
289 | rq->ioprio = 0; | 290 | rq->ioprio = 0; |
290 | rq->buffer = NULL; | 291 | rq->buffer = NULL; |
291 | rq->ref_count = 1; | 292 | rq->ref_count = 1; |
@@ -2943,7 +2944,7 @@ static int __make_request(request_queue_t *q, struct bio *bio) | |||
2943 | req->ioprio = ioprio_best(req->ioprio, prio); | 2944 | req->ioprio = ioprio_best(req->ioprio, prio); |
2944 | drive_stat_acct(req, nr_sectors, 0); | 2945 | drive_stat_acct(req, nr_sectors, 0); |
2945 | if (!attempt_back_merge(q, req)) | 2946 | if (!attempt_back_merge(q, req)) |
2946 | elv_merged_request(q, req); | 2947 | elv_merged_request(q, req, el_ret); |
2947 | goto out; | 2948 | goto out; |
2948 | 2949 | ||
2949 | case ELEVATOR_FRONT_MERGE: | 2950 | case ELEVATOR_FRONT_MERGE: |
@@ -2970,7 +2971,7 @@ static int __make_request(request_queue_t *q, struct bio *bio) | |||
2970 | req->ioprio = ioprio_best(req->ioprio, prio); | 2971 | req->ioprio = ioprio_best(req->ioprio, prio); |
2971 | drive_stat_acct(req, nr_sectors, 0); | 2972 | drive_stat_acct(req, nr_sectors, 0); |
2972 | if (!attempt_front_merge(q, req)) | 2973 | if (!attempt_front_merge(q, req)) |
2973 | elv_merged_request(q, req); | 2974 | elv_merged_request(q, req, el_ret); |
2974 | goto out; | 2975 | goto out; |
2975 | 2976 | ||
2976 | /* ELV_NO_MERGE: elevator says don't/can't merge. */ | 2977 | /* ELV_NO_MERGE: elevator says don't/can't merge. */ |
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 8f5486964671..a905c4934a55 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h | |||
@@ -230,6 +230,7 @@ struct request { | |||
230 | struct bio *biotail; | 230 | struct bio *biotail; |
231 | 231 | ||
232 | struct hlist_node hash; /* merge hash */ | 232 | struct hlist_node hash; /* merge hash */ |
233 | struct rb_node rb_node; /* sort/lookup */ | ||
233 | 234 | ||
234 | void *elevator_private; | 235 | void *elevator_private; |
235 | void *completion_data; | 236 | void *completion_data; |
diff --git a/include/linux/elevator.h b/include/linux/elevator.h index 2c270e90b33e..95b2a04b969c 100644 --- a/include/linux/elevator.h +++ b/include/linux/elevator.h | |||
@@ -6,7 +6,7 @@ typedef int (elevator_merge_fn) (request_queue_t *, struct request **, | |||
6 | 6 | ||
7 | typedef void (elevator_merge_req_fn) (request_queue_t *, struct request *, struct request *); | 7 | typedef void (elevator_merge_req_fn) (request_queue_t *, struct request *, struct request *); |
8 | 8 | ||
9 | typedef void (elevator_merged_fn) (request_queue_t *, struct request *); | 9 | typedef void (elevator_merged_fn) (request_queue_t *, struct request *, int); |
10 | 10 | ||
11 | typedef int (elevator_dispatch_fn) (request_queue_t *, int); | 11 | typedef int (elevator_dispatch_fn) (request_queue_t *, int); |
12 | 12 | ||
@@ -96,7 +96,7 @@ extern void elv_insert(request_queue_t *, struct request *, int); | |||
96 | extern int elv_merge(request_queue_t *, struct request **, struct bio *); | 96 | extern int elv_merge(request_queue_t *, struct request **, struct bio *); |
97 | extern void elv_merge_requests(request_queue_t *, struct request *, | 97 | extern void elv_merge_requests(request_queue_t *, struct request *, |
98 | struct request *); | 98 | struct request *); |
99 | extern void elv_merged_request(request_queue_t *, struct request *); | 99 | extern void elv_merged_request(request_queue_t *, struct request *, int); |
100 | extern void elv_dequeue_request(request_queue_t *, struct request *); | 100 | extern void elv_dequeue_request(request_queue_t *, struct request *); |
101 | extern void elv_requeue_request(request_queue_t *, struct request *); | 101 | extern void elv_requeue_request(request_queue_t *, struct request *); |
102 | extern int elv_queue_empty(request_queue_t *); | 102 | extern int elv_queue_empty(request_queue_t *); |
@@ -127,6 +127,19 @@ extern void elevator_exit(elevator_t *); | |||
127 | extern int elv_rq_merge_ok(struct request *, struct bio *); | 127 | extern int elv_rq_merge_ok(struct request *, struct bio *); |
128 | 128 | ||
129 | /* | 129 | /* |
130 | * Helper functions. | ||
131 | */ | ||
132 | extern struct request *elv_rb_former_request(request_queue_t *, struct request *); | ||
133 | extern struct request *elv_rb_latter_request(request_queue_t *, struct request *); | ||
134 | |||
135 | /* | ||
136 | * rb support functions. | ||
137 | */ | ||
138 | extern struct request *elv_rb_add(struct rb_root *, struct request *); | ||
139 | extern void elv_rb_del(struct rb_root *, struct request *); | ||
140 | extern struct request *elv_rb_find(struct rb_root *, sector_t); | ||
141 | |||
142 | /* | ||
130 | * Return values from elevator merger | 143 | * Return values from elevator merger |
131 | */ | 144 | */ |
132 | #define ELEVATOR_NO_MERGE 0 | 145 | #define ELEVATOR_NO_MERGE 0 |
@@ -151,5 +164,6 @@ enum { | |||
151 | }; | 164 | }; |
152 | 165 | ||
153 | #define rq_end_sector(rq) ((rq)->sector + (rq)->nr_sectors) | 166 | #define rq_end_sector(rq) ((rq)->sector + (rq)->nr_sectors) |
167 | #define rb_entry_rq(node) rb_entry((node), struct request, rb_node) | ||
154 | 168 | ||
155 | #endif | 169 | #endif |