diff options
-rw-r--r-- | block/as-iosched.c | 139 | ||||
-rw-r--r-- | block/cfq-iosched.c | 86 | ||||
-rw-r--r-- | block/deadline-iosched.c | 128 | ||||
-rw-r--r-- | block/elevator.c | 147 | ||||
-rw-r--r-- | block/ll_rw_blk.c | 2 | ||||
-rw-r--r-- | include/linux/blkdev.h | 17 | ||||
-rw-r--r-- | include/linux/elevator.h | 2 |
7 files changed, 146 insertions, 375 deletions
diff --git a/block/as-iosched.c b/block/as-iosched.c index ad1cc4077819..6db494333c3a 100644 --- a/block/as-iosched.c +++ b/block/as-iosched.c | |||
@@ -14,7 +14,6 @@ | |||
14 | #include <linux/slab.h> | 14 | #include <linux/slab.h> |
15 | #include <linux/init.h> | 15 | #include <linux/init.h> |
16 | #include <linux/compiler.h> | 16 | #include <linux/compiler.h> |
17 | #include <linux/hash.h> | ||
18 | #include <linux/rbtree.h> | 17 | #include <linux/rbtree.h> |
19 | #include <linux/interrupt.h> | 18 | #include <linux/interrupt.h> |
20 | 19 | ||
@@ -95,7 +94,6 @@ struct as_data { | |||
95 | 94 | ||
96 | struct as_rq *next_arq[2]; /* next in sort order */ | 95 | struct as_rq *next_arq[2]; /* next in sort order */ |
97 | sector_t last_sector[2]; /* last REQ_SYNC & REQ_ASYNC sectors */ | 96 | sector_t last_sector[2]; /* last REQ_SYNC & REQ_ASYNC sectors */ |
98 | struct hlist_head *hash; /* request hash */ | ||
99 | 97 | ||
100 | unsigned long exit_prob; /* probability a task will exit while | 98 | unsigned long exit_prob; /* probability a task will exit while |
101 | being waited on */ | 99 | being waited on */ |
@@ -162,11 +160,6 @@ struct as_rq { | |||
162 | struct io_context *io_context; /* The submitting task */ | 160 | struct io_context *io_context; /* The submitting task */ |
163 | 161 | ||
164 | /* | 162 | /* |
165 | * request hash, key is the ending offset (for back merge lookup) | ||
166 | */ | ||
167 | struct hlist_node hash; | ||
168 | |||
169 | /* | ||
170 | * expire fifo | 163 | * expire fifo |
171 | */ | 164 | */ |
172 | struct list_head fifo; | 165 | struct list_head fifo; |
@@ -273,77 +266,6 @@ static void as_put_io_context(struct as_rq *arq) | |||
273 | } | 266 | } |
274 | 267 | ||
275 | /* | 268 | /* |
276 | * the back merge hash support functions | ||
277 | */ | ||
278 | static const int as_hash_shift = 6; | ||
279 | #define AS_HASH_BLOCK(sec) ((sec) >> 3) | ||
280 | #define AS_HASH_FN(sec) (hash_long(AS_HASH_BLOCK((sec)), as_hash_shift)) | ||
281 | #define AS_HASH_ENTRIES (1 << as_hash_shift) | ||
282 | #define rq_hash_key(rq) ((rq)->sector + (rq)->nr_sectors) | ||
283 | |||
284 | static inline void __as_del_arq_hash(struct as_rq *arq) | ||
285 | { | ||
286 | hlist_del_init(&arq->hash); | ||
287 | } | ||
288 | |||
289 | static inline void as_del_arq_hash(struct as_rq *arq) | ||
290 | { | ||
291 | if (!hlist_unhashed(&arq->hash)) | ||
292 | __as_del_arq_hash(arq); | ||
293 | } | ||
294 | |||
295 | static void as_add_arq_hash(struct as_data *ad, struct as_rq *arq) | ||
296 | { | ||
297 | struct request *rq = arq->request; | ||
298 | |||
299 | BUG_ON(!hlist_unhashed(&arq->hash)); | ||
300 | |||
301 | hlist_add_head(&arq->hash, &ad->hash[AS_HASH_FN(rq_hash_key(rq))]); | ||
302 | } | ||
303 | |||
304 | /* | ||
305 | * move hot entry to front of chain | ||
306 | */ | ||
307 | static inline void as_hot_arq_hash(struct as_data *ad, struct as_rq *arq) | ||
308 | { | ||
309 | struct request *rq = arq->request; | ||
310 | struct hlist_head *head = &ad->hash[AS_HASH_FN(rq_hash_key(rq))]; | ||
311 | |||
312 | if (hlist_unhashed(&arq->hash)) { | ||
313 | WARN_ON(1); | ||
314 | return; | ||
315 | } | ||
316 | |||
317 | if (&arq->hash != head->first) { | ||
318 | hlist_del(&arq->hash); | ||
319 | hlist_add_head(&arq->hash, head); | ||
320 | } | ||
321 | } | ||
322 | |||
323 | static struct request *as_find_arq_hash(struct as_data *ad, sector_t offset) | ||
324 | { | ||
325 | struct hlist_head *hash_list = &ad->hash[AS_HASH_FN(offset)]; | ||
326 | struct hlist_node *entry, *next; | ||
327 | struct as_rq *arq; | ||
328 | |||
329 | hlist_for_each_entry_safe(arq, entry, next, hash_list, hash) { | ||
330 | struct request *__rq = arq->request; | ||
331 | |||
332 | BUG_ON(hlist_unhashed(&arq->hash)); | ||
333 | |||
334 | if (!rq_mergeable(__rq)) { | ||
335 | as_del_arq_hash(arq); | ||
336 | continue; | ||
337 | } | ||
338 | |||
339 | if (rq_hash_key(__rq) == offset) | ||
340 | return __rq; | ||
341 | } | ||
342 | |||
343 | return NULL; | ||
344 | } | ||
345 | |||
346 | /* | ||
347 | * rb tree support functions | 269 | * rb tree support functions |
348 | */ | 270 | */ |
349 | #define rb_entry_arq(node) rb_entry((node), struct as_rq, rb_node) | 271 | #define rb_entry_arq(node) rb_entry((node), struct as_rq, rb_node) |
@@ -1060,7 +982,6 @@ static void as_remove_queued_request(request_queue_t *q, struct request *rq) | |||
1060 | ad->next_arq[data_dir] = as_find_next_arq(ad, arq); | 982 | ad->next_arq[data_dir] = as_find_next_arq(ad, arq); |
1061 | 983 | ||
1062 | list_del_init(&arq->fifo); | 984 | list_del_init(&arq->fifo); |
1063 | as_del_arq_hash(arq); | ||
1064 | as_del_arq_rb(ad, arq); | 985 | as_del_arq_rb(ad, arq); |
1065 | } | 986 | } |
1066 | 987 | ||
@@ -1349,8 +1270,6 @@ static void as_add_request(request_queue_t *q, struct request *rq) | |||
1349 | } | 1270 | } |
1350 | 1271 | ||
1351 | as_add_arq_rb(ad, arq); | 1272 | as_add_arq_rb(ad, arq); |
1352 | if (rq_mergeable(arq->request)) | ||
1353 | as_add_arq_hash(ad, arq); | ||
1354 | 1273 | ||
1355 | /* | 1274 | /* |
1356 | * set expire time (only used for reads) and add to fifo list | 1275 | * set expire time (only used for reads) and add to fifo list |
@@ -1428,42 +1347,17 @@ as_merge(request_queue_t *q, struct request **req, struct bio *bio) | |||
1428 | struct as_data *ad = q->elevator->elevator_data; | 1347 | struct as_data *ad = q->elevator->elevator_data; |
1429 | sector_t rb_key = bio->bi_sector + bio_sectors(bio); | 1348 | sector_t rb_key = bio->bi_sector + bio_sectors(bio); |
1430 | struct request *__rq; | 1349 | struct request *__rq; |
1431 | int ret; | ||
1432 | |||
1433 | /* | ||
1434 | * see if the merge hash can satisfy a back merge | ||
1435 | */ | ||
1436 | __rq = as_find_arq_hash(ad, bio->bi_sector); | ||
1437 | if (__rq) { | ||
1438 | BUG_ON(__rq->sector + __rq->nr_sectors != bio->bi_sector); | ||
1439 | |||
1440 | if (elv_rq_merge_ok(__rq, bio)) { | ||
1441 | ret = ELEVATOR_BACK_MERGE; | ||
1442 | goto out; | ||
1443 | } | ||
1444 | } | ||
1445 | 1350 | ||
1446 | /* | 1351 | /* |
1447 | * check for front merge | 1352 | * check for front merge |
1448 | */ | 1353 | */ |
1449 | __rq = as_find_arq_rb(ad, rb_key, bio_data_dir(bio)); | 1354 | __rq = as_find_arq_rb(ad, rb_key, bio_data_dir(bio)); |
1450 | if (__rq) { | 1355 | if (__rq && elv_rq_merge_ok(__rq, bio)) { |
1451 | BUG_ON(rb_key != rq_rb_key(__rq)); | 1356 | *req = __rq; |
1452 | 1357 | return ELEVATOR_FRONT_MERGE; | |
1453 | if (elv_rq_merge_ok(__rq, bio)) { | ||
1454 | ret = ELEVATOR_FRONT_MERGE; | ||
1455 | goto out; | ||
1456 | } | ||
1457 | } | 1358 | } |
1458 | 1359 | ||
1459 | return ELEVATOR_NO_MERGE; | 1360 | return ELEVATOR_NO_MERGE; |
1460 | out: | ||
1461 | if (ret) { | ||
1462 | if (rq_mergeable(__rq)) | ||
1463 | as_hot_arq_hash(ad, RQ_DATA(__rq)); | ||
1464 | } | ||
1465 | *req = __rq; | ||
1466 | return ret; | ||
1467 | } | 1361 | } |
1468 | 1362 | ||
1469 | static void as_merged_request(request_queue_t *q, struct request *req) | 1363 | static void as_merged_request(request_queue_t *q, struct request *req) |
@@ -1472,12 +1366,6 @@ static void as_merged_request(request_queue_t *q, struct request *req) | |||
1472 | struct as_rq *arq = RQ_DATA(req); | 1366 | struct as_rq *arq = RQ_DATA(req); |
1473 | 1367 | ||
1474 | /* | 1368 | /* |
1475 | * hash always needs to be repositioned, key is end sector | ||
1476 | */ | ||
1477 | as_del_arq_hash(arq); | ||
1478 | as_add_arq_hash(ad, arq); | ||
1479 | |||
1480 | /* | ||
1481 | * if the merge was a front merge, we need to reposition request | 1369 | * if the merge was a front merge, we need to reposition request |
1482 | */ | 1370 | */ |
1483 | if (rq_rb_key(req) != arq->rb_key) { | 1371 | if (rq_rb_key(req) != arq->rb_key) { |
@@ -1501,13 +1389,6 @@ static void as_merged_requests(request_queue_t *q, struct request *req, | |||
1501 | BUG_ON(!arq); | 1389 | BUG_ON(!arq); |
1502 | BUG_ON(!anext); | 1390 | BUG_ON(!anext); |
1503 | 1391 | ||
1504 | /* | ||
1505 | * reposition arq (this is the merged request) in hash, and in rbtree | ||
1506 | * in case of a front merge | ||
1507 | */ | ||
1508 | as_del_arq_hash(arq); | ||
1509 | as_add_arq_hash(ad, arq); | ||
1510 | |||
1511 | if (rq_rb_key(req) != arq->rb_key) { | 1392 | if (rq_rb_key(req) != arq->rb_key) { |
1512 | as_del_arq_rb(ad, arq); | 1393 | as_del_arq_rb(ad, arq); |
1513 | as_add_arq_rb(ad, arq); | 1394 | as_add_arq_rb(ad, arq); |
@@ -1591,7 +1472,6 @@ static int as_set_request(request_queue_t *q, struct request *rq, | |||
1591 | arq->request = rq; | 1472 | arq->request = rq; |
1592 | arq->state = AS_RQ_PRESCHED; | 1473 | arq->state = AS_RQ_PRESCHED; |
1593 | arq->io_context = NULL; | 1474 | arq->io_context = NULL; |
1594 | INIT_HLIST_NODE(&arq->hash); | ||
1595 | INIT_LIST_HEAD(&arq->fifo); | 1475 | INIT_LIST_HEAD(&arq->fifo); |
1596 | rq->elevator_private = arq; | 1476 | rq->elevator_private = arq; |
1597 | return 0; | 1477 | return 0; |
@@ -1628,7 +1508,6 @@ static void as_exit_queue(elevator_t *e) | |||
1628 | 1508 | ||
1629 | mempool_destroy(ad->arq_pool); | 1509 | mempool_destroy(ad->arq_pool); |
1630 | put_io_context(ad->io_context); | 1510 | put_io_context(ad->io_context); |
1631 | kfree(ad->hash); | ||
1632 | kfree(ad); | 1511 | kfree(ad); |
1633 | } | 1512 | } |
1634 | 1513 | ||
@@ -1639,7 +1518,6 @@ static void as_exit_queue(elevator_t *e) | |||
1639 | static void *as_init_queue(request_queue_t *q, elevator_t *e) | 1518 | static void *as_init_queue(request_queue_t *q, elevator_t *e) |
1640 | { | 1519 | { |
1641 | struct as_data *ad; | 1520 | struct as_data *ad; |
1642 | int i; | ||
1643 | 1521 | ||
1644 | if (!arq_pool) | 1522 | if (!arq_pool) |
1645 | return NULL; | 1523 | return NULL; |
@@ -1651,17 +1529,9 @@ static void *as_init_queue(request_queue_t *q, elevator_t *e) | |||
1651 | 1529 | ||
1652 | ad->q = q; /* Identify what queue the data belongs to */ | 1530 | ad->q = q; /* Identify what queue the data belongs to */ |
1653 | 1531 | ||
1654 | ad->hash = kmalloc_node(sizeof(struct hlist_head)*AS_HASH_ENTRIES, | ||
1655 | GFP_KERNEL, q->node); | ||
1656 | if (!ad->hash) { | ||
1657 | kfree(ad); | ||
1658 | return NULL; | ||
1659 | } | ||
1660 | |||
1661 | ad->arq_pool = mempool_create_node(BLKDEV_MIN_RQ, mempool_alloc_slab, | 1532 | ad->arq_pool = mempool_create_node(BLKDEV_MIN_RQ, mempool_alloc_slab, |
1662 | mempool_free_slab, arq_pool, q->node); | 1533 | mempool_free_slab, arq_pool, q->node); |
1663 | if (!ad->arq_pool) { | 1534 | if (!ad->arq_pool) { |
1664 | kfree(ad->hash); | ||
1665 | kfree(ad); | 1535 | kfree(ad); |
1666 | return NULL; | 1536 | return NULL; |
1667 | } | 1537 | } |
@@ -1672,9 +1542,6 @@ static void *as_init_queue(request_queue_t *q, elevator_t *e) | |||
1672 | init_timer(&ad->antic_timer); | 1542 | init_timer(&ad->antic_timer); |
1673 | INIT_WORK(&ad->antic_work, as_work_handler, q); | 1543 | INIT_WORK(&ad->antic_work, as_work_handler, q); |
1674 | 1544 | ||
1675 | for (i = 0; i < AS_HASH_ENTRIES; i++) | ||
1676 | INIT_HLIST_HEAD(&ad->hash[i]); | ||
1677 | |||
1678 | INIT_LIST_HEAD(&ad->fifo_list[REQ_SYNC]); | 1545 | INIT_LIST_HEAD(&ad->fifo_list[REQ_SYNC]); |
1679 | INIT_LIST_HEAD(&ad->fifo_list[REQ_ASYNC]); | 1546 | INIT_LIST_HEAD(&ad->fifo_list[REQ_ASYNC]); |
1680 | ad->sort_list[REQ_SYNC] = RB_ROOT; | 1547 | ad->sort_list[REQ_SYNC] = RB_ROOT; |
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index 3a3aee08ec5f..1b803c0c90f1 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c | |||
@@ -41,16 +41,6 @@ static DEFINE_SPINLOCK(cfq_exit_lock); | |||
41 | #define CFQ_QHASH_ENTRIES (1 << CFQ_QHASH_SHIFT) | 41 | #define CFQ_QHASH_ENTRIES (1 << CFQ_QHASH_SHIFT) |
42 | #define list_entry_qhash(entry) hlist_entry((entry), struct cfq_queue, cfq_hash) | 42 | #define list_entry_qhash(entry) hlist_entry((entry), struct cfq_queue, cfq_hash) |
43 | 43 | ||
44 | /* | ||
45 | * for the hash of crq inside the cfqq | ||
46 | */ | ||
47 | #define CFQ_MHASH_SHIFT 6 | ||
48 | #define CFQ_MHASH_BLOCK(sec) ((sec) >> 3) | ||
49 | #define CFQ_MHASH_ENTRIES (1 << CFQ_MHASH_SHIFT) | ||
50 | #define CFQ_MHASH_FN(sec) hash_long(CFQ_MHASH_BLOCK(sec), CFQ_MHASH_SHIFT) | ||
51 | #define rq_hash_key(rq) ((rq)->sector + (rq)->nr_sectors) | ||
52 | #define list_entry_hash(ptr) hlist_entry((ptr), struct cfq_rq, hash) | ||
53 | |||
54 | #define list_entry_cfqq(ptr) list_entry((ptr), struct cfq_queue, cfq_list) | 44 | #define list_entry_cfqq(ptr) list_entry((ptr), struct cfq_queue, cfq_list) |
55 | #define list_entry_fifo(ptr) list_entry((ptr), struct request, queuelist) | 45 | #define list_entry_fifo(ptr) list_entry((ptr), struct request, queuelist) |
56 | 46 | ||
@@ -112,11 +102,6 @@ struct cfq_data { | |||
112 | */ | 102 | */ |
113 | struct hlist_head *cfq_hash; | 103 | struct hlist_head *cfq_hash; |
114 | 104 | ||
115 | /* | ||
116 | * global crq hash for all queues | ||
117 | */ | ||
118 | struct hlist_head *crq_hash; | ||
119 | |||
120 | mempool_t *crq_pool; | 105 | mempool_t *crq_pool; |
121 | 106 | ||
122 | int rq_in_driver; | 107 | int rq_in_driver; |
@@ -203,7 +188,6 @@ struct cfq_rq { | |||
203 | struct rb_node rb_node; | 188 | struct rb_node rb_node; |
204 | sector_t rb_key; | 189 | sector_t rb_key; |
205 | struct request *request; | 190 | struct request *request; |
206 | struct hlist_node hash; | ||
207 | 191 | ||
208 | struct cfq_queue *cfq_queue; | 192 | struct cfq_queue *cfq_queue; |
209 | struct cfq_io_context *io_context; | 193 | struct cfq_io_context *io_context; |
@@ -272,42 +256,6 @@ static void cfq_dispatch_insert(request_queue_t *, struct cfq_rq *); | |||
272 | static struct cfq_queue *cfq_get_queue(struct cfq_data *cfqd, unsigned int key, struct task_struct *tsk, gfp_t gfp_mask); | 256 | static struct cfq_queue *cfq_get_queue(struct cfq_data *cfqd, unsigned int key, struct task_struct *tsk, gfp_t gfp_mask); |
273 | 257 | ||
274 | /* | 258 | /* |
275 | * lots of deadline iosched dupes, can be abstracted later... | ||
276 | */ | ||
277 | static inline void cfq_del_crq_hash(struct cfq_rq *crq) | ||
278 | { | ||
279 | hlist_del_init(&crq->hash); | ||
280 | } | ||
281 | |||
282 | static inline void cfq_add_crq_hash(struct cfq_data *cfqd, struct cfq_rq *crq) | ||
283 | { | ||
284 | const int hash_idx = CFQ_MHASH_FN(rq_hash_key(crq->request)); | ||
285 | |||
286 | hlist_add_head(&crq->hash, &cfqd->crq_hash[hash_idx]); | ||
287 | } | ||
288 | |||
289 | static struct request *cfq_find_rq_hash(struct cfq_data *cfqd, sector_t offset) | ||
290 | { | ||
291 | struct hlist_head *hash_list = &cfqd->crq_hash[CFQ_MHASH_FN(offset)]; | ||
292 | struct hlist_node *entry, *next; | ||
293 | |||
294 | hlist_for_each_safe(entry, next, hash_list) { | ||
295 | struct cfq_rq *crq = list_entry_hash(entry); | ||
296 | struct request *__rq = crq->request; | ||
297 | |||
298 | if (!rq_mergeable(__rq)) { | ||
299 | cfq_del_crq_hash(crq); | ||
300 | continue; | ||
301 | } | ||
302 | |||
303 | if (rq_hash_key(__rq) == offset) | ||
304 | return __rq; | ||
305 | } | ||
306 | |||
307 | return NULL; | ||
308 | } | ||
309 | |||
310 | /* | ||
311 | * scheduler run of queue, if there are requests pending and no one in the | 259 | * scheduler run of queue, if there are requests pending and no one in the |
312 | * driver that will restart queueing | 260 | * driver that will restart queueing |
313 | */ | 261 | */ |
@@ -677,7 +625,6 @@ static void cfq_remove_request(struct request *rq) | |||
677 | 625 | ||
678 | list_del_init(&rq->queuelist); | 626 | list_del_init(&rq->queuelist); |
679 | cfq_del_crq_rb(crq); | 627 | cfq_del_crq_rb(crq); |
680 | cfq_del_crq_hash(crq); | ||
681 | } | 628 | } |
682 | 629 | ||
683 | static int | 630 | static int |
@@ -685,34 +632,20 @@ cfq_merge(request_queue_t *q, struct request **req, struct bio *bio) | |||
685 | { | 632 | { |
686 | struct cfq_data *cfqd = q->elevator->elevator_data; | 633 | struct cfq_data *cfqd = q->elevator->elevator_data; |
687 | struct request *__rq; | 634 | struct request *__rq; |
688 | int ret; | ||
689 | |||
690 | __rq = cfq_find_rq_hash(cfqd, bio->bi_sector); | ||
691 | if (__rq && elv_rq_merge_ok(__rq, bio)) { | ||
692 | ret = ELEVATOR_BACK_MERGE; | ||
693 | goto out; | ||
694 | } | ||
695 | 635 | ||
696 | __rq = cfq_find_rq_fmerge(cfqd, bio); | 636 | __rq = cfq_find_rq_fmerge(cfqd, bio); |
697 | if (__rq && elv_rq_merge_ok(__rq, bio)) { | 637 | if (__rq && elv_rq_merge_ok(__rq, bio)) { |
698 | ret = ELEVATOR_FRONT_MERGE; | 638 | *req = __rq; |
699 | goto out; | 639 | return ELEVATOR_FRONT_MERGE; |
700 | } | 640 | } |
701 | 641 | ||
702 | return ELEVATOR_NO_MERGE; | 642 | return ELEVATOR_NO_MERGE; |
703 | out: | ||
704 | *req = __rq; | ||
705 | return ret; | ||
706 | } | 643 | } |
707 | 644 | ||
708 | static void cfq_merged_request(request_queue_t *q, struct request *req) | 645 | static void cfq_merged_request(request_queue_t *q, struct request *req) |
709 | { | 646 | { |
710 | struct cfq_data *cfqd = q->elevator->elevator_data; | ||
711 | struct cfq_rq *crq = RQ_DATA(req); | 647 | struct cfq_rq *crq = RQ_DATA(req); |
712 | 648 | ||
713 | cfq_del_crq_hash(crq); | ||
714 | cfq_add_crq_hash(cfqd, crq); | ||
715 | |||
716 | if (rq_rb_key(req) != crq->rb_key) { | 649 | if (rq_rb_key(req) != crq->rb_key) { |
717 | struct cfq_queue *cfqq = crq->cfq_queue; | 650 | struct cfq_queue *cfqq = crq->cfq_queue; |
718 | 651 | ||
@@ -1825,9 +1758,6 @@ static void cfq_insert_request(request_queue_t *q, struct request *rq) | |||
1825 | 1758 | ||
1826 | list_add_tail(&rq->queuelist, &cfqq->fifo); | 1759 | list_add_tail(&rq->queuelist, &cfqq->fifo); |
1827 | 1760 | ||
1828 | if (rq_mergeable(rq)) | ||
1829 | cfq_add_crq_hash(cfqd, crq); | ||
1830 | |||
1831 | cfq_crq_enqueued(cfqd, cfqq, crq); | 1761 | cfq_crq_enqueued(cfqd, cfqq, crq); |
1832 | } | 1762 | } |
1833 | 1763 | ||
@@ -2055,7 +1985,6 @@ cfq_set_request(request_queue_t *q, struct request *rq, struct bio *bio, | |||
2055 | RB_CLEAR_NODE(&crq->rb_node); | 1985 | RB_CLEAR_NODE(&crq->rb_node); |
2056 | crq->rb_key = 0; | 1986 | crq->rb_key = 0; |
2057 | crq->request = rq; | 1987 | crq->request = rq; |
2058 | INIT_HLIST_NODE(&crq->hash); | ||
2059 | crq->cfq_queue = cfqq; | 1988 | crq->cfq_queue = cfqq; |
2060 | crq->io_context = cic; | 1989 | crq->io_context = cic; |
2061 | 1990 | ||
@@ -2221,7 +2150,6 @@ static void cfq_exit_queue(elevator_t *e) | |||
2221 | cfq_shutdown_timer_wq(cfqd); | 2150 | cfq_shutdown_timer_wq(cfqd); |
2222 | 2151 | ||
2223 | mempool_destroy(cfqd->crq_pool); | 2152 | mempool_destroy(cfqd->crq_pool); |
2224 | kfree(cfqd->crq_hash); | ||
2225 | kfree(cfqd->cfq_hash); | 2153 | kfree(cfqd->cfq_hash); |
2226 | kfree(cfqd); | 2154 | kfree(cfqd); |
2227 | } | 2155 | } |
@@ -2246,20 +2174,14 @@ static void *cfq_init_queue(request_queue_t *q, elevator_t *e) | |||
2246 | INIT_LIST_HEAD(&cfqd->empty_list); | 2174 | INIT_LIST_HEAD(&cfqd->empty_list); |
2247 | INIT_LIST_HEAD(&cfqd->cic_list); | 2175 | INIT_LIST_HEAD(&cfqd->cic_list); |
2248 | 2176 | ||
2249 | cfqd->crq_hash = kmalloc(sizeof(struct hlist_head) * CFQ_MHASH_ENTRIES, GFP_KERNEL); | ||
2250 | if (!cfqd->crq_hash) | ||
2251 | goto out_crqhash; | ||
2252 | |||
2253 | cfqd->cfq_hash = kmalloc(sizeof(struct hlist_head) * CFQ_QHASH_ENTRIES, GFP_KERNEL); | 2177 | cfqd->cfq_hash = kmalloc(sizeof(struct hlist_head) * CFQ_QHASH_ENTRIES, GFP_KERNEL); |
2254 | if (!cfqd->cfq_hash) | 2178 | if (!cfqd->cfq_hash) |
2255 | goto out_cfqhash; | 2179 | goto out_crqhash; |
2256 | 2180 | ||
2257 | cfqd->crq_pool = mempool_create_slab_pool(BLKDEV_MIN_RQ, crq_pool); | 2181 | cfqd->crq_pool = mempool_create_slab_pool(BLKDEV_MIN_RQ, crq_pool); |
2258 | if (!cfqd->crq_pool) | 2182 | if (!cfqd->crq_pool) |
2259 | goto out_crqpool; | 2183 | goto out_crqpool; |
2260 | 2184 | ||
2261 | for (i = 0; i < CFQ_MHASH_ENTRIES; i++) | ||
2262 | INIT_HLIST_HEAD(&cfqd->crq_hash[i]); | ||
2263 | for (i = 0; i < CFQ_QHASH_ENTRIES; i++) | 2185 | for (i = 0; i < CFQ_QHASH_ENTRIES; i++) |
2264 | INIT_HLIST_HEAD(&cfqd->cfq_hash[i]); | 2186 | INIT_HLIST_HEAD(&cfqd->cfq_hash[i]); |
2265 | 2187 | ||
@@ -2289,8 +2211,6 @@ static void *cfq_init_queue(request_queue_t *q, elevator_t *e) | |||
2289 | return cfqd; | 2211 | return cfqd; |
2290 | out_crqpool: | 2212 | out_crqpool: |
2291 | kfree(cfqd->cfq_hash); | 2213 | kfree(cfqd->cfq_hash); |
2292 | out_cfqhash: | ||
2293 | kfree(cfqd->crq_hash); | ||
2294 | out_crqhash: | 2214 | out_crqhash: |
2295 | kfree(cfqd); | 2215 | kfree(cfqd); |
2296 | return NULL; | 2216 | return NULL; |
diff --git a/block/deadline-iosched.c b/block/deadline-iosched.c index c7ca9f0b6498..b66e820f544d 100644 --- a/block/deadline-iosched.c +++ b/block/deadline-iosched.c | |||
@@ -12,7 +12,6 @@ | |||
12 | #include <linux/slab.h> | 12 | #include <linux/slab.h> |
13 | #include <linux/init.h> | 13 | #include <linux/init.h> |
14 | #include <linux/compiler.h> | 14 | #include <linux/compiler.h> |
15 | #include <linux/hash.h> | ||
16 | #include <linux/rbtree.h> | 15 | #include <linux/rbtree.h> |
17 | 16 | ||
18 | /* | 17 | /* |
@@ -24,13 +23,6 @@ static const int writes_starved = 2; /* max times reads can starve a write */ | |||
24 | static const int fifo_batch = 16; /* # of sequential requests treated as one | 23 | static const int fifo_batch = 16; /* # of sequential requests treated as one |
25 | by the above parameters. For throughput. */ | 24 | by the above parameters. For throughput. */ |
26 | 25 | ||
27 | static const int deadline_hash_shift = 5; | ||
28 | #define DL_HASH_BLOCK(sec) ((sec) >> 3) | ||
29 | #define DL_HASH_FN(sec) (hash_long(DL_HASH_BLOCK((sec)), deadline_hash_shift)) | ||
30 | #define DL_HASH_ENTRIES (1 << deadline_hash_shift) | ||
31 | #define rq_hash_key(rq) ((rq)->sector + (rq)->nr_sectors) | ||
32 | #define ON_HASH(drq) (!hlist_unhashed(&(drq)->hash)) | ||
33 | |||
34 | struct deadline_data { | 26 | struct deadline_data { |
35 | /* | 27 | /* |
36 | * run time data | 28 | * run time data |
@@ -46,7 +38,6 @@ struct deadline_data { | |||
46 | * next in sort order. read, write or both are NULL | 38 | * next in sort order. read, write or both are NULL |
47 | */ | 39 | */ |
48 | struct deadline_rq *next_drq[2]; | 40 | struct deadline_rq *next_drq[2]; |
49 | struct hlist_head *hash; /* request hash */ | ||
50 | unsigned int batching; /* number of sequential requests made */ | 41 | unsigned int batching; /* number of sequential requests made */ |
51 | sector_t last_sector; /* head position */ | 42 | sector_t last_sector; /* head position */ |
52 | unsigned int starved; /* times reads have starved writes */ | 43 | unsigned int starved; /* times reads have starved writes */ |
@@ -75,11 +66,6 @@ struct deadline_rq { | |||
75 | struct request *request; | 66 | struct request *request; |
76 | 67 | ||
77 | /* | 68 | /* |
78 | * request hash, key is the ending offset (for back merge lookup) | ||
79 | */ | ||
80 | struct hlist_node hash; | ||
81 | |||
82 | /* | ||
83 | * expire fifo | 69 | * expire fifo |
84 | */ | 70 | */ |
85 | struct list_head fifo; | 71 | struct list_head fifo; |
@@ -93,69 +79,6 @@ static kmem_cache_t *drq_pool; | |||
93 | #define RQ_DATA(rq) ((struct deadline_rq *) (rq)->elevator_private) | 79 | #define RQ_DATA(rq) ((struct deadline_rq *) (rq)->elevator_private) |
94 | 80 | ||
95 | /* | 81 | /* |
96 | * the back merge hash support functions | ||
97 | */ | ||
98 | static inline void __deadline_del_drq_hash(struct deadline_rq *drq) | ||
99 | { | ||
100 | hlist_del_init(&drq->hash); | ||
101 | } | ||
102 | |||
103 | static inline void deadline_del_drq_hash(struct deadline_rq *drq) | ||
104 | { | ||
105 | if (ON_HASH(drq)) | ||
106 | __deadline_del_drq_hash(drq); | ||
107 | } | ||
108 | |||
109 | static inline void | ||
110 | deadline_add_drq_hash(struct deadline_data *dd, struct deadline_rq *drq) | ||
111 | { | ||
112 | struct request *rq = drq->request; | ||
113 | |||
114 | BUG_ON(ON_HASH(drq)); | ||
115 | |||
116 | hlist_add_head(&drq->hash, &dd->hash[DL_HASH_FN(rq_hash_key(rq))]); | ||
117 | } | ||
118 | |||
119 | /* | ||
120 | * move hot entry to front of chain | ||
121 | */ | ||
122 | static inline void | ||
123 | deadline_hot_drq_hash(struct deadline_data *dd, struct deadline_rq *drq) | ||
124 | { | ||
125 | struct request *rq = drq->request; | ||
126 | struct hlist_head *head = &dd->hash[DL_HASH_FN(rq_hash_key(rq))]; | ||
127 | |||
128 | if (ON_HASH(drq) && &drq->hash != head->first) { | ||
129 | hlist_del(&drq->hash); | ||
130 | hlist_add_head(&drq->hash, head); | ||
131 | } | ||
132 | } | ||
133 | |||
134 | static struct request * | ||
135 | deadline_find_drq_hash(struct deadline_data *dd, sector_t offset) | ||
136 | { | ||
137 | struct hlist_head *hash_list = &dd->hash[DL_HASH_FN(offset)]; | ||
138 | struct hlist_node *entry, *next; | ||
139 | struct deadline_rq *drq; | ||
140 | |||
141 | hlist_for_each_entry_safe(drq, entry, next, hash_list, hash) { | ||
142 | struct request *__rq = drq->request; | ||
143 | |||
144 | BUG_ON(!ON_HASH(drq)); | ||
145 | |||
146 | if (!rq_mergeable(__rq)) { | ||
147 | __deadline_del_drq_hash(drq); | ||
148 | continue; | ||
149 | } | ||
150 | |||
151 | if (rq_hash_key(__rq) == offset) | ||
152 | return __rq; | ||
153 | } | ||
154 | |||
155 | return NULL; | ||
156 | } | ||
157 | |||
158 | /* | ||
159 | * rb tree support functions | 82 | * rb tree support functions |
160 | */ | 83 | */ |
161 | #define rb_entry_drq(node) rb_entry((node), struct deadline_rq, rb_node) | 84 | #define rb_entry_drq(node) rb_entry((node), struct deadline_rq, rb_node) |
@@ -267,22 +190,19 @@ deadline_add_request(struct request_queue *q, struct request *rq) | |||
267 | { | 190 | { |
268 | struct deadline_data *dd = q->elevator->elevator_data; | 191 | struct deadline_data *dd = q->elevator->elevator_data; |
269 | struct deadline_rq *drq = RQ_DATA(rq); | 192 | struct deadline_rq *drq = RQ_DATA(rq); |
270 | |||
271 | const int data_dir = rq_data_dir(drq->request); | 193 | const int data_dir = rq_data_dir(drq->request); |
272 | 194 | ||
273 | deadline_add_drq_rb(dd, drq); | 195 | deadline_add_drq_rb(dd, drq); |
196 | |||
274 | /* | 197 | /* |
275 | * set expire time (only used for reads) and add to fifo list | 198 | * set expire time (only used for reads) and add to fifo list |
276 | */ | 199 | */ |
277 | drq->expires = jiffies + dd->fifo_expire[data_dir]; | 200 | drq->expires = jiffies + dd->fifo_expire[data_dir]; |
278 | list_add_tail(&drq->fifo, &dd->fifo_list[data_dir]); | 201 | list_add_tail(&drq->fifo, &dd->fifo_list[data_dir]); |
279 | |||
280 | if (rq_mergeable(rq)) | ||
281 | deadline_add_drq_hash(dd, drq); | ||
282 | } | 202 | } |
283 | 203 | ||
284 | /* | 204 | /* |
285 | * remove rq from rbtree, fifo, and hash | 205 | * remove rq from rbtree and fifo. |
286 | */ | 206 | */ |
287 | static void deadline_remove_request(request_queue_t *q, struct request *rq) | 207 | static void deadline_remove_request(request_queue_t *q, struct request *rq) |
288 | { | 208 | { |
@@ -291,7 +211,6 @@ static void deadline_remove_request(request_queue_t *q, struct request *rq) | |||
291 | 211 | ||
292 | list_del_init(&drq->fifo); | 212 | list_del_init(&drq->fifo); |
293 | deadline_del_drq_rb(dd, drq); | 213 | deadline_del_drq_rb(dd, drq); |
294 | deadline_del_drq_hash(drq); | ||
295 | } | 214 | } |
296 | 215 | ||
297 | static int | 216 | static int |
@@ -302,19 +221,6 @@ deadline_merge(request_queue_t *q, struct request **req, struct bio *bio) | |||
302 | int ret; | 221 | int ret; |
303 | 222 | ||
304 | /* | 223 | /* |
305 | * see if the merge hash can satisfy a back merge | ||
306 | */ | ||
307 | __rq = deadline_find_drq_hash(dd, bio->bi_sector); | ||
308 | if (__rq) { | ||
309 | BUG_ON(__rq->sector + __rq->nr_sectors != bio->bi_sector); | ||
310 | |||
311 | if (elv_rq_merge_ok(__rq, bio)) { | ||
312 | ret = ELEVATOR_BACK_MERGE; | ||
313 | goto out; | ||
314 | } | ||
315 | } | ||
316 | |||
317 | /* | ||
318 | * check for front merge | 224 | * check for front merge |
319 | */ | 225 | */ |
320 | if (dd->front_merges) { | 226 | if (dd->front_merges) { |
@@ -333,8 +239,6 @@ deadline_merge(request_queue_t *q, struct request **req, struct bio *bio) | |||
333 | 239 | ||
334 | return ELEVATOR_NO_MERGE; | 240 | return ELEVATOR_NO_MERGE; |
335 | out: | 241 | out: |
336 | if (ret) | ||
337 | deadline_hot_drq_hash(dd, RQ_DATA(__rq)); | ||
338 | *req = __rq; | 242 | *req = __rq; |
339 | return ret; | 243 | return ret; |
340 | } | 244 | } |
@@ -345,12 +249,6 @@ static void deadline_merged_request(request_queue_t *q, struct request *req) | |||
345 | struct deadline_rq *drq = RQ_DATA(req); | 249 | struct deadline_rq *drq = RQ_DATA(req); |
346 | 250 | ||
347 | /* | 251 | /* |
348 | * hash always needs to be repositioned, key is end sector | ||
349 | */ | ||
350 | deadline_del_drq_hash(drq); | ||
351 | deadline_add_drq_hash(dd, drq); | ||
352 | |||
353 | /* | ||
354 | * if the merge was a front merge, we need to reposition request | 252 | * if the merge was a front merge, we need to reposition request |
355 | */ | 253 | */ |
356 | if (rq_rb_key(req) != drq->rb_key) { | 254 | if (rq_rb_key(req) != drq->rb_key) { |
@@ -370,13 +268,6 @@ deadline_merged_requests(request_queue_t *q, struct request *req, | |||
370 | BUG_ON(!drq); | 268 | BUG_ON(!drq); |
371 | BUG_ON(!dnext); | 269 | BUG_ON(!dnext); |
372 | 270 | ||
373 | /* | ||
374 | * reposition drq (this is the merged request) in hash, and in rbtree | ||
375 | * in case of a front merge | ||
376 | */ | ||
377 | deadline_del_drq_hash(drq); | ||
378 | deadline_add_drq_hash(dd, drq); | ||
379 | |||
380 | if (rq_rb_key(req) != drq->rb_key) { | 271 | if (rq_rb_key(req) != drq->rb_key) { |
381 | deadline_del_drq_rb(dd, drq); | 272 | deadline_del_drq_rb(dd, drq); |
382 | deadline_add_drq_rb(dd, drq); | 273 | deadline_add_drq_rb(dd, drq); |
@@ -594,7 +485,6 @@ static void deadline_exit_queue(elevator_t *e) | |||
594 | BUG_ON(!list_empty(&dd->fifo_list[WRITE])); | 485 | BUG_ON(!list_empty(&dd->fifo_list[WRITE])); |
595 | 486 | ||
596 | mempool_destroy(dd->drq_pool); | 487 | mempool_destroy(dd->drq_pool); |
597 | kfree(dd->hash); | ||
598 | kfree(dd); | 488 | kfree(dd); |
599 | } | 489 | } |
600 | 490 | ||
@@ -605,7 +495,6 @@ static void deadline_exit_queue(elevator_t *e) | |||
605 | static void *deadline_init_queue(request_queue_t *q, elevator_t *e) | 495 | static void *deadline_init_queue(request_queue_t *q, elevator_t *e) |
606 | { | 496 | { |
607 | struct deadline_data *dd; | 497 | struct deadline_data *dd; |
608 | int i; | ||
609 | 498 | ||
610 | if (!drq_pool) | 499 | if (!drq_pool) |
611 | return NULL; | 500 | return NULL; |
@@ -615,24 +504,13 @@ static void *deadline_init_queue(request_queue_t *q, elevator_t *e) | |||
615 | return NULL; | 504 | return NULL; |
616 | memset(dd, 0, sizeof(*dd)); | 505 | memset(dd, 0, sizeof(*dd)); |
617 | 506 | ||
618 | dd->hash = kmalloc_node(sizeof(struct hlist_head)*DL_HASH_ENTRIES, | ||
619 | GFP_KERNEL, q->node); | ||
620 | if (!dd->hash) { | ||
621 | kfree(dd); | ||
622 | return NULL; | ||
623 | } | ||
624 | |||
625 | dd->drq_pool = mempool_create_node(BLKDEV_MIN_RQ, mempool_alloc_slab, | 507 | dd->drq_pool = mempool_create_node(BLKDEV_MIN_RQ, mempool_alloc_slab, |
626 | mempool_free_slab, drq_pool, q->node); | 508 | mempool_free_slab, drq_pool, q->node); |
627 | if (!dd->drq_pool) { | 509 | if (!dd->drq_pool) { |
628 | kfree(dd->hash); | ||
629 | kfree(dd); | 510 | kfree(dd); |
630 | return NULL; | 511 | return NULL; |
631 | } | 512 | } |
632 | 513 | ||
633 | for (i = 0; i < DL_HASH_ENTRIES; i++) | ||
634 | INIT_HLIST_HEAD(&dd->hash[i]); | ||
635 | |||
636 | INIT_LIST_HEAD(&dd->fifo_list[READ]); | 514 | INIT_LIST_HEAD(&dd->fifo_list[READ]); |
637 | INIT_LIST_HEAD(&dd->fifo_list[WRITE]); | 515 | INIT_LIST_HEAD(&dd->fifo_list[WRITE]); |
638 | dd->sort_list[READ] = RB_ROOT; | 516 | dd->sort_list[READ] = RB_ROOT; |
@@ -667,8 +545,6 @@ deadline_set_request(request_queue_t *q, struct request *rq, struct bio *bio, | |||
667 | RB_CLEAR_NODE(&drq->rb_node); | 545 | RB_CLEAR_NODE(&drq->rb_node); |
668 | drq->request = rq; | 546 | drq->request = rq; |
669 | 547 | ||
670 | INIT_HLIST_NODE(&drq->hash); | ||
671 | |||
672 | INIT_LIST_HEAD(&drq->fifo); | 548 | INIT_LIST_HEAD(&drq->fifo); |
673 | 549 | ||
674 | rq->elevator_private = drq; | 550 | rq->elevator_private = drq; |
diff --git a/block/elevator.c b/block/elevator.c index 4ac97b642042..cff1102dac9d 100644 --- a/block/elevator.c +++ b/block/elevator.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <linux/compiler.h> | 33 | #include <linux/compiler.h> |
34 | #include <linux/delay.h> | 34 | #include <linux/delay.h> |
35 | #include <linux/blktrace_api.h> | 35 | #include <linux/blktrace_api.h> |
36 | #include <linux/hash.h> | ||
36 | 37 | ||
37 | #include <asm/uaccess.h> | 38 | #include <asm/uaccess.h> |
38 | 39 | ||
@@ -40,6 +41,16 @@ static DEFINE_SPINLOCK(elv_list_lock); | |||
40 | static LIST_HEAD(elv_list); | 41 | static LIST_HEAD(elv_list); |
41 | 42 | ||
42 | /* | 43 | /* |
44 | * Merge hash stuff. | ||
45 | */ | ||
46 | static const int elv_hash_shift = 6; | ||
47 | #define ELV_HASH_BLOCK(sec) ((sec) >> 3) | ||
48 | #define ELV_HASH_FN(sec) (hash_long(ELV_HASH_BLOCK((sec)), elv_hash_shift)) | ||
49 | #define ELV_HASH_ENTRIES (1 << elv_hash_shift) | ||
50 | #define rq_hash_key(rq) ((rq)->sector + (rq)->nr_sectors) | ||
51 | #define ELV_ON_HASH(rq) (!hlist_unhashed(&(rq)->hash)) | ||
52 | |||
53 | /* | ||
43 | * can we safely merge with this request? | 54 | * can we safely merge with this request? |
44 | */ | 55 | */ |
45 | inline int elv_rq_merge_ok(struct request *rq, struct bio *bio) | 56 | inline int elv_rq_merge_ok(struct request *rq, struct bio *bio) |
@@ -153,25 +164,41 @@ static struct kobj_type elv_ktype; | |||
153 | 164 | ||
154 | static elevator_t *elevator_alloc(struct elevator_type *e) | 165 | static elevator_t *elevator_alloc(struct elevator_type *e) |
155 | { | 166 | { |
156 | elevator_t *eq = kmalloc(sizeof(elevator_t), GFP_KERNEL); | 167 | elevator_t *eq; |
157 | if (eq) { | 168 | int i; |
158 | memset(eq, 0, sizeof(*eq)); | 169 | |
159 | eq->ops = &e->ops; | 170 | eq = kmalloc(sizeof(elevator_t), GFP_KERNEL); |
160 | eq->elevator_type = e; | 171 | if (unlikely(!eq)) |
161 | kobject_init(&eq->kobj); | 172 | goto err; |
162 | snprintf(eq->kobj.name, KOBJ_NAME_LEN, "%s", "iosched"); | 173 | |
163 | eq->kobj.ktype = &elv_ktype; | 174 | memset(eq, 0, sizeof(*eq)); |
164 | mutex_init(&eq->sysfs_lock); | 175 | eq->ops = &e->ops; |
165 | } else { | 176 | eq->elevator_type = e; |
166 | elevator_put(e); | 177 | kobject_init(&eq->kobj); |
167 | } | 178 | snprintf(eq->kobj.name, KOBJ_NAME_LEN, "%s", "iosched"); |
179 | eq->kobj.ktype = &elv_ktype; | ||
180 | mutex_init(&eq->sysfs_lock); | ||
181 | |||
182 | eq->hash = kmalloc(sizeof(struct hlist_head) * ELV_HASH_ENTRIES, GFP_KERNEL); | ||
183 | if (!eq->hash) | ||
184 | goto err; | ||
185 | |||
186 | for (i = 0; i < ELV_HASH_ENTRIES; i++) | ||
187 | INIT_HLIST_HEAD(&eq->hash[i]); | ||
188 | |||
168 | return eq; | 189 | return eq; |
190 | err: | ||
191 | kfree(eq); | ||
192 | elevator_put(e); | ||
193 | return NULL; | ||
169 | } | 194 | } |
170 | 195 | ||
171 | static void elevator_release(struct kobject *kobj) | 196 | static void elevator_release(struct kobject *kobj) |
172 | { | 197 | { |
173 | elevator_t *e = container_of(kobj, elevator_t, kobj); | 198 | elevator_t *e = container_of(kobj, elevator_t, kobj); |
199 | |||
174 | elevator_put(e->elevator_type); | 200 | elevator_put(e->elevator_type); |
201 | kfree(e->hash); | ||
175 | kfree(e); | 202 | kfree(e); |
176 | } | 203 | } |
177 | 204 | ||
@@ -223,6 +250,53 @@ void elevator_exit(elevator_t *e) | |||
223 | kobject_put(&e->kobj); | 250 | kobject_put(&e->kobj); |
224 | } | 251 | } |
225 | 252 | ||
253 | static inline void __elv_rqhash_del(struct request *rq) | ||
254 | { | ||
255 | hlist_del_init(&rq->hash); | ||
256 | } | ||
257 | |||
258 | static void elv_rqhash_del(request_queue_t *q, struct request *rq) | ||
259 | { | ||
260 | if (ELV_ON_HASH(rq)) | ||
261 | __elv_rqhash_del(rq); | ||
262 | } | ||
263 | |||
264 | static void elv_rqhash_add(request_queue_t *q, struct request *rq) | ||
265 | { | ||
266 | elevator_t *e = q->elevator; | ||
267 | |||
268 | BUG_ON(ELV_ON_HASH(rq)); | ||
269 | hlist_add_head(&rq->hash, &e->hash[ELV_HASH_FN(rq_hash_key(rq))]); | ||
270 | } | ||
271 | |||
272 | static void elv_rqhash_reposition(request_queue_t *q, struct request *rq) | ||
273 | { | ||
274 | __elv_rqhash_del(rq); | ||
275 | elv_rqhash_add(q, rq); | ||
276 | } | ||
277 | |||
278 | static struct request *elv_rqhash_find(request_queue_t *q, sector_t offset) | ||
279 | { | ||
280 | elevator_t *e = q->elevator; | ||
281 | struct hlist_head *hash_list = &e->hash[ELV_HASH_FN(offset)]; | ||
282 | struct hlist_node *entry, *next; | ||
283 | struct request *rq; | ||
284 | |||
285 | hlist_for_each_entry_safe(rq, entry, next, hash_list, hash) { | ||
286 | BUG_ON(!ELV_ON_HASH(rq)); | ||
287 | |||
288 | if (unlikely(!rq_mergeable(rq))) { | ||
289 | __elv_rqhash_del(rq); | ||
290 | continue; | ||
291 | } | ||
292 | |||
293 | if (rq_hash_key(rq) == offset) | ||
294 | return rq; | ||
295 | } | ||
296 | |||
297 | return NULL; | ||
298 | } | ||
299 | |||
226 | /* | 300 | /* |
227 | * Insert rq into dispatch queue of q. Queue lock must be held on | 301 | * Insert rq into dispatch queue of q. Queue lock must be held on |
228 | * entry. If sort != 0, rq is sort-inserted; otherwise, rq will be | 302 | * entry. If sort != 0, rq is sort-inserted; otherwise, rq will be |
@@ -235,6 +309,9 @@ void elv_dispatch_sort(request_queue_t *q, struct request *rq) | |||
235 | 309 | ||
236 | if (q->last_merge == rq) | 310 | if (q->last_merge == rq) |
237 | q->last_merge = NULL; | 311 | q->last_merge = NULL; |
312 | |||
313 | elv_rqhash_del(q, rq); | ||
314 | |||
238 | q->nr_sorted--; | 315 | q->nr_sorted--; |
239 | 316 | ||
240 | boundary = q->end_sector; | 317 | boundary = q->end_sector; |
@@ -258,11 +335,32 @@ void elv_dispatch_sort(request_queue_t *q, struct request *rq) | |||
258 | list_add(&rq->queuelist, entry); | 335 | list_add(&rq->queuelist, entry); |
259 | } | 336 | } |
260 | 337 | ||
338 | /* | ||
339 | * This should be in elevator.h, but that requires pulling in rq and q | ||
340 | */ | ||
341 | void elv_dispatch_add_tail(struct request_queue *q, struct request *rq) | ||
342 | { | ||
343 | if (q->last_merge == rq) | ||
344 | q->last_merge = NULL; | ||
345 | |||
346 | elv_rqhash_del(q, rq); | ||
347 | |||
348 | q->nr_sorted--; | ||
349 | |||
350 | q->end_sector = rq_end_sector(rq); | ||
351 | q->boundary_rq = rq; | ||
352 | list_add_tail(&rq->queuelist, &q->queue_head); | ||
353 | } | ||
354 | |||
261 | int elv_merge(request_queue_t *q, struct request **req, struct bio *bio) | 355 | int elv_merge(request_queue_t *q, struct request **req, struct bio *bio) |
262 | { | 356 | { |
263 | elevator_t *e = q->elevator; | 357 | elevator_t *e = q->elevator; |
358 | struct request *__rq; | ||
264 | int ret; | 359 | int ret; |
265 | 360 | ||
361 | /* | ||
362 | * First try one-hit cache. | ||
363 | */ | ||
266 | if (q->last_merge) { | 364 | if (q->last_merge) { |
267 | ret = elv_try_merge(q->last_merge, bio); | 365 | ret = elv_try_merge(q->last_merge, bio); |
268 | if (ret != ELEVATOR_NO_MERGE) { | 366 | if (ret != ELEVATOR_NO_MERGE) { |
@@ -271,6 +369,15 @@ int elv_merge(request_queue_t *q, struct request **req, struct bio *bio) | |||
271 | } | 369 | } |
272 | } | 370 | } |
273 | 371 | ||
372 | /* | ||
373 | * See if our hash lookup can find a potential backmerge. | ||
374 | */ | ||
375 | __rq = elv_rqhash_find(q, bio->bi_sector); | ||
376 | if (__rq && elv_rq_merge_ok(__rq, bio)) { | ||
377 | *req = __rq; | ||
378 | return ELEVATOR_BACK_MERGE; | ||
379 | } | ||
380 | |||
274 | if (e->ops->elevator_merge_fn) | 381 | if (e->ops->elevator_merge_fn) |
275 | return e->ops->elevator_merge_fn(q, req, bio); | 382 | return e->ops->elevator_merge_fn(q, req, bio); |
276 | 383 | ||
@@ -284,6 +391,8 @@ void elv_merged_request(request_queue_t *q, struct request *rq) | |||
284 | if (e->ops->elevator_merged_fn) | 391 | if (e->ops->elevator_merged_fn) |
285 | e->ops->elevator_merged_fn(q, rq); | 392 | e->ops->elevator_merged_fn(q, rq); |
286 | 393 | ||
394 | elv_rqhash_reposition(q, rq); | ||
395 | |||
287 | q->last_merge = rq; | 396 | q->last_merge = rq; |
288 | } | 397 | } |
289 | 398 | ||
@@ -294,8 +403,11 @@ void elv_merge_requests(request_queue_t *q, struct request *rq, | |||
294 | 403 | ||
295 | if (e->ops->elevator_merge_req_fn) | 404 | if (e->ops->elevator_merge_req_fn) |
296 | e->ops->elevator_merge_req_fn(q, rq, next); | 405 | e->ops->elevator_merge_req_fn(q, rq, next); |
297 | q->nr_sorted--; | ||
298 | 406 | ||
407 | elv_rqhash_reposition(q, rq); | ||
408 | elv_rqhash_del(q, next); | ||
409 | |||
410 | q->nr_sorted--; | ||
299 | q->last_merge = rq; | 411 | q->last_merge = rq; |
300 | } | 412 | } |
301 | 413 | ||
@@ -371,8 +483,12 @@ void elv_insert(request_queue_t *q, struct request *rq, int where) | |||
371 | BUG_ON(!blk_fs_request(rq)); | 483 | BUG_ON(!blk_fs_request(rq)); |
372 | rq->cmd_flags |= REQ_SORTED; | 484 | rq->cmd_flags |= REQ_SORTED; |
373 | q->nr_sorted++; | 485 | q->nr_sorted++; |
374 | if (q->last_merge == NULL && rq_mergeable(rq)) | 486 | if (rq_mergeable(rq)) { |
375 | q->last_merge = rq; | 487 | elv_rqhash_add(q, rq); |
488 | if (!q->last_merge) | ||
489 | q->last_merge = rq; | ||
490 | } | ||
491 | |||
376 | /* | 492 | /* |
377 | * Some ioscheds (cfq) run q->request_fn directly, so | 493 | * Some ioscheds (cfq) run q->request_fn directly, so |
378 | * rq cannot be accessed after calling | 494 | * rq cannot be accessed after calling |
@@ -557,6 +673,7 @@ struct request *elv_next_request(request_queue_t *q) | |||
557 | void elv_dequeue_request(request_queue_t *q, struct request *rq) | 673 | void elv_dequeue_request(request_queue_t *q, struct request *rq) |
558 | { | 674 | { |
559 | BUG_ON(list_empty(&rq->queuelist)); | 675 | BUG_ON(list_empty(&rq->queuelist)); |
676 | BUG_ON(ELV_ON_HASH(rq)); | ||
560 | 677 | ||
561 | list_del_init(&rq->queuelist); | 678 | list_del_init(&rq->queuelist); |
562 | 679 | ||
diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index 9b91bb70c5ed..9cbf7b550c78 100644 --- a/block/ll_rw_blk.c +++ b/block/ll_rw_blk.c | |||
@@ -281,6 +281,7 @@ 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); | ||
284 | 285 | ||
285 | rq->errors = 0; | 286 | rq->errors = 0; |
286 | rq->rq_status = RQ_ACTIVE; | 287 | rq->rq_status = RQ_ACTIVE; |
@@ -2700,6 +2701,7 @@ void __blk_put_request(request_queue_t *q, struct request *req) | |||
2700 | int priv = req->cmd_flags & REQ_ELVPRIV; | 2701 | int priv = req->cmd_flags & REQ_ELVPRIV; |
2701 | 2702 | ||
2702 | BUG_ON(!list_empty(&req->queuelist)); | 2703 | BUG_ON(!list_empty(&req->queuelist)); |
2704 | BUG_ON(!hlist_unhashed(&req->hash)); | ||
2703 | 2705 | ||
2704 | blk_free_request(q, req); | 2706 | blk_free_request(q, req); |
2705 | freed_request(q, rw, priv); | 2707 | freed_request(q, rw, priv); |
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index b2a412cf468f..8f5486964671 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h | |||
@@ -229,6 +229,8 @@ struct request { | |||
229 | struct bio *bio; | 229 | struct bio *bio; |
230 | struct bio *biotail; | 230 | struct bio *biotail; |
231 | 231 | ||
232 | struct hlist_node hash; /* merge hash */ | ||
233 | |||
232 | void *elevator_private; | 234 | void *elevator_private; |
233 | void *completion_data; | 235 | void *completion_data; |
234 | 236 | ||
@@ -697,21 +699,6 @@ static inline void blkdev_dequeue_request(struct request *req) | |||
697 | } | 699 | } |
698 | 700 | ||
699 | /* | 701 | /* |
700 | * This should be in elevator.h, but that requires pulling in rq and q | ||
701 | */ | ||
702 | static inline void elv_dispatch_add_tail(struct request_queue *q, | ||
703 | struct request *rq) | ||
704 | { | ||
705 | if (q->last_merge == rq) | ||
706 | q->last_merge = NULL; | ||
707 | q->nr_sorted--; | ||
708 | |||
709 | q->end_sector = rq_end_sector(rq); | ||
710 | q->boundary_rq = rq; | ||
711 | list_add_tail(&rq->queuelist, &q->queue_head); | ||
712 | } | ||
713 | |||
714 | /* | ||
715 | * Access functions for manipulating queue properties | 702 | * Access functions for manipulating queue properties |
716 | */ | 703 | */ |
717 | extern request_queue_t *blk_init_queue_node(request_fn_proc *rfn, | 704 | extern request_queue_t *blk_init_queue_node(request_fn_proc *rfn, |
diff --git a/include/linux/elevator.h b/include/linux/elevator.h index 1713ace808bf..2c270e90b33e 100644 --- a/include/linux/elevator.h +++ b/include/linux/elevator.h | |||
@@ -82,12 +82,14 @@ struct elevator_queue | |||
82 | struct kobject kobj; | 82 | struct kobject kobj; |
83 | struct elevator_type *elevator_type; | 83 | struct elevator_type *elevator_type; |
84 | struct mutex sysfs_lock; | 84 | struct mutex sysfs_lock; |
85 | struct hlist_head *hash; | ||
85 | }; | 86 | }; |
86 | 87 | ||
87 | /* | 88 | /* |
88 | * block elevator interface | 89 | * block elevator interface |
89 | */ | 90 | */ |
90 | extern void elv_dispatch_sort(request_queue_t *, struct request *); | 91 | extern void elv_dispatch_sort(request_queue_t *, struct request *); |
92 | extern void elv_dispatch_add_tail(request_queue_t *, struct request *); | ||
91 | extern void elv_add_request(request_queue_t *, struct request *, int, int); | 93 | extern void elv_add_request(request_queue_t *, struct request *, int, int); |
92 | extern void __elv_add_request(request_queue_t *, struct request *, int, int); | 94 | extern void __elv_add_request(request_queue_t *, struct request *, int, int); |
93 | extern void elv_insert(request_queue_t *, struct request *, int); | 95 | extern void elv_insert(request_queue_t *, struct request *, int); |