Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[PATCH] elevator: move the backmerging logic into the elevator core

Right now, every IO scheduler implements its own backmerging (except for
noop, which does no merging). That results in duplicated code for
essentially the same operation, which is never a good thing. This patch
moves the backmerging out of the io schedulers and into the elevator
core. We save 1.6kb of text and as a bonus get backmerging for noop as
well. Win-win!

Signed-off-by: Jens Axboe <axboe@suse.de>

authored by

Jens Axboe and committed by
Jens Axboe
9817064b 4aff5e23

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