Re: [RFC v3 PATCH 1/2] bsg: Add infrastructure to send in kernel bsg commands.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, 16 Jun 2011 08:36:19 -0400
Chad Dupuis <chad.dupuis@xxxxxxxxxx> wrote:

> This is version 3 of this patch which is based on review comments here:
> http://marc.info/?l=linux-scsi&m=130590738308822&w=2
> 
> Essentially, the code was refactored to reduce code duplication.
> 
> From: Chad Dupuis <chad.dupuis@xxxxxxxxxx>
> 
> This patch adds a new exported function, bsg_private_command() that allows a
> device driver or other kernel code to be able to send bsg commands from within
> the kernel using sg_io_v4.  The private command infrastructure mimics the ioctl
> interface except that the bsg request queue needs to be explicitly passed in.
> 
> bsg_map_hdr() and blk_fill_sgv4_hdr_rq() needed to be refactored slightly as
> well to allow for both user and kernel buffers.  Two helper functions were
> created as a front-end to bsg_map_hdr() so as to call bsg_map_hdr() with the correct
> semantics depending on the type of buffer that we're using.  bsg_map_hdr() and
> blk_fill_sgv4_hdr_rq() also have an extra argument, is_user, to tell what type
> of buffer is being used as well.
> 
> Signed-off-by: Chad Dupuis <chad.dupuis@xxxxxxxxxx>
> ---
>   block/bsg.c         |  138 ++++++++++++++++++++++++++++++++++++++++-----------
>   include/linux/bsg.h |    1 +
>   2 files changed, 109 insertions(+), 30 deletions(-)

What git tree can this be applied? I can't apply this to Linus' or
scsi-misc cleanly.


> diff --git a/block/bsg.c b/block/bsg.c
> index 0c8b64a..9babd96 100644
> --- a/block/bsg.c
> +++ b/block/bsg.c
> @@ -74,6 +74,8 @@ static int bsg_major;
> 
>   static struct kmem_cache *bsg_cmd_cachep;
> 
> +static struct request *
> +bsg_map_hdr(struct request_queue *, struct sg_io_v4 *, fmode_t, u8 *, int);
>   /*
>    * our internal command type
>    */
> @@ -173,8 +175,8 @@ unlock:
>   }
> 
>   static int blk_fill_sgv4_hdr_rq(struct request_queue *q, struct request *rq,
> -                               struct sg_io_v4 *hdr, struct bsg_device *bd,
> -                               fmode_t has_write_perm)
> +                               struct sg_io_v4 *hdr, fmode_t has_write_perm,
> +                               int is_user)
>   {
>         if (hdr->request_len > BLK_MAX_CDB) {
>                 rq->cmd = kzalloc(hdr->request_len, GFP_KERNEL);
> @@ -182,9 +184,14 @@ static int blk_fill_sgv4_hdr_rq(struct request_queue *q, struct request *rq,
>                         return -ENOMEM;
>         }
> 
> -       if (copy_from_user(rq->cmd, (void *)(unsigned long)hdr->request,
> -                          hdr->request_len))
> -               return -EFAULT;
> +       if (is_user) {
> +               if (copy_from_user(rq->cmd,
> +                   (void *)(unsigned long)hdr->request, hdr->request_len))
> +                       return -EFAULT;
> +       } else {
> +               memcpy(rq->cmd, (void *)(unsigned long)hdr->request,
> +                   hdr->request_len);
> +       }
> 
>         if (hdr->subprotocol == BSG_SUB_PROTOCOL_SCSI_CMD) {
>                 if (blk_verify_command(rq->cmd, has_write_perm))
> @@ -238,18 +245,13 @@ bsg_validate_sgv4_hdr(struct request_queue *q, struct sg_io_v4 *hdr, int *rw)
>         return ret;
>   }
> 
> -/*
> - * map sg_io_v4 to a request.
> - */
> +#define BSG_BUFFER_KERN                0
> +#define BSG_BUFFER_USER                1
>   static struct request *
> -bsg_map_hdr(struct bsg_device *bd, struct sg_io_v4 *hdr, fmode_t has_write_perm,
> -           u8 *sense)
> +bsg_map_hdr_user(struct bsg_device *bd, struct sg_io_v4 *hdr,
> +                fmode_t has_write_perm, u8 *sense)
>   {
>         struct request_queue *q = bd->queue;
> -       struct request *rq, *next_rq = NULL;
> -       int ret, rw;
> -       unsigned int dxfer_len;
> -       void *dxferp = NULL;
>         struct bsg_class_device *bcd = &q->bsg_dev;
> 
>         /* if the LLD has been removed then the bsg_unregister_queue will
> @@ -259,6 +261,28 @@ bsg_map_hdr(struct bsg_device *bd, struct sg_io_v4 *hdr, fmode_t has_write_perm,
>         if (!bcd->class_dev)
>                 return ERR_PTR(-ENXIO);
> 
> +       return(bsg_map_hdr(q, hdr, has_write_perm, sense, BSG_BUFFER_USER));
> +}
> +
> +static struct request *
> +bsg_map_hdr_kern(struct request_queue *q, struct sg_io_v4 *hdr,
> +                 fmode_t has_write_perm, u8 *sense)
> +{
> +       return(bsg_map_hdr(q, hdr, has_write_perm, sense, BSG_BUFFER_KERN));
> +}
> +
> +/*
> + * map sg_io_v4 to a request.
> + */
> +static struct request *
> +bsg_map_hdr(struct request_queue *q, struct sg_io_v4 *hdr,
> +           fmode_t has_write_perm, u8 *sense, int is_user)
> +{
> +       struct request *rq, *next_rq = NULL;
> +       int ret, rw;
> +       unsigned int dxfer_len;
> +       void *dxferp = NULL;
> +
>         dprintk("map hdr %llx/%u %llx/%u\n", (unsigned long long) hdr->dout_xferp,
>                 hdr->dout_xfer_len, (unsigned long long) hdr->din_xferp,
>                 hdr->din_xfer_len);
> @@ -273,7 +297,7 @@ bsg_map_hdr(struct bsg_device *bd, struct sg_io_v4 *hdr, fmode_t has_write_perm,
>         rq = blk_get_request(q, rw, GFP_KERNEL);
>         if (!rq)
>                 return ERR_PTR(-ENOMEM);
> -       ret = blk_fill_sgv4_hdr_rq(q, rq, hdr, bd, has_write_perm);
> +       ret = blk_fill_sgv4_hdr_rq(q, rq, hdr, has_write_perm, is_user);
>         if (ret)
>                 goto out;
> 
> @@ -292,8 +316,14 @@ bsg_map_hdr(struct bsg_device *bd, struct sg_io_v4 *hdr, fmode_t has_write_perm,
>                 next_rq->cmd_type = rq->cmd_type;
> 
>                 dxferp = (void*)(unsigned long)hdr->din_xferp;
> -               ret =  blk_rq_map_user(q, next_rq, NULL, dxferp,
> -                                      hdr->din_xfer_len, GFP_KERNEL);
> +
> +               if (is_user)
> +                       ret =  blk_rq_map_user(q, next_rq, NULL, dxferp,
> +                                              hdr->din_xfer_len, GFP_KERNEL);
> +               else
> +                       ret =  blk_rq_map_kern(q, next_rq, dxferp,
> +                                              hdr->din_xfer_len, GFP_KERNEL);
> +
>                 if (ret)
>                         goto out;
>         }
> @@ -308,8 +338,13 @@ bsg_map_hdr(struct bsg_device *bd, struct sg_io_v4 *hdr, fmode_t has_write_perm,
>                 dxfer_len = 0;
> 
>         if (dxfer_len) {
> -               ret = blk_rq_map_user(q, rq, NULL, dxferp, dxfer_len,
> -                                     GFP_KERNEL);
> +               if (is_user)
> +                       ret = blk_rq_map_user(q, rq, NULL, dxferp, dxfer_len,
> +                                             GFP_KERNEL);
> +               else
> +                       ret = blk_rq_map_kern(q, rq, dxferp, dxfer_len,
> +                                             GFP_KERNEL);
> +
>                 if (ret)
>                         goto out;
>         }
> @@ -323,7 +358,8 @@ out:
>                 kfree(rq->cmd);
>         blk_put_request(rq);
>         if (next_rq) {
> -               blk_rq_unmap_user(next_rq->bio);
> +               if (is_user)
> +                       blk_rq_unmap_user(next_rq->bio);
>                 blk_put_request(next_rq);
>         }
>         return ERR_PTR(ret);
> @@ -425,7 +461,8 @@ static struct bsg_command *bsg_get_done_cmd(struct bsg_device *bd)
>   }
> 
>   static int blk_complete_sgv4_hdr_rq(struct request *rq, struct sg_io_v4 *hdr,
> -                                   struct bio *bio, struct bio *bidi_bio)
> +                                   struct bio *bio, struct bio *bidi_bio,
> +                                   int is_user)
>   {
>         int ret = 0;
> 
> @@ -445,8 +482,13 @@ static int blk_complete_sgv4_hdr_rq(struct request *rq, struct sg_io_v4 *hdr,
>                 int len = min_t(unsigned int, hdr->max_response_len,
>                                         rq->sense_len);
> 
> -               ret = copy_to_user((void*)(unsigned long)hdr->response,
> -                                  rq->sense, len);
> +               if (is_user)
> +                       ret = copy_to_user((void*)(unsigned long)hdr->response,
> +                                          rq->sense, len);
> +               else
> +                       memcpy((void*)(unsigned long)hdr->response, rq->sense,
> +                              len);
> +
>                 if (!ret)
>                         hdr->response_len = len;
>                 else
> @@ -456,7 +498,8 @@ static int blk_complete_sgv4_hdr_rq(struct request *rq, struct sg_io_v4 *hdr,
>         if (rq->next_rq) {
>                 hdr->dout_resid = rq->resid_len;
>                 hdr->din_resid = rq->next_rq->resid_len;
> -               blk_rq_unmap_user(bidi_bio);
> +               if (is_user)
> +                       blk_rq_unmap_user(bidi_bio);
>                 blk_put_request(rq->next_rq);
>         } else if (rq_data_dir(rq) == READ)
>                 hdr->din_resid = rq->resid_len;
> @@ -472,7 +515,8 @@ static int blk_complete_sgv4_hdr_rq(struct request *rq, struct sg_io_v4 *hdr,
>         if (!ret && rq->errors < 0)
>                 ret = rq->errors;
> 
> -       blk_rq_unmap_user(bio);
> +       if (is_user)
> +               blk_rq_unmap_user(bio);
>         if (rq->cmd != rq->__cmd)
>                 kfree(rq->cmd);
>         blk_put_request(rq);
> @@ -519,7 +563,7 @@ static int bsg_complete_all_commands(struct bsg_device *bd)
>                         break;
> 
>                 tret = blk_complete_sgv4_hdr_rq(bc->rq, &bc->hdr, bc->bio,
> -                                               bc->bidi_bio);
> +                                               bc->bidi_bio, 1);
>                 if (!ret)
>                         ret = tret;
> 
> @@ -554,7 +598,7 @@ __bsg_read(char __user *buf, size_t count, struct bsg_device *bd,
>                  * bsg_complete_work() cannot do that for us
>                  */
>                 ret = blk_complete_sgv4_hdr_rq(bc->rq, &bc->hdr, bc->bio,
> -                                              bc->bidi_bio);
> +                                              bc->bidi_bio, 1);
> 
>                 if (copy_to_user(buf, &bc->hdr, sizeof(bc->hdr)))
>                         ret = -EFAULT;
> @@ -645,7 +689,7 @@ static int __bsg_write(struct bsg_device *bd, const char __user *buf,
>                 /*
>                  * get a request, fill in the blanks, and add to request queue
>                  */
> -               rq = bsg_map_hdr(bd, &bc->hdr, has_write_perm, bc->sense);
> +               rq = bsg_map_hdr_user(bd, &bc->hdr, has_write_perm, bc->sense);
>                 if (IS_ERR(rq)) {
>                         ret = PTR_ERR(rq);
>                         rq = NULL;
> @@ -936,7 +980,7 @@ static long bsg_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
>                 if (copy_from_user(&hdr, uarg, sizeof(hdr)))
>                         return -EFAULT;
> 
> -               rq = bsg_map_hdr(bd, &hdr, file->f_mode & FMODE_WRITE, sense);
> +               rq = bsg_map_hdr_user(bd, &hdr, file->f_mode & FMODE_WRITE, sense);
>                 if (IS_ERR(rq))
>                         return PTR_ERR(rq);
> 
> @@ -946,7 +990,7 @@ static long bsg_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
> 
>                 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);
> +               ret = blk_complete_sgv4_hdr_rq(rq, &hdr, bio, bidi_bio, 1);
> 
>                 if (copy_to_user(uarg, &hdr, sizeof(hdr)))
>                         return -EFAULT;
> @@ -965,6 +1009,40 @@ static long bsg_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
>         }
>   }

Rather than adding 'is_user' argument to everywhere, it could cleaner
to add something like 'int from_kernel' in struct bsg_command? No?


> +int bsg_private_command (struct request_queue *q, struct sg_io_v4 *hdr)
> +{
> +       struct request *rq;
> +       struct bio *bio, *bidi_bio = NULL;
> +       int at_head;
> +       u8 sense[SCSI_SENSE_BUFFERSIZE];
> +       fmode_t has_write_perm = 0;
> +       int ret;
> +
> +       if (!q)
> +               return -ENXIO;
> +
> +       /* Fake that we have write permission */
> +       has_write_perm |= FMODE_WRITE;
> +
> +       rq = bsg_map_hdr_kern(q, hdr, has_write_perm, sense);
> +
> +       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(q, NULL, rq, at_head);
> +       ret = blk_complete_sgv4_hdr_rq(rq, hdr, bio, bidi_bio, 0);
> +
> +       return ret;
> +}
> +EXPORT_SYMBOL(bsg_private_command);

EXPORT_SYMBOL_GPL, please.

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [SCSI Target Devel]     [Linux SCSI Target Infrastructure]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Linux IIO]     [Samba]     [Device Mapper]
  Powered by Linux