Skip to content

Commit df308a1

Browse files
Christoph Hellwigaxboe
authored andcommitted
block: fix aligning of bounced dio read bios
bio_iov_iter_align_down expects the "normal" biovec layout from vector 0, while bio_iov_iter_bounce_read abuses vector 0 for a bounce buffer allocation. Pass an explicit bvec to bio_iov_iter_align_down to deal with this case to avoid a double unpin. Additionally we need to free the folio if no bio_vec could be added, and adjust the size of the first bio_vec that contains the bounce buffer when the I/O size is aligned down. Fixes: e7b8b3c ("block: align down bounces bios") Reported-by: 0wnerD1ed <l7z@0b1t.tech> Signed-off-by: Christoph Hellwig <hch@lst.de> Tested-by: 0wnerD1ed <l7z@0b1t.tech> Reviewed-by: Keith Busch <kbusch@kernel.org> Link: https://patch.msgid.link/20260716091306.316625-3-hch@lst.de Signed-off-by: Jens Axboe <axboe@kernel.dk>
1 parent 4f221ef commit df308a1

1 file changed

Lines changed: 28 additions & 23 deletions

File tree

block/bio.c

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1199,7 +1199,7 @@ void bio_iov_bvec_set(struct bio *bio, const struct iov_iter *iter)
11991199
* for the next iteration.
12001200
*/
12011201
static int bio_iov_iter_align_down(struct bio *bio, struct iov_iter *iter,
1202-
unsigned len_align_mask)
1202+
struct bio_vec *bv, unsigned len_align_mask)
12031203
{
12041204
size_t nbytes = bio->bi_iter.bi_size & len_align_mask;
12051205

@@ -1208,23 +1208,16 @@ static int bio_iov_iter_align_down(struct bio *bio, struct iov_iter *iter,
12081208

12091209
iov_iter_revert(iter, nbytes);
12101210
bio->bi_iter.bi_size -= nbytes;
1211-
do {
1212-
struct bio_vec *bv = &bio->bi_io_vec[bio->bi_vcnt - 1];
1213-
1214-
if (nbytes < bv->bv_len) {
1215-
bv->bv_len -= nbytes;
1216-
break;
1217-
}
1218-
1211+
while (nbytes >= bv->bv_len) {
12191212
if (bio_flagged(bio, BIO_PAGE_PINNED))
12201213
unpin_user_page(bv->bv_page);
12211214

1222-
bio->bi_vcnt--;
1215+
if (!--bio->bi_vcnt)
1216+
return -EFAULT;
12231217
nbytes -= bv->bv_len;
1224-
} while (nbytes);
1225-
1226-
if (!bio->bi_vcnt)
1227-
return -EFAULT;
1218+
bv--;
1219+
}
1220+
bv->bv_len -= nbytes;
12281221
return 0;
12291222
}
12301223

@@ -1284,7 +1277,8 @@ int bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter,
12841277

12851278
if (is_pci_p2pdma_page(bio->bi_io_vec->bv_page))
12861279
bio->bi_opf |= REQ_NOMERGE;
1287-
return bio_iov_iter_align_down(bio, iter, len_align_mask);
1280+
return bio_iov_iter_align_down(bio, iter,
1281+
&bio->bi_io_vec[bio->bi_vcnt - 1], len_align_mask);
12881282
}
12891283

12901284
static struct folio *folio_alloc_greedy(gfp_t gfp, size_t *size,
@@ -1369,29 +1363,27 @@ static int bio_iov_iter_bounce_write(struct bio *bio, struct iov_iter *iter,
13691363

13701364
if (!bio->bi_iter.bi_size)
13711365
return -ENOMEM;
1372-
return bio_iov_iter_align_down(bio, iter, minsize - 1);
1366+
return bio_iov_iter_align_down(bio, iter,
1367+
&bio->bi_io_vec[bio->bi_vcnt - 1], minsize - 1);
13731368
}
13741369

13751370
static int bio_iov_iter_bounce_read(struct bio *bio, struct iov_iter *iter,
13761371
size_t maxlen, size_t minsize)
13771372
{
13781373
size_t len = min3(iov_iter_count(iter), maxlen, SZ_1M);
13791374
struct folio *folio;
1375+
ssize_t ret;
13801376

13811377
folio = folio_alloc_greedy(GFP_KERNEL, &len, minsize);
13821378
if (!folio)
13831379
return -ENOMEM;
13841380

13851381
do {
1386-
ssize_t ret;
1387-
13881382
ret = iov_iter_extract_bvecs(iter, bio->bi_io_vec + 1, len,
13891383
&bio->bi_vcnt, bio->bi_max_vecs - 1, 0);
13901384
if (ret <= 0) {
1391-
if (!bio->bi_vcnt) {
1392-
folio_put(folio);
1393-
return ret;
1394-
}
1385+
if (!bio->bi_vcnt)
1386+
goto out_folio_put;
13951387
break;
13961388
}
13971389
len -= ret;
@@ -1407,7 +1399,20 @@ static int bio_iov_iter_bounce_read(struct bio *bio, struct iov_iter *iter,
14071399
bvec_set_folio(&bio->bi_io_vec[0], folio, bio->bi_iter.bi_size, 0);
14081400
if (iov_iter_extract_will_pin(iter))
14091401
bio_set_flag(bio, BIO_PAGE_PINNED);
1410-
return bio_iov_iter_align_down(bio, iter, minsize - 1);
1402+
1403+
/* The first vec stores the bounce buffer, so do not subtract 1 here. */
1404+
ret = bio_iov_iter_align_down(bio, iter,
1405+
&bio->bi_io_vec[bio->bi_vcnt], minsize - 1);
1406+
if (ret)
1407+
goto out_folio_put;
1408+
1409+
/* Update the bounc buffer bv_len to the aligned down size. */
1410+
bio->bi_io_vec[0].bv_len = bio->bi_iter.bi_size;
1411+
return 0;
1412+
1413+
out_folio_put:
1414+
folio_put(folio);
1415+
return ret;
14111416
}
14121417

14131418
/**

0 commit comments

Comments
 (0)