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 <h...@lst.de>
---
 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(-)

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-s...@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 */
 };
 
-- 
2.20.1

Reply via email to