aboutsummaryrefslogtreecommitdiffstats
path: root/block/scsi_ioctl.c
diff options
context:
space:
mode:
Diffstat (limited to 'block/scsi_ioctl.c')
-rw-r--r--block/scsi_ioctl.c13
1 files changed, 12 insertions, 1 deletions
diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c
index 84b7f8709f41..82a0ca2f6729 100644
--- a/block/scsi_ioctl.c
+++ b/block/scsi_ioctl.c
@@ -290,6 +290,7 @@ static int sg_io(struct request_queue *q, struct gendisk *bd_disk,
290 290
291 if (hdr->iovec_count) { 291 if (hdr->iovec_count) {
292 const int size = sizeof(struct sg_iovec) * hdr->iovec_count; 292 const int size = sizeof(struct sg_iovec) * hdr->iovec_count;
293 size_t iov_data_len;
293 struct sg_iovec *iov; 294 struct sg_iovec *iov;
294 295
295 iov = kmalloc(size, GFP_KERNEL); 296 iov = kmalloc(size, GFP_KERNEL);
@@ -304,8 +305,18 @@ static int sg_io(struct request_queue *q, struct gendisk *bd_disk,
304 goto out; 305 goto out;
305 } 306 }
306 307
308 /* SG_IO howto says that the shorter of the two wins */
309 iov_data_len = iov_length((struct iovec *)iov,
310 hdr->iovec_count);
311 if (hdr->dxfer_len < iov_data_len) {
312 hdr->iovec_count = iov_shorten((struct iovec *)iov,
313 hdr->iovec_count,
314 hdr->dxfer_len);
315 iov_data_len = hdr->dxfer_len;
316 }
317
307 ret = blk_rq_map_user_iov(q, rq, NULL, iov, hdr->iovec_count, 318 ret = blk_rq_map_user_iov(q, rq, NULL, iov, hdr->iovec_count,
308 hdr->dxfer_len, GFP_KERNEL); 319 iov_data_len, GFP_KERNEL);
309 kfree(iov); 320 kfree(iov);
310 } else if (hdr->dxfer_len) 321 } else if (hdr->dxfer_len)
311 ret = blk_rq_map_user(q, rq, NULL, hdr->dxferp, hdr->dxfer_len, 322 ret = blk_rq_map_user(q, rq, NULL, hdr->dxferp, hdr->dxfer_len,