aboutsummaryrefslogtreecommitdiffstats
path: root/block
diff options
context:
space:
mode:
authorDavid Woodhouse <David.Woodhouse@intel.com>2008-08-09 11:42:20 -0400
committerJens Axboe <jens.axboe@oracle.com>2008-10-09 02:56:02 -0400
commite17fc0a1ccf88f6d4dcb363729f3141b0958c325 (patch)
tree0a7c2dc1c3159c2af14d87c67ca83e158b2c78b5 /block
parentd30a2605be9d5132d95944916e8f578fcfe4f976 (diff)
Allow elevators to sort/merge discard requests
But blkdev_issue_discard() still emits requests which are interpreted as soft barriers, because naïve callers might otherwise issue subsequent writes to those same sectors, which might cross on the queue (if they're reallocated quickly enough). Callers still _can_ issue non-barrier discard requests, but they have to take care of queue ordering for themselves. Signed-off-by: David Woodhouse <David.Woodhouse@intel.com> Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
Diffstat (limited to 'block')
-rw-r--r--block/blk-barrier.c2
-rw-r--r--block/blk-core.c12
-rw-r--r--block/blk-merge.c27
-rw-r--r--block/elevator.c12
-rw-r--r--block/ioctl.c2
5 files changed, 36 insertions, 19 deletions
diff --git a/block/blk-barrier.c b/block/blk-barrier.c
index e5448131d4f..988b63479b2 100644
--- a/block/blk-barrier.c
+++ b/block/blk-barrier.c
@@ -372,7 +372,7 @@ int blkdev_issue_discard(struct block_device *bdev, sector_t sector,
372 nr_sects = 0; 372 nr_sects = 0;
373 } 373 }
374 bio_get(bio); 374 bio_get(bio);
375 submit_bio(WRITE_DISCARD, bio); 375 submit_bio(DISCARD_BARRIER, bio);
376 376
377 /* Check if it failed immediately */ 377 /* Check if it failed immediately */
378 if (bio_flagged(bio, BIO_EOPNOTSUPP)) 378 if (bio_flagged(bio, BIO_EOPNOTSUPP))
diff --git a/block/blk-core.c b/block/blk-core.c
index 1e143c4f9d3..1261516dd42 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -1077,12 +1077,13 @@ void init_request_from_bio(struct request *req, struct bio *bio)
1077 /* 1077 /*
1078 * REQ_BARRIER implies no merging, but lets make it explicit 1078 * REQ_BARRIER implies no merging, but lets make it explicit
1079 */ 1079 */
1080 if (unlikely(bio_barrier(bio)))
1081 req->cmd_flags |= (REQ_HARDBARRIER | REQ_NOMERGE);
1082 if (unlikely(bio_discard(bio))) { 1080 if (unlikely(bio_discard(bio))) {
1083 req->cmd_flags |= (REQ_SOFTBARRIER | REQ_DISCARD); 1081 req->cmd_flags |= REQ_DISCARD;
1082 if (bio_barrier(bio))
1083 req->cmd_flags |= REQ_SOFTBARRIER;
1084 req->q->prepare_discard_fn(req->q, req); 1084 req->q->prepare_discard_fn(req->q, req);
1085 } 1085 } else if (unlikely(bio_barrier(bio)))
1086 req->cmd_flags |= (REQ_HARDBARRIER | REQ_NOMERGE);
1086 1087
1087 if (bio_sync(bio)) 1088 if (bio_sync(bio))
1088 req->cmd_flags |= REQ_RW_SYNC; 1089 req->cmd_flags |= REQ_RW_SYNC;
@@ -1114,7 +1115,8 @@ static int __make_request(struct request_queue *q, struct bio *bio)
1114 blk_queue_bounce(q, &bio); 1115 blk_queue_bounce(q, &bio);
1115 1116
1116 barrier = bio_barrier(bio); 1117 barrier = bio_barrier(bio);
1117 if (unlikely(barrier) && (q->next_ordered == QUEUE_ORDERED_NONE)) { 1118 if (unlikely(barrier) && bio_has_data(bio) &&
1119 (q->next_ordered == QUEUE_ORDERED_NONE)) {
1118 err = -EOPNOTSUPP; 1120 err = -EOPNOTSUPP;
1119 goto end_io; 1121 goto end_io;
1120 } 1122 }
diff --git a/block/blk-merge.c b/block/blk-merge.c
index 5efc9e7a68b..6cf8f0c70a5 100644
--- a/block/blk-merge.c
+++ b/block/blk-merge.c
@@ -11,7 +11,7 @@
11 11
12void blk_recalc_rq_sectors(struct request *rq, int nsect) 12void blk_recalc_rq_sectors(struct request *rq, int nsect)
13{ 13{
14 if (blk_fs_request(rq)) { 14 if (blk_fs_request(rq) || blk_discard_rq(rq)) {
15 rq->hard_sector += nsect; 15 rq->hard_sector += nsect;
16 rq->hard_nr_sectors -= nsect; 16 rq->hard_nr_sectors -= nsect;
17 17
@@ -131,13 +131,17 @@ static int blk_phys_contig_segment(struct request_queue *q, struct bio *bio,
131 if (!test_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags)) 131 if (!test_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags))
132 return 0; 132 return 0;
133 133
134 if (!BIOVEC_PHYS_MERGEABLE(__BVEC_END(bio), __BVEC_START(nxt)))
135 return 0;
136 if (bio->bi_size + nxt->bi_size > q->max_segment_size) 134 if (bio->bi_size + nxt->bi_size > q->max_segment_size)
137 return 0; 135 return 0;
138 136
137 if (!bio_has_data(bio))
138 return 1;
139
140 if (!BIOVEC_PHYS_MERGEABLE(__BVEC_END(bio), __BVEC_START(nxt)))
141 return 0;
142
139 /* 143 /*
140 * bio and nxt are contigous in memory, check if the queue allows 144 * bio and nxt are contiguous in memory; check if the queue allows
141 * these two to be merged into one 145 * these two to be merged into one
142 */ 146 */
143 if (BIO_SEG_BOUNDARY(q, bio, nxt)) 147 if (BIO_SEG_BOUNDARY(q, bio, nxt))
@@ -153,8 +157,9 @@ static int blk_hw_contig_segment(struct request_queue *q, struct bio *bio,
153 blk_recount_segments(q, bio); 157 blk_recount_segments(q, bio);
154 if (!bio_flagged(nxt, BIO_SEG_VALID)) 158 if (!bio_flagged(nxt, BIO_SEG_VALID))
155 blk_recount_segments(q, nxt); 159 blk_recount_segments(q, nxt);
156 if (!BIOVEC_VIRT_MERGEABLE(__BVEC_END(bio), __BVEC_START(nxt)) || 160 if (bio_has_data(bio) &&
157 BIOVEC_VIRT_OVERSIZE(bio->bi_hw_back_size + nxt->bi_hw_front_size)) 161 (!BIOVEC_VIRT_MERGEABLE(__BVEC_END(bio), __BVEC_START(nxt)) ||
162 BIOVEC_VIRT_OVERSIZE(bio->bi_hw_back_size + nxt->bi_hw_front_size)))
158 return 0; 163 return 0;
159 if (bio->bi_hw_back_size + nxt->bi_hw_front_size > q->max_segment_size) 164 if (bio->bi_hw_back_size + nxt->bi_hw_front_size > q->max_segment_size)
160 return 0; 165 return 0;
@@ -317,8 +322,9 @@ int ll_back_merge_fn(struct request_queue *q, struct request *req,
317 if (!bio_flagged(bio, BIO_SEG_VALID)) 322 if (!bio_flagged(bio, BIO_SEG_VALID))
318 blk_recount_segments(q, bio); 323 blk_recount_segments(q, bio);
319 len = req->biotail->bi_hw_back_size + bio->bi_hw_front_size; 324 len = req->biotail->bi_hw_back_size + bio->bi_hw_front_size;
320 if (BIOVEC_VIRT_MERGEABLE(__BVEC_END(req->biotail), __BVEC_START(bio)) 325 if (!bio_has_data(bio) ||
321 && !BIOVEC_VIRT_OVERSIZE(len)) { 326 (BIOVEC_VIRT_MERGEABLE(__BVEC_END(req->biotail), __BVEC_START(bio))
327 && !BIOVEC_VIRT_OVERSIZE(len))) {
322 int mergeable = ll_new_mergeable(q, req, bio); 328 int mergeable = ll_new_mergeable(q, req, bio);
323 329
324 if (mergeable) { 330 if (mergeable) {
@@ -356,8 +362,9 @@ int ll_front_merge_fn(struct request_queue *q, struct request *req,
356 blk_recount_segments(q, bio); 362 blk_recount_segments(q, bio);
357 if (!bio_flagged(req->bio, BIO_SEG_VALID)) 363 if (!bio_flagged(req->bio, BIO_SEG_VALID))
358 blk_recount_segments(q, req->bio); 364 blk_recount_segments(q, req->bio);
359 if (BIOVEC_VIRT_MERGEABLE(__BVEC_END(bio), __BVEC_START(req->bio)) && 365 if (!bio_has_data(bio) ||
360 !BIOVEC_VIRT_OVERSIZE(len)) { 366 (BIOVEC_VIRT_MERGEABLE(__BVEC_END(bio), __BVEC_START(req->bio)) &&
367 !BIOVEC_VIRT_OVERSIZE(len))) {
361 int mergeable = ll_new_mergeable(q, req, bio); 368 int mergeable = ll_new_mergeable(q, req, bio);
362 369
363 if (mergeable) { 370 if (mergeable) {
diff --git a/block/elevator.c b/block/elevator.c
index ed6f8f32d27..4f5127054e3 100644
--- a/block/elevator.c
+++ b/block/elevator.c
@@ -75,6 +75,12 @@ int elv_rq_merge_ok(struct request *rq, struct bio *bio)
75 return 0; 75 return 0;
76 76
77 /* 77 /*
78 * Don't merge file system requests and discard requests
79 */
80 if (bio_discard(bio) != bio_discard(rq->bio))
81 return 0;
82
83 /*
78 * different data direction or already started, don't merge 84 * different data direction or already started, don't merge
79 */ 85 */
80 if (bio_data_dir(bio) != rq_data_dir(rq)) 86 if (bio_data_dir(bio) != rq_data_dir(rq))
@@ -438,6 +444,8 @@ void elv_dispatch_sort(struct request_queue *q, struct request *rq)
438 list_for_each_prev(entry, &q->queue_head) { 444 list_for_each_prev(entry, &q->queue_head) {
439 struct request *pos = list_entry_rq(entry); 445 struct request *pos = list_entry_rq(entry);
440 446
447 if (blk_discard_rq(rq) != blk_discard_rq(pos))
448 break;
441 if (rq_data_dir(rq) != rq_data_dir(pos)) 449 if (rq_data_dir(rq) != rq_data_dir(pos))
442 break; 450 break;
443 if (pos->cmd_flags & stop_flags) 451 if (pos->cmd_flags & stop_flags)
@@ -607,7 +615,7 @@ void elv_insert(struct request_queue *q, struct request *rq, int where)
607 break; 615 break;
608 616
609 case ELEVATOR_INSERT_SORT: 617 case ELEVATOR_INSERT_SORT:
610 BUG_ON(!blk_fs_request(rq)); 618 BUG_ON(!blk_fs_request(rq) && !blk_discard_rq(rq));
611 rq->cmd_flags |= REQ_SORTED; 619 rq->cmd_flags |= REQ_SORTED;
612 q->nr_sorted++; 620 q->nr_sorted++;
613 if (rq_mergeable(rq)) { 621 if (rq_mergeable(rq)) {
@@ -692,7 +700,7 @@ void __elv_add_request(struct request_queue *q, struct request *rq, int where,
692 * this request is scheduling boundary, update 700 * this request is scheduling boundary, update
693 * end_sector 701 * end_sector
694 */ 702 */
695 if (blk_fs_request(rq)) { 703 if (blk_fs_request(rq) || blk_discard_rq(rq)) {
696 q->end_sector = rq_end_sector(rq); 704 q->end_sector = rq_end_sector(rq);
697 q->boundary_rq = rq; 705 q->boundary_rq = rq;
698 } 706 }
diff --git a/block/ioctl.c b/block/ioctl.c
index 342298bb608..375c57922b0 100644
--- a/block/ioctl.c
+++ b/block/ioctl.c
@@ -161,7 +161,7 @@ static int blk_ioctl_discard(struct block_device *bdev, uint64_t start,
161 bio->bi_size = len << 9; 161 bio->bi_size = len << 9;
162 len = 0; 162 len = 0;
163 } 163 }
164 submit_bio(WRITE_DISCARD, bio); 164 submit_bio(DISCARD_NOBARRIER, bio);
165 165
166 wait_for_completion(&wait); 166 wait_for_completion(&wait);
167 167