Skip to content

Commit 429120f

Browse files
Ming Leiaxboe
authored andcommitted
block: fix splitting segments on boundary masks
We ran into a problem with a mpt3sas based controller, where we would see random (and hard to reproduce) file corruption). The issue seemed specific to this controller, but wasn't specific to the file system. After a lot of debugging, we find out that it's caused by segments spanning a 4G memory boundary. This shouldn't happen, as the default setting for segment boundary masks is 4G. Turns out there are two issues in get_max_segment_size(): 1) The default segment boundary mask is bypassed 2) The segment start address isn't taken into account when checking segment boundary limit Fix these two issues by removing the bypass of the segment boundary check even if the mask is set to the default value, and taking into account the actual start address of the request when checking if a segment needs splitting. Cc: [email protected] # v5.1+ Reviewed-by: Chris Mason <[email protected]> Tested-by: Chris Mason <[email protected]> Fixes: dcebd75 ("block: use bio_for_each_bvec() to compute multi-page bvec count") Signed-off-by: Ming Lei <[email protected]> Dropped const on the page pointer, ppc page_to_phys() doesn't mark the page as const... Signed-off-by: Jens Axboe <[email protected]>
1 parent 85a8ce6 commit 429120f

File tree

1 file changed

+9
-9
lines changed

1 file changed

+9
-9
lines changed

block/blk-merge.c

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -157,16 +157,14 @@ static inline unsigned get_max_io_size(struct request_queue *q,
157157
return sectors & (lbs - 1);
158158
}
159159

160-
static unsigned get_max_segment_size(const struct request_queue *q,
161-
unsigned offset)
160+
static inline unsigned get_max_segment_size(const struct request_queue *q,
161+
struct page *start_page,
162+
unsigned long offset)
162163
{
163164
unsigned long mask = queue_segment_boundary(q);
164165

165-
/* default segment boundary mask means no boundary limit */
166-
if (mask == BLK_SEG_BOUNDARY_MASK)
167-
return queue_max_segment_size(q);
168-
169-
return min_t(unsigned long, mask - (mask & offset) + 1,
166+
offset = mask & (page_to_phys(start_page) + offset);
167+
return min_t(unsigned long, mask - offset + 1,
170168
queue_max_segment_size(q));
171169
}
172170

@@ -201,7 +199,8 @@ static bool bvec_split_segs(const struct request_queue *q,
201199
unsigned seg_size = 0;
202200

203201
while (len && *nsegs < max_segs) {
204-
seg_size = get_max_segment_size(q, bv->bv_offset + total_len);
202+
seg_size = get_max_segment_size(q, bv->bv_page,
203+
bv->bv_offset + total_len);
205204
seg_size = min(seg_size, len);
206205

207206
(*nsegs)++;
@@ -419,7 +418,8 @@ static unsigned blk_bvec_map_sg(struct request_queue *q,
419418

420419
while (nbytes > 0) {
421420
unsigned offset = bvec->bv_offset + total;
422-
unsigned len = min(get_max_segment_size(q, offset), nbytes);
421+
unsigned len = min(get_max_segment_size(q, bvec->bv_page,
422+
offset), nbytes);
423423
struct page *page = bvec->bv_page;
424424

425425
/*

0 commit comments

Comments
 (0)