Commit 6e941592 authored by Jens Axboe's avatar Jens Axboe

[PATCH] incorrect block layer segment accounting

There's a long standing bug in blk_recount_segments(). Clustering means
physical segment colascing, not hardware segment colascing. This
basically means that we are mapping more segments than here than the bio
+ requests contains, and this causes a bug in the SCSI layer for host
adapters that have CLUSTERING enabled.

This patch makes sure that we are clustering physical segments
correctly, and correctly accounting hardware segments. Please apply.
parent b11523f3
...@@ -673,31 +673,22 @@ void blk_recount_segments(request_queue_t *q, struct bio *bio) ...@@ -673,31 +673,22 @@ void blk_recount_segments(request_queue_t *q, struct bio *bio)
seg_size = nr_phys_segs = nr_hw_segs = 0; seg_size = nr_phys_segs = nr_hw_segs = 0;
bio_for_each_segment(bv, bio, i) { bio_for_each_segment(bv, bio, i) {
if (bvprv && cluster) { if (bvprv && cluster) {
int phys, seg; if (seg_size + bv->bv_len > q->max_segment_size)
if (seg_size + bv->bv_len > q->max_segment_size) {
nr_phys_segs++;
goto new_segment; goto new_segment;
} if (!BIOVEC_PHYS_MERGEABLE(bvprv, bv))
phys = BIOVEC_PHYS_MERGEABLE(bvprv, bv);
seg = BIOVEC_SEG_BOUNDARY(q, bvprv, bv);
if (!phys || !seg)
nr_phys_segs++;
if (!seg)
goto new_segment; goto new_segment;
if (!BIOVEC_SEG_BOUNDARY(q, bvprv, bv))
if (!BIOVEC_VIRT_MERGEABLE(bvprv, bv))
goto new_segment; goto new_segment;
seg_size += bv->bv_len; seg_size += bv->bv_len;
bvprv = bv; bvprv = bv;
continue; continue;
} else {
nr_phys_segs++;
} }
new_segment: new_segment:
if (!bvprv || !BIOVEC_VIRT_MERGEABLE(bvprv, bv))
nr_hw_segs++; nr_hw_segs++;
nr_phys_segs++;
bvprv = bv; bvprv = bv;
seg_size = bv->bv_len; seg_size = bv->bv_len;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment