aboutsummaryrefslogtreecommitdiffstats
path: root/block
diff options
context:
space:
mode:
authorKent Overstreet <kmo@daterainc.com>2013-08-07 17:20:17 -0400
committerJens Axboe <axboe@kernel.dk>2013-11-08 11:02:14 -0500
commite0ce0eacb3197ad6e4ae37006c73af9411f97ecc (patch)
tree132ece8fa1907169c50a54e12322db3d35a2def0 /block
parent23779fbc99302dddab7f056ae47c3463169cbb64 (diff)
block: Use rw_copy_check_uvector()
No need for silly open coding - and struct sg_iovec has exactly the same layout as struct iovec... Signed-off-by: Kent Overstreet <kmo@daterainc.com> Cc: Jens Axboe <axboe@kernel.dk> Signed-off-by: Jens Axboe <axboe@kernel.dk>
Diffstat (limited to 'block')
-rw-r--r--block/scsi_ioctl.c39
1 files changed, 10 insertions, 29 deletions
diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c
index a5ffcc988f0b..625e3e471d65 100644
--- a/block/scsi_ioctl.c
+++ b/block/scsi_ioctl.c
@@ -286,7 +286,8 @@ static int sg_io(struct request_queue *q, struct gendisk *bd_disk,
286 struct sg_io_hdr *hdr, fmode_t mode) 286 struct sg_io_hdr *hdr, fmode_t mode)
287{ 287{
288 unsigned long start_time; 288 unsigned long start_time;
289 int writing = 0, ret = 0; 289 ssize_t ret = 0;
290 int writing = 0;
290 struct request *rq; 291 struct request *rq;
291 char sense[SCSI_SENSE_BUFFERSIZE]; 292 char sense[SCSI_SENSE_BUFFERSIZE];
292 struct bio *bio; 293 struct bio *bio;
@@ -321,37 +322,16 @@ static int sg_io(struct request_queue *q, struct gendisk *bd_disk,
321 } 322 }
322 323
323 if (hdr->iovec_count) { 324 if (hdr->iovec_count) {
324 const int size = sizeof(struct sg_iovec) * hdr->iovec_count;
325 size_t iov_data_len; 325 size_t iov_data_len;
326 struct sg_iovec *sg_iov;
327 struct iovec *iov; 326 struct iovec *iov;
328 int i;
329 327
330 sg_iov = kmalloc(size, GFP_KERNEL); 328 ret = rw_copy_check_uvector(-1, hdr->dxferp, hdr->iovec_count,
331 if (!sg_iov) { 329 0, NULL, &iov);
332 ret = -ENOMEM; 330 if (ret < 0)
333 goto out; 331 goto out;
334 }
335
336 if (copy_from_user(sg_iov, hdr->dxferp, size)) {
337 kfree(sg_iov);
338 ret = -EFAULT;
339 goto out;
340 }
341 332
342 /* 333 iov_data_len = ret;
343 * Sum up the vecs, making sure they don't overflow 334 ret = 0;
344 */
345 iov = (struct iovec *) sg_iov;
346 iov_data_len = 0;
347 for (i = 0; i < hdr->iovec_count; i++) {
348 if (iov_data_len + iov[i].iov_len < iov_data_len) {
349 kfree(sg_iov);
350 ret = -EINVAL;
351 goto out;
352 }
353 iov_data_len += iov[i].iov_len;
354 }
355 335
356 /* SG_IO howto says that the shorter of the two wins */ 336 /* SG_IO howto says that the shorter of the two wins */
357 if (hdr->dxfer_len < iov_data_len) { 337 if (hdr->dxfer_len < iov_data_len) {
@@ -361,9 +341,10 @@ static int sg_io(struct request_queue *q, struct gendisk *bd_disk,
361 iov_data_len = hdr->dxfer_len; 341 iov_data_len = hdr->dxfer_len;
362 } 342 }
363 343
364 ret = blk_rq_map_user_iov(q, rq, NULL, sg_iov, hdr->iovec_count, 344 ret = blk_rq_map_user_iov(q, rq, NULL, (struct sg_iovec *) iov,
345 hdr->iovec_count,
365 iov_data_len, GFP_KERNEL); 346 iov_data_len, GFP_KERNEL);
366 kfree(sg_iov); 347 kfree(iov);
367 } else if (hdr->dxfer_len) 348 } else if (hdr->dxfer_len)
368 ret = blk_rq_map_user(q, rq, NULL, hdr->dxferp, hdr->dxfer_len, 349 ret = blk_rq_map_user(q, rq, NULL, hdr->dxferp, hdr->dxfer_len,
369 GFP_KERNEL); 350 GFP_KERNEL);