aboutsummaryrefslogtreecommitdiff
path: root/drivers/block/scsi_ioctl.c
diff options
context:
space:
mode:
authorJames Bottomley <James.Bottomley@SteelEye.com>2005-06-20 14:06:52 +0200
committerJens Axboe <axboe@suse.de>2005-06-20 14:06:52 +0200
commitf1970baf6d74e03bd32072ab453f2fc01bc1b8d3 (patch)
tree559898cdf83bd0f93b8a72248c6423a6548fb604 /drivers/block/scsi_ioctl.c
parentdd1cab95f356f1395278633565f198463cf6bd24 (diff)
[PATCH] Add scatter-gather support for the block layer SG_IO
Signed-off-by: Jens Axboe <axboe@suse.de>
Diffstat (limited to 'drivers/block/scsi_ioctl.c')
-rw-r--r--drivers/block/scsi_ioctl.c34
1 files changed, 23 insertions, 11 deletions
diff --git a/drivers/block/scsi_ioctl.c b/drivers/block/scsi_ioctl.c
index 93c4ca874be..09a7e73a081 100644
--- a/drivers/block/scsi_ioctl.c
+++ b/drivers/block/scsi_ioctl.c
@@ -231,17 +231,11 @@ static int sg_io(struct file *file, request_queue_t *q,
if (verify_command(file, cmd))
return -EPERM;
- /*
- * we'll do that later
- */
- if (hdr->iovec_count)
- return -EOPNOTSUPP;
-
if (hdr->dxfer_len > (q->max_sectors << 9))
return -EIO;
reading = writing = 0;
- if (hdr->dxfer_len) {
+ if (hdr->dxfer_len)
switch (hdr->dxfer_direction) {
default:
return -EINVAL;
@@ -261,11 +255,29 @@ static int sg_io(struct file *file, request_queue_t *q,
if (!rq)
return -ENOMEM;
- if (reading || writing) {
- ret = blk_rq_map_user(q, rq, hdr->dxferp, hdr->dxfer_len);
- if (ret)
+ if (hdr->iovec_count) {
+ const int size = sizeof(struct sg_iovec) * hdr->iovec_count;
+ struct sg_iovec *iov;
+
+ iov = kmalloc(size, GFP_KERNEL);
+ if (!iov) {
+ ret = -ENOMEM;
goto out;
- }
+ }
+
+ if (copy_from_user(iov, hdr->dxferp, size)) {
+ kfree(iov);
+ ret = -EFAULT;
+ goto out;
+ }
+
+ ret = blk_rq_map_user_iov(q, rq, iov, hdr->iovec_count);
+ kfree(iov);
+ } else if (hdr->dxfer_len)
+ ret = blk_rq_map_user(q, rq, hdr->dxferp, hdr->dxfer_len);
+
+ if (ret)
+ goto out;
/*
* fill in request structure