diff options
author | Bart Van Assche <bvanassche@acm.org> | 2019-08-01 18:50:43 -0400 |
---|---|---|
committer | Jens Axboe <axboe@kernel.dk> | 2019-08-04 23:41:29 -0400 |
commit | 708b25b344fd9bedd02ccc0f8eee71f7006d7d07 (patch) | |
tree | 10e66635ab399a06a933807a59db788164a18fb4 /block | |
parent | ff9811b3cf2092fe6c39cf694e5e7f949f3b2c16 (diff) |
block: Simplify blk_bio_segment_split()
Move the max_sectors check into bvec_split_segs() such that a single
call to that function can do all the necessary checks. This patch
optimizes the fast path further, namely if a bvec fits in a page.
Cc: Christoph Hellwig <hch@lst.de>
Cc: Ming Lei <ming.lei@redhat.com>
Cc: Hannes Reinecke <hare@suse.com>
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Diffstat (limited to 'block')
-rw-r--r-- | block/blk-merge.c | 68 |
1 files changed, 33 insertions, 35 deletions
diff --git a/block/blk-merge.c b/block/blk-merge.c index 7cea5050bbcf..a6bc08255b1b 100644 --- a/block/blk-merge.c +++ b/block/blk-merge.c | |||
@@ -157,22 +157,36 @@ static unsigned get_max_segment_size(const struct request_queue *q, | |||
157 | queue_max_segment_size(q)); | 157 | queue_max_segment_size(q)); |
158 | } | 158 | } |
159 | 159 | ||
160 | /* | 160 | /** |
161 | * Split the bvec @bv into segments, and update all kinds of | 161 | * bvec_split_segs - verify whether or not a bvec should be split in the middle |
162 | * variables. | 162 | * @q: [in] request queue associated with the bio associated with @bv |
163 | * @bv: [in] bvec to examine | ||
164 | * @nsegs: [in,out] Number of segments in the bio being built. Incremented | ||
165 | * by the number of segments from @bv that may be appended to that | ||
166 | * bio without exceeding @max_segs | ||
167 | * @sectors: [in,out] Number of sectors in the bio being built. Incremented | ||
168 | * by the number of sectors from @bv that may be appended to that | ||
169 | * bio without exceeding @max_sectors | ||
170 | * @max_segs: [in] upper bound for *@nsegs | ||
171 | * @max_sectors: [in] upper bound for *@sectors | ||
172 | * | ||
173 | * When splitting a bio, it can happen that a bvec is encountered that is too | ||
174 | * big to fit in a single segment and hence that it has to be split in the | ||
175 | * middle. This function verifies whether or not that should happen. The value | ||
176 | * %true is returned if and only if appending the entire @bv to a bio with | ||
177 | * *@nsegs segments and *@sectors sectors would make that bio unacceptable for | ||
178 | * the block driver. | ||
163 | */ | 179 | */ |
164 | static bool bvec_split_segs(const struct request_queue *q, | 180 | static bool bvec_split_segs(const struct request_queue *q, |
165 | const struct bio_vec *bv, unsigned *nsegs, | 181 | const struct bio_vec *bv, unsigned *nsegs, |
166 | unsigned *sectors, unsigned max_segs) | 182 | unsigned *sectors, unsigned max_segs, |
183 | unsigned max_sectors) | ||
167 | { | 184 | { |
168 | unsigned len = bv->bv_len; | 185 | unsigned max_len = (min(max_sectors, UINT_MAX >> 9) - *sectors) << 9; |
186 | unsigned len = min(bv->bv_len, max_len); | ||
169 | unsigned total_len = 0; | 187 | unsigned total_len = 0; |
170 | unsigned seg_size = 0; | 188 | unsigned seg_size = 0; |
171 | 189 | ||
172 | /* | ||
173 | * Multi-page bvec may be too big to hold in one segment, so the | ||
174 | * current bvec has to be splitted as multiple segments. | ||
175 | */ | ||
176 | while (len && *nsegs < max_segs) { | 190 | while (len && *nsegs < max_segs) { |
177 | seg_size = get_max_segment_size(q, bv->bv_offset + total_len); | 191 | seg_size = get_max_segment_size(q, bv->bv_offset + total_len); |
178 | seg_size = min(seg_size, len); | 192 | seg_size = min(seg_size, len); |
@@ -187,8 +201,8 @@ static bool bvec_split_segs(const struct request_queue *q, | |||
187 | 201 | ||
188 | *sectors += total_len >> 9; | 202 | *sectors += total_len >> 9; |
189 | 203 | ||
190 | /* split in the middle of the bvec if len != 0 */ | 204 | /* tell the caller to split the bvec if it is too big to fit */ |
191 | return !!len; | 205 | return len > 0 || bv->bv_len > max_len; |
192 | } | 206 | } |
193 | 207 | ||
194 | /** | 208 | /** |
@@ -229,34 +243,18 @@ static struct bio *blk_bio_segment_split(struct request_queue *q, | |||
229 | if (bvprvp && bvec_gap_to_prev(q, bvprvp, bv.bv_offset)) | 243 | if (bvprvp && bvec_gap_to_prev(q, bvprvp, bv.bv_offset)) |
230 | goto split; | 244 | goto split; |
231 | 245 | ||
232 | if (sectors + (bv.bv_len >> 9) > max_sectors) { | 246 | if (nsegs < max_segs && |
233 | /* | 247 | sectors + (bv.bv_len >> 9) <= max_sectors && |
234 | * Consider this a new segment if we're splitting in | 248 | bv.bv_offset + bv.bv_len <= PAGE_SIZE) { |
235 | * the middle of this vector. | 249 | nsegs++; |
236 | */ | 250 | sectors += bv.bv_len >> 9; |
237 | if (nsegs < max_segs && | 251 | } else if (bvec_split_segs(q, &bv, &nsegs, §ors, max_segs, |
238 | sectors < max_sectors) { | 252 | max_sectors)) { |
239 | /* split in the middle of bvec */ | ||
240 | bv.bv_len = (max_sectors - sectors) << 9; | ||
241 | bvec_split_segs(q, &bv, &nsegs, | ||
242 | §ors, max_segs); | ||
243 | } | ||
244 | goto split; | 253 | goto split; |
245 | } | 254 | } |
246 | 255 | ||
247 | if (nsegs == max_segs) | ||
248 | goto split; | ||
249 | |||
250 | bvprv = bv; | 256 | bvprv = bv; |
251 | bvprvp = &bvprv; | 257 | bvprvp = &bvprv; |
252 | |||
253 | if (bv.bv_offset + bv.bv_len <= PAGE_SIZE) { | ||
254 | nsegs++; | ||
255 | sectors += bv.bv_len >> 9; | ||
256 | } else if (bvec_split_segs(q, &bv, &nsegs, §ors, | ||
257 | max_segs)) { | ||
258 | goto split; | ||
259 | } | ||
260 | } | 258 | } |
261 | 259 | ||
262 | *segs = nsegs; | 260 | *segs = nsegs; |
@@ -363,7 +361,7 @@ unsigned int blk_recalc_rq_segments(struct request *rq) | |||
363 | 361 | ||
364 | rq_for_each_bvec(bv, rq, iter) | 362 | rq_for_each_bvec(bv, rq, iter) |
365 | bvec_split_segs(rq->q, &bv, &nr_phys_segs, &nr_sectors, | 363 | bvec_split_segs(rq->q, &bv, &nr_phys_segs, &nr_sectors, |
366 | UINT_MAX); | 364 | UINT_MAX, UINT_MAX); |
367 | return nr_phys_segs; | 365 | return nr_phys_segs; |
368 | } | 366 | } |
369 | 367 | ||