Commit db339b40 authored by Caleb Sander Mateos's avatar Caleb Sander Mateos Committed by Jens Axboe
Browse files

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: default avatarCaleb Sander Mateos <csander@purestorage.com>
Fixes: e87d66ab ("ublk: use rq_for_each_segment() for user copy")
Reviewed-by: default avatarMing Lei <ming.lei@redhat.com>
Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent cfdeb588
Loading
Loading
Loading
Loading
+6 −6
Original line number Diff line number Diff line
@@ -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;