X-Git-Url: http://git.cascardo.eti.br/?a=blobdiff_plain;f=block%2Fscsi_ioctl.c;h=71bdf88884b2c6545176f4d964656d6ab62181ff;hb=b43035a5ec4deecd43019728ab9347df82dd121f;hp=f322b6a441d82fbe7db9a177ac0837fc54618cf2;hpb=ee2fae03d68e702866a8661fbee7ff2f2f3754d7;p=cascardo%2Flinux.git diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c index f322b6a441d8..71bdf88884b2 100644 --- a/block/scsi_ioctl.c +++ b/block/scsi_ioctl.c @@ -41,8 +41,6 @@ const unsigned char scsi_command_size[8] = EXPORT_SYMBOL(scsi_command_size); -#define BLK_DEFAULT_TIMEOUT (60 * HZ) - #include static int sg_get_version(int __user *p) @@ -78,7 +76,9 @@ static int sg_set_timeout(request_queue_t *q, int __user *p) static int sg_get_reserved_size(request_queue_t *q, int __user *p) { - return put_user(q->sg_reserved_size, p); + unsigned val = min(q->sg_reserved_size, q->max_sectors << 9); + + return put_user(val, p); } static int sg_set_reserved_size(request_queue_t *q, int __user *p) @@ -112,7 +112,7 @@ static int sg_emulated_host(request_queue_t *q, int __user *p) #define safe_for_read(cmd) [cmd] = CMD_READ_SAFE #define safe_for_write(cmd) [cmd] = CMD_WRITE_SAFE -static int verify_command(struct file *file, unsigned char *cmd) +int blk_verify_command(unsigned char *cmd, int has_write_perm) { static unsigned char cmd_type[256] = { @@ -191,18 +191,11 @@ static int verify_command(struct file *file, unsigned char *cmd) safe_for_write(GPCMD_SET_STREAMING), }; unsigned char type = cmd_type[cmd[0]]; - int has_write_perm = 0; /* Anybody who can open the device can do a read-safe command */ if (type & CMD_READ_SAFE) return 0; - /* - * file can be NULL from ioctl_by_bdev()... - */ - if (file) - has_write_perm = file->f_mode & FMODE_WRITE; - /* Write-safe commands just require a writable open.. */ if ((type & CMD_WRITE_SAFE) && has_write_perm) return 0; @@ -219,25 +212,96 @@ static int verify_command(struct file *file, unsigned char *cmd) /* Otherwise fail it with an "Operation not permitted" */ return -EPERM; } +EXPORT_SYMBOL_GPL(blk_verify_command); + +int blk_fill_sghdr_rq(request_queue_t *q, struct request *rq, + struct sg_io_hdr *hdr, int has_write_perm) +{ + memset(rq->cmd, 0, BLK_MAX_CDB); /* ATAPI hates garbage after CDB */ + + if (copy_from_user(rq->cmd, hdr->cmdp, hdr->cmd_len)) + return -EFAULT; + if (blk_verify_command(rq->cmd, has_write_perm)) + return -EPERM; + + /* + * fill in request structure + */ + rq->cmd_len = hdr->cmd_len; + rq->cmd_type = REQ_TYPE_BLOCK_PC; + + rq->timeout = (hdr->timeout * HZ) / 1000; + if (!rq->timeout) + rq->timeout = q->sg_timeout; + if (!rq->timeout) + rq->timeout = BLK_DEFAULT_SG_TIMEOUT; + + return 0; +} +EXPORT_SYMBOL_GPL(blk_fill_sghdr_rq); + +/* + * unmap a request that was previously mapped to this sg_io_hdr. handles + * both sg and non-sg sg_io_hdr. + */ +int blk_unmap_sghdr_rq(struct request *rq, struct sg_io_hdr *hdr) +{ + blk_rq_unmap_user(rq->bio); + blk_put_request(rq); + return 0; +} +EXPORT_SYMBOL_GPL(blk_unmap_sghdr_rq); + +int blk_complete_sghdr_rq(struct request *rq, struct sg_io_hdr *hdr, + struct bio *bio) +{ + int r, ret = 0; + + /* + * fill in all the output members + */ + hdr->status = rq->errors & 0xff; + hdr->masked_status = status_byte(rq->errors); + hdr->msg_status = msg_byte(rq->errors); + hdr->host_status = host_byte(rq->errors); + hdr->driver_status = driver_byte(rq->errors); + hdr->info = 0; + if (hdr->masked_status || hdr->host_status || hdr->driver_status) + hdr->info |= SG_INFO_CHECK; + hdr->resid = rq->data_len; + hdr->sb_len_wr = 0; + + if (rq->sense_len && hdr->sbp) { + int len = min((unsigned int) hdr->mx_sb_len, rq->sense_len); + + if (!copy_to_user(hdr->sbp, rq->sense, len)) + hdr->sb_len_wr = len; + else + ret = -EFAULT; + } + + rq->bio = bio; + r = blk_unmap_sghdr_rq(rq, hdr); + if (ret) + r = ret; + + return r; +} +EXPORT_SYMBOL_GPL(blk_complete_sghdr_rq); static int sg_io(struct file *file, request_queue_t *q, struct gendisk *bd_disk, struct sg_io_hdr *hdr) { unsigned long start_time; - int writing = 0, ret = 0; + int writing = 0, ret = 0, has_write_perm = 0; struct request *rq; char sense[SCSI_SENSE_BUFFERSIZE]; - unsigned char cmd[BLK_MAX_CDB]; struct bio *bio; if (hdr->interface_id != 'S') return -EINVAL; if (hdr->cmd_len > BLK_MAX_CDB) return -EINVAL; - if (copy_from_user(cmd, hdr->cmdp, hdr->cmd_len)) - return -EFAULT; - if (verify_command(file, cmd)) - return -EPERM; if (hdr->dxfer_len > (q->max_hw_sectors << 9)) return -EIO; @@ -258,24 +322,13 @@ static int sg_io(struct file *file, request_queue_t *q, if (!rq) return -ENOMEM; - /* - * fill in request structure - */ - rq->cmd_len = hdr->cmd_len; - memset(rq->cmd, 0, BLK_MAX_CDB); /* ATAPI hates garbage after CDB */ - memcpy(rq->cmd, cmd, hdr->cmd_len); - - memset(sense, 0, sizeof(sense)); - rq->sense = sense; - rq->sense_len = 0; - - rq->cmd_type = REQ_TYPE_BLOCK_PC; + if (file) + has_write_perm = file->f_mode & FMODE_WRITE; - rq->timeout = jiffies_to_msecs(hdr->timeout); - if (!rq->timeout) - rq->timeout = q->sg_timeout; - if (!rq->timeout) - rq->timeout = BLK_DEFAULT_TIMEOUT; + if (blk_fill_sghdr_rq(q, rq, hdr, has_write_perm)) { + blk_put_request(rq); + return -EFAULT; + } if (hdr->iovec_count) { const int size = sizeof(struct sg_iovec) * hdr->iovec_count; @@ -303,6 +356,9 @@ static int sg_io(struct file *file, request_queue_t *q, goto out; bio = rq->bio; + memset(sense, 0, sizeof(sense)); + rq->sense = sense; + rq->sense_len = 0; rq->retries = 0; start_time = jiffies; @@ -313,32 +369,9 @@ static int sg_io(struct file *file, request_queue_t *q, */ blk_execute_rq(q, bd_disk, rq, 0); - /* write to all output members */ - hdr->status = 0xff & rq->errors; - hdr->masked_status = status_byte(rq->errors); - hdr->msg_status = msg_byte(rq->errors); - hdr->host_status = host_byte(rq->errors); - hdr->driver_status = driver_byte(rq->errors); - hdr->info = 0; - if (hdr->masked_status || hdr->host_status || hdr->driver_status) - hdr->info |= SG_INFO_CHECK; - hdr->resid = rq->data_len; hdr->duration = ((jiffies - start_time) * 1000) / HZ; - hdr->sb_len_wr = 0; - - if (rq->sense_len && hdr->sbp) { - int len = min((unsigned int) hdr->mx_sb_len, rq->sense_len); - - if (!copy_to_user(hdr->sbp, rq->sense, len)) - hdr->sb_len_wr = len; - } - - rq->bio = bio; - if (blk_rq_unmap_user(rq)) - ret = -EFAULT; - /* may not have succeeded, but output values written to control - * structure (struct sg_io_hdr). */ + return blk_complete_sghdr_rq(rq, hdr, bio); out: blk_put_request(rq); return ret; @@ -403,11 +436,10 @@ int sg_scsi_ioctl(struct file *file, struct request_queue *q, bytes = max(in_len, out_len); if (bytes) { - buffer = kmalloc(bytes, q->bounce_gfp | GFP_USER| __GFP_NOWARN); + buffer = kzalloc(bytes, q->bounce_gfp | GFP_USER| __GFP_NOWARN); if (!buffer) return -ENOMEM; - memset(buffer, 0, bytes); } rq = blk_get_request(q, in_len ? WRITE : READ, __GFP_WAIT); @@ -425,7 +457,7 @@ int sg_scsi_ioctl(struct file *file, struct request_queue *q, if (in_len && copy_from_user(buffer, sic->data + cmdlen, in_len)) goto error; - err = verify_command(file, rq->cmd); + err = blk_verify_command(rq->cmd, file->f_mode & FMODE_WRITE); if (err) goto error; @@ -452,7 +484,7 @@ int sg_scsi_ioctl(struct file *file, struct request_queue *q, rq->retries = 1; break; default: - rq->timeout = BLK_DEFAULT_TIMEOUT; + rq->timeout = BLK_DEFAULT_SG_TIMEOUT; break; } @@ -499,7 +531,7 @@ static int __blk_send_generic(request_queue_t *q, struct gendisk *bd_disk, int c rq->cmd_type = REQ_TYPE_BLOCK_PC; rq->data = NULL; rq->data_len = 0; - rq->timeout = BLK_DEFAULT_TIMEOUT; + rq->timeout = BLK_DEFAULT_SG_TIMEOUT; memset(rq->cmd, 0, sizeof(rq->cmd)); rq->cmd[0] = cmd; rq->cmd[4] = data; @@ -515,16 +547,12 @@ static inline int blk_send_start_stop(request_queue_t *q, struct gendisk *bd_dis return __blk_send_generic(q, bd_disk, GPCMD_START_STOP_UNIT, data); } -int scsi_cmd_ioctl(struct file *file, struct gendisk *bd_disk, unsigned int cmd, void __user *arg) +int scsi_cmd_ioctl(struct file *file, struct request_queue *q, + struct gendisk *bd_disk, unsigned int cmd, void __user *arg) { - request_queue_t *q; int err; - q = bd_disk->queue; - if (!q) - return -ENXIO; - - if (blk_get_queue(q)) + if (!q || blk_get_queue(q)) return -ENXIO; switch (cmd) {