aboutsummaryrefslogtreecommitdiffstats
path: root/block
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2011-01-25 06:43:52 -0500
committerJens Axboe <jaxboe@fusionio.com>2011-01-25 06:43:52 -0500
commit143a87f4c9c629067afea5b6703d66ea88c82f8e (patch)
tree6abeae59e1d309d3c1a11eab97e22639c7fc5bd5 /block
parent414b4ff5eecff0097d09c4a7da12e435fd503692 (diff)
block: improve flush bio completion
bio's for flush are completed twice - once during the data phase and one more time after the whole sequence is complete. The first completion shouldn't notify completion to the issuer. This was achieved by skipping all bio completion steps in req_bio_endio() for the first completion; however, this has two drawbacks. * Error is not recorded in bio and must be tracked somewhere else. * Partial completion is not supported. Both don't cause problems for the current users; however, they make further improvements difficult. Change req_bio_endio() such that it only skips the actual notification part for the first completion. bio completion is implemented with partial completions on mind anyway so this is as simple as moving the REQ_FLUSH_SEQ conditional such that only calling of bio_endio() is skipped. Signed-off-by: Tejun Heo <tj@kernel.org> Signed-off-by: Jens Axboe <jaxboe@fusionio.com>
Diffstat (limited to 'block')
-rw-r--r--block/blk-core.c48
1 files changed, 21 insertions, 27 deletions
diff --git a/block/blk-core.c b/block/blk-core.c
index fc7d8ad76f44..617bb9e40927 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -136,37 +136,31 @@ static void req_bio_endio(struct request *rq, struct bio *bio,
136{ 136{
137 struct request_queue *q = rq->q; 137 struct request_queue *q = rq->q;
138 138
139 if (!(rq->cmd_flags & REQ_FLUSH_SEQ)) { 139 if (error)
140 if (error) 140 clear_bit(BIO_UPTODATE, &bio->bi_flags);
141 clear_bit(BIO_UPTODATE, &bio->bi_flags); 141 else if (!test_bit(BIO_UPTODATE, &bio->bi_flags))
142 else if (!test_bit(BIO_UPTODATE, &bio->bi_flags)) 142 error = -EIO;
143 error = -EIO; 143
144 144 if (unlikely(nbytes > bio->bi_size)) {
145 if (unlikely(nbytes > bio->bi_size)) { 145 printk(KERN_ERR "%s: want %u bytes done, %u left\n",
146 printk(KERN_ERR "%s: want %u bytes done, %u left\n", 146 __func__, nbytes, bio->bi_size);
147 __func__, nbytes, bio->bi_size); 147 nbytes = bio->bi_size;
148 nbytes = bio->bi_size; 148 }
149 }
150 149
151 if (unlikely(rq->cmd_flags & REQ_QUIET)) 150 if (unlikely(rq->cmd_flags & REQ_QUIET))
152 set_bit(BIO_QUIET, &bio->bi_flags); 151 set_bit(BIO_QUIET, &bio->bi_flags);
153 152
154 bio->bi_size -= nbytes; 153 bio->bi_size -= nbytes;
155 bio->bi_sector += (nbytes >> 9); 154 bio->bi_sector += (nbytes >> 9);
156 155
157 if (bio_integrity(bio)) 156 if (bio_integrity(bio))
158 bio_integrity_advance(bio, nbytes); 157 bio_integrity_advance(bio, nbytes);
159 158
160 if (bio->bi_size == 0) 159 /* don't actually finish bio if it's part of flush sequence */
161 bio_endio(bio, error); 160 if (bio->bi_size == 0 && !(rq->cmd_flags & REQ_FLUSH_SEQ))
162 } else { 161 bio_endio(bio, error);
163 /* 162 else if (error && !q->flush_err)
164 * Okay, this is the sequenced flush request in 163 q->flush_err = error;
165 * progress, just record the error;
166 */
167 if (error && !q->flush_err)
168 q->flush_err = error;
169 }
170} 164}
171 165
172void blk_dump_rq_flags(struct request *rq, char *msg) 166void blk_dump_rq_flags(struct request *rq, char *msg)