aboutsummaryrefslogtreecommitdiffstats
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
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>
-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
-rw-r--r--include/linux/bio.h2
-rw-r--r--include/linux/blkdev.h5
-rw-r--r--include/linux/fs.h3
8 files changed, 42 insertions, 23 deletions
diff --git a/block/blk-barrier.c b/block/blk-barrier.c
index e5448131d4f1..988b63479b2f 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 1e143c4f9d34..1261516dd42a 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 5efc9e7a68b7..6cf8f0c70a51 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 ed6f8f32d27e..4f5127054e3f 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 342298bb6080..375c57922b00 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
diff --git a/include/linux/bio.h b/include/linux/bio.h
index 1fdfc5621c83..33c3947d61e9 100644
--- a/include/linux/bio.h
+++ b/include/linux/bio.h
@@ -188,8 +188,8 @@ struct bio {
188#define bio_failfast(bio) ((bio)->bi_rw & (1 << BIO_RW_FAILFAST)) 188#define bio_failfast(bio) ((bio)->bi_rw & (1 << BIO_RW_FAILFAST))
189#define bio_rw_ahead(bio) ((bio)->bi_rw & (1 << BIO_RW_AHEAD)) 189#define bio_rw_ahead(bio) ((bio)->bi_rw & (1 << BIO_RW_AHEAD))
190#define bio_rw_meta(bio) ((bio)->bi_rw & (1 << BIO_RW_META)) 190#define bio_rw_meta(bio) ((bio)->bi_rw & (1 << BIO_RW_META))
191#define bio_empty_barrier(bio) (bio_barrier(bio) && !bio_has_data(bio))
192#define bio_discard(bio) ((bio)->bi_rw & (1 << BIO_RW_DISCARD)) 191#define bio_discard(bio) ((bio)->bi_rw & (1 << BIO_RW_DISCARD))
192#define bio_empty_barrier(bio) (bio_barrier(bio) && !bio_has_data(bio) && !bio_discard(bio))
193 193
194static inline unsigned int bio_cur_sectors(struct bio *bio) 194static inline unsigned int bio_cur_sectors(struct bio *bio)
195{ 195{
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 727886d25c4e..e9eb35c9bf26 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -541,7 +541,7 @@ enum {
541#define blk_noretry_request(rq) ((rq)->cmd_flags & REQ_FAILFAST) 541#define blk_noretry_request(rq) ((rq)->cmd_flags & REQ_FAILFAST)
542#define blk_rq_started(rq) ((rq)->cmd_flags & REQ_STARTED) 542#define blk_rq_started(rq) ((rq)->cmd_flags & REQ_STARTED)
543 543
544#define blk_account_rq(rq) (blk_rq_started(rq) && blk_fs_request(rq)) 544#define blk_account_rq(rq) (blk_rq_started(rq) && (blk_fs_request(rq) || blk_discard_rq(rq)))
545 545
546#define blk_pm_suspend_request(rq) ((rq)->cmd_type == REQ_TYPE_PM_SUSPEND) 546#define blk_pm_suspend_request(rq) ((rq)->cmd_type == REQ_TYPE_PM_SUSPEND)
547#define blk_pm_resume_request(rq) ((rq)->cmd_type == REQ_TYPE_PM_RESUME) 547#define blk_pm_resume_request(rq) ((rq)->cmd_type == REQ_TYPE_PM_RESUME)
@@ -598,7 +598,8 @@ static inline void blk_clear_queue_full(struct request_queue *q, int rw)
598#define RQ_NOMERGE_FLAGS \ 598#define RQ_NOMERGE_FLAGS \
599 (REQ_NOMERGE | REQ_STARTED | REQ_HARDBARRIER | REQ_SOFTBARRIER) 599 (REQ_NOMERGE | REQ_STARTED | REQ_HARDBARRIER | REQ_SOFTBARRIER)
600#define rq_mergeable(rq) \ 600#define rq_mergeable(rq) \
601 (!((rq)->cmd_flags & RQ_NOMERGE_FLAGS) && blk_fs_request((rq))) 601 (!((rq)->cmd_flags & RQ_NOMERGE_FLAGS) && \
602 (blk_discard_rq(rq) || blk_fs_request((rq))))
602 603
603/* 604/*
604 * q->prep_rq_fn return values 605 * q->prep_rq_fn return values
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 88358ca6af25..860689f541b1 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -87,7 +87,8 @@ extern int dir_notify_enable;
87#define WRITE_SYNC (WRITE | (1 << BIO_RW_SYNC)) 87#define WRITE_SYNC (WRITE | (1 << BIO_RW_SYNC))
88#define SWRITE_SYNC (SWRITE | (1 << BIO_RW_SYNC)) 88#define SWRITE_SYNC (SWRITE | (1 << BIO_RW_SYNC))
89#define WRITE_BARRIER (WRITE | (1 << BIO_RW_BARRIER)) 89#define WRITE_BARRIER (WRITE | (1 << BIO_RW_BARRIER))
90#define WRITE_DISCARD (WRITE | (1 << BIO_RW_DISCARD)) 90#define DISCARD_NOBARRIER (1 << BIO_RW_DISCARD)
91#define DISCARD_BARRIER ((1 << BIO_RW_DISCARD) | (1 << BIO_RW_BARRIER))
91 92
92#define SEL_IN 1 93#define SEL_IN 1
93#define SEL_OUT 2 94#define SEL_OUT 2