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: e87d66ab27 ("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>
master
Caleb Sander Mateos 2025-12-08 20:14:23 -07:00 committed by Jens Axboe
parent cfdeb588ae
commit db339b4067
1 changed files with 6 additions and 6 deletions

View File

@ -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;