From ccf3209f0044e46236e238494181ae1a73275fad Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 9 Nov 2018 20:12:25 +0100 Subject: scsi: bsg: refactor bsg_ioctl Move all actual functionality into helpers, just leaving the dispatch in this function. Signed-off-by: Christoph Hellwig Reviewed-by: Benjamin Block Tested-by: Benjamin Block Tested-by: Avri Altman Acked-by: Jens Axboe Signed-off-by: Martin K. Petersen --- block/bsg.c | 158 +++++++++++++++++++++++++++--------------------------------- 1 file changed, 72 insertions(+), 86 deletions(-) (limited to 'block') diff --git a/block/bsg.c b/block/bsg.c index 50e5f8f666f2..a799b0ace55c 100644 --- a/block/bsg.c +++ b/block/bsg.c @@ -138,32 +138,35 @@ static const struct bsg_ops bsg_scsi_ops = { .free_rq = bsg_scsi_free_rq, }; -static struct request * -bsg_map_hdr(struct request_queue *q, struct sg_io_v4 *hdr, fmode_t mode) +static int bsg_sg_io(struct request_queue *q, fmode_t mode, void __user *uarg) { struct request *rq, *next_rq = NULL; + struct bio *bio, *bidi_bio = NULL; + struct sg_io_v4 hdr; int ret; - if (!q->bsg_dev.class_dev) - return ERR_PTR(-ENXIO); + if (copy_from_user(&hdr, uarg, sizeof(hdr))) + return -EFAULT; - if (hdr->guard != 'Q') - return ERR_PTR(-EINVAL); + if (!q->bsg_dev.class_dev) + return -ENXIO; - ret = q->bsg_dev.ops->check_proto(hdr); + if (hdr.guard != 'Q') + return -EINVAL; + ret = q->bsg_dev.ops->check_proto(&hdr); if (ret) - return ERR_PTR(ret); + return ret; - rq = blk_get_request(q, hdr->dout_xfer_len ? + rq = blk_get_request(q, hdr.dout_xfer_len ? REQ_OP_SCSI_OUT : REQ_OP_SCSI_IN, 0); if (IS_ERR(rq)) - return rq; + return PTR_ERR(rq); - ret = q->bsg_dev.ops->fill_hdr(rq, hdr, mode); + ret = q->bsg_dev.ops->fill_hdr(rq, &hdr, mode); if (ret) goto out; - rq->timeout = msecs_to_jiffies(hdr->timeout); + rq->timeout = msecs_to_jiffies(hdr.timeout); if (!rq->timeout) rq->timeout = q->sg_timeout; if (!rq->timeout) @@ -171,7 +174,7 @@ bsg_map_hdr(struct request_queue *q, struct sg_io_v4 *hdr, fmode_t mode) if (rq->timeout < BLK_MIN_SG_TIMEOUT) rq->timeout = BLK_MIN_SG_TIMEOUT; - if (hdr->dout_xfer_len && hdr->din_xfer_len) { + if (hdr.dout_xfer_len && hdr.din_xfer_len) { if (!test_bit(QUEUE_FLAG_BIDI, &q->queue_flags)) { ret = -EOPNOTSUPP; goto out; @@ -188,42 +191,29 @@ bsg_map_hdr(struct request_queue *q, struct sg_io_v4 *hdr, fmode_t mode) } rq->next_rq = next_rq; - ret = blk_rq_map_user(q, next_rq, NULL, uptr64(hdr->din_xferp), - hdr->din_xfer_len, GFP_KERNEL); + ret = blk_rq_map_user(q, next_rq, NULL, uptr64(hdr.din_xferp), + hdr.din_xfer_len, GFP_KERNEL); if (ret) goto out_free_nextrq; } - if (hdr->dout_xfer_len) { - ret = blk_rq_map_user(q, rq, NULL, uptr64(hdr->dout_xferp), - hdr->dout_xfer_len, GFP_KERNEL); - } else if (hdr->din_xfer_len) { - ret = blk_rq_map_user(q, rq, NULL, uptr64(hdr->din_xferp), - hdr->din_xfer_len, GFP_KERNEL); + if (hdr.dout_xfer_len) { + ret = blk_rq_map_user(q, rq, NULL, uptr64(hdr.dout_xferp), + hdr.dout_xfer_len, GFP_KERNEL); + } else if (hdr.din_xfer_len) { + ret = blk_rq_map_user(q, rq, NULL, uptr64(hdr.din_xferp), + hdr.din_xfer_len, GFP_KERNEL); } if (ret) goto out_unmap_nextrq; - return rq; -out_unmap_nextrq: + bio = rq->bio; if (rq->next_rq) - blk_rq_unmap_user(rq->next_rq->bio); -out_free_nextrq: - if (rq->next_rq) - blk_put_request(rq->next_rq); -out: - q->bsg_dev.ops->free_rq(rq); - blk_put_request(rq); - return ERR_PTR(ret); -} - -static int blk_complete_sgv4_hdr_rq(struct request *rq, struct sg_io_v4 *hdr, - struct bio *bio, struct bio *bidi_bio) -{ - int ret; + bidi_bio = rq->next_rq->bio; - ret = rq->q->bsg_dev.ops->complete_rq(rq, hdr); + blk_execute_rq(q, NULL, rq, !(hdr.flags & BSG_FLAG_Q_AT_TAIL)); + ret = rq->q->bsg_dev.ops->complete_rq(rq, &hdr); if (rq->next_rq) { blk_rq_unmap_user(bidi_bio); @@ -233,6 +223,20 @@ static int blk_complete_sgv4_hdr_rq(struct request *rq, struct sg_io_v4 *hdr, blk_rq_unmap_user(bio); rq->q->bsg_dev.ops->free_rq(rq); blk_put_request(rq); + + if (copy_to_user(uarg, &hdr, sizeof(hdr))) + return -EFAULT; + return ret; + +out_unmap_nextrq: + if (rq->next_rq) + blk_rq_unmap_user(rq->next_rq->bio); +out_free_nextrq: + if (rq->next_rq) + blk_put_request(rq->next_rq); +out: + q->bsg_dev.ops->free_rq(rq); + blk_put_request(rq); return ret; } @@ -367,31 +371,39 @@ static int bsg_release(struct inode *inode, struct file *file) return bsg_put_device(bd); } +static int bsg_get_command_q(struct bsg_device *bd, int __user *uarg) +{ + return put_user(bd->max_queue, uarg); +} + +static int bsg_set_command_q(struct bsg_device *bd, int __user *uarg) +{ + int queue; + + if (get_user(queue, uarg)) + return -EFAULT; + if (queue < 1) + return -EINVAL; + + spin_lock_irq(&bd->lock); + bd->max_queue = queue; + spin_unlock_irq(&bd->lock); + return 0; +} + static long bsg_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct bsg_device *bd = file->private_data; - int __user *uarg = (int __user *) arg; - int ret; + void __user *uarg = (void __user *) arg; switch (cmd) { - /* - * our own ioctls - */ + /* + * Our own ioctls + */ case SG_GET_COMMAND_Q: - return put_user(bd->max_queue, uarg); - case SG_SET_COMMAND_Q: { - int queue; - - if (get_user(queue, uarg)) - return -EFAULT; - if (queue < 1) - return -EINVAL; - - spin_lock_irq(&bd->lock); - bd->max_queue = queue; - spin_unlock_irq(&bd->lock); - return 0; - } + return bsg_get_command_q(bd, uarg); + case SG_SET_COMMAND_Q: + return bsg_set_command_q(bd, uarg); /* * SCSI/sg ioctls @@ -404,36 +416,10 @@ static long bsg_ioctl(struct file *file, unsigned int cmd, unsigned long arg) case SG_GET_RESERVED_SIZE: case SG_SET_RESERVED_SIZE: case SG_EMULATED_HOST: - case SCSI_IOCTL_SEND_COMMAND: { - void __user *uarg = (void __user *) arg; + case SCSI_IOCTL_SEND_COMMAND: return scsi_cmd_ioctl(bd->queue, NULL, file->f_mode, cmd, uarg); - } - case SG_IO: { - struct request *rq; - struct bio *bio, *bidi_bio = NULL; - struct sg_io_v4 hdr; - int at_head; - - if (copy_from_user(&hdr, uarg, sizeof(hdr))) - return -EFAULT; - - rq = bsg_map_hdr(bd->queue, &hdr, file->f_mode); - if (IS_ERR(rq)) - return PTR_ERR(rq); - - bio = rq->bio; - if (rq->next_rq) - bidi_bio = rq->next_rq->bio; - - at_head = (0 == (hdr.flags & BSG_FLAG_Q_AT_TAIL)); - blk_execute_rq(bd->queue, NULL, rq, at_head); - ret = blk_complete_sgv4_hdr_rq(rq, &hdr, bio, bidi_bio); - - if (copy_to_user(uarg, &hdr, sizeof(hdr))) - return -EFAULT; - - return ret; - } + case SG_IO: + return bsg_sg_io(bd->queue, file->f_mode, uarg); default: return -ENOTTY; } -- cgit v1.2.3 From 972248e9111ee6fe9fb56c24ecfd7434f3d713ac Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 29 Jan 2019 09:32:03 +0100 Subject: scsi: bsg-lib: handle bidi requests without block layer help We can just stash away the second request in struct bsg_job instead of using the block layer req->next_rq field, allowing for the eventual removal of the latter. Signed-off-by: Christoph Hellwig Acked-by: Jens Axboe Signed-off-by: Martin K. Petersen --- block/bsg-lib.c | 44 +++++++++++++++++++++---- block/bsg.c | 68 ++++++++------------------------------- drivers/scsi/scsi_transport_sas.c | 1 - include/linux/bsg-lib.h | 4 +++ 4 files changed, 56 insertions(+), 61 deletions(-) (limited to 'block') diff --git a/block/bsg-lib.c b/block/bsg-lib.c index 192129856342..005e2b75d775 100644 --- a/block/bsg-lib.c +++ b/block/bsg-lib.c @@ -51,11 +51,40 @@ static int bsg_transport_fill_hdr(struct request *rq, struct sg_io_v4 *hdr, fmode_t mode) { struct bsg_job *job = blk_mq_rq_to_pdu(rq); + int ret; job->request_len = hdr->request_len; job->request = memdup_user(uptr64(hdr->request), hdr->request_len); + if (IS_ERR(job->request)) + return PTR_ERR(job->request); + + if (hdr->dout_xfer_len && hdr->din_xfer_len) { + job->bidi_rq = blk_get_request(rq->q, REQ_OP_SCSI_IN, 0); + if (IS_ERR(job->bidi_rq)) { + ret = PTR_ERR(job->bidi_rq); + goto out; + } + + ret = blk_rq_map_user(rq->q, job->bidi_rq, NULL, + uptr64(hdr->din_xferp), hdr->din_xfer_len, + GFP_KERNEL); + if (ret) + goto out_free_bidi_rq; + + job->bidi_bio = job->bidi_rq->bio; + } else { + job->bidi_rq = NULL; + job->bidi_bio = NULL; + } - return PTR_ERR_OR_ZERO(job->request); + return 0; + +out_free_bidi_rq: + if (job->bidi_rq) + blk_put_request(job->bidi_rq); +out: + kfree(job->request); + return ret; } static int bsg_transport_complete_rq(struct request *rq, struct sg_io_v4 *hdr) @@ -93,7 +122,7 @@ static int bsg_transport_complete_rq(struct request *rq, struct sg_io_v4 *hdr) /* we assume all request payload was transferred, residual == 0 */ hdr->dout_resid = 0; - if (rq->next_rq) { + if (job->bidi_rq) { unsigned int rsp_len = job->reply_payload.payload_len; if (WARN_ON(job->reply_payload_rcv_len > rsp_len)) @@ -111,6 +140,11 @@ static void bsg_transport_free_rq(struct request *rq) { struct bsg_job *job = blk_mq_rq_to_pdu(rq); + if (job->bidi_rq) { + blk_rq_unmap_user(job->bidi_bio); + blk_put_request(job->bidi_rq); + } + kfree(job->request); } @@ -200,7 +234,6 @@ static int bsg_map_buffer(struct bsg_buffer *buf, struct request *req) */ static bool bsg_prepare_job(struct device *dev, struct request *req) { - struct request *rsp = req->next_rq; struct bsg_job *job = blk_mq_rq_to_pdu(req); int ret; @@ -211,8 +244,8 @@ static bool bsg_prepare_job(struct device *dev, struct request *req) if (ret) goto failjob_rls_job; } - if (rsp && rsp->bio) { - ret = bsg_map_buffer(&job->reply_payload, rsp); + if (job->bidi_rq) { + ret = bsg_map_buffer(&job->reply_payload, job->bidi_rq); if (ret) goto failjob_rls_rqst_payload; } @@ -369,7 +402,6 @@ struct request_queue *bsg_setup_queue(struct device *dev, const char *name, } q->queuedata = dev; - blk_queue_flag_set(QUEUE_FLAG_BIDI, q); blk_queue_rq_timeout(q, BLK_DEFAULT_SG_TIMEOUT); ret = bsg_register_queue(q, dev, name, &bsg_transport_ops); diff --git a/block/bsg.c b/block/bsg.c index a799b0ace55c..f306853c6b08 100644 --- a/block/bsg.c +++ b/block/bsg.c @@ -74,6 +74,11 @@ static int bsg_scsi_fill_hdr(struct request *rq, struct sg_io_v4 *hdr, { struct scsi_request *sreq = scsi_req(rq); + if (hdr->dout_xfer_len && hdr->din_xfer_len) { + pr_warn_once("BIDI support in bsg has been removed.\n"); + return -EOPNOTSUPP; + } + sreq->cmd_len = hdr->request_len; if (sreq->cmd_len > BLK_MAX_CDB) { sreq->cmd = kzalloc(sreq->cmd_len, GFP_KERNEL); @@ -114,14 +119,10 @@ static int bsg_scsi_complete_rq(struct request *rq, struct sg_io_v4 *hdr) hdr->response_len = len; } - if (rq->next_rq) { - hdr->dout_resid = sreq->resid_len; - hdr->din_resid = scsi_req(rq->next_rq)->resid_len; - } else if (rq_data_dir(rq) == READ) { + if (rq_data_dir(rq) == READ) hdr->din_resid = sreq->resid_len; - } else { + else hdr->dout_resid = sreq->resid_len; - } return ret; } @@ -140,8 +141,8 @@ static const struct bsg_ops bsg_scsi_ops = { static int bsg_sg_io(struct request_queue *q, fmode_t mode, void __user *uarg) { - struct request *rq, *next_rq = NULL; - struct bio *bio, *bidi_bio = NULL; + struct request *rq; + struct bio *bio; struct sg_io_v4 hdr; int ret; @@ -164,7 +165,7 @@ static int bsg_sg_io(struct request_queue *q, fmode_t mode, void __user *uarg) ret = q->bsg_dev.ops->fill_hdr(rq, &hdr, mode); if (ret) - goto out; + return ret; rq->timeout = msecs_to_jiffies(hdr.timeout); if (!rq->timeout) @@ -174,29 +175,6 @@ static int bsg_sg_io(struct request_queue *q, fmode_t mode, void __user *uarg) if (rq->timeout < BLK_MIN_SG_TIMEOUT) rq->timeout = BLK_MIN_SG_TIMEOUT; - if (hdr.dout_xfer_len && hdr.din_xfer_len) { - if (!test_bit(QUEUE_FLAG_BIDI, &q->queue_flags)) { - ret = -EOPNOTSUPP; - goto out; - } - - pr_warn_once( - "BIDI support in bsg has been deprecated and might be removed. " - "Please report your use case to linux-scsi@vger.kernel.org\n"); - - next_rq = blk_get_request(q, REQ_OP_SCSI_IN, 0); - if (IS_ERR(next_rq)) { - ret = PTR_ERR(next_rq); - goto out; - } - - rq->next_rq = next_rq; - ret = blk_rq_map_user(q, next_rq, NULL, uptr64(hdr.din_xferp), - hdr.din_xfer_len, GFP_KERNEL); - if (ret) - goto out_free_nextrq; - } - if (hdr.dout_xfer_len) { ret = blk_rq_map_user(q, rq, NULL, uptr64(hdr.dout_xferp), hdr.dout_xfer_len, GFP_KERNEL); @@ -206,38 +184,20 @@ static int bsg_sg_io(struct request_queue *q, fmode_t mode, void __user *uarg) } if (ret) - goto out_unmap_nextrq; + goto out_free_rq; bio = rq->bio; - if (rq->next_rq) - bidi_bio = rq->next_rq->bio; blk_execute_rq(q, NULL, rq, !(hdr.flags & BSG_FLAG_Q_AT_TAIL)); ret = rq->q->bsg_dev.ops->complete_rq(rq, &hdr); - - if (rq->next_rq) { - blk_rq_unmap_user(bidi_bio); - blk_put_request(rq->next_rq); - } - blk_rq_unmap_user(bio); + +out_free_rq: rq->q->bsg_dev.ops->free_rq(rq); blk_put_request(rq); - - if (copy_to_user(uarg, &hdr, sizeof(hdr))) + if (!ret && copy_to_user(uarg, &hdr, sizeof(hdr))) return -EFAULT; return ret; - -out_unmap_nextrq: - if (rq->next_rq) - blk_rq_unmap_user(rq->next_rq->bio); -out_free_nextrq: - if (rq->next_rq) - blk_put_request(rq->next_rq); -out: - q->bsg_dev.ops->free_rq(rq); - blk_put_request(rq); - return ret; } static struct bsg_device *bsg_alloc_device(void) diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c index 692b46937e52..60f1a81d2034 100644 --- a/drivers/scsi/scsi_transport_sas.c +++ b/drivers/scsi/scsi_transport_sas.c @@ -213,7 +213,6 @@ static int sas_bsg_initialize(struct Scsi_Host *shost, struct sas_rphy *rphy) to_sas_host_attrs(shost)->q = q; } - blk_queue_flag_set(QUEUE_FLAG_BIDI, q); return 0; } diff --git a/include/linux/bsg-lib.h b/include/linux/bsg-lib.h index b356e0006731..7f14517a559b 100644 --- a/include/linux/bsg-lib.h +++ b/include/linux/bsg-lib.h @@ -69,6 +69,10 @@ struct bsg_job { int result; unsigned int reply_payload_rcv_len; + /* BIDI support */ + struct request *bidi_rq; + struct bio *bidi_bio; + void *dd_data; /* Used for driver-specific storage */ }; -- cgit v1.2.3 From 69ed175c195595c73901e18366cb0ebeaeb68b8a Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 9 Nov 2018 19:35:11 +0100 Subject: scsi: block: remove req->special No users left. Signed-off-by: Christoph Hellwig Acked-by: Jens Axboe Signed-off-by: Martin K. Petersen --- block/blk-mq.c | 1 - drivers/scsi/sd.c | 2 -- include/linux/blkdev.h | 2 -- 3 files changed, 5 deletions(-) (limited to 'block') diff --git a/block/blk-mq.c b/block/blk-mq.c index 3ba37b9e15e9..502cbf964a3b 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -331,7 +331,6 @@ static struct request *blk_mq_rq_ctx_init(struct blk_mq_alloc_data *data, #if defined(CONFIG_BLK_DEV_INTEGRITY) rq->nr_integrity_segments = 0; #endif - rq->special = NULL; /* tag was already set */ rq->extra_len = 0; WRITE_ONCE(rq->deadline, 0); diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 3db9b1fe7516..c124459041dc 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1171,8 +1171,6 @@ static blk_status_t sd_setup_read_write_cmnd(struct scsi_cmnd *cmd) if (ret != BLK_STS_OK) return ret; - WARN_ON_ONCE(cmd != rq->special); - if (!scsi_device_online(sdp) || sdp->changed) { scmd_printk(KERN_ERR, cmd, "device offline or changed\n"); return BLK_STS_IOERR; diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 338604dff7d0..fd1450d53f1c 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -216,8 +216,6 @@ struct request { unsigned short write_hint; unsigned short ioprio; - void *special; /* opaque pointer available for LLD use */ - unsigned int extra_len; /* length of alignment and padding */ enum mq_rq_state state; -- cgit v1.2.3 From 8b3238cabd50e2715b6544e724e74685209b190a Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 6 Dec 2018 08:01:10 -0800 Subject: scsi: block: remove bidi support Unused now, and another field in struct request bites the dust. Signed-off-by: Christoph Hellwig Acked-by: Jens Axboe Signed-off-by: Martin K. Petersen --- block/blk-mq-debugfs.c | 1 - block/blk-mq.c | 3 --- include/linux/blkdev.h | 6 ------ 3 files changed, 10 deletions(-) (limited to 'block') diff --git a/block/blk-mq-debugfs.c b/block/blk-mq-debugfs.c index 90d68760af08..ac832547160a 100644 --- a/block/blk-mq-debugfs.c +++ b/block/blk-mq-debugfs.c @@ -115,7 +115,6 @@ static int queue_pm_only_show(void *data, struct seq_file *m) static const char *const blk_queue_flag_name[] = { QUEUE_FLAG_NAME(STOPPED), QUEUE_FLAG_NAME(DYING), - QUEUE_FLAG_NAME(BIDI), QUEUE_FLAG_NAME(NOMERGES), QUEUE_FLAG_NAME(SAME_COMP), QUEUE_FLAG_NAME(FAIL_IO), diff --git a/block/blk-mq.c b/block/blk-mq.c index 502cbf964a3b..820d131a6893 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -339,7 +339,6 @@ static struct request *blk_mq_rq_ctx_init(struct blk_mq_alloc_data *data, rq->end_io = NULL; rq->end_io_data = NULL; - rq->next_rq = NULL; data->ctx->rq_dispatched[op_is_sync(op)]++; refcount_set(&rq->ref, 1); @@ -549,8 +548,6 @@ inline void __blk_mq_end_request(struct request *rq, blk_status_t error) rq_qos_done(rq->q, rq); rq->end_io(rq, error); } else { - if (unlikely(blk_bidi_rq(rq))) - blk_mq_free_request(rq->next_rq); blk_mq_free_request(rq); } } diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index fd1450d53f1c..21beb456b97a 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -234,9 +234,6 @@ struct request { */ rq_end_io_fn *end_io; void *end_io_data; - - /* for bidi */ - struct request *next_rq; }; static inline bool blk_op_is_scsi(unsigned int op) @@ -572,7 +569,6 @@ struct request_queue { #define QUEUE_FLAG_STOPPED 1 /* queue is stopped */ #define QUEUE_FLAG_DYING 2 /* queue being torn down */ -#define QUEUE_FLAG_BIDI 4 /* queue supports bidi requests */ #define QUEUE_FLAG_NOMERGES 5 /* disable merge attempts */ #define QUEUE_FLAG_SAME_COMP 6 /* complete on same CPU-group */ #define QUEUE_FLAG_FAIL_IO 7 /* fake timeout */ @@ -644,8 +640,6 @@ static inline bool blk_account_rq(struct request *rq) return (rq->rq_flags & RQF_STARTED) && !blk_rq_is_passthrough(rq); } -#define blk_bidi_rq(rq) ((rq)->next_rq != NULL) - #define list_entry_rq(ptr) list_entry((ptr), struct request, queuelist) #define rq_data_dir(rq) (op_is_write(req_op(rq)) ? WRITE : READ) -- cgit v1.2.3