aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--block/blk-core.c86
-rw-r--r--block/blk-settings.c16
-rw-r--r--block/blk-sysfs.c3
-rw-r--r--include/linux/blkdev.h9
-rw-r--r--include/trace/events/block.h25
-rw-r--r--kernel/trace/blktrace.c23
6 files changed, 78 insertions, 84 deletions
diff --git a/block/blk-core.c b/block/blk-core.c
index 90f22cc30799..3c8121072507 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -198,19 +198,6 @@ void blk_dump_rq_flags(struct request *rq, char *msg)
198} 198}
199EXPORT_SYMBOL(blk_dump_rq_flags); 199EXPORT_SYMBOL(blk_dump_rq_flags);
200 200
201/*
202 * Make sure that plugs that were pending when this function was entered,
203 * are now complete and requests pushed to the queue.
204*/
205static inline void queue_sync_plugs(struct request_queue *q)
206{
207 /*
208 * If the current process is plugged and has barriers submitted,
209 * we will livelock if we don't unplug first.
210 */
211 blk_flush_plug(current);
212}
213
214static void blk_delay_work(struct work_struct *work) 201static void blk_delay_work(struct work_struct *work)
215{ 202{
216 struct request_queue *q; 203 struct request_queue *q;
@@ -298,7 +285,6 @@ void blk_sync_queue(struct request_queue *q)
298{ 285{
299 del_timer_sync(&q->timeout); 286 del_timer_sync(&q->timeout);
300 cancel_delayed_work_sync(&q->delay_work); 287 cancel_delayed_work_sync(&q->delay_work);
301 queue_sync_plugs(q);
302} 288}
303EXPORT_SYMBOL(blk_sync_queue); 289EXPORT_SYMBOL(blk_sync_queue);
304 290
@@ -1311,7 +1297,15 @@ get_rq:
1311 1297
1312 plug = current->plug; 1298 plug = current->plug;
1313 if (plug) { 1299 if (plug) {
1314 if (!plug->should_sort && !list_empty(&plug->list)) { 1300 /*
1301 * If this is the first request added after a plug, fire
1302 * of a plug trace. If others have been added before, check
1303 * if we have multiple devices in this plug. If so, make a
1304 * note to sort the list before dispatch.
1305 */
1306 if (list_empty(&plug->list))
1307 trace_block_plug(q);
1308 else if (!plug->should_sort) {
1315 struct request *__rq; 1309 struct request *__rq;
1316 1310
1317 __rq = list_entry_rq(plug->list.prev); 1311 __rq = list_entry_rq(plug->list.prev);
@@ -2668,33 +2662,56 @@ static int plug_rq_cmp(void *priv, struct list_head *a, struct list_head *b)
2668 return !(rqa->q <= rqb->q); 2662 return !(rqa->q <= rqb->q);
2669} 2663}
2670 2664
2671static void flush_plug_list(struct blk_plug *plug) 2665static void queue_unplugged(struct request_queue *q, unsigned int depth,
2666 bool force_kblockd)
2667{
2668 trace_block_unplug_io(q, depth);
2669 __blk_run_queue(q, force_kblockd);
2670
2671 if (q->unplugged_fn)
2672 q->unplugged_fn(q);
2673}
2674
2675void blk_flush_plug_list(struct blk_plug *plug, bool force_kblockd)
2672{ 2676{
2673 struct request_queue *q; 2677 struct request_queue *q;
2674 unsigned long flags; 2678 unsigned long flags;
2675 struct request *rq; 2679 struct request *rq;
2680 LIST_HEAD(list);
2681 unsigned int depth;
2676 2682
2677 BUG_ON(plug->magic != PLUG_MAGIC); 2683 BUG_ON(plug->magic != PLUG_MAGIC);
2678 2684
2679 if (list_empty(&plug->list)) 2685 if (list_empty(&plug->list))
2680 return; 2686 return;
2681 2687
2682 if (plug->should_sort) 2688 list_splice_init(&plug->list, &list);
2683 list_sort(NULL, &plug->list, plug_rq_cmp); 2689
2690 if (plug->should_sort) {
2691 list_sort(NULL, &list, plug_rq_cmp);
2692 plug->should_sort = 0;
2693 }
2684 2694
2685 q = NULL; 2695 q = NULL;
2696 depth = 0;
2697
2698 /*
2699 * Save and disable interrupts here, to avoid doing it for every
2700 * queue lock we have to take.
2701 */
2686 local_irq_save(flags); 2702 local_irq_save(flags);
2687 while (!list_empty(&plug->list)) { 2703 while (!list_empty(&list)) {
2688 rq = list_entry_rq(plug->list.next); 2704 rq = list_entry_rq(list.next);
2689 list_del_init(&rq->queuelist); 2705 list_del_init(&rq->queuelist);
2690 BUG_ON(!(rq->cmd_flags & REQ_ON_PLUG)); 2706 BUG_ON(!(rq->cmd_flags & REQ_ON_PLUG));
2691 BUG_ON(!rq->q); 2707 BUG_ON(!rq->q);
2692 if (rq->q != q) { 2708 if (rq->q != q) {
2693 if (q) { 2709 if (q) {
2694 __blk_run_queue(q, false); 2710 queue_unplugged(q, depth, force_kblockd);
2695 spin_unlock(q->queue_lock); 2711 spin_unlock(q->queue_lock);
2696 } 2712 }
2697 q = rq->q; 2713 q = rq->q;
2714 depth = 0;
2698 spin_lock(q->queue_lock); 2715 spin_lock(q->queue_lock);
2699 } 2716 }
2700 rq->cmd_flags &= ~REQ_ON_PLUG; 2717 rq->cmd_flags &= ~REQ_ON_PLUG;
@@ -2706,38 +2723,27 @@ static void flush_plug_list(struct blk_plug *plug)
2706 __elv_add_request(q, rq, ELEVATOR_INSERT_FLUSH); 2723 __elv_add_request(q, rq, ELEVATOR_INSERT_FLUSH);
2707 else 2724 else
2708 __elv_add_request(q, rq, ELEVATOR_INSERT_SORT_MERGE); 2725 __elv_add_request(q, rq, ELEVATOR_INSERT_SORT_MERGE);
2726
2727 depth++;
2709 } 2728 }
2710 2729
2711 if (q) { 2730 if (q) {
2712 __blk_run_queue(q, false); 2731 queue_unplugged(q, depth, force_kblockd);
2713 spin_unlock(q->queue_lock); 2732 spin_unlock(q->queue_lock);
2714 } 2733 }
2715 2734
2716 BUG_ON(!list_empty(&plug->list));
2717 local_irq_restore(flags); 2735 local_irq_restore(flags);
2718} 2736}
2719 2737EXPORT_SYMBOL(blk_flush_plug_list);
2720static void __blk_finish_plug(struct task_struct *tsk, struct blk_plug *plug)
2721{
2722 flush_plug_list(plug);
2723
2724 if (plug == tsk->plug)
2725 tsk->plug = NULL;
2726}
2727 2738
2728void blk_finish_plug(struct blk_plug *plug) 2739void blk_finish_plug(struct blk_plug *plug)
2729{ 2740{
2730 if (plug) 2741 blk_flush_plug_list(plug, false);
2731 __blk_finish_plug(current, plug);
2732}
2733EXPORT_SYMBOL(blk_finish_plug);
2734 2742
2735void __blk_flush_plug(struct task_struct *tsk, struct blk_plug *plug) 2743 if (plug == current->plug)
2736{ 2744 current->plug = NULL;
2737 __blk_finish_plug(tsk, plug);
2738 tsk->plug = plug;
2739} 2745}
2740EXPORT_SYMBOL(__blk_flush_plug); 2746EXPORT_SYMBOL(blk_finish_plug);
2741 2747
2742int __init blk_dev_init(void) 2748int __init blk_dev_init(void)
2743{ 2749{
diff --git a/block/blk-settings.c b/block/blk-settings.c
index 1fa769293597..eb949045bb12 100644
--- a/block/blk-settings.c
+++ b/block/blk-settings.c
@@ -790,6 +790,22 @@ void blk_queue_flush(struct request_queue *q, unsigned int flush)
790} 790}
791EXPORT_SYMBOL_GPL(blk_queue_flush); 791EXPORT_SYMBOL_GPL(blk_queue_flush);
792 792
793/**
794 * blk_queue_unplugged - register a callback for an unplug event
795 * @q: the request queue for the device
796 * @fn: the function to call
797 *
798 * Some stacked drivers may need to know when IO is dispatched on an
799 * unplug event. By registrering a callback here, they will be notified
800 * when someone flushes their on-stack queue plug. The function will be
801 * called with the queue lock held.
802 */
803void blk_queue_unplugged(struct request_queue *q, unplugged_fn *fn)
804{
805 q->unplugged_fn = fn;
806}
807EXPORT_SYMBOL(blk_queue_unplugged);
808
793static int __init blk_settings_init(void) 809static int __init blk_settings_init(void)
794{ 810{
795 blk_max_low_pfn = max_low_pfn - 1; 811 blk_max_low_pfn = max_low_pfn - 1;
diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c
index 261c75c665ae..6d735122bc59 100644
--- a/block/blk-sysfs.c
+++ b/block/blk-sysfs.c
@@ -498,7 +498,6 @@ int blk_register_queue(struct gendisk *disk)
498{ 498{
499 int ret; 499 int ret;
500 struct device *dev = disk_to_dev(disk); 500 struct device *dev = disk_to_dev(disk);
501
502 struct request_queue *q = disk->queue; 501 struct request_queue *q = disk->queue;
503 502
504 if (WARN_ON(!q)) 503 if (WARN_ON(!q))
@@ -521,7 +520,7 @@ int blk_register_queue(struct gendisk *disk)
521 if (ret) { 520 if (ret) {
522 kobject_uevent(&q->kobj, KOBJ_REMOVE); 521 kobject_uevent(&q->kobj, KOBJ_REMOVE);
523 kobject_del(&q->kobj); 522 kobject_del(&q->kobj);
524 blk_trace_remove_sysfs(disk_to_dev(disk)); 523 blk_trace_remove_sysfs(dev);
525 kobject_put(&dev->kobj); 524 kobject_put(&dev->kobj);
526 return ret; 525 return ret;
527 } 526 }
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 32176cc8e715..1c76506fcf11 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -196,6 +196,7 @@ typedef void (request_fn_proc) (struct request_queue *q);
196typedef int (make_request_fn) (struct request_queue *q, struct bio *bio); 196typedef int (make_request_fn) (struct request_queue *q, struct bio *bio);
197typedef int (prep_rq_fn) (struct request_queue *, struct request *); 197typedef int (prep_rq_fn) (struct request_queue *, struct request *);
198typedef void (unprep_rq_fn) (struct request_queue *, struct request *); 198typedef void (unprep_rq_fn) (struct request_queue *, struct request *);
199typedef void (unplugged_fn) (struct request_queue *);
199 200
200struct bio_vec; 201struct bio_vec;
201struct bvec_merge_data { 202struct bvec_merge_data {
@@ -283,6 +284,7 @@ struct request_queue
283 rq_timed_out_fn *rq_timed_out_fn; 284 rq_timed_out_fn *rq_timed_out_fn;
284 dma_drain_needed_fn *dma_drain_needed; 285 dma_drain_needed_fn *dma_drain_needed;
285 lld_busy_fn *lld_busy_fn; 286 lld_busy_fn *lld_busy_fn;
287 unplugged_fn *unplugged_fn;
286 288
287 /* 289 /*
288 * Dispatch queue sorting 290 * Dispatch queue sorting
@@ -841,6 +843,7 @@ extern void blk_queue_dma_alignment(struct request_queue *, int);
841extern void blk_queue_update_dma_alignment(struct request_queue *, int); 843extern void blk_queue_update_dma_alignment(struct request_queue *, int);
842extern void blk_queue_softirq_done(struct request_queue *, softirq_done_fn *); 844extern void blk_queue_softirq_done(struct request_queue *, softirq_done_fn *);
843extern void blk_queue_rq_timed_out(struct request_queue *, rq_timed_out_fn *); 845extern void blk_queue_rq_timed_out(struct request_queue *, rq_timed_out_fn *);
846extern void blk_queue_unplugged(struct request_queue *, unplugged_fn *);
844extern void blk_queue_rq_timeout(struct request_queue *, unsigned int); 847extern void blk_queue_rq_timeout(struct request_queue *, unsigned int);
845extern void blk_queue_flush(struct request_queue *q, unsigned int flush); 848extern void blk_queue_flush(struct request_queue *q, unsigned int flush);
846extern struct backing_dev_info *blk_get_backing_dev_info(struct block_device *bdev); 849extern struct backing_dev_info *blk_get_backing_dev_info(struct block_device *bdev);
@@ -862,14 +865,14 @@ struct blk_plug {
862 865
863extern void blk_start_plug(struct blk_plug *); 866extern void blk_start_plug(struct blk_plug *);
864extern void blk_finish_plug(struct blk_plug *); 867extern void blk_finish_plug(struct blk_plug *);
865extern void __blk_flush_plug(struct task_struct *, struct blk_plug *); 868extern void blk_flush_plug_list(struct blk_plug *, bool);
866 869
867static inline void blk_flush_plug(struct task_struct *tsk) 870static inline void blk_flush_plug(struct task_struct *tsk)
868{ 871{
869 struct blk_plug *plug = tsk->plug; 872 struct blk_plug *plug = tsk->plug;
870 873
871 if (unlikely(plug)) 874 if (plug)
872 __blk_flush_plug(tsk, plug); 875 blk_flush_plug_list(plug, true);
873} 876}
874 877
875static inline bool blk_needs_flush_plug(struct task_struct *tsk) 878static inline bool blk_needs_flush_plug(struct task_struct *tsk)
diff --git a/include/trace/events/block.h b/include/trace/events/block.h
index 78f18adb49c8..006e60b58306 100644
--- a/include/trace/events/block.h
+++ b/include/trace/events/block.h
@@ -401,9 +401,9 @@ TRACE_EVENT(block_plug,
401 401
402DECLARE_EVENT_CLASS(block_unplug, 402DECLARE_EVENT_CLASS(block_unplug,
403 403
404 TP_PROTO(struct request_queue *q), 404 TP_PROTO(struct request_queue *q, unsigned int depth),
405 405
406 TP_ARGS(q), 406 TP_ARGS(q, depth),
407 407
408 TP_STRUCT__entry( 408 TP_STRUCT__entry(
409 __field( int, nr_rq ) 409 __field( int, nr_rq )
@@ -411,7 +411,7 @@ DECLARE_EVENT_CLASS(block_unplug,
411 ), 411 ),
412 412
413 TP_fast_assign( 413 TP_fast_assign(
414 __entry->nr_rq = q->rq.count[READ] + q->rq.count[WRITE]; 414 __entry->nr_rq = depth;
415 memcpy(__entry->comm, current->comm, TASK_COMM_LEN); 415 memcpy(__entry->comm, current->comm, TASK_COMM_LEN);
416 ), 416 ),
417 417
@@ -419,31 +419,18 @@ DECLARE_EVENT_CLASS(block_unplug,
419); 419);
420 420
421/** 421/**
422 * block_unplug_timer - timed release of operations requests in queue to device driver
423 * @q: request queue to unplug
424 *
425 * Unplug the request queue @q because a timer expired and allow block
426 * operation requests to be sent to the device driver.
427 */
428DEFINE_EVENT(block_unplug, block_unplug_timer,
429
430 TP_PROTO(struct request_queue *q),
431
432 TP_ARGS(q)
433);
434
435/**
436 * block_unplug_io - release of operations requests in request queue 422 * block_unplug_io - release of operations requests in request queue
437 * @q: request queue to unplug 423 * @q: request queue to unplug
424 * @depth: number of requests just added to the queue
438 * 425 *
439 * Unplug request queue @q because device driver is scheduled to work 426 * Unplug request queue @q because device driver is scheduled to work
440 * on elements in the request queue. 427 * on elements in the request queue.
441 */ 428 */
442DEFINE_EVENT(block_unplug, block_unplug_io, 429DEFINE_EVENT(block_unplug, block_unplug_io,
443 430
444 TP_PROTO(struct request_queue *q), 431 TP_PROTO(struct request_queue *q, unsigned int depth),
445 432
446 TP_ARGS(q) 433 TP_ARGS(q, depth)
447); 434);
448 435
449/** 436/**
diff --git a/kernel/trace/blktrace.c b/kernel/trace/blktrace.c
index 7aa40f8e182d..3e3970d53d14 100644
--- a/kernel/trace/blktrace.c
+++ b/kernel/trace/blktrace.c
@@ -850,32 +850,19 @@ static void blk_add_trace_plug(void *ignore, struct request_queue *q)
850 __blk_add_trace(bt, 0, 0, 0, BLK_TA_PLUG, 0, 0, NULL); 850 __blk_add_trace(bt, 0, 0, 0, BLK_TA_PLUG, 0, 0, NULL);
851} 851}
852 852
853static void blk_add_trace_unplug_io(void *ignore, struct request_queue *q) 853static void blk_add_trace_unplug_io(void *ignore, struct request_queue *q,
854 unsigned int depth)
854{ 855{
855 struct blk_trace *bt = q->blk_trace; 856 struct blk_trace *bt = q->blk_trace;
856 857
857 if (bt) { 858 if (bt) {
858 unsigned int pdu = q->rq.count[READ] + q->rq.count[WRITE]; 859 __be64 rpdu = cpu_to_be64(depth);
859 __be64 rpdu = cpu_to_be64(pdu);
860 860
861 __blk_add_trace(bt, 0, 0, 0, BLK_TA_UNPLUG_IO, 0, 861 __blk_add_trace(bt, 0, 0, 0, BLK_TA_UNPLUG_IO, 0,
862 sizeof(rpdu), &rpdu); 862 sizeof(rpdu), &rpdu);
863 } 863 }
864} 864}
865 865
866static void blk_add_trace_unplug_timer(void *ignore, struct request_queue *q)
867{
868 struct blk_trace *bt = q->blk_trace;
869
870 if (bt) {
871 unsigned int pdu = q->rq.count[READ] + q->rq.count[WRITE];
872 __be64 rpdu = cpu_to_be64(pdu);
873
874 __blk_add_trace(bt, 0, 0, 0, BLK_TA_UNPLUG_TIMER, 0,
875 sizeof(rpdu), &rpdu);
876 }
877}
878
879static void blk_add_trace_split(void *ignore, 866static void blk_add_trace_split(void *ignore,
880 struct request_queue *q, struct bio *bio, 867 struct request_queue *q, struct bio *bio,
881 unsigned int pdu) 868 unsigned int pdu)
@@ -1015,8 +1002,6 @@ static void blk_register_tracepoints(void)
1015 WARN_ON(ret); 1002 WARN_ON(ret);
1016 ret = register_trace_block_plug(blk_add_trace_plug, NULL); 1003 ret = register_trace_block_plug(blk_add_trace_plug, NULL);
1017 WARN_ON(ret); 1004 WARN_ON(ret);
1018 ret = register_trace_block_unplug_timer(blk_add_trace_unplug_timer, NULL);
1019 WARN_ON(ret);
1020 ret = register_trace_block_unplug_io(blk_add_trace_unplug_io, NULL); 1005 ret = register_trace_block_unplug_io(blk_add_trace_unplug_io, NULL);
1021 WARN_ON(ret); 1006 WARN_ON(ret);
1022 ret = register_trace_block_split(blk_add_trace_split, NULL); 1007 ret = register_trace_block_split(blk_add_trace_split, NULL);
@@ -1033,7 +1018,6 @@ static void blk_unregister_tracepoints(void)
1033 unregister_trace_block_bio_remap(blk_add_trace_bio_remap, NULL); 1018 unregister_trace_block_bio_remap(blk_add_trace_bio_remap, NULL);
1034 unregister_trace_block_split(blk_add_trace_split, NULL); 1019 unregister_trace_block_split(blk_add_trace_split, NULL);
1035 unregister_trace_block_unplug_io(blk_add_trace_unplug_io, NULL); 1020 unregister_trace_block_unplug_io(blk_add_trace_unplug_io, NULL);
1036 unregister_trace_block_unplug_timer(blk_add_trace_unplug_timer, NULL);
1037 unregister_trace_block_plug(blk_add_trace_plug, NULL); 1021 unregister_trace_block_plug(blk_add_trace_plug, NULL);
1038 unregister_trace_block_sleeprq(blk_add_trace_sleeprq, NULL); 1022 unregister_trace_block_sleeprq(blk_add_trace_sleeprq, NULL);
1039 unregister_trace_block_getrq(blk_add_trace_getrq, NULL); 1023 unregister_trace_block_getrq(blk_add_trace_getrq, NULL);
@@ -1348,7 +1332,6 @@ static const struct {
1348 [__BLK_TA_COMPLETE] = {{ "C", "complete" }, blk_log_with_error }, 1332 [__BLK_TA_COMPLETE] = {{ "C", "complete" }, blk_log_with_error },
1349 [__BLK_TA_PLUG] = {{ "P", "plug" }, blk_log_plug }, 1333 [__BLK_TA_PLUG] = {{ "P", "plug" }, blk_log_plug },
1350 [__BLK_TA_UNPLUG_IO] = {{ "U", "unplug_io" }, blk_log_unplug }, 1334 [__BLK_TA_UNPLUG_IO] = {{ "U", "unplug_io" }, blk_log_unplug },
1351 [__BLK_TA_UNPLUG_TIMER] = {{ "UT", "unplug_timer" }, blk_log_unplug },
1352 [__BLK_TA_INSERT] = {{ "I", "insert" }, blk_log_generic }, 1335 [__BLK_TA_INSERT] = {{ "I", "insert" }, blk_log_generic },
1353 [__BLK_TA_SPLIT] = {{ "X", "split" }, blk_log_split }, 1336 [__BLK_TA_SPLIT] = {{ "X", "split" }, blk_log_split },
1354 [__BLK_TA_BOUNCE] = {{ "B", "bounce" }, blk_log_generic }, 1337 [__BLK_TA_BOUNCE] = {{ "B", "bounce" }, blk_log_generic },