abd_bio_map_off: avoid splitting scatter pages across bios
This is the same change as the previous commit, but for scatter abds. Its less clear if this change is needed. Since scatter abds are only ever added a page at time, both sides of the split should always be added in consecutive segments. Intuitively though, it may be possible for a partially-filled bio to be used, or a bio with an odd number of iovecs, and that then could lead to a misaligned bio. While I've not been able to reproduce this at all, it seems to make sense to protect against it. Signed-off-by: Rob Norris <rob.norris@klarasystems.com> (cherry picked from commit cbdf21fd1a32a5e696a22cad497d9211221fa309)
This commit is contained in:
parent
1bd475d6c6
commit
74e8091130
|
@ -1143,7 +1143,9 @@ abd_bio_map_off(struct bio *bio, abd_t *abd,
|
|||
abd_iter_init(&aiter, abd);
|
||||
abd_iter_advance(&aiter, off);
|
||||
|
||||
for (int i = 0; i < bio->bi_max_vecs; i++) {
|
||||
boolean_t is_split = B_FALSE;
|
||||
unsigned int split_rem = 0;
|
||||
for (int i = bio->bi_vcnt; i < bio->bi_max_vecs; i++) {
|
||||
struct page *pg;
|
||||
size_t len, sgoff, pgoff;
|
||||
struct scatterlist *sg;
|
||||
|
@ -1154,7 +1156,36 @@ abd_bio_map_off(struct bio *bio, abd_t *abd,
|
|||
sg = aiter.iter_sg;
|
||||
sgoff = aiter.iter_offset;
|
||||
pgoff = sgoff & (PAGESIZE - 1);
|
||||
len = MIN(io_size, PAGESIZE - pgoff);
|
||||
|
||||
if (is_split &&
|
||||
(io_size <= split_rem || ((i + 1) == bio->bi_max_vecs))) {
|
||||
/*
|
||||
* Last segment and we're split, so we have to add just
|
||||
* enough to restore alignment.
|
||||
*/
|
||||
len = split_rem;
|
||||
is_split = B_FALSE;
|
||||
}
|
||||
else if (pgoff != 0) {
|
||||
/*
|
||||
* This is a split page, so we need to ensure that we
|
||||
* have room for the tail within this bio.
|
||||
*/
|
||||
if ((i + 1) == bio->bi_max_vecs)
|
||||
break;
|
||||
|
||||
/* Take up to the end of the page */
|
||||
len = PAGE_SIZE - pgoff;
|
||||
|
||||
is_split = B_TRUE;
|
||||
split_rem = pgoff;
|
||||
}
|
||||
else
|
||||
len = PAGE_SIZE;
|
||||
|
||||
if (len > io_size)
|
||||
len = io_size;
|
||||
|
||||
ASSERT(len > 0);
|
||||
|
||||
pg = nth_page(sg_page(sg), sgoff >> PAGE_SHIFT);
|
||||
|
|
Loading…
Reference in New Issue