aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCaleb Sander Mateos <csander@purestorage.com>2025-12-08 20:14:23 -0700
committerJens Axboe <axboe@kernel.dk>2025-12-09 10:20:18 -0700
commitdb339b4067eccb7fa3d9787d5d3ab5d466fd9efa (patch)
treee22f25413fa7a98bf0c418e78e2d3aa53a9043ab
parentcfdeb588ae1dff5d52da37d2797d0203e8605480 (diff)
downloadlinux-db339b4067eccb7fa3d9787d5d3ab5d466fd9efa.tar.gz
ublk: don't mutate struct bio_vec in iteration
__bio_for_each_segment() uses the returned struct bio_vec's bv_len field to advance the struct bvec_iter at the end of each loop iteration. So it's incorrect to modify it during the loop. Don't assign to bv_len (or bv_offset, for that matter) in ublk_copy_user_pages(). Signed-off-by: Caleb Sander Mateos <csander@purestorage.com> Fixes: e87d66ab27ac ("ublk: use rq_for_each_segment() for user copy") Reviewed-by: Ming Lei <ming.lei@redhat.com> Signed-off-by: Jens Axboe <axboe@kernel.dk>
-rw-r--r--drivers/block/ublk_drv.c12
1 files changed, 6 insertions, 6 deletions
diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c
index 3ecaafacfd2038..df9831783a1339 100644
--- a/drivers/block/ublk_drv.c
+++ b/drivers/block/ublk_drv.c
@@ -926,6 +926,7 @@ static size_t ublk_copy_user_pages(const struct request *req,
size_t done = 0;
rq_for_each_segment(bv, req, iter) {
+ unsigned len;
void *bv_buf;
size_t copied;
@@ -934,18 +935,17 @@ static size_t ublk_copy_user_pages(const struct request *req,
continue;
}
- bv.bv_offset += offset;
- bv.bv_len -= offset;
- bv_buf = bvec_kmap_local(&bv);
+ len = bv.bv_len - offset;
+ bv_buf = kmap_local_page(bv.bv_page) + bv.bv_offset + offset;
if (dir == ITER_DEST)
- copied = copy_to_iter(bv_buf, bv.bv_len, uiter);
+ copied = copy_to_iter(bv_buf, len, uiter);
else
- copied = copy_from_iter(bv_buf, bv.bv_len, uiter);
+ copied = copy_from_iter(bv_buf, len, uiter);
kunmap_local(bv_buf);
done += copied;
- if (copied < bv.bv_len)
+ if (copied < len)
break;
offset = 0;