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.c19
1 files changed, 16 insertions, 3 deletions
diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c
index 626ee274c5c4..82a0ca2f6729 100644
--- a/block/scsi_ioctl.c
+++ b/block/scsi_ioctl.c
@@ -217,7 +217,7 @@ static int blk_fill_sghdr_rq(struct request_queue *q, struct request *rq,
217static int blk_complete_sghdr_rq(struct request *rq, struct sg_io_hdr *hdr, 217static int blk_complete_sghdr_rq(struct request *rq, struct sg_io_hdr *hdr,
218 struct bio *bio) 218 struct bio *bio)
219{ 219{
220 int ret = 0; 220 int r, ret = 0;
221 221
222 /* 222 /*
223 * fill in all the output members 223 * fill in all the output members
@@ -242,7 +242,9 @@ static int blk_complete_sghdr_rq(struct request *rq, struct sg_io_hdr *hdr,
242 ret = -EFAULT; 242 ret = -EFAULT;
243 } 243 }
244 244
245 blk_rq_unmap_user(bio); 245 r = blk_rq_unmap_user(bio);
246 if (!ret)
247 ret = r;
246 blk_put_request(rq); 248 blk_put_request(rq);
247 249
248 return ret; 250 return ret;
@@ -288,6 +290,7 @@ static int sg_io(struct request_queue *q, struct gendisk *bd_disk,
288 290
289 if (hdr->iovec_count) { 291 if (hdr->iovec_count) {
290 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;
291 struct sg_iovec *iov; 294 struct sg_iovec *iov;
292 295
293 iov = kmalloc(size, GFP_KERNEL); 296 iov = kmalloc(size, GFP_KERNEL);
@@ -302,8 +305,18 @@ static int sg_io(struct request_queue *q, struct gendisk *bd_disk,
302 goto out; 305 goto out;
303 } 306 }
304 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
305 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,
306 hdr->dxfer_len, GFP_KERNEL); 319 iov_data_len, GFP_KERNEL);
307 kfree(iov); 320 kfree(iov);
308 } else if (hdr->dxfer_len) 321 } else if (hdr->dxfer_len)
309 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,