Commit a718e9a2 authored by Jens Axboe's avatar Jens Axboe Committed by Linus Torvalds

[PATCH] kill CDROM_SEND_PACKET

The CDROM_SEND_PACKET ioctl is both slow and ugly, this patch keeps the
functionality but utilizes the much better sg_io() framework.
parent cf46e949
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include <linux/cdrom.h> #include <linux/cdrom.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/bio.h> #include <linux/bio.h>
#include <linux/times.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <scsi/scsi.h> #include <scsi/scsi.h>
...@@ -140,40 +141,36 @@ static int sg_emulated_host(request_queue_t *q, int *p) ...@@ -140,40 +141,36 @@ static int sg_emulated_host(request_queue_t *q, int *p)
} }
static int sg_io(request_queue_t *q, struct block_device *bdev, static int sg_io(request_queue_t *q, struct block_device *bdev,
struct sg_io_hdr *uptr) struct sg_io_hdr *hdr)
{ {
unsigned long start_time; unsigned long start_time;
int reading, writing; int reading, writing;
struct sg_io_hdr hdr;
struct request *rq; struct request *rq;
struct bio *bio; struct bio *bio;
char sense[SCSI_SENSE_BUFFERSIZE]; char sense[SCSI_SENSE_BUFFERSIZE];
void *buffer; void *buffer;
if (copy_from_user(&hdr, uptr, sizeof(*uptr))) if (hdr->interface_id != 'S')
return -EFAULT;
if (hdr.interface_id != 'S')
return -EINVAL; return -EINVAL;
if (hdr.cmd_len > sizeof(rq->cmd)) if (hdr->cmd_len > sizeof(rq->cmd))
return -EINVAL; return -EINVAL;
/* /*
* we'll do that later * we'll do that later
*/ */
if (hdr.iovec_count) if (hdr->iovec_count)
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (hdr.dxfer_len > (q->max_sectors << 9)) if (hdr->dxfer_len > (q->max_sectors << 9))
return -EIO; return -EIO;
reading = writing = 0; reading = writing = 0;
buffer = NULL; buffer = NULL;
bio = NULL; bio = NULL;
if (hdr.dxfer_len) { if (hdr->dxfer_len) {
unsigned int bytes = (hdr.dxfer_len + 511) & ~511; unsigned int bytes = (hdr->dxfer_len + 511) & ~511;
switch (hdr.dxfer_direction) { switch (hdr->dxfer_direction) {
default: default:
return -EINVAL; return -EINVAL;
case SG_DXFER_TO_FROM_DEV: case SG_DXFER_TO_FROM_DEV:
...@@ -191,8 +188,8 @@ static int sg_io(request_queue_t *q, struct block_device *bdev, ...@@ -191,8 +188,8 @@ static int sg_io(request_queue_t *q, struct block_device *bdev,
* first try to map it into a bio. reading from device will * first try to map it into a bio. reading from device will
* be a write to vm. * be a write to vm.
*/ */
bio = bio_map_user(bdev, (unsigned long) hdr.dxferp, bio = bio_map_user(bdev, (unsigned long) hdr->dxferp,
hdr.dxfer_len, reading); hdr->dxfer_len, reading);
/* /*
* if bio setup failed, fall back to slow approach * if bio setup failed, fall back to slow approach
...@@ -203,11 +200,11 @@ static int sg_io(request_queue_t *q, struct block_device *bdev, ...@@ -203,11 +200,11 @@ static int sg_io(request_queue_t *q, struct block_device *bdev,
return -ENOMEM; return -ENOMEM;
if (writing) { if (writing) {
if (copy_from_user(buffer, hdr.dxferp, if (copy_from_user(buffer, hdr->dxferp,
hdr.dxfer_len)) hdr->dxfer_len))
goto out_buffer; goto out_buffer;
} else } else
memset(buffer, 0, hdr.dxfer_len); memset(buffer, 0, hdr->dxfer_len);
} }
} }
...@@ -216,11 +213,10 @@ static int sg_io(request_queue_t *q, struct block_device *bdev, ...@@ -216,11 +213,10 @@ static int sg_io(request_queue_t *q, struct block_device *bdev,
/* /*
* fill in request structure * fill in request structure
*/ */
rq->cmd_len = hdr.cmd_len; rq->cmd_len = hdr->cmd_len;
if (copy_from_user(rq->cmd, hdr.cmdp, hdr.cmd_len)) memcpy(rq->cmd, hdr->cmdp, hdr->cmd_len);
goto out_request; if (sizeof(rq->cmd) != hdr->cmd_len)
if (sizeof(rq->cmd) != hdr.cmd_len) memset(rq->cmd + hdr->cmd_len, 0, sizeof(rq->cmd) - hdr->cmd_len);
memset(rq->cmd + hdr.cmd_len, 0, sizeof(rq->cmd) - hdr.cmd_len);
memset(sense, 0, sizeof(sense)); memset(sense, 0, sizeof(sense));
rq->sense = sense; rq->sense = sense;
...@@ -234,9 +230,9 @@ static int sg_io(request_queue_t *q, struct block_device *bdev, ...@@ -234,9 +230,9 @@ static int sg_io(request_queue_t *q, struct block_device *bdev,
blk_rq_bio_prep(q, rq, bio); blk_rq_bio_prep(q, rq, bio);
rq->data = buffer; rq->data = buffer;
rq->data_len = hdr.dxfer_len; rq->data_len = hdr->dxfer_len;
rq->timeout = (hdr.timeout * HZ) / 1000; rq->timeout = (hdr->timeout * HZ) / 1000;
if (!rq->timeout) if (!rq->timeout)
rq->timeout = q->sg_timeout; rq->timeout = q->sg_timeout;
if (!rq->timeout) if (!rq->timeout)
...@@ -254,33 +250,30 @@ static int sg_io(request_queue_t *q, struct block_device *bdev, ...@@ -254,33 +250,30 @@ static int sg_io(request_queue_t *q, struct block_device *bdev,
bio_unmap_user(bio, reading); bio_unmap_user(bio, reading);
/* write to all output members */ /* write to all output members */
hdr.status = rq->errors; hdr->status = rq->errors;
hdr.masked_status = (hdr.status >> 1) & 0x1f; hdr->masked_status = (hdr->status >> 1) & 0x1f;
hdr.msg_status = 0; hdr->msg_status = 0;
hdr.host_status = 0; hdr->host_status = 0;
hdr.driver_status = 0; hdr->driver_status = 0;
hdr.info = 0; hdr->info = 0;
if (hdr.masked_status || hdr.host_status || hdr.driver_status) if (hdr->masked_status || hdr->host_status || hdr->driver_status)
hdr.info |= SG_INFO_CHECK; hdr->info |= SG_INFO_CHECK;
hdr.resid = rq->data_len; hdr->resid = rq->data_len;
hdr.duration = ((jiffies - start_time) * 1000) / HZ; hdr->duration = ((jiffies - start_time) * 1000) / HZ;
hdr.sb_len_wr = 0; hdr->sb_len_wr = 0;
if (rq->sense_len && hdr.sbp) { if (rq->sense_len && hdr->sbp) {
int len = min((unsigned int) hdr.mx_sb_len, rq->sense_len); int len = min((unsigned int) hdr->mx_sb_len, rq->sense_len);
if (!copy_to_user(hdr.sbp, rq->sense, len)) if (!copy_to_user(hdr->sbp, rq->sense, len))
hdr.sb_len_wr = len; hdr->sb_len_wr = len;
} }
blk_put_request(rq); blk_put_request(rq);
if (copy_to_user(uptr, &hdr, sizeof(*uptr)))
goto out_buffer;
if (buffer) { if (buffer) {
if (reading) if (reading)
if (copy_to_user(hdr.dxferp, buffer, hdr.dxfer_len)) if (copy_to_user(hdr->dxferp, buffer, hdr->dxfer_len))
goto out_buffer; goto out_buffer;
kfree(buffer); kfree(buffer);
...@@ -289,8 +282,6 @@ static int sg_io(request_queue_t *q, struct block_device *bdev, ...@@ -289,8 +282,6 @@ static int sg_io(request_queue_t *q, struct block_device *bdev,
/* may not have succeeded, but output values written to control /* may not have succeeded, but output values written to control
* structure (struct sg_io_hdr). */ * structure (struct sg_io_hdr). */
return 0; return 0;
out_request:
blk_put_request(rq);
out_buffer: out_buffer:
kfree(buffer); kfree(buffer);
return -EFAULT; return -EFAULT;
...@@ -437,9 +428,71 @@ int scsi_cmd_ioctl(struct block_device *bdev, unsigned int cmd, unsigned long ar ...@@ -437,9 +428,71 @@ int scsi_cmd_ioctl(struct block_device *bdev, unsigned int cmd, unsigned long ar
case SG_EMULATED_HOST: case SG_EMULATED_HOST:
err = sg_emulated_host(q, (int *) arg); err = sg_emulated_host(q, (int *) arg);
break; break;
case SG_IO: case SG_IO: {
err = sg_io(q, bdev, (struct sg_io_hdr *) arg); struct sg_io_hdr hdr;
if (copy_from_user(&hdr, (struct sg_io_hdr *) arg, sizeof(hdr))) {
err = -EFAULT;
break;
}
err = sg_io(q, bdev, &hdr);
if (copy_to_user((struct sg_io_hdr *) arg, &hdr, sizeof(hdr)))
err = -EFAULT;
break;
}
case CDROM_SEND_PACKET: {
struct cdrom_generic_command cgc;
struct sg_io_hdr hdr;
if (copy_from_user(&cgc, (struct cdrom_generic_command *) arg, sizeof(cgc))) {
err = -EFAULT;
break;
}
cgc.timeout = clock_t_to_jiffies(cgc.timeout);
memset(&hdr, 0, sizeof(hdr));
hdr.interface_id = 'S';
hdr.cmd_len = sizeof(cgc.cmd);
hdr.dxfer_len = cgc.buflen;
err = 0;
switch (cgc.data_direction) {
case CGC_DATA_UNKNOWN:
hdr.dxfer_direction = SG_DXFER_UNKNOWN;
break;
case CGC_DATA_WRITE:
hdr.dxfer_direction = SG_DXFER_TO_DEV;
break;
case CGC_DATA_READ:
hdr.dxfer_direction = SG_DXFER_FROM_DEV;
break;
case CGC_DATA_NONE:
hdr.dxfer_direction = SG_DXFER_NONE;
break;
default:
err = -EINVAL;
}
if (err)
break; break;
hdr.dxferp = cgc.buffer;
hdr.sbp = (char *) cgc.sense;
if (hdr.sbp)
hdr.mx_sb_len = sizeof(struct request_sense);
hdr.timeout = cgc.timeout;
hdr.cmdp = cgc.cmd;
hdr.cmd_len = sizeof(cgc.cmd);
err = sg_io(q, bdev, &hdr);
if (hdr.status)
err = -EIO;
cgc.stat = err;
cgc.buflen = hdr.resid;
if (copy_to_user((struct cdrom_generic_command *) arg, &cgc, sizeof(cgc)))
err = -EFAULT;
break;
}
/* /*
* old junk scsi send command ioctl * old junk scsi send command ioctl
*/ */
......
...@@ -1856,57 +1856,6 @@ static int cdrom_switch_blocksize(struct cdrom_device_info *cdi, int size) ...@@ -1856,57 +1856,6 @@ static int cdrom_switch_blocksize(struct cdrom_device_info *cdi, int size)
return cdo->generic_packet(cdi, &cgc); return cdo->generic_packet(cdi, &cgc);
} }
static int cdrom_do_cmd(struct cdrom_device_info *cdi,
struct cdrom_generic_command *cgc)
{
struct request_sense *usense, sense;
unsigned char *ubuf;
int ret;
if (cgc->data_direction == CGC_DATA_UNKNOWN)
return -EINVAL;
if (cgc->buflen < 0 || cgc->buflen >= 131072)
return -EINVAL;
usense = cgc->sense;
cgc->sense = &sense;
if (usense && !access_ok(VERIFY_WRITE, usense, sizeof(*usense))) {
return -EFAULT;
}
ubuf = cgc->buffer;
if (cgc->data_direction == CGC_DATA_READ ||
cgc->data_direction == CGC_DATA_WRITE) {
cgc->buffer = kmalloc(cgc->buflen, GFP_KERNEL);
if (cgc->buffer == NULL)
return -ENOMEM;
}
if (cgc->data_direction == CGC_DATA_READ) {
if (!access_ok(VERIFY_READ, ubuf, cgc->buflen)) {
kfree(cgc->buffer);
return -EFAULT;
}
} else if (cgc->data_direction == CGC_DATA_WRITE) {
if (copy_from_user(cgc->buffer, ubuf, cgc->buflen)) {
kfree(cgc->buffer);
return -EFAULT;
}
}
ret = cdi->ops->generic_packet(cdi, cgc);
__copy_to_user(usense, cgc->sense, sizeof(*usense));
if (!ret && cgc->data_direction == CGC_DATA_READ)
__copy_to_user(ubuf, cgc->buffer, cgc->buflen);
if (cgc->data_direction == CGC_DATA_READ ||
cgc->data_direction == CGC_DATA_WRITE) {
kfree(cgc->buffer);
}
return ret;
}
static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
unsigned long arg) unsigned long arg)
{ {
...@@ -2176,14 +2125,6 @@ static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, ...@@ -2176,14 +2125,6 @@ static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
return 0; return 0;
} }
case CDROM_SEND_PACKET: {
if (!CDROM_CAN(CDC_GENERIC_PACKET))
return -ENOSYS;
cdinfo(CD_DO_IOCTL, "entering CDROM_SEND_PACKET\n");
IOCTL_IN(arg, struct cdrom_generic_command, cgc);
cgc.timeout = clock_t_to_jiffies(cgc.timeout);
return cdrom_do_cmd(cdi, &cgc);
}
case CDROM_NEXT_WRITABLE: { case CDROM_NEXT_WRITABLE: {
long next = 0; long next = 0;
cdinfo(CD_DO_IOCTL, "entering CDROM_NEXT_WRITABLE\n"); cdinfo(CD_DO_IOCTL, "entering CDROM_NEXT_WRITABLE\n");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment