diff options
Diffstat (limited to 'block')
-rw-r--r-- | block/as-iosched.c | 13 | ||||
-rw-r--r-- | block/cfq-iosched.c | 98 | ||||
-rw-r--r-- | block/deadline-iosched.c | 13 | ||||
-rw-r--r-- | block/elevator.c | 63 | ||||
-rw-r--r-- | block/ll_rw_blk.c | 26 | ||||
-rw-r--r-- | block/noop-iosched.c | 7 |
6 files changed, 139 insertions, 81 deletions
diff --git a/block/as-iosched.c b/block/as-iosched.c index ed336ab453ba..0c750393be4a 100644 --- a/block/as-iosched.c +++ b/block/as-iosched.c | |||
@@ -1647,17 +1647,17 @@ static void as_exit_queue(elevator_t *e) | |||
1647 | * initialize elevator private data (as_data), and alloc a arq for | 1647 | * initialize elevator private data (as_data), and alloc a arq for |
1648 | * each request on the free lists | 1648 | * each request on the free lists |
1649 | */ | 1649 | */ |
1650 | static int as_init_queue(request_queue_t *q, elevator_t *e) | 1650 | static void *as_init_queue(request_queue_t *q, elevator_t *e) |
1651 | { | 1651 | { |
1652 | struct as_data *ad; | 1652 | struct as_data *ad; |
1653 | int i; | 1653 | int i; |
1654 | 1654 | ||
1655 | if (!arq_pool) | 1655 | if (!arq_pool) |
1656 | return -ENOMEM; | 1656 | return NULL; |
1657 | 1657 | ||
1658 | ad = kmalloc_node(sizeof(*ad), GFP_KERNEL, q->node); | 1658 | ad = kmalloc_node(sizeof(*ad), GFP_KERNEL, q->node); |
1659 | if (!ad) | 1659 | if (!ad) |
1660 | return -ENOMEM; | 1660 | return NULL; |
1661 | memset(ad, 0, sizeof(*ad)); | 1661 | memset(ad, 0, sizeof(*ad)); |
1662 | 1662 | ||
1663 | ad->q = q; /* Identify what queue the data belongs to */ | 1663 | ad->q = q; /* Identify what queue the data belongs to */ |
@@ -1666,7 +1666,7 @@ static int as_init_queue(request_queue_t *q, elevator_t *e) | |||
1666 | GFP_KERNEL, q->node); | 1666 | GFP_KERNEL, q->node); |
1667 | if (!ad->hash) { | 1667 | if (!ad->hash) { |
1668 | kfree(ad); | 1668 | kfree(ad); |
1669 | return -ENOMEM; | 1669 | return NULL; |
1670 | } | 1670 | } |
1671 | 1671 | ||
1672 | ad->arq_pool = mempool_create_node(BLKDEV_MIN_RQ, mempool_alloc_slab, | 1672 | ad->arq_pool = mempool_create_node(BLKDEV_MIN_RQ, mempool_alloc_slab, |
@@ -1674,7 +1674,7 @@ static int as_init_queue(request_queue_t *q, elevator_t *e) | |||
1674 | if (!ad->arq_pool) { | 1674 | if (!ad->arq_pool) { |
1675 | kfree(ad->hash); | 1675 | kfree(ad->hash); |
1676 | kfree(ad); | 1676 | kfree(ad); |
1677 | return -ENOMEM; | 1677 | return NULL; |
1678 | } | 1678 | } |
1679 | 1679 | ||
1680 | /* anticipatory scheduling helpers */ | 1680 | /* anticipatory scheduling helpers */ |
@@ -1695,14 +1695,13 @@ static int as_init_queue(request_queue_t *q, elevator_t *e) | |||
1695 | ad->antic_expire = default_antic_expire; | 1695 | ad->antic_expire = default_antic_expire; |
1696 | ad->batch_expire[REQ_SYNC] = default_read_batch_expire; | 1696 | ad->batch_expire[REQ_SYNC] = default_read_batch_expire; |
1697 | ad->batch_expire[REQ_ASYNC] = default_write_batch_expire; | 1697 | ad->batch_expire[REQ_ASYNC] = default_write_batch_expire; |
1698 | e->elevator_data = ad; | ||
1699 | 1698 | ||
1700 | ad->current_batch_expires = jiffies + ad->batch_expire[REQ_SYNC]; | 1699 | ad->current_batch_expires = jiffies + ad->batch_expire[REQ_SYNC]; |
1701 | ad->write_batch_count = ad->batch_expire[REQ_ASYNC] / 10; | 1700 | ad->write_batch_count = ad->batch_expire[REQ_ASYNC] / 10; |
1702 | if (ad->write_batch_count < 2) | 1701 | if (ad->write_batch_count < 2) |
1703 | ad->write_batch_count = 2; | 1702 | ad->write_batch_count = 2; |
1704 | 1703 | ||
1705 | return 0; | 1704 | return ad; |
1706 | } | 1705 | } |
1707 | 1706 | ||
1708 | /* | 1707 | /* |
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index 01c416ba8437..6200d9b9af28 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c | |||
@@ -33,7 +33,7 @@ static int cfq_slice_idle = HZ / 70; | |||
33 | 33 | ||
34 | #define CFQ_KEY_ASYNC (0) | 34 | #define CFQ_KEY_ASYNC (0) |
35 | 35 | ||
36 | static DEFINE_RWLOCK(cfq_exit_lock); | 36 | static DEFINE_SPINLOCK(cfq_exit_lock); |
37 | 37 | ||
38 | /* | 38 | /* |
39 | * for the hash of cfqq inside the cfqd | 39 | * for the hash of cfqq inside the cfqd |
@@ -128,6 +128,7 @@ struct cfq_data { | |||
128 | mempool_t *crq_pool; | 128 | mempool_t *crq_pool; |
129 | 129 | ||
130 | int rq_in_driver; | 130 | int rq_in_driver; |
131 | int hw_tag; | ||
131 | 132 | ||
132 | /* | 133 | /* |
133 | * schedule slice state info | 134 | * schedule slice state info |
@@ -495,10 +496,13 @@ static void cfq_resort_rr_list(struct cfq_queue *cfqq, int preempted) | |||
495 | 496 | ||
496 | /* | 497 | /* |
497 | * if queue was preempted, just add to front to be fair. busy_rr | 498 | * if queue was preempted, just add to front to be fair. busy_rr |
498 | * isn't sorted. | 499 | * isn't sorted, but insert at the back for fairness. |
499 | */ | 500 | */ |
500 | if (preempted || list == &cfqd->busy_rr) { | 501 | if (preempted || list == &cfqd->busy_rr) { |
501 | list_add(&cfqq->cfq_list, list); | 502 | if (preempted) |
503 | list = list->prev; | ||
504 | |||
505 | list_add_tail(&cfqq->cfq_list, list); | ||
502 | return; | 506 | return; |
503 | } | 507 | } |
504 | 508 | ||
@@ -658,6 +662,15 @@ static void cfq_activate_request(request_queue_t *q, struct request *rq) | |||
658 | struct cfq_data *cfqd = q->elevator->elevator_data; | 662 | struct cfq_data *cfqd = q->elevator->elevator_data; |
659 | 663 | ||
660 | cfqd->rq_in_driver++; | 664 | cfqd->rq_in_driver++; |
665 | |||
666 | /* | ||
667 | * If the depth is larger 1, it really could be queueing. But lets | ||
668 | * make the mark a little higher - idling could still be good for | ||
669 | * low queueing, and a low queueing number could also just indicate | ||
670 | * a SCSI mid layer like behaviour where limit+1 is often seen. | ||
671 | */ | ||
672 | if (!cfqd->hw_tag && cfqd->rq_in_driver > 4) | ||
673 | cfqd->hw_tag = 1; | ||
661 | } | 674 | } |
662 | 675 | ||
663 | static void cfq_deactivate_request(request_queue_t *q, struct request *rq) | 676 | static void cfq_deactivate_request(request_queue_t *q, struct request *rq) |
@@ -873,6 +886,13 @@ static struct cfq_queue *cfq_set_active_queue(struct cfq_data *cfqd) | |||
873 | cfqq = list_entry_cfqq(cfqd->cur_rr.next); | 886 | cfqq = list_entry_cfqq(cfqd->cur_rr.next); |
874 | 887 | ||
875 | /* | 888 | /* |
889 | * If no new queues are available, check if the busy list has some | ||
890 | * before falling back to idle io. | ||
891 | */ | ||
892 | if (!cfqq && !list_empty(&cfqd->busy_rr)) | ||
893 | cfqq = list_entry_cfqq(cfqd->busy_rr.next); | ||
894 | |||
895 | /* | ||
876 | * if we have idle queues and no rt or be queues had pending | 896 | * if we have idle queues and no rt or be queues had pending |
877 | * requests, either allow immediate service if the grace period | 897 | * requests, either allow immediate service if the grace period |
878 | * has passed or arm the idle grace timer | 898 | * has passed or arm the idle grace timer |
@@ -1278,7 +1298,7 @@ static void cfq_exit_io_context(struct io_context *ioc) | |||
1278 | /* | 1298 | /* |
1279 | * put the reference this task is holding to the various queues | 1299 | * put the reference this task is holding to the various queues |
1280 | */ | 1300 | */ |
1281 | read_lock_irqsave(&cfq_exit_lock, flags); | 1301 | spin_lock_irqsave(&cfq_exit_lock, flags); |
1282 | 1302 | ||
1283 | n = rb_first(&ioc->cic_root); | 1303 | n = rb_first(&ioc->cic_root); |
1284 | while (n != NULL) { | 1304 | while (n != NULL) { |
@@ -1288,7 +1308,7 @@ static void cfq_exit_io_context(struct io_context *ioc) | |||
1288 | n = rb_next(n); | 1308 | n = rb_next(n); |
1289 | } | 1309 | } |
1290 | 1310 | ||
1291 | read_unlock_irqrestore(&cfq_exit_lock, flags); | 1311 | spin_unlock_irqrestore(&cfq_exit_lock, flags); |
1292 | } | 1312 | } |
1293 | 1313 | ||
1294 | static struct cfq_io_context * | 1314 | static struct cfq_io_context * |
@@ -1297,17 +1317,12 @@ cfq_alloc_io_context(struct cfq_data *cfqd, gfp_t gfp_mask) | |||
1297 | struct cfq_io_context *cic = kmem_cache_alloc(cfq_ioc_pool, gfp_mask); | 1317 | struct cfq_io_context *cic = kmem_cache_alloc(cfq_ioc_pool, gfp_mask); |
1298 | 1318 | ||
1299 | if (cic) { | 1319 | if (cic) { |
1300 | RB_CLEAR(&cic->rb_node); | 1320 | memset(cic, 0, sizeof(*cic)); |
1301 | cic->key = NULL; | 1321 | RB_CLEAR_COLOR(&cic->rb_node); |
1302 | cic->cfqq[ASYNC] = NULL; | ||
1303 | cic->cfqq[SYNC] = NULL; | ||
1304 | cic->last_end_request = jiffies; | 1322 | cic->last_end_request = jiffies; |
1305 | cic->ttime_total = 0; | 1323 | INIT_LIST_HEAD(&cic->queue_list); |
1306 | cic->ttime_samples = 0; | ||
1307 | cic->ttime_mean = 0; | ||
1308 | cic->dtor = cfq_free_io_context; | 1324 | cic->dtor = cfq_free_io_context; |
1309 | cic->exit = cfq_exit_io_context; | 1325 | cic->exit = cfq_exit_io_context; |
1310 | INIT_LIST_HEAD(&cic->queue_list); | ||
1311 | atomic_inc(&ioc_count); | 1326 | atomic_inc(&ioc_count); |
1312 | } | 1327 | } |
1313 | 1328 | ||
@@ -1394,17 +1409,17 @@ static int cfq_ioc_set_ioprio(struct io_context *ioc, unsigned int ioprio) | |||
1394 | struct cfq_io_context *cic; | 1409 | struct cfq_io_context *cic; |
1395 | struct rb_node *n; | 1410 | struct rb_node *n; |
1396 | 1411 | ||
1397 | write_lock(&cfq_exit_lock); | 1412 | spin_lock(&cfq_exit_lock); |
1398 | 1413 | ||
1399 | n = rb_first(&ioc->cic_root); | 1414 | n = rb_first(&ioc->cic_root); |
1400 | while (n != NULL) { | 1415 | while (n != NULL) { |
1401 | cic = rb_entry(n, struct cfq_io_context, rb_node); | 1416 | cic = rb_entry(n, struct cfq_io_context, rb_node); |
1402 | 1417 | ||
1403 | changed_ioprio(cic); | 1418 | changed_ioprio(cic); |
1404 | n = rb_next(n); | 1419 | n = rb_next(n); |
1405 | } | 1420 | } |
1406 | 1421 | ||
1407 | write_unlock(&cfq_exit_lock); | 1422 | spin_unlock(&cfq_exit_lock); |
1408 | 1423 | ||
1409 | return 0; | 1424 | return 0; |
1410 | } | 1425 | } |
@@ -1452,7 +1467,8 @@ retry: | |||
1452 | * set ->slice_left to allow preemption for a new process | 1467 | * set ->slice_left to allow preemption for a new process |
1453 | */ | 1468 | */ |
1454 | cfqq->slice_left = 2 * cfqd->cfq_slice_idle; | 1469 | cfqq->slice_left = 2 * cfqd->cfq_slice_idle; |
1455 | cfq_mark_cfqq_idle_window(cfqq); | 1470 | if (!cfqd->hw_tag) |
1471 | cfq_mark_cfqq_idle_window(cfqq); | ||
1456 | cfq_mark_cfqq_prio_changed(cfqq); | 1472 | cfq_mark_cfqq_prio_changed(cfqq); |
1457 | cfq_init_prio_data(cfqq); | 1473 | cfq_init_prio_data(cfqq); |
1458 | } | 1474 | } |
@@ -1469,9 +1485,10 @@ out: | |||
1469 | static void | 1485 | static void |
1470 | cfq_drop_dead_cic(struct io_context *ioc, struct cfq_io_context *cic) | 1486 | cfq_drop_dead_cic(struct io_context *ioc, struct cfq_io_context *cic) |
1471 | { | 1487 | { |
1472 | read_lock(&cfq_exit_lock); | 1488 | spin_lock(&cfq_exit_lock); |
1473 | rb_erase(&cic->rb_node, &ioc->cic_root); | 1489 | rb_erase(&cic->rb_node, &ioc->cic_root); |
1474 | read_unlock(&cfq_exit_lock); | 1490 | list_del_init(&cic->queue_list); |
1491 | spin_unlock(&cfq_exit_lock); | ||
1475 | kmem_cache_free(cfq_ioc_pool, cic); | 1492 | kmem_cache_free(cfq_ioc_pool, cic); |
1476 | atomic_dec(&ioc_count); | 1493 | atomic_dec(&ioc_count); |
1477 | } | 1494 | } |
@@ -1539,11 +1556,11 @@ restart: | |||
1539 | BUG(); | 1556 | BUG(); |
1540 | } | 1557 | } |
1541 | 1558 | ||
1542 | read_lock(&cfq_exit_lock); | 1559 | spin_lock(&cfq_exit_lock); |
1543 | rb_link_node(&cic->rb_node, parent, p); | 1560 | rb_link_node(&cic->rb_node, parent, p); |
1544 | rb_insert_color(&cic->rb_node, &ioc->cic_root); | 1561 | rb_insert_color(&cic->rb_node, &ioc->cic_root); |
1545 | list_add(&cic->queue_list, &cfqd->cic_list); | 1562 | list_add(&cic->queue_list, &cfqd->cic_list); |
1546 | read_unlock(&cfq_exit_lock); | 1563 | spin_unlock(&cfq_exit_lock); |
1547 | } | 1564 | } |
1548 | 1565 | ||
1549 | /* | 1566 | /* |
@@ -1642,7 +1659,7 @@ cfq_update_idle_window(struct cfq_data *cfqd, struct cfq_queue *cfqq, | |||
1642 | { | 1659 | { |
1643 | int enable_idle = cfq_cfqq_idle_window(cfqq); | 1660 | int enable_idle = cfq_cfqq_idle_window(cfqq); |
1644 | 1661 | ||
1645 | if (!cic->ioc->task || !cfqd->cfq_slice_idle) | 1662 | if (!cic->ioc->task || !cfqd->cfq_slice_idle || cfqd->hw_tag) |
1646 | enable_idle = 0; | 1663 | enable_idle = 0; |
1647 | else if (sample_valid(cic->ttime_samples)) { | 1664 | else if (sample_valid(cic->ttime_samples)) { |
1648 | if (cic->ttime_mean > cfqd->cfq_slice_idle) | 1665 | if (cic->ttime_mean > cfqd->cfq_slice_idle) |
@@ -1733,14 +1750,24 @@ cfq_crq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq, | |||
1733 | 1750 | ||
1734 | cfqq->next_crq = cfq_choose_req(cfqd, cfqq->next_crq, crq); | 1751 | cfqq->next_crq = cfq_choose_req(cfqd, cfqq->next_crq, crq); |
1735 | 1752 | ||
1753 | cic = crq->io_context; | ||
1754 | |||
1736 | /* | 1755 | /* |
1737 | * we never wait for an async request and we don't allow preemption | 1756 | * we never wait for an async request and we don't allow preemption |
1738 | * of an async request. so just return early | 1757 | * of an async request. so just return early |
1739 | */ | 1758 | */ |
1740 | if (!cfq_crq_is_sync(crq)) | 1759 | if (!cfq_crq_is_sync(crq)) { |
1760 | /* | ||
1761 | * sync process issued an async request, if it's waiting | ||
1762 | * then expire it and kick rq handling. | ||
1763 | */ | ||
1764 | if (cic == cfqd->active_cic && | ||
1765 | del_timer(&cfqd->idle_slice_timer)) { | ||
1766 | cfq_slice_expired(cfqd, 0); | ||
1767 | cfq_start_queueing(cfqd, cfqq); | ||
1768 | } | ||
1741 | return; | 1769 | return; |
1742 | 1770 | } | |
1743 | cic = crq->io_context; | ||
1744 | 1771 | ||
1745 | cfq_update_io_thinktime(cfqd, cic); | 1772 | cfq_update_io_thinktime(cfqd, cic); |
1746 | cfq_update_io_seektime(cfqd, cic, crq); | 1773 | cfq_update_io_seektime(cfqd, cic, crq); |
@@ -2158,10 +2185,9 @@ static void cfq_idle_class_timer(unsigned long data) | |||
2158 | * race with a non-idle queue, reset timer | 2185 | * race with a non-idle queue, reset timer |
2159 | */ | 2186 | */ |
2160 | end = cfqd->last_end_request + CFQ_IDLE_GRACE; | 2187 | end = cfqd->last_end_request + CFQ_IDLE_GRACE; |
2161 | if (!time_after_eq(jiffies, end)) { | 2188 | if (!time_after_eq(jiffies, end)) |
2162 | cfqd->idle_class_timer.expires = end; | 2189 | mod_timer(&cfqd->idle_class_timer, end); |
2163 | add_timer(&cfqd->idle_class_timer); | 2190 | else |
2164 | } else | ||
2165 | cfq_schedule_dispatch(cfqd); | 2191 | cfq_schedule_dispatch(cfqd); |
2166 | 2192 | ||
2167 | spin_unlock_irqrestore(cfqd->queue->queue_lock, flags); | 2193 | spin_unlock_irqrestore(cfqd->queue->queue_lock, flags); |
@@ -2181,7 +2207,7 @@ static void cfq_exit_queue(elevator_t *e) | |||
2181 | 2207 | ||
2182 | cfq_shutdown_timer_wq(cfqd); | 2208 | cfq_shutdown_timer_wq(cfqd); |
2183 | 2209 | ||
2184 | write_lock(&cfq_exit_lock); | 2210 | spin_lock(&cfq_exit_lock); |
2185 | spin_lock_irq(q->queue_lock); | 2211 | spin_lock_irq(q->queue_lock); |
2186 | 2212 | ||
2187 | if (cfqd->active_queue) | 2213 | if (cfqd->active_queue) |
@@ -2204,7 +2230,7 @@ static void cfq_exit_queue(elevator_t *e) | |||
2204 | } | 2230 | } |
2205 | 2231 | ||
2206 | spin_unlock_irq(q->queue_lock); | 2232 | spin_unlock_irq(q->queue_lock); |
2207 | write_unlock(&cfq_exit_lock); | 2233 | spin_unlock(&cfq_exit_lock); |
2208 | 2234 | ||
2209 | cfq_shutdown_timer_wq(cfqd); | 2235 | cfq_shutdown_timer_wq(cfqd); |
2210 | 2236 | ||
@@ -2214,14 +2240,14 @@ static void cfq_exit_queue(elevator_t *e) | |||
2214 | kfree(cfqd); | 2240 | kfree(cfqd); |
2215 | } | 2241 | } |
2216 | 2242 | ||
2217 | static int cfq_init_queue(request_queue_t *q, elevator_t *e) | 2243 | static void *cfq_init_queue(request_queue_t *q, elevator_t *e) |
2218 | { | 2244 | { |
2219 | struct cfq_data *cfqd; | 2245 | struct cfq_data *cfqd; |
2220 | int i; | 2246 | int i; |
2221 | 2247 | ||
2222 | cfqd = kmalloc(sizeof(*cfqd), GFP_KERNEL); | 2248 | cfqd = kmalloc(sizeof(*cfqd), GFP_KERNEL); |
2223 | if (!cfqd) | 2249 | if (!cfqd) |
2224 | return -ENOMEM; | 2250 | return NULL; |
2225 | 2251 | ||
2226 | memset(cfqd, 0, sizeof(*cfqd)); | 2252 | memset(cfqd, 0, sizeof(*cfqd)); |
2227 | 2253 | ||
@@ -2251,8 +2277,6 @@ static int cfq_init_queue(request_queue_t *q, elevator_t *e) | |||
2251 | for (i = 0; i < CFQ_QHASH_ENTRIES; i++) | 2277 | for (i = 0; i < CFQ_QHASH_ENTRIES; i++) |
2252 | INIT_HLIST_HEAD(&cfqd->cfq_hash[i]); | 2278 | INIT_HLIST_HEAD(&cfqd->cfq_hash[i]); |
2253 | 2279 | ||
2254 | e->elevator_data = cfqd; | ||
2255 | |||
2256 | cfqd->queue = q; | 2280 | cfqd->queue = q; |
2257 | 2281 | ||
2258 | cfqd->max_queued = q->nr_requests / 4; | 2282 | cfqd->max_queued = q->nr_requests / 4; |
@@ -2279,14 +2303,14 @@ static int cfq_init_queue(request_queue_t *q, elevator_t *e) | |||
2279 | cfqd->cfq_slice_async_rq = cfq_slice_async_rq; | 2303 | cfqd->cfq_slice_async_rq = cfq_slice_async_rq; |
2280 | cfqd->cfq_slice_idle = cfq_slice_idle; | 2304 | cfqd->cfq_slice_idle = cfq_slice_idle; |
2281 | 2305 | ||
2282 | return 0; | 2306 | return cfqd; |
2283 | out_crqpool: | 2307 | out_crqpool: |
2284 | kfree(cfqd->cfq_hash); | 2308 | kfree(cfqd->cfq_hash); |
2285 | out_cfqhash: | 2309 | out_cfqhash: |
2286 | kfree(cfqd->crq_hash); | 2310 | kfree(cfqd->crq_hash); |
2287 | out_crqhash: | 2311 | out_crqhash: |
2288 | kfree(cfqd); | 2312 | kfree(cfqd); |
2289 | return -ENOMEM; | 2313 | return NULL; |
2290 | } | 2314 | } |
2291 | 2315 | ||
2292 | static void cfq_slab_kill(void) | 2316 | static void cfq_slab_kill(void) |
diff --git a/block/deadline-iosched.c b/block/deadline-iosched.c index 06962d8402a3..c94de8e12fbf 100644 --- a/block/deadline-iosched.c +++ b/block/deadline-iosched.c | |||
@@ -612,24 +612,24 @@ static void deadline_exit_queue(elevator_t *e) | |||
612 | * initialize elevator private data (deadline_data), and alloc a drq for | 612 | * initialize elevator private data (deadline_data), and alloc a drq for |
613 | * each request on the free lists | 613 | * each request on the free lists |
614 | */ | 614 | */ |
615 | static int deadline_init_queue(request_queue_t *q, elevator_t *e) | 615 | static void *deadline_init_queue(request_queue_t *q, elevator_t *e) |
616 | { | 616 | { |
617 | struct deadline_data *dd; | 617 | struct deadline_data *dd; |
618 | int i; | 618 | int i; |
619 | 619 | ||
620 | if (!drq_pool) | 620 | if (!drq_pool) |
621 | return -ENOMEM; | 621 | return NULL; |
622 | 622 | ||
623 | dd = kmalloc_node(sizeof(*dd), GFP_KERNEL, q->node); | 623 | dd = kmalloc_node(sizeof(*dd), GFP_KERNEL, q->node); |
624 | if (!dd) | 624 | if (!dd) |
625 | return -ENOMEM; | 625 | return NULL; |
626 | memset(dd, 0, sizeof(*dd)); | 626 | memset(dd, 0, sizeof(*dd)); |
627 | 627 | ||
628 | dd->hash = kmalloc_node(sizeof(struct list_head)*DL_HASH_ENTRIES, | 628 | dd->hash = kmalloc_node(sizeof(struct list_head)*DL_HASH_ENTRIES, |
629 | GFP_KERNEL, q->node); | 629 | GFP_KERNEL, q->node); |
630 | if (!dd->hash) { | 630 | if (!dd->hash) { |
631 | kfree(dd); | 631 | kfree(dd); |
632 | return -ENOMEM; | 632 | return NULL; |
633 | } | 633 | } |
634 | 634 | ||
635 | dd->drq_pool = mempool_create_node(BLKDEV_MIN_RQ, mempool_alloc_slab, | 635 | dd->drq_pool = mempool_create_node(BLKDEV_MIN_RQ, mempool_alloc_slab, |
@@ -637,7 +637,7 @@ static int deadline_init_queue(request_queue_t *q, elevator_t *e) | |||
637 | if (!dd->drq_pool) { | 637 | if (!dd->drq_pool) { |
638 | kfree(dd->hash); | 638 | kfree(dd->hash); |
639 | kfree(dd); | 639 | kfree(dd); |
640 | return -ENOMEM; | 640 | return NULL; |
641 | } | 641 | } |
642 | 642 | ||
643 | for (i = 0; i < DL_HASH_ENTRIES; i++) | 643 | for (i = 0; i < DL_HASH_ENTRIES; i++) |
@@ -652,8 +652,7 @@ static int deadline_init_queue(request_queue_t *q, elevator_t *e) | |||
652 | dd->writes_starved = writes_starved; | 652 | dd->writes_starved = writes_starved; |
653 | dd->front_merges = 1; | 653 | dd->front_merges = 1; |
654 | dd->fifo_batch = fifo_batch; | 654 | dd->fifo_batch = fifo_batch; |
655 | e->elevator_data = dd; | 655 | return dd; |
656 | return 0; | ||
657 | } | 656 | } |
658 | 657 | ||
659 | static void deadline_put_request(request_queue_t *q, struct request *rq) | 658 | static void deadline_put_request(request_queue_t *q, struct request *rq) |
diff --git a/block/elevator.c b/block/elevator.c index 29825792cbd5..a0afdd317cef 100644 --- a/block/elevator.c +++ b/block/elevator.c | |||
@@ -121,16 +121,16 @@ static struct elevator_type *elevator_get(const char *name) | |||
121 | return e; | 121 | return e; |
122 | } | 122 | } |
123 | 123 | ||
124 | static int elevator_attach(request_queue_t *q, struct elevator_queue *eq) | 124 | static void *elevator_init_queue(request_queue_t *q, struct elevator_queue *eq) |
125 | { | 125 | { |
126 | int ret = 0; | 126 | return eq->ops->elevator_init_fn(q, eq); |
127 | } | ||
127 | 128 | ||
129 | static void elevator_attach(request_queue_t *q, struct elevator_queue *eq, | ||
130 | void *data) | ||
131 | { | ||
128 | q->elevator = eq; | 132 | q->elevator = eq; |
129 | 133 | eq->elevator_data = data; | |
130 | if (eq->ops->elevator_init_fn) | ||
131 | ret = eq->ops->elevator_init_fn(q, eq); | ||
132 | |||
133 | return ret; | ||
134 | } | 134 | } |
135 | 135 | ||
136 | static char chosen_elevator[16]; | 136 | static char chosen_elevator[16]; |
@@ -181,6 +181,7 @@ int elevator_init(request_queue_t *q, char *name) | |||
181 | struct elevator_type *e = NULL; | 181 | struct elevator_type *e = NULL; |
182 | struct elevator_queue *eq; | 182 | struct elevator_queue *eq; |
183 | int ret = 0; | 183 | int ret = 0; |
184 | void *data; | ||
184 | 185 | ||
185 | INIT_LIST_HEAD(&q->queue_head); | 186 | INIT_LIST_HEAD(&q->queue_head); |
186 | q->last_merge = NULL; | 187 | q->last_merge = NULL; |
@@ -202,10 +203,13 @@ int elevator_init(request_queue_t *q, char *name) | |||
202 | if (!eq) | 203 | if (!eq) |
203 | return -ENOMEM; | 204 | return -ENOMEM; |
204 | 205 | ||
205 | ret = elevator_attach(q, eq); | 206 | data = elevator_init_queue(q, eq); |
206 | if (ret) | 207 | if (!data) { |
207 | kobject_put(&eq->kobj); | 208 | kobject_put(&eq->kobj); |
209 | return -ENOMEM; | ||
210 | } | ||
208 | 211 | ||
212 | elevator_attach(q, eq, data); | ||
209 | return ret; | 213 | return ret; |
210 | } | 214 | } |
211 | 215 | ||
@@ -333,6 +337,7 @@ void elv_insert(request_queue_t *q, struct request *rq, int where) | |||
333 | { | 337 | { |
334 | struct list_head *pos; | 338 | struct list_head *pos; |
335 | unsigned ordseq; | 339 | unsigned ordseq; |
340 | int unplug_it = 1; | ||
336 | 341 | ||
337 | blk_add_trace_rq(q, rq, BLK_TA_INSERT); | 342 | blk_add_trace_rq(q, rq, BLK_TA_INSERT); |
338 | 343 | ||
@@ -399,6 +404,11 @@ void elv_insert(request_queue_t *q, struct request *rq, int where) | |||
399 | } | 404 | } |
400 | 405 | ||
401 | list_add_tail(&rq->queuelist, pos); | 406 | list_add_tail(&rq->queuelist, pos); |
407 | /* | ||
408 | * most requeues happen because of a busy condition, don't | ||
409 | * force unplug of the queue for that case. | ||
410 | */ | ||
411 | unplug_it = 0; | ||
402 | break; | 412 | break; |
403 | 413 | ||
404 | default: | 414 | default: |
@@ -407,7 +417,7 @@ void elv_insert(request_queue_t *q, struct request *rq, int where) | |||
407 | BUG(); | 417 | BUG(); |
408 | } | 418 | } |
409 | 419 | ||
410 | if (blk_queue_plugged(q)) { | 420 | if (unplug_it && blk_queue_plugged(q)) { |
411 | int nrq = q->rq.count[READ] + q->rq.count[WRITE] | 421 | int nrq = q->rq.count[READ] + q->rq.count[WRITE] |
412 | - q->in_flight; | 422 | - q->in_flight; |
413 | 423 | ||
@@ -716,13 +726,16 @@ int elv_register_queue(struct request_queue *q) | |||
716 | return error; | 726 | return error; |
717 | } | 727 | } |
718 | 728 | ||
729 | static void __elv_unregister_queue(elevator_t *e) | ||
730 | { | ||
731 | kobject_uevent(&e->kobj, KOBJ_REMOVE); | ||
732 | kobject_del(&e->kobj); | ||
733 | } | ||
734 | |||
719 | void elv_unregister_queue(struct request_queue *q) | 735 | void elv_unregister_queue(struct request_queue *q) |
720 | { | 736 | { |
721 | if (q) { | 737 | if (q) |
722 | elevator_t *e = q->elevator; | 738 | __elv_unregister_queue(q->elevator); |
723 | kobject_uevent(&e->kobj, KOBJ_REMOVE); | ||
724 | kobject_del(&e->kobj); | ||
725 | } | ||
726 | } | 739 | } |
727 | 740 | ||
728 | int elv_register(struct elevator_type *e) | 741 | int elv_register(struct elevator_type *e) |
@@ -774,6 +787,7 @@ EXPORT_SYMBOL_GPL(elv_unregister); | |||
774 | static int elevator_switch(request_queue_t *q, struct elevator_type *new_e) | 787 | static int elevator_switch(request_queue_t *q, struct elevator_type *new_e) |
775 | { | 788 | { |
776 | elevator_t *old_elevator, *e; | 789 | elevator_t *old_elevator, *e; |
790 | void *data; | ||
777 | 791 | ||
778 | /* | 792 | /* |
779 | * Allocate new elevator | 793 | * Allocate new elevator |
@@ -782,6 +796,12 @@ static int elevator_switch(request_queue_t *q, struct elevator_type *new_e) | |||
782 | if (!e) | 796 | if (!e) |
783 | return 0; | 797 | return 0; |
784 | 798 | ||
799 | data = elevator_init_queue(q, e); | ||
800 | if (!data) { | ||
801 | kobject_put(&e->kobj); | ||
802 | return 0; | ||
803 | } | ||
804 | |||
785 | /* | 805 | /* |
786 | * Turn on BYPASS and drain all requests w/ elevator private data | 806 | * Turn on BYPASS and drain all requests w/ elevator private data |
787 | */ | 807 | */ |
@@ -800,19 +820,19 @@ static int elevator_switch(request_queue_t *q, struct elevator_type *new_e) | |||
800 | elv_drain_elevator(q); | 820 | elv_drain_elevator(q); |
801 | } | 821 | } |
802 | 822 | ||
803 | spin_unlock_irq(q->queue_lock); | ||
804 | |||
805 | /* | 823 | /* |
806 | * unregister old elevator data | 824 | * Remember old elevator. |
807 | */ | 825 | */ |
808 | elv_unregister_queue(q); | ||
809 | old_elevator = q->elevator; | 826 | old_elevator = q->elevator; |
810 | 827 | ||
811 | /* | 828 | /* |
812 | * attach and start new elevator | 829 | * attach and start new elevator |
813 | */ | 830 | */ |
814 | if (elevator_attach(q, e)) | 831 | elevator_attach(q, e, data); |
815 | goto fail; | 832 | |
833 | spin_unlock_irq(q->queue_lock); | ||
834 | |||
835 | __elv_unregister_queue(old_elevator); | ||
816 | 836 | ||
817 | if (elv_register_queue(q)) | 837 | if (elv_register_queue(q)) |
818 | goto fail_register; | 838 | goto fail_register; |
@@ -831,7 +851,6 @@ fail_register: | |||
831 | */ | 851 | */ |
832 | elevator_exit(e); | 852 | elevator_exit(e); |
833 | e = NULL; | 853 | e = NULL; |
834 | fail: | ||
835 | q->elevator = old_elevator; | 854 | q->elevator = old_elevator; |
836 | elv_register_queue(q); | 855 | elv_register_queue(q); |
837 | clear_bit(QUEUE_FLAG_ELVSWITCH, &q->queue_flags); | 856 | clear_bit(QUEUE_FLAG_ELVSWITCH, &q->queue_flags); |
diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index 1755c053fd68..7eb36c53f4b7 100644 --- a/block/ll_rw_blk.c +++ b/block/ll_rw_blk.c | |||
@@ -1732,8 +1732,21 @@ void blk_run_queue(struct request_queue *q) | |||
1732 | 1732 | ||
1733 | spin_lock_irqsave(q->queue_lock, flags); | 1733 | spin_lock_irqsave(q->queue_lock, flags); |
1734 | blk_remove_plug(q); | 1734 | blk_remove_plug(q); |
1735 | if (!elv_queue_empty(q)) | 1735 | |
1736 | q->request_fn(q); | 1736 | /* |
1737 | * Only recurse once to avoid overrunning the stack, let the unplug | ||
1738 | * handling reinvoke the handler shortly if we already got there. | ||
1739 | */ | ||
1740 | if (!elv_queue_empty(q)) { | ||
1741 | if (!test_and_set_bit(QUEUE_FLAG_REENTER, &q->queue_flags)) { | ||
1742 | q->request_fn(q); | ||
1743 | clear_bit(QUEUE_FLAG_REENTER, &q->queue_flags); | ||
1744 | } else { | ||
1745 | blk_plug_device(q); | ||
1746 | kblockd_schedule_work(&q->unplug_work); | ||
1747 | } | ||
1748 | } | ||
1749 | |||
1737 | spin_unlock_irqrestore(q->queue_lock, flags); | 1750 | spin_unlock_irqrestore(q->queue_lock, flags); |
1738 | } | 1751 | } |
1739 | EXPORT_SYMBOL(blk_run_queue); | 1752 | EXPORT_SYMBOL(blk_run_queue); |
@@ -3385,7 +3398,7 @@ static int blk_cpu_notify(struct notifier_block *self, unsigned long action, | |||
3385 | } | 3398 | } |
3386 | 3399 | ||
3387 | 3400 | ||
3388 | static struct notifier_block __devinitdata blk_cpu_notifier = { | 3401 | static struct notifier_block blk_cpu_notifier = { |
3389 | .notifier_call = blk_cpu_notify, | 3402 | .notifier_call = blk_cpu_notify, |
3390 | }; | 3403 | }; |
3391 | 3404 | ||
@@ -3439,7 +3452,12 @@ void end_that_request_last(struct request *req, int uptodate) | |||
3439 | if (unlikely(laptop_mode) && blk_fs_request(req)) | 3452 | if (unlikely(laptop_mode) && blk_fs_request(req)) |
3440 | laptop_io_completion(); | 3453 | laptop_io_completion(); |
3441 | 3454 | ||
3442 | if (disk && blk_fs_request(req)) { | 3455 | /* |
3456 | * Account IO completion. bar_rq isn't accounted as a normal | ||
3457 | * IO on queueing nor completion. Accounting the containing | ||
3458 | * request is enough. | ||
3459 | */ | ||
3460 | if (disk && blk_fs_request(req) && req != &req->q->bar_rq) { | ||
3443 | unsigned long duration = jiffies - req->start_time; | 3461 | unsigned long duration = jiffies - req->start_time; |
3444 | const int rw = rq_data_dir(req); | 3462 | const int rw = rq_data_dir(req); |
3445 | 3463 | ||
diff --git a/block/noop-iosched.c b/block/noop-iosched.c index f370e4a7fe6d..56a7c620574f 100644 --- a/block/noop-iosched.c +++ b/block/noop-iosched.c | |||
@@ -65,16 +65,15 @@ noop_latter_request(request_queue_t *q, struct request *rq) | |||
65 | return list_entry(rq->queuelist.next, struct request, queuelist); | 65 | return list_entry(rq->queuelist.next, struct request, queuelist); |
66 | } | 66 | } |
67 | 67 | ||
68 | static int noop_init_queue(request_queue_t *q, elevator_t *e) | 68 | static void *noop_init_queue(request_queue_t *q, elevator_t *e) |
69 | { | 69 | { |
70 | struct noop_data *nd; | 70 | struct noop_data *nd; |
71 | 71 | ||
72 | nd = kmalloc(sizeof(*nd), GFP_KERNEL); | 72 | nd = kmalloc(sizeof(*nd), GFP_KERNEL); |
73 | if (!nd) | 73 | if (!nd) |
74 | return -ENOMEM; | 74 | return NULL; |
75 | INIT_LIST_HEAD(&nd->queue); | 75 | INIT_LIST_HEAD(&nd->queue); |
76 | e->elevator_data = nd; | 76 | return nd; |
77 | return 0; | ||
78 | } | 77 | } |
79 | 78 | ||
80 | static void noop_exit_queue(elevator_t *e) | 79 | static void noop_exit_queue(elevator_t *e) |