diff options
author | Jens Axboe <axboe@fb.com> | 2014-05-29 11:53:32 -0400 |
---|---|---|
committer | Jens Axboe <axboe@fb.com> | 2014-05-29 11:53:32 -0400 |
commit | 05f1dd5315217398fc8d122bdee80f96a9f21274 (patch) | |
tree | f1decfafa5f0d974d2f9c707a514bf68b9e2cddb /block | |
parent | 4d92a9beb39d80a7d8ff7c04ae12a10290105ae5 (diff) |
block: add queue flag for disabling SG merging
If devices are not SG starved, we waste a lot of time potentially
collapsing SG segments. Enough that 1.5% of the CPU time goes
to this, at only 400K IOPS. Add a queue flag, QUEUE_FLAG_NO_SG_MERGE,
which just returns the number of vectors in a bio instead of looping
over all segments and checking for collapsible ones.
Add a BLK_MQ_F_SG_MERGE flag so that drivers can opt-in on the sg
merging, if they so desire.
Signed-off-by: Jens Axboe <axboe@fb.com>
Diffstat (limited to 'block')
-rw-r--r-- | block/blk-merge.c | 28 | ||||
-rw-r--r-- | block/blk-mq.c | 3 |
2 files changed, 24 insertions, 7 deletions
diff --git a/block/blk-merge.c b/block/blk-merge.c index 6c583f9c5b65..b3bf0df0f4c2 100644 --- a/block/blk-merge.c +++ b/block/blk-merge.c | |||
@@ -13,7 +13,7 @@ static unsigned int __blk_recalc_rq_segments(struct request_queue *q, | |||
13 | struct bio *bio) | 13 | struct bio *bio) |
14 | { | 14 | { |
15 | struct bio_vec bv, bvprv = { NULL }; | 15 | struct bio_vec bv, bvprv = { NULL }; |
16 | int cluster, high, highprv = 1; | 16 | int cluster, high, highprv = 1, no_sg_merge; |
17 | unsigned int seg_size, nr_phys_segs; | 17 | unsigned int seg_size, nr_phys_segs; |
18 | struct bio *fbio, *bbio; | 18 | struct bio *fbio, *bbio; |
19 | struct bvec_iter iter; | 19 | struct bvec_iter iter; |
@@ -35,12 +35,21 @@ static unsigned int __blk_recalc_rq_segments(struct request_queue *q, | |||
35 | cluster = blk_queue_cluster(q); | 35 | cluster = blk_queue_cluster(q); |
36 | seg_size = 0; | 36 | seg_size = 0; |
37 | nr_phys_segs = 0; | 37 | nr_phys_segs = 0; |
38 | no_sg_merge = test_bit(QUEUE_FLAG_NO_SG_MERGE, &q->queue_flags); | ||
39 | high = 0; | ||
38 | for_each_bio(bio) { | 40 | for_each_bio(bio) { |
39 | bio_for_each_segment(bv, bio, iter) { | 41 | bio_for_each_segment(bv, bio, iter) { |
40 | /* | 42 | /* |
43 | * If SG merging is disabled, each bio vector is | ||
44 | * a segment | ||
45 | */ | ||
46 | if (no_sg_merge) | ||
47 | goto new_segment; | ||
48 | |||
49 | /* | ||
41 | * the trick here is making sure that a high page is | 50 | * the trick here is making sure that a high page is |
42 | * never considered part of another segment, since that | 51 | * never considered part of another segment, since |
43 | * might change with the bounce page. | 52 | * that might change with the bounce page. |
44 | */ | 53 | */ |
45 | high = page_to_pfn(bv.bv_page) > queue_bounce_pfn(q); | 54 | high = page_to_pfn(bv.bv_page) > queue_bounce_pfn(q); |
46 | if (!high && !highprv && cluster) { | 55 | if (!high && !highprv && cluster) { |
@@ -84,11 +93,16 @@ void blk_recalc_rq_segments(struct request *rq) | |||
84 | 93 | ||
85 | void blk_recount_segments(struct request_queue *q, struct bio *bio) | 94 | void blk_recount_segments(struct request_queue *q, struct bio *bio) |
86 | { | 95 | { |
87 | struct bio *nxt = bio->bi_next; | 96 | if (test_bit(QUEUE_FLAG_NO_SG_MERGE, &q->queue_flags)) |
97 | bio->bi_phys_segments = bio->bi_vcnt; | ||
98 | else { | ||
99 | struct bio *nxt = bio->bi_next; | ||
100 | |||
101 | bio->bi_next = NULL; | ||
102 | bio->bi_phys_segments = __blk_recalc_rq_segments(q, bio); | ||
103 | bio->bi_next = nxt; | ||
104 | } | ||
88 | 105 | ||
89 | bio->bi_next = NULL; | ||
90 | bio->bi_phys_segments = __blk_recalc_rq_segments(q, bio); | ||
91 | bio->bi_next = nxt; | ||
92 | bio->bi_flags |= (1 << BIO_SEG_VALID); | 106 | bio->bi_flags |= (1 << BIO_SEG_VALID); |
93 | } | 107 | } |
94 | EXPORT_SYMBOL(blk_recount_segments); | 108 | EXPORT_SYMBOL(blk_recount_segments); |
diff --git a/block/blk-mq.c b/block/blk-mq.c index f27fe44230c2..f98d977fd150 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c | |||
@@ -1829,6 +1829,9 @@ struct request_queue *blk_mq_init_queue(struct blk_mq_tag_set *set) | |||
1829 | q->mq_ops = set->ops; | 1829 | q->mq_ops = set->ops; |
1830 | q->queue_flags |= QUEUE_FLAG_MQ_DEFAULT; | 1830 | q->queue_flags |= QUEUE_FLAG_MQ_DEFAULT; |
1831 | 1831 | ||
1832 | if (!(set->flags & BLK_MQ_F_SG_MERGE)) | ||
1833 | q->queue_flags |= 1 << QUEUE_FLAG_NO_SG_MERGE; | ||
1834 | |||
1832 | q->sg_reserved_size = INT_MAX; | 1835 | q->sg_reserved_size = INT_MAX; |
1833 | 1836 | ||
1834 | INIT_WORK(&q->requeue_work, blk_mq_requeue_work); | 1837 | INIT_WORK(&q->requeue_work, blk_mq_requeue_work); |