* [PATCH 0/5] Convert RPMB block device to a character device
@ 2017-06-15 12:12 Linus Walleij
2017-06-15 12:12 ` [PATCH 1/5] mmc: block: Move duplicate check Linus Walleij
` (4 more replies)
0 siblings, 5 replies; 17+ messages in thread
From: Linus Walleij @ 2017-06-15 12:12 UTC (permalink / raw)
To: linux-mmc, Ulf Hansson
Cc: linux-block, Jens Axboe, Christoph Hellwig, Arnd Bergmann,
Bartlomiej Zolnierkiewicz, Paolo Valente, Avri Altman,
Adrian Hunter, Linus Walleij
Looking for ways to get rid of the RPMB "block device" and the
extra block queue. This is one approach, I don't know if it will
stick, let's discuss it, especially the RFC patch.
Patches 1,2,3 can be applied as cleanups unless they collide with
something else.
Patch 5 is a consequence of the character device conversion.
For motivation and in-depth description of the problem I am trying
to solve, see patch 4, the RFC.
Linus Walleij (5):
mmc: block: Move duplicate check
mmc: block: Refactor mmc_blk_part_switch()
mmc: block: Reparametrize mmc_blk_ioctl_[multi]_cmd()
RFC: mmc: block: Convert RPMB to a character device
mmc: block: Delete mmc_access_rpmb()
drivers/mmc/core/block.c | 384 ++++++++++++++++++++++++++++++++++++-----------
drivers/mmc/core/queue.c | 2 +-
drivers/mmc/core/queue.h | 4 +-
3 files changed, 303 insertions(+), 87 deletions(-)
--
2.9.4
^ permalink raw reply [flat|nested] 17+ messages in thread* [PATCH 1/5] mmc: block: Move duplicate check 2017-06-15 12:12 [PATCH 0/5] Convert RPMB block device to a character device Linus Walleij @ 2017-06-15 12:12 ` Linus Walleij 2017-06-16 0:46 ` Shawn Lin 2017-06-15 12:12 ` [PATCH 2/5] mmc: block: Refactor mmc_blk_part_switch() Linus Walleij ` (3 subsequent siblings) 4 siblings, 1 reply; 17+ messages in thread From: Linus Walleij @ 2017-06-15 12:12 UTC (permalink / raw) To: linux-mmc, Ulf Hansson Cc: linux-block, Jens Axboe, Christoph Hellwig, Arnd Bergmann, Bartlomiej Zolnierkiewicz, Paolo Valente, Avri Altman, Adrian Hunter, Linus Walleij, Shawn Lin mmc_blk_ioctl() calls either mmc_blk_ioctl_cmd() or mmc_blk_ioctl_multi_cmd() and each of these make the same check. Factor it into a new helper function, call it on both branches of the switch() statement and save a chunk of duplicate code. Cc: Shawn Lin <shawn.lin@rock-chips.com> Signed-off-by: Linus Walleij <linus.walleij@linaro.org> --- ChangeLog v1->v2: - We need to check the block device only if an actual well-known ioctl() is coming in, on the path of the switch() statments, only those branches that handle actual ioctl()s. Create a new helper function to check the block device and call that. --- drivers/mmc/core/block.c | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index 1ce6012ce3c1..d1b824e65590 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -566,14 +566,6 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev, int err = 0, ioc_err = 0; struct request *req; - /* - * The caller must have CAP_SYS_RAWIO, and must be calling this on the - * whole block device, not on a partition. This prevents overspray - * between sibling partitions. - */ - if ((!capable(CAP_SYS_RAWIO)) || (bdev != bdev->bd_contains)) - return -EPERM; - idata = mmc_blk_ioctl_copy_from_user(ic_ptr); if (IS_ERR(idata)) return PTR_ERR(idata); @@ -626,14 +618,6 @@ static int mmc_blk_ioctl_multi_cmd(struct block_device *bdev, __u64 num_of_cmds; struct request *req; - /* - * The caller must have CAP_SYS_RAWIO, and must be calling this on the - * whole block device, not on a partition. This prevents overspray - * between sibling partitions. - */ - if ((!capable(CAP_SYS_RAWIO)) || (bdev != bdev->bd_contains)) - return -EPERM; - if (copy_from_user(&num_of_cmds, &user->num_of_cmds, sizeof(num_of_cmds))) return -EFAULT; @@ -697,14 +681,34 @@ static int mmc_blk_ioctl_multi_cmd(struct block_device *bdev, return ioc_err ? ioc_err : err; } +static int mmc_blk_check_blkdev(struct block_device *bdev) +{ + /* + * The caller must have CAP_SYS_RAWIO, and must be calling this on the + * whole block device, not on a partition. This prevents overspray + * between sibling partitions. + */ + if ((!capable(CAP_SYS_RAWIO)) || (bdev != bdev->bd_contains)) + return -EPERM; + return 0; +} + static int mmc_blk_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, unsigned long arg) { + int ret; + switch (cmd) { case MMC_IOC_CMD: + ret = mmc_blk_check_blkdev(bdev); + if (ret) + return ret; return mmc_blk_ioctl_cmd(bdev, (struct mmc_ioc_cmd __user *)arg); case MMC_IOC_MULTI_CMD: + ret = mmc_blk_check_blkdev(bdev); + if (ret) + return ret; return mmc_blk_ioctl_multi_cmd(bdev, (struct mmc_ioc_multi_cmd __user *)arg); default: -- 2.9.4 ^ permalink raw reply related [flat|nested] 17+ messages in thread
* Re: [PATCH 1/5] mmc: block: Move duplicate check 2017-06-15 12:12 ` [PATCH 1/5] mmc: block: Move duplicate check Linus Walleij @ 2017-06-16 0:46 ` Shawn Lin 0 siblings, 0 replies; 17+ messages in thread From: Shawn Lin @ 2017-06-16 0:46 UTC (permalink / raw) To: Linus Walleij, linux-mmc, Ulf Hansson Cc: shawn.lin, linux-block, Jens Axboe, Christoph Hellwig, Arnd Bergmann, Bartlomiej Zolnierkiewicz, Paolo Valente, Avri Altman, Adrian Hunter Hi, On 2017/6/15 20:12, Linus Walleij wrote: > mmc_blk_ioctl() calls either mmc_blk_ioctl_cmd() or > mmc_blk_ioctl_multi_cmd() and each of these make the same > check. Factor it into a new helper function, call it on > both branches of the switch() statement and save a chunk > of duplicate code. > > Cc: Shawn Lin <shawn.lin@rock-chips.com> > Signed-off-by: Linus Walleij <linus.walleij@linaro.org> > --- > ChangeLog v1->v2: > - We need to check the block device only if an actual > well-known ioctl() is coming in, on the path of the > switch() statments, only those branches that handle > actual ioctl()s. Create a new helper function to check > the block device and call that. Reviewed-by: Shawn Lin <shawn.lin@rock-chips.com> > --- > drivers/mmc/core/block.c | 36 ++++++++++++++++++++---------------- > 1 file changed, 20 insertions(+), 16 deletions(-) > > diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c > index 1ce6012ce3c1..d1b824e65590 100644 > --- a/drivers/mmc/core/block.c > +++ b/drivers/mmc/core/block.c > @@ -566,14 +566,6 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev, > int err = 0, ioc_err = 0; > struct request *req; > > - /* > - * The caller must have CAP_SYS_RAWIO, and must be calling this on the > - * whole block device, not on a partition. This prevents overspray > - * between sibling partitions. > - */ > - if ((!capable(CAP_SYS_RAWIO)) || (bdev != bdev->bd_contains)) > - return -EPERM; > - > idata = mmc_blk_ioctl_copy_from_user(ic_ptr); > if (IS_ERR(idata)) > return PTR_ERR(idata); > @@ -626,14 +618,6 @@ static int mmc_blk_ioctl_multi_cmd(struct block_device *bdev, > __u64 num_of_cmds; > struct request *req; > > - /* > - * The caller must have CAP_SYS_RAWIO, and must be calling this on the > - * whole block device, not on a partition. This prevents overspray > - * between sibling partitions. > - */ > - if ((!capable(CAP_SYS_RAWIO)) || (bdev != bdev->bd_contains)) > - return -EPERM; > - > if (copy_from_user(&num_of_cmds, &user->num_of_cmds, > sizeof(num_of_cmds))) > return -EFAULT; > @@ -697,14 +681,34 @@ static int mmc_blk_ioctl_multi_cmd(struct block_device *bdev, > return ioc_err ? ioc_err : err; > } > > +static int mmc_blk_check_blkdev(struct block_device *bdev) > +{ > + /* > + * The caller must have CAP_SYS_RAWIO, and must be calling this on the > + * whole block device, not on a partition. This prevents overspray > + * between sibling partitions. > + */ > + if ((!capable(CAP_SYS_RAWIO)) || (bdev != bdev->bd_contains)) > + return -EPERM; > + return 0; > +} > + > static int mmc_blk_ioctl(struct block_device *bdev, fmode_t mode, > unsigned int cmd, unsigned long arg) > { > + int ret; > + > switch (cmd) { > case MMC_IOC_CMD: > + ret = mmc_blk_check_blkdev(bdev); > + if (ret) > + return ret; > return mmc_blk_ioctl_cmd(bdev, > (struct mmc_ioc_cmd __user *)arg); > case MMC_IOC_MULTI_CMD: > + ret = mmc_blk_check_blkdev(bdev); > + if (ret) > + return ret; > return mmc_blk_ioctl_multi_cmd(bdev, > (struct mmc_ioc_multi_cmd __user *)arg); > default: > ^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 2/5] mmc: block: Refactor mmc_blk_part_switch() 2017-06-15 12:12 [PATCH 0/5] Convert RPMB block device to a character device Linus Walleij 2017-06-15 12:12 ` [PATCH 1/5] mmc: block: Move duplicate check Linus Walleij @ 2017-06-15 12:12 ` Linus Walleij 2017-06-19 19:53 ` Tomas Winkler 2017-06-15 12:12 ` [PATCH 3/5] mmc: block: Reparametrize mmc_blk_ioctl_[multi]_cmd() Linus Walleij ` (2 subsequent siblings) 4 siblings, 1 reply; 17+ messages in thread From: Linus Walleij @ 2017-06-15 12:12 UTC (permalink / raw) To: linux-mmc, Ulf Hansson Cc: linux-block, Jens Axboe, Christoph Hellwig, Arnd Bergmann, Bartlomiej Zolnierkiewicz, Paolo Valente, Avri Altman, Adrian Hunter, Linus Walleij Instead of passing a struct mmc_blk_data * to mmc_blk_part_switch() let's pass the actual partition type we want to switch to. This is necessary in order not to have a block device with a backing mmc_blk_data and request queue and all for every hardware partition, such as RPMB. Signed-off-by: Linus Walleij <linus.walleij@linaro.org> --- drivers/mmc/core/block.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index d1b824e65590..94b97f97be1a 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -127,7 +127,7 @@ module_param(perdev_minors, int, 0444); MODULE_PARM_DESC(perdev_minors, "Minors numbers to allocate per device"); static inline int mmc_blk_part_switch(struct mmc_card *card, - struct mmc_blk_data *md); + unsigned int part_type); static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk) { @@ -490,7 +490,7 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md, mrq.cmd = &cmd; - err = mmc_blk_part_switch(card, md); + err = mmc_blk_part_switch(card, md->part_type); if (err) return err; @@ -767,29 +767,29 @@ static int mmc_blk_part_switch_post(struct mmc_card *card, } static inline int mmc_blk_part_switch(struct mmc_card *card, - struct mmc_blk_data *md) + unsigned int part_type) { int ret = 0; struct mmc_blk_data *main_md = dev_get_drvdata(&card->dev); - if (main_md->part_curr == md->part_type) + if (main_md->part_curr == part_type) return 0; if (mmc_card_mmc(card)) { u8 part_config = card->ext_csd.part_config; - ret = mmc_blk_part_switch_pre(card, md->part_type); + ret = mmc_blk_part_switch_pre(card, part_type); if (ret) return ret; part_config &= ~EXT_CSD_PART_CONFIG_ACC_MASK; - part_config |= md->part_type; + part_config |= part_type; ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONFIG, part_config, card->ext_csd.part_time); if (ret) { - mmc_blk_part_switch_post(card, md->part_type); + mmc_blk_part_switch_post(card, part_type); return ret; } @@ -798,7 +798,7 @@ static inline int mmc_blk_part_switch(struct mmc_card *card, ret = mmc_blk_part_switch_post(card, main_md->part_curr); } - main_md->part_curr = md->part_type; + main_md->part_curr = part_type; return ret; } @@ -1141,7 +1141,7 @@ static int mmc_blk_reset(struct mmc_blk_data *md, struct mmc_host *host, int part_err; main_md->part_curr = main_md->part_type; - part_err = mmc_blk_part_switch(host->card, md); + part_err = mmc_blk_part_switch(host->card, md->part_type); if (part_err) { /* * We have failed to get back into the correct @@ -1180,6 +1180,7 @@ static void mmc_blk_issue_drv_op(struct mmc_queue *mq, struct request *req) struct mmc_queue_req *mq_rq; struct mmc_card *card = mq->card; struct mmc_blk_data *md = mq->blkdata; + struct mmc_blk_data *main_md = dev_get_drvdata(&card->dev); struct mmc_blk_ioc_data **idata; u8 **ext_csd; u32 status; @@ -1198,7 +1199,7 @@ static void mmc_blk_issue_drv_op(struct mmc_queue *mq, struct request *req) } /* Always switch back to main area after RPMB access */ if (md->area_type & MMC_BLK_DATA_AREA_RPMB) - mmc_blk_part_switch(card, dev_get_drvdata(&card->dev)); + mmc_blk_part_switch(card, main_md->part_type); break; case MMC_DRV_OP_BOOT_WP: ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_WP, @@ -1906,7 +1907,7 @@ void mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) /* claim host only for the first request */ mmc_get_card(card); - ret = mmc_blk_part_switch(card, md); + ret = mmc_blk_part_switch(card, md->part_type); if (ret) { if (req) { blk_end_request_all(req, -EIO); @@ -2436,7 +2437,7 @@ static void mmc_blk_remove(struct mmc_card *card) mmc_blk_remove_parts(card, md); pm_runtime_get_sync(&card->dev); mmc_claim_host(card->host); - mmc_blk_part_switch(card, md); + mmc_blk_part_switch(card, md->part_type); mmc_release_host(card->host); if (card->type != MMC_TYPE_SD_COMBO) pm_runtime_disable(&card->dev); -- 2.9.4 ^ permalink raw reply related [flat|nested] 17+ messages in thread
* Re: [PATCH 2/5] mmc: block: Refactor mmc_blk_part_switch() 2017-06-15 12:12 ` [PATCH 2/5] mmc: block: Refactor mmc_blk_part_switch() Linus Walleij @ 2017-06-19 19:53 ` Tomas Winkler 2017-06-20 11:23 ` Linus Walleij 0 siblings, 1 reply; 17+ messages in thread From: Tomas Winkler @ 2017-06-19 19:53 UTC (permalink / raw) To: Linus Walleij Cc: linux-mmc, Ulf Hansson, linux-block, Jens Axboe, Christoph Hellwig, Arnd Bergmann, Bartlomiej Zolnierkiewicz, Paolo Valente, Avri Altman, Adrian Hunter, Tomas Winkler On Thu, Jun 15, 2017 at 3:12 PM, Linus Walleij <linus.walleij@linaro.org> wrote: > > Instead of passing a struct mmc_blk_data * to mmc_blk_part_switch() > let's pass the actual partition type we want to switch to. This > is necessary in order not to have a block device with a backing > mmc_blk_data and request queue and all for every hardware partition, > such as RPMB. > > Signed-off-by: Linus Walleij <linus.walleij@linaro.org> > --- > drivers/mmc/core/block.c | 25 +++++++++++++------------ > 1 file changed, 13 insertions(+), 12 deletions(-) > > diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c > index d1b824e65590..94b97f97be1a 100644 > --- a/drivers/mmc/core/block.c > +++ b/drivers/mmc/core/block.c > @@ -127,7 +127,7 @@ module_param(perdev_minors, int, 0444); > MODULE_PARM_DESC(perdev_minors, "Minors numbers to allocate per device"); > > static inline int mmc_blk_part_switch(struct mmc_card *card, > - struct mmc_blk_data *md); > + unsigned int part_type); Maybe it's time to change this misleading 'part_type' name, this a bit that represent the actual partition to access and not a type of an partition. Maybe part_to_access will more reflect the spec wording. Need to change also in mmc_blk_data; > > > static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk) > { > @@ -490,7 +490,7 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md, > > mrq.cmd = &cmd; > > - err = mmc_blk_part_switch(card, md); > + err = mmc_blk_part_switch(card, md->part_type); > if (err) > return err; > > @@ -767,29 +767,29 @@ static int mmc_blk_part_switch_post(struct mmc_card *card, > } > > static inline int mmc_blk_part_switch(struct mmc_card *card, > - struct mmc_blk_data *md) > + unsigned int part_type) > { > int ret = 0; > struct mmc_blk_data *main_md = dev_get_drvdata(&card->dev); > > - if (main_md->part_curr == md->part_type) > + if (main_md->part_curr == part_type) > return 0; > > if (mmc_card_mmc(card)) { > u8 part_config = card->ext_csd.part_config; > > - ret = mmc_blk_part_switch_pre(card, md->part_type); > + ret = mmc_blk_part_switch_pre(card, part_type); > if (ret) > return ret; > > part_config &= ~EXT_CSD_PART_CONFIG_ACC_MASK; > - part_config |= md->part_type; > + part_config |= part_type; > > ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, > EXT_CSD_PART_CONFIG, part_config, > card->ext_csd.part_time); > if (ret) { > - mmc_blk_part_switch_post(card, md->part_type); > + mmc_blk_part_switch_post(card, part_type); > return ret; > } > > @@ -798,7 +798,7 @@ static inline int mmc_blk_part_switch(struct mmc_card *card, > ret = mmc_blk_part_switch_post(card, main_md->part_curr); > } > > - main_md->part_curr = md->part_type; > + main_md->part_curr = part_type; > return ret; > } > > @@ -1141,7 +1141,7 @@ static int mmc_blk_reset(struct mmc_blk_data *md, struct mmc_host *host, > int part_err; > > main_md->part_curr = main_md->part_type; > - part_err = mmc_blk_part_switch(host->card, md); > + part_err = mmc_blk_part_switch(host->card, md->part_type); > if (part_err) { > /* > * We have failed to get back into the correct > @@ -1180,6 +1180,7 @@ static void mmc_blk_issue_drv_op(struct mmc_queue *mq, struct request *req) > struct mmc_queue_req *mq_rq; > struct mmc_card *card = mq->card; > struct mmc_blk_data *md = mq->blkdata; > + struct mmc_blk_data *main_md = dev_get_drvdata(&card->dev); Doesn't apply here, maybe need rebase over next or I'm missing some patches. > struct mmc_blk_ioc_data **idata; > u8 **ext_csd; > u32 status; > @@ -1198,7 +1199,7 @@ static void mmc_blk_issue_drv_op(struct mmc_queue *mq, struct request *req) > } > /* Always switch back to main area after RPMB access */ > if (md->area_type & MMC_BLK_DATA_AREA_RPMB) > - mmc_blk_part_switch(card, dev_get_drvdata(&card->dev)); > + mmc_blk_part_switch(card, main_md->part_type); Actually this switch back should be probably done for any partition which is not user data area. so this should be if (md->area_type != MMC_BLK_DATA_AREA_MAIN) > break; > case MMC_DRV_OP_BOOT_WP: > ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_WP, > @@ -1906,7 +1907,7 @@ void mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) > /* claim host only for the first request */ > mmc_get_card(card); > > - ret = mmc_blk_part_switch(card, md); > + ret = mmc_blk_part_switch(card, md->part_type); > if (ret) { > if (req) { > blk_end_request_all(req, -EIO); > @@ -2436,7 +2437,7 @@ static void mmc_blk_remove(struct mmc_card *card) > mmc_blk_remove_parts(card, md); > pm_runtime_get_sync(&card->dev); > mmc_claim_host(card->host); > - mmc_blk_part_switch(card, md); > + mmc_blk_part_switch(card, md->part_type); > mmc_release_host(card->host); > if (card->type != MMC_TYPE_SD_COMBO) > pm_runtime_disable(&card->dev); > -- > 2.9.4 > > -- > To unsubscribe from this list: send the line "unsubscribe linux-mmc" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 2/5] mmc: block: Refactor mmc_blk_part_switch() 2017-06-19 19:53 ` Tomas Winkler @ 2017-06-20 11:23 ` Linus Walleij 0 siblings, 0 replies; 17+ messages in thread From: Linus Walleij @ 2017-06-20 11:23 UTC (permalink / raw) To: Tomas Winkler Cc: linux-mmc@vger.kernel.org, Ulf Hansson, linux-block, Jens Axboe, Christoph Hellwig, Arnd Bergmann, Bartlomiej Zolnierkiewicz, Paolo Valente, Avri Altman, Adrian Hunter, Tomas Winkler On Mon, Jun 19, 2017 at 9:53 PM, Tomas Winkler <tomasw@gmail.com> wrote: > On Thu, Jun 15, 2017 at 3:12 PM, Linus Walleij <linus.walleij@linaro.org> wrote: >> >> Instead of passing a struct mmc_blk_data * to mmc_blk_part_switch() >> let's pass the actual partition type we want to switch to. This >> is necessary in order not to have a block device with a backing >> mmc_blk_data and request queue and all for every hardware partition, >> such as RPMB. >> >> Signed-off-by: Linus Walleij <linus.walleij@linaro.org> >> --- >> drivers/mmc/core/block.c | 25 +++++++++++++------------ >> 1 file changed, 13 insertions(+), 12 deletions(-) >> >> diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c >> index d1b824e65590..94b97f97be1a 100644 >> --- a/drivers/mmc/core/block.c >> +++ b/drivers/mmc/core/block.c >> @@ -127,7 +127,7 @@ module_param(perdev_minors, int, 0444); >> MODULE_PARM_DESC(perdev_minors, "Minors numbers to allocate per device"); >> >> static inline int mmc_blk_part_switch(struct mmc_card *card, >> - struct mmc_blk_data *md); >> + unsigned int part_type); > > Maybe it's time to change this misleading 'part_type' name, this a bit > that represent the actual partition to > access and not a type of an partition. Maybe part_to_access will more > reflect the spec wording. > Need to change also in mmc_blk_data; That would be a separate patch I think (one patch, one technical step) what about target_partition or something? >> /* Always switch back to main area after RPMB access */ >> if (md->area_type & MMC_BLK_DATA_AREA_RPMB) >> - mmc_blk_part_switch(card, dev_get_drvdata(&card->dev)); >> + mmc_blk_part_switch(card, main_md->part_type); > > Actually this switch back should be probably done for any partition > which is not user data area. > so this should be > if (md->area_type != MMC_BLK_DATA_AREA_MAIN) That is another technical step so it should be a separate patch as well. Actually I think this code is broken in several ways, especially if you do something crazy like access the main partition, both boot partitions and the RPMB partition at the same time. It will invariably screw something up. I am trying to rework this to use the block layer properly, RPMB is just the first step... Yours, Linus Walleij ^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 3/5] mmc: block: Reparametrize mmc_blk_ioctl_[multi]_cmd() 2017-06-15 12:12 [PATCH 0/5] Convert RPMB block device to a character device Linus Walleij 2017-06-15 12:12 ` [PATCH 1/5] mmc: block: Move duplicate check Linus Walleij 2017-06-15 12:12 ` [PATCH 2/5] mmc: block: Refactor mmc_blk_part_switch() Linus Walleij @ 2017-06-15 12:12 ` Linus Walleij 2017-06-19 20:12 ` Tomas Winkler 2017-06-15 12:12 ` [PATCH 4/5] RFC: mmc: block: Convert RPMB to a character device Linus Walleij 2017-06-15 12:12 ` [PATCH 5/5] mmc: block: Delete mmc_access_rpmb() Linus Walleij 4 siblings, 1 reply; 17+ messages in thread From: Linus Walleij @ 2017-06-15 12:12 UTC (permalink / raw) To: linux-mmc, Ulf Hansson Cc: linux-block, Jens Axboe, Christoph Hellwig, Arnd Bergmann, Bartlomiej Zolnierkiewicz, Paolo Valente, Avri Altman, Adrian Hunter, Linus Walleij Instead of passing a block device to mmc_blk_ioctl[_multi]_cmd(), let's pass struct mmc_blk_data() so we operate ioctl()s on the MMC block device representation rather than the vanilla block device. This saves a little duplicated code and makes it possible to issue ioctl()s not targeted for a specific block device but rather for a specific partition/area. Signed-off-by: Linus Walleij <linus.walleij@linaro.org> --- drivers/mmc/core/block.c | 43 ++++++++++++++++++------------------------- 1 file changed, 18 insertions(+), 25 deletions(-) diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index 94b97f97be1a..b8c71fdb6ed4 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -555,12 +555,11 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md, return err; } -static int mmc_blk_ioctl_cmd(struct block_device *bdev, +static int mmc_blk_ioctl_cmd(struct mmc_blk_data *md, struct mmc_ioc_cmd __user *ic_ptr) { struct mmc_blk_ioc_data *idata; struct mmc_blk_ioc_data *idatas[1]; - struct mmc_blk_data *md; struct mmc_queue *mq; struct mmc_card *card; int err = 0, ioc_err = 0; @@ -570,12 +569,6 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev, if (IS_ERR(idata)) return PTR_ERR(idata); - md = mmc_blk_get(bdev->bd_disk); - if (!md) { - err = -EINVAL; - goto cmd_err; - } - card = md->queue.card; if (IS_ERR(card)) { err = PTR_ERR(card); @@ -599,20 +592,17 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev, blk_put_request(req); cmd_done: - mmc_blk_put(md); -cmd_err: kfree(idata->buf); kfree(idata); return ioc_err ? ioc_err : err; } -static int mmc_blk_ioctl_multi_cmd(struct block_device *bdev, +static int mmc_blk_ioctl_multi_cmd(struct mmc_blk_data *md, struct mmc_ioc_multi_cmd __user *user) { struct mmc_blk_ioc_data **idata = NULL; struct mmc_ioc_cmd __user *cmds = user->cmds; struct mmc_card *card; - struct mmc_blk_data *md; struct mmc_queue *mq; int i, err = 0, ioc_err = 0; __u64 num_of_cmds; @@ -638,16 +628,10 @@ static int mmc_blk_ioctl_multi_cmd(struct block_device *bdev, } } - md = mmc_blk_get(bdev->bd_disk); - if (!md) { - err = -EINVAL; - goto cmd_err; - } - card = md->queue.card; if (IS_ERR(card)) { err = PTR_ERR(card); - goto cmd_done; + goto cmd_err; } @@ -670,8 +654,6 @@ static int mmc_blk_ioctl_multi_cmd(struct block_device *bdev, blk_put_request(req); -cmd_done: - mmc_blk_put(md); cmd_err: for (i = 0; i < num_of_cmds; i++) { kfree(idata[i]->buf); @@ -696,6 +678,7 @@ static int mmc_blk_check_blkdev(struct block_device *bdev) static int mmc_blk_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, unsigned long arg) { + struct mmc_blk_data *md; int ret; switch (cmd) { @@ -703,14 +686,24 @@ static int mmc_blk_ioctl(struct block_device *bdev, fmode_t mode, ret = mmc_blk_check_blkdev(bdev); if (ret) return ret; - return mmc_blk_ioctl_cmd(bdev, - (struct mmc_ioc_cmd __user *)arg); + md = mmc_blk_get(bdev->bd_disk); + if (!md) + return -EINVAL; + ret = mmc_blk_ioctl_cmd(md, + (struct mmc_ioc_cmd __user *)arg); + mmc_blk_put(md); + return ret; case MMC_IOC_MULTI_CMD: ret = mmc_blk_check_blkdev(bdev); if (ret) return ret; - return mmc_blk_ioctl_multi_cmd(bdev, - (struct mmc_ioc_multi_cmd __user *)arg); + md = mmc_blk_get(bdev->bd_disk); + if (!md) + return -EINVAL; + ret = mmc_blk_ioctl_multi_cmd(md, + (struct mmc_ioc_multi_cmd __user *)arg); + mmc_blk_put(md); + return ret; default: return -EINVAL; } -- 2.9.4 ^ permalink raw reply related [flat|nested] 17+ messages in thread
* Re: [PATCH 3/5] mmc: block: Reparametrize mmc_blk_ioctl_[multi]_cmd() 2017-06-15 12:12 ` [PATCH 3/5] mmc: block: Reparametrize mmc_blk_ioctl_[multi]_cmd() Linus Walleij @ 2017-06-19 20:12 ` Tomas Winkler 0 siblings, 0 replies; 17+ messages in thread From: Tomas Winkler @ 2017-06-19 20:12 UTC (permalink / raw) To: Linus Walleij Cc: linux-mmc, Ulf Hansson, linux-block, Jens Axboe, Christoph Hellwig, Arnd Bergmann, Bartlomiej Zolnierkiewicz, Paolo Valente, Avri Altman, Adrian Hunter, Tomas Winkler > Instead of passing a block device to > mmc_blk_ioctl[_multi]_cmd(), let's pass struct mmc_blk_data() > so we operate ioctl()s on the MMC block device representation > rather than the vanilla block device. > > This saves a little duplicated code and makes it possible to > issue ioctl()s not targeted for a specific block device but > rather for a specific partition/area. > > Signed-off-by: Linus Walleij <linus.walleij@linaro.org> > --- > drivers/mmc/core/block.c | 43 ++++++++++++++++++------------------------- > 1 file changed, 18 insertions(+), 25 deletions(-) > > diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c > index 94b97f97be1a..b8c71fdb6ed4 100644 > --- a/drivers/mmc/core/block.c > +++ b/drivers/mmc/core/block.c > @@ -555,12 +555,11 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md, > return err; > } > > -static int mmc_blk_ioctl_cmd(struct block_device *bdev, > +static int mmc_blk_ioctl_cmd(struct mmc_blk_data *md, > struct mmc_ioc_cmd __user *ic_ptr) > { > struct mmc_blk_ioc_data *idata; > struct mmc_blk_ioc_data *idatas[1]; > - struct mmc_blk_data *md; > struct mmc_queue *mq; > struct mmc_card *card; > int err = 0, ioc_err = 0; > @@ -570,12 +569,6 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev, > if (IS_ERR(idata)) > return PTR_ERR(idata); > > - md = mmc_blk_get(bdev->bd_disk); > - if (!md) { > - err = -EINVAL; > - goto cmd_err; > - } > - > card = md->queue.card; > if (IS_ERR(card)) { > err = PTR_ERR(card); > @@ -599,20 +592,17 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev, > blk_put_request(req); > > cmd_done: > - mmc_blk_put(md); > -cmd_err: > kfree(idata->buf); > kfree(idata); > return ioc_err ? ioc_err : err; > } > > -static int mmc_blk_ioctl_multi_cmd(struct block_device *bdev, > +static int mmc_blk_ioctl_multi_cmd(struct mmc_blk_data *md, > struct mmc_ioc_multi_cmd __user *user) > { > struct mmc_blk_ioc_data **idata = NULL; > struct mmc_ioc_cmd __user *cmds = user->cmds; > struct mmc_card *card; > - struct mmc_blk_data *md; > struct mmc_queue *mq; > int i, err = 0, ioc_err = 0; > __u64 num_of_cmds; > @@ -638,16 +628,10 @@ static int mmc_blk_ioctl_multi_cmd(struct block_device *bdev, > } > } > > - md = mmc_blk_get(bdev->bd_disk); > - if (!md) { > - err = -EINVAL; > - goto cmd_err; > - } > - > card = md->queue.card; > if (IS_ERR(card)) { > err = PTR_ERR(card); > - goto cmd_done; > + goto cmd_err; > } > > > @@ -670,8 +654,6 @@ static int mmc_blk_ioctl_multi_cmd(struct block_device *bdev, > > blk_put_request(req); > > -cmd_done: > - mmc_blk_put(md); > cmd_err: > for (i = 0; i < num_of_cmds; i++) { > kfree(idata[i]->buf); > @@ -696,6 +678,7 @@ static int mmc_blk_check_blkdev(struct block_device *bdev) > static int mmc_blk_ioctl(struct block_device *bdev, fmode_t mode, > unsigned int cmd, unsigned long arg) > { > + struct mmc_blk_data *md; > int ret; > > switch (cmd) { > @@ -703,14 +686,24 @@ static int mmc_blk_ioctl(struct block_device *bdev, fmode_t mode, > ret = mmc_blk_check_blkdev(bdev); > if (ret) > return ret; > - return mmc_blk_ioctl_cmd(bdev, > - (struct mmc_ioc_cmd __user *)arg); > + md = mmc_blk_get(bdev->bd_disk); > + if (!md) > + return -EINVAL; > + ret = mmc_blk_ioctl_cmd(md, > + (struct mmc_ioc_cmd __user *)arg); No need to break the line here, ... I would just cast it inside the handler. > + mmc_blk_put(md); > + return ret; > case MMC_IOC_MULTI_CMD: > ret = mmc_blk_check_blkdev(bdev); > if (ret) > return ret; > - return mmc_blk_ioctl_multi_cmd(bdev, > - (struct mmc_ioc_multi_cmd __user *)arg); > + md = mmc_blk_get(bdev->bd_disk); > + if (!md) > + return -EINVAL; > + ret = mmc_blk_ioctl_multi_cmd(md, > + (struct mmc_ioc_multi_cmd __user *)arg); > + mmc_blk_put(md); > + return ret; > default: > return -EINVAL; > } > -- > 2.9.4 > Looks, okay from my side. ^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 4/5] RFC: mmc: block: Convert RPMB to a character device 2017-06-15 12:12 [PATCH 0/5] Convert RPMB block device to a character device Linus Walleij ` (2 preceding siblings ...) 2017-06-15 12:12 ` [PATCH 3/5] mmc: block: Reparametrize mmc_blk_ioctl_[multi]_cmd() Linus Walleij @ 2017-06-15 12:12 ` Linus Walleij 2017-06-16 7:22 ` Avri Altman ` (2 more replies) 2017-06-15 12:12 ` [PATCH 5/5] mmc: block: Delete mmc_access_rpmb() Linus Walleij 4 siblings, 3 replies; 17+ messages in thread From: Linus Walleij @ 2017-06-15 12:12 UTC (permalink / raw) To: linux-mmc, Ulf Hansson Cc: linux-block, Jens Axboe, Christoph Hellwig, Arnd Bergmann, Bartlomiej Zolnierkiewicz, Paolo Valente, Avri Altman, Adrian Hunter, Linus Walleij The RPMB partition on the eMMC devices is a special area used for storing cryptographically safe information signed by a special secret key. To write and read records from this special area, authentication is needed. The RPMB area is *only* and *exclusively* accessed using ioctl():s from userspace. It is not really a block device, as blocks cannot be read or written from the device, also the signed chunks that can be stored on the RPMB are actually 256 bytes, not 512 making a block device a real bad fit. Currently the RPMB partition spawns a separate block device named /dev/mmcblkNrpmb for each device with an RPMB partition, including the creation of a block queue with its own kernel thread and all overhead associated with this. On the Ux500 HREFv60 platform, for example, the two eMMCs means that two block queues with separate threads are created for no use whatsoever. I have concluded that this block device design for RPMB is actually pretty wrong. The RPMB area should have been designed to be accessed from /dev/mmcblkN directly, using ioctl()s on the main block device. It is however way too late to change that, since userspace expects to open an RPMB device in /dev/mmcblkNrpmb and we cannot break userspace. This patch tries to amend the situation using the following strategy: - Stop creating a block device for the RPMB partition/area - Instead create a custom, dynamic character device with the same name. - Make this new character device support exactly the same set of ioctl()s as the old block device. - Wrap the requests back to the same ioctl() handlers, but issue them on the block queue of the main partition/area, i.e. /dev/mmcblkN We need to create a special "rpmb" bus type in order to get udev and/or busybox hot/coldplug to instantiate the device node properly. Before the patch, this appears in 'ps aux': 101 root 0:00 [mmcqd/2rpmb] 123 root 0:00 [mmcqd/3rpmb] After applying the patch these surplus block queue threads are gone, but RPMB is as usable as ever using the userspace MMC tools, such as 'mmc rpmb read-counter'. We get instead those dynamice devices in /dev: brw-rw---- 1 root root 179, 0 Jan 1 2000 mmcblk0 brw-rw---- 1 root root 179, 1 Jan 1 2000 mmcblk0p1 brw-rw---- 1 root root 179, 2 Jan 1 2000 mmcblk0p2 brw-rw---- 1 root root 179, 5 Jan 1 2000 mmcblk0p5 brw-rw---- 1 root root 179, 8 Jan 1 2000 mmcblk2 brw-rw---- 1 root root 179, 16 Jan 1 2000 mmcblk2boot0 brw-rw---- 1 root root 179, 24 Jan 1 2000 mmcblk2boot1 crw-rw---- 1 root root 248, 0 Jan 1 2000 mmcblk2rpmb brw-rw---- 1 root root 179, 32 Jan 1 2000 mmcblk3 brw-rw---- 1 root root 179, 40 Jan 1 2000 mmcblk3boot0 brw-rw---- 1 root root 179, 48 Jan 1 2000 mmcblk3boot1 brw-rw---- 1 root root 179, 33 Jan 1 2000 mmcblk3p1 crw-rw---- 1 root root 248, 1 Jan 1 2000 mmcblk3rpmb Notice the (248,0) and (248,1) character devices for RPMB. Tomas Winkler <tomas.winkler@intel.com> Signed-off-by: Linus Walleij <linus.walleij@linaro.org> --- Some discussion points: I am aware of Tomas Winklers attempts to make RPMB handling into its own subsystem. I have no such ambitions whatsoever, I am only trying to sensibly accomodate what we already have and handle our RPMB in a way that is not littering the place with weirdo block devices. The patch is a lot of "that should have been done differently from the outset" and "it is not a perfect solution", I'd appreciate if you take a look at the kernel before and after this patch and think of it as a path forward, are things better or worse like this, thinking toward the future. I guess it would be nicer if I could (from the KERNEL) create a symlink from mmcblk2rpmb -> mmcblk2 or a second mknod creating mmcblk2rpmb with the same major/minor numbers as the main device. I guess that can be done with udev scripts, but that breaks all setups with old udev scripts, busybox, Android etc. So creating a proper device seems necessary to satisfy userspace. I haven't been able to do much testing as my RPMB-capable device seems to be failing to do anything sensible, but I atleast get the same error codes from "mmc rpmb read-counter /deb/mmcblkNrpmb" before/after the patch. --- drivers/mmc/core/block.c | 278 +++++++++++++++++++++++++++++++++++++++++++---- drivers/mmc/core/queue.h | 2 + 2 files changed, 256 insertions(+), 24 deletions(-) diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index b8c71fdb6ed4..0a226bc23429 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -28,6 +28,7 @@ #include <linux/hdreg.h> #include <linux/kdev_t.h> #include <linux/blkdev.h> +#include <linux/cdev.h> #include <linux/mutex.h> #include <linux/scatterlist.h> #include <linux/string_helpers.h> @@ -86,6 +87,7 @@ static int max_devices; #define MAX_DEVICES 256 static DEFINE_IDA(mmc_blk_ida); +static DEFINE_IDA(mmc_rpmb_ida); /* * There is one mmc_blk_data per slot. @@ -96,6 +98,7 @@ struct mmc_blk_data { struct gendisk *disk; struct mmc_queue queue; struct list_head part; + struct list_head rpmbs; unsigned int flags; #define MMC_BLK_CMD23 (1 << 0) /* Can do SET_BLOCK_COUNT for multiblock */ @@ -121,6 +124,30 @@ struct mmc_blk_data { int area_type; }; +/* Device type for RPMB character devices */ +static dev_t rpmb_devt; + +/* Bus type for RPMB character devices */ +static struct bus_type rpmb_bus_type = { + .name = "rpmb", +}; + +/** + * struct mmc_rpmb_data - special RPMB device type for these areas + * @dev: the device for the RPMB area + * @chrdev: character device for the RPMB area + * @id: unique device ID number + * @md: parent MMC block device + * @node: list item, so we can put this device on a list + */ +struct mmc_rpmb_data { + struct device dev; + struct cdev chrdev; + int id; + struct mmc_blk_data *md; + struct list_head node; +}; + static DEFINE_MUTEX(open_lock); module_param(perdev_minors, int, 0444); @@ -432,21 +459,29 @@ static int ioctl_do_sanitize(struct mmc_card *card) } static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md, - struct mmc_blk_ioc_data *idata) + struct mmc_blk_ioc_data *idata, bool rpmb_ioctl) { struct mmc_command cmd = {}; struct mmc_data data = {}; struct mmc_request mrq = {}; struct scatterlist sg; int err; - bool is_rpmb = false; + unsigned int target_part; u32 status = 0; if (!card || !md || !idata) return -EINVAL; - if (md->area_type & MMC_BLK_DATA_AREA_RPMB) - is_rpmb = true; + /* + * The RPMB accesses comes in from the character device, so we + * need to target these explicitly. Else we just target the + * partition type for the block device the ioctl() was issued + * on. + */ + if (rpmb_ioctl) + target_part = EXT_CSD_PART_CONFIG_ACC_RPMB; + else + target_part = md->part_type; cmd.opcode = idata->ic.opcode; cmd.arg = idata->ic.arg; @@ -490,7 +525,7 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md, mrq.cmd = &cmd; - err = mmc_blk_part_switch(card, md->part_type); + err = mmc_blk_part_switch(card, target_part); if (err) return err; @@ -500,7 +535,7 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md, return err; } - if (is_rpmb) { + if (rpmb_ioctl) { err = mmc_set_blockcount(card, data.blocks, idata->ic.write_flag & (1 << 31)); if (err) @@ -540,7 +575,7 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md, memcpy(&(idata->ic.response), cmd.resp, sizeof(cmd.resp)); - if (is_rpmb) { + if (rpmb_ioctl) { /* * Ensure RPMB command has completed by polling CMD13 * "Send Status". @@ -556,7 +591,8 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md, } static int mmc_blk_ioctl_cmd(struct mmc_blk_data *md, - struct mmc_ioc_cmd __user *ic_ptr) + struct mmc_ioc_cmd __user *ic_ptr, + bool rpmb_ioctl) { struct mmc_blk_ioc_data *idata; struct mmc_blk_ioc_data *idatas[1]; @@ -583,7 +619,10 @@ static int mmc_blk_ioctl_cmd(struct mmc_blk_data *md, idata->ic.write_flag ? REQ_OP_DRV_OUT : REQ_OP_DRV_IN, __GFP_RECLAIM); idatas[0] = idata; - req_to_mmc_queue_req(req)->drv_op = MMC_DRV_OP_IOCTL; + if (rpmb_ioctl) + req_to_mmc_queue_req(req)->drv_op = MMC_DRV_OP_IOCTL_RPMB; + else + req_to_mmc_queue_req(req)->drv_op = MMC_DRV_OP_IOCTL; req_to_mmc_queue_req(req)->drv_op_data = idatas; req_to_mmc_queue_req(req)->ioc_count = 1; blk_execute_rq(mq->queue, NULL, req, 0); @@ -598,7 +637,8 @@ static int mmc_blk_ioctl_cmd(struct mmc_blk_data *md, } static int mmc_blk_ioctl_multi_cmd(struct mmc_blk_data *md, - struct mmc_ioc_multi_cmd __user *user) + struct mmc_ioc_multi_cmd __user *user, + bool rpmb_ioctl) { struct mmc_blk_ioc_data **idata = NULL; struct mmc_ioc_cmd __user *cmds = user->cmds; @@ -642,7 +682,10 @@ static int mmc_blk_ioctl_multi_cmd(struct mmc_blk_data *md, req = blk_get_request(mq->queue, idata[0]->ic.write_flag ? REQ_OP_DRV_OUT : REQ_OP_DRV_IN, __GFP_RECLAIM); - req_to_mmc_queue_req(req)->drv_op = MMC_DRV_OP_IOCTL; + if (rpmb_ioctl) + req_to_mmc_queue_req(req)->drv_op = MMC_DRV_OP_IOCTL_RPMB; + else + req_to_mmc_queue_req(req)->drv_op = MMC_DRV_OP_IOCTL; req_to_mmc_queue_req(req)->drv_op_data = idata; req_to_mmc_queue_req(req)->ioc_count = num_of_cmds; blk_execute_rq(mq->queue, NULL, req, 0); @@ -690,7 +733,8 @@ static int mmc_blk_ioctl(struct block_device *bdev, fmode_t mode, if (!md) return -EINVAL; ret = mmc_blk_ioctl_cmd(md, - (struct mmc_ioc_cmd __user *)arg); + (struct mmc_ioc_cmd __user *)arg, + false); mmc_blk_put(md); return ret; case MMC_IOC_MULTI_CMD: @@ -701,7 +745,8 @@ static int mmc_blk_ioctl(struct block_device *bdev, fmode_t mode, if (!md) return -EINVAL; ret = mmc_blk_ioctl_multi_cmd(md, - (struct mmc_ioc_multi_cmd __user *)arg); + (struct mmc_ioc_multi_cmd __user *)arg, + false); mmc_blk_put(md); return ret; default: @@ -1173,26 +1218,29 @@ static void mmc_blk_issue_drv_op(struct mmc_queue *mq, struct request *req) struct mmc_queue_req *mq_rq; struct mmc_card *card = mq->card; struct mmc_blk_data *md = mq->blkdata; - struct mmc_blk_data *main_md = dev_get_drvdata(&card->dev); struct mmc_blk_ioc_data **idata; + bool rpmb_ioctl; u8 **ext_csd; u32 status; int ret; int i; mq_rq = req_to_mmc_queue_req(req); + rpmb_ioctl = (mq_rq->drv_op == MMC_DRV_OP_IOCTL_RPMB); switch (mq_rq->drv_op) { case MMC_DRV_OP_IOCTL: + case MMC_DRV_OP_IOCTL_RPMB: idata = mq_rq->drv_op_data; for (i = 0; i < mq_rq->ioc_count; i++) { - ret = __mmc_blk_ioctl_cmd(card, md, idata[i]); + ret = __mmc_blk_ioctl_cmd(card, md, idata[i], + rpmb_ioctl); if (ret) break; } /* Always switch back to main area after RPMB access */ - if (md->area_type & MMC_BLK_DATA_AREA_RPMB) - mmc_blk_part_switch(card, main_md->part_type); + if (rpmb_ioctl) + mmc_blk_part_switch(card, 0); break; case MMC_DRV_OP_BOOT_WP: ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_WP, @@ -2006,6 +2054,7 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card, spin_lock_init(&md->lock); INIT_LIST_HEAD(&md->part); + INIT_LIST_HEAD(&md->rpmbs); md->usage = 1; ret = mmc_init_queue(&md->queue, card, &md->lock, subname); @@ -2124,6 +2173,151 @@ static int mmc_blk_alloc_part(struct mmc_card *card, return 0; } +/** + * rpmb_ioctl() - ioctl handler for the RPMB chardev + * @filp: the character device file + * @cmd: the ioctl() command + * @arg: the argument from userspace + * + * This will essentially just redirect the ioctl()s coming in over to + * the main block device spawning the RPMB character device. + */ +static long rpmb_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + struct mmc_rpmb_data *rpmb = filp->private_data; + int ret; + + switch (cmd) { + case MMC_IOC_CMD: + ret = mmc_blk_ioctl_cmd(rpmb->md, + (struct mmc_ioc_cmd __user *)arg, + true); + break; + case MMC_IOC_MULTI_CMD: + ret = mmc_blk_ioctl_multi_cmd(rpmb->md, + (struct mmc_ioc_multi_cmd __user *)arg, + true); + break; + default: + ret = -EINVAL; + break; + } + + return 0; +} + +#ifdef CONFIG_COMPAT +static long rpmb_ioctl_compat(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + return rpmb_ioctl(filp, cmd, (unsigned long)compat_ptr(arg)); +} +#endif + +static int rpmb_chrdev_open(struct inode *inode, struct file *filp) +{ + struct mmc_rpmb_data *rpmb = container_of(inode->i_cdev, + struct mmc_rpmb_data, chrdev); + + get_device(&rpmb->dev); + filp->private_data = rpmb; + mutex_lock(&open_lock); + rpmb->md->usage++; + mutex_unlock(&open_lock); + + return nonseekable_open(inode, filp); +} + +static int rpmb_chrdev_release(struct inode *inode, struct file *filp) +{ + struct mmc_rpmb_data *rpmb = container_of(inode->i_cdev, + struct mmc_rpmb_data, chrdev); + + put_device(&rpmb->dev); + mutex_lock(&open_lock); + rpmb->md->usage--; + mutex_unlock(&open_lock); + + return 0; +} + +static const struct file_operations rpmb_fileops = { + .release = rpmb_chrdev_release, + .open = rpmb_chrdev_open, + .owner = THIS_MODULE, + .llseek = no_llseek, + .unlocked_ioctl = rpmb_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = rpmb_ioctl_compat, +#endif +}; + + +static int mmc_blk_alloc_rpmb_part(struct mmc_card *card, + struct mmc_blk_data *md, + sector_t size, + const char *subname) +{ + int devidx, ret; + char rpmb_name[DISK_NAME_LEN]; + char cap_str[10]; + struct mmc_rpmb_data *rpmb; + + /* This creates the minor number for the RPMB char device */ + devidx = ida_simple_get(&mmc_rpmb_ida, 0, max_devices, GFP_KERNEL); + if (devidx < 0) + return devidx; + + rpmb = kzalloc(sizeof(*rpmb), GFP_KERNEL); + if (!rpmb) + return -ENOMEM; + + snprintf(rpmb_name, sizeof(rpmb_name), + "mmcblk%u%s", card->host->index, subname ? subname : ""); + + rpmb->id = devidx; + rpmb->dev.init_name = rpmb_name; + rpmb->dev.bus = &rpmb_bus_type; + rpmb->dev.devt = MKDEV(MAJOR(rpmb_devt), rpmb->id); + rpmb->dev.parent = &card->dev; + device_initialize(&rpmb->dev); + dev_set_drvdata(&rpmb->dev, rpmb); + rpmb->md = md; + + cdev_init(&rpmb->chrdev, &rpmb_fileops); + rpmb->chrdev.owner = THIS_MODULE; + ret = cdev_device_add(&rpmb->chrdev, &rpmb->dev); + if (ret) { + pr_err("%s: could not add character device\n", rpmb_name); + goto out_remove_ida; + } + + list_add(&rpmb->node, &md->rpmbs); + + string_get_size((u64)size, 512, STRING_UNITS_2, + cap_str, sizeof(cap_str)); + + pr_info("%s: %s %s partition %u %s, chardev (%d:%d)\n", + rpmb_name, mmc_card_id(card), + mmc_card_name(card), EXT_CSD_PART_CONFIG_ACC_RPMB, cap_str, + MAJOR(rpmb_devt), rpmb->id); + + return 0; + +out_remove_ida: + ida_simple_remove(&mmc_rpmb_ida, rpmb->id); + kfree(rpmb); + return ret; +} + +static void mmc_blk_remove_rpmb_part(struct mmc_rpmb_data *rpmb) +{ + cdev_device_del(&rpmb->chrdev, &rpmb->dev); + device_del(&rpmb->dev); + ida_simple_remove(&mmc_rpmb_ida, rpmb->id); + kfree(rpmb); +} + /* MMC Physical partitions consist of two boot partitions and * up to four general purpose partitions. * For each partition enabled in EXT_CSD a block device will be allocatedi @@ -2132,13 +2326,25 @@ static int mmc_blk_alloc_part(struct mmc_card *card, static int mmc_blk_alloc_parts(struct mmc_card *card, struct mmc_blk_data *md) { - int idx, ret = 0; + int idx, ret; if (!mmc_card_mmc(card)) return 0; for (idx = 0; idx < card->nr_parts; idx++) { - if (card->part[idx].size) { + if (card->part[idx].area_type & MMC_BLK_DATA_AREA_RPMB) { + /* + * RPMB partitions does not provide block access, they + * are only accessed using ioctl():s. Thus create + * special RPMB block devices that do not have a + * backing block queue for these. + */ + ret = mmc_blk_alloc_rpmb_part(card, md, + card->part[idx].size >> 9, + card->part[idx].name); + if (ret) + return ret; + } else if (card->part[idx].size) { ret = mmc_blk_alloc_part(card, md, card->part[idx].part_cfg, card->part[idx].size >> 9, @@ -2150,7 +2356,7 @@ static int mmc_blk_alloc_parts(struct mmc_card *card, struct mmc_blk_data *md) } } - return ret; + return 0; } static void mmc_blk_remove_req(struct mmc_blk_data *md) @@ -2183,7 +2389,15 @@ static void mmc_blk_remove_parts(struct mmc_card *card, { struct list_head *pos, *q; struct mmc_blk_data *part_md; + struct mmc_rpmb_data *rpmb; + /* Remove RPMB partitions */ + list_for_each_safe(pos, q, &md->rpmbs) { + rpmb = list_entry(pos, struct mmc_rpmb_data, node); + list_del(pos); + mmc_blk_remove_rpmb_part(rpmb); + } + /* Remove block partitions */ list_for_each_safe(pos, q, &md->part) { part_md = list_entry(pos, struct mmc_blk_data, part); list_del(pos); @@ -2502,6 +2716,17 @@ static int __init mmc_blk_init(void) { int res; + res = bus_register(&rpmb_bus_type); + if (res < 0) { + pr_err("mmcblk: could not register RPMB bus type\n"); + return res; + } + res = alloc_chrdev_region(&rpmb_devt, 0, MAX_DEVICES, "rpmb"); + if (res < 0) { + pr_err("mmcblk: failed to allocate rpmb chrdev region\n"); + goto out_bus_unreg; + } + if (perdev_minors != CONFIG_MMC_BLOCK_MINORS) pr_info("mmcblk: using %d minors per device\n", perdev_minors); @@ -2509,16 +2734,20 @@ static int __init mmc_blk_init(void) res = register_blkdev(MMC_BLOCK_MAJOR, "mmc"); if (res) - goto out; + goto out_chrdev_unreg; res = mmc_register_driver(&mmc_driver); if (res) - goto out2; + goto out_blkdev_unreg; return 0; - out2: + +out_blkdev_unreg: unregister_blkdev(MMC_BLOCK_MAJOR, "mmc"); - out: +out_chrdev_unreg: + unregister_chrdev_region(rpmb_devt, MAX_DEVICES); +out_bus_unreg: + bus_unregister(&rpmb_bus_type); return res; } @@ -2526,6 +2755,7 @@ static void __exit mmc_blk_exit(void) { mmc_unregister_driver(&mmc_driver); unregister_blkdev(MMC_BLOCK_MAJOR, "mmc"); + unregister_chrdev_region(rpmb_devt, MAX_DEVICES); } module_init(mmc_blk_init); diff --git a/drivers/mmc/core/queue.h b/drivers/mmc/core/queue.h index 04fc89360a7a..a2b6a9fcab01 100644 --- a/drivers/mmc/core/queue.h +++ b/drivers/mmc/core/queue.h @@ -35,12 +35,14 @@ struct mmc_blk_request { /** * enum mmc_drv_op - enumerates the operations in the mmc_queue_req * @MMC_DRV_OP_IOCTL: ioctl operation + * @MMC_DRV_OP_IOCTL_RPMB: RPMB-oriented ioctl operation * @MMC_DRV_OP_BOOT_WP: write protect boot partitions * @MMC_DRV_OP_GET_CARD_STATUS: get card status * @MMC_DRV_OP_GET_EXT_CSD: get the EXT CSD from an eMMC card */ enum mmc_drv_op { MMC_DRV_OP_IOCTL, + MMC_DRV_OP_IOCTL_RPMB, MMC_DRV_OP_BOOT_WP, MMC_DRV_OP_GET_CARD_STATUS, MMC_DRV_OP_GET_EXT_CSD, -- 2.9.4 ^ permalink raw reply related [flat|nested] 17+ messages in thread
* RE: [PATCH 4/5] RFC: mmc: block: Convert RPMB to a character device 2017-06-15 12:12 ` [PATCH 4/5] RFC: mmc: block: Convert RPMB to a character device Linus Walleij @ 2017-06-16 7:22 ` Avri Altman 2017-06-19 21:28 ` Tomas Winkler 2017-06-16 7:45 ` Christoph Hellwig 2017-06-19 21:18 ` Tomas Winkler 2 siblings, 1 reply; 17+ messages in thread From: Avri Altman @ 2017-06-16 7:22 UTC (permalink / raw) To: Linus Walleij, linux-mmc@vger.kernel.org, Ulf Hansson Cc: linux-block@vger.kernel.org, Jens Axboe, Christoph Hellwig, Arnd Bergmann, Bartlomiej Zolnierkiewicz, Paolo Valente, Adrian Hunter Hi, > -----Original Message----- > From: Linus Walleij [mailto:linus.walleij@linaro.org] > Sent: Thursday, June 15, 2017 3:13 PM > To: linux-mmc@vger.kernel.org; Ulf Hansson <ulf.hansson@linaro.org> > Cc: linux-block@vger.kernel.org; Jens Axboe <axboe@kernel.dk>; Christoph > Hellwig <hch@lst.de>; Arnd Bergmann <arnd@arndb.de>; Bartlomiej > Zolnierkiewicz <b.zolnierkie@samsung.com>; Paolo Valente > <paolo.valente@linaro.org>; Avri Altman <Avri.Altman@wdc.com>; Adrian > Hunter <adrian.hunter@intel.com>; Linus Walleij <linus.walleij@linaro.org= > > Subject: [PATCH 4/5] RFC: mmc: block: Convert RPMB to a character device >=20 > The RPMB partition on the eMMC devices is a special area used for storing > cryptographically safe information signed by a special secret key. To wri= te > and read records from this special area, authentication is needed. >=20 > The RPMB area is *only* and *exclusively* accessed using ioctl():s from > userspace. It is not really a block device, as blocks cannot be read or w= ritten > from the device, also the signed chunks that can be stored on the RPMB ar= e > actually > 256 bytes, not 512 making a block device a real bad fit. >=20 > Currently the RPMB partition spawns a separate block device named > /dev/mmcblkNrpmb for each device with an RPMB partition, including the > creation of a block queue with its own kernel thread and all overhead > associated with this. On the Ux500 > HREFv60 platform, for example, the two eMMCs means that two block > queues with separate threads are created for no use whatsoever. >=20 > I have concluded that this block device design for RPMB is actually prett= y > wrong. The RPMB area should have been designed to be accessed from > /dev/mmcblkN directly, using ioctl()s on the main block device. It is how= ever > way too late to change that, since userspace expects to open an RPMB > device in /dev/mmcblkNrpmb and we cannot break userspace. >=20 Not sure how much you are bound by this. Previous attempts, adopting a pragmatic approach - just added another ioctl= number, and used /dev/mmcblkN. Moreover, a designated ioctl allows to address more cleanly the rpmb-specif= ic needs, that are somehow awkward using multi_cmd. Within the context of an RFC, would be interesting to know if someone even = used /dev/mmcblkNrpmb? > Some discussion points: >=20 > I am aware of Tomas Winklers attempts to make RPMB handling into its own > subsystem. I have no such ambitions whatsoever, I am only trying to sensi= bly > accomodate what we already have and handle our RPMB in a way that is not > littering the place with weirdo block devices. I think that the key benefit of Tomas's approach, is being so comprehensive= . Thus enables pmb access of embedded block devices - mmc as well as other. Cheers, Avri ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 4/5] RFC: mmc: block: Convert RPMB to a character device 2017-06-16 7:22 ` Avri Altman @ 2017-06-19 21:28 ` Tomas Winkler 0 siblings, 0 replies; 17+ messages in thread From: Tomas Winkler @ 2017-06-19 21:28 UTC (permalink / raw) To: Avri Altman Cc: Linus Walleij, linux-mmc@vger.kernel.org, Ulf Hansson, linux-block@vger.kernel.org, Jens Axboe, Christoph Hellwig, Arnd Bergmann, Bartlomiej Zolnierkiewicz, Paolo Valente, Adrian Hunter, Tomas Winkler On Fri, Jun 16, 2017 at 10:22 AM, Avri Altman <Avri.Altman@wdc.com> wrote: > Hi, > >> -----Original Message----- >> From: Linus Walleij [mailto:linus.walleij@linaro.org] >> Sent: Thursday, June 15, 2017 3:13 PM >> To: linux-mmc@vger.kernel.org; Ulf Hansson <ulf.hansson@linaro.org> >> Cc: linux-block@vger.kernel.org; Jens Axboe <axboe@kernel.dk>; Christoph >> Hellwig <hch@lst.de>; Arnd Bergmann <arnd@arndb.de>; Bartlomiej >> Zolnierkiewicz <b.zolnierkie@samsung.com>; Paolo Valente >> <paolo.valente@linaro.org>; Avri Altman <Avri.Altman@wdc.com>; Adrian >> Hunter <adrian.hunter@intel.com>; Linus Walleij <linus.walleij@linaro.org> >> Subject: [PATCH 4/5] RFC: mmc: block: Convert RPMB to a character device >> >> The RPMB partition on the eMMC devices is a special area used for storing >> cryptographically safe information signed by a special secret key. To write >> and read records from this special area, authentication is needed. >> >> The RPMB area is *only* and *exclusively* accessed using ioctl():s from >> userspace. It is not really a block device, as blocks cannot be read or written >> from the device, also the signed chunks that can be stored on the RPMB are >> actually >> 256 bytes, not 512 making a block device a real bad fit. >> >> Currently the RPMB partition spawns a separate block device named >> /dev/mmcblkNrpmb for each device with an RPMB partition, including the >> creation of a block queue with its own kernel thread and all overhead >> associated with this. On the Ux500 >> HREFv60 platform, for example, the two eMMCs means that two block >> queues with separate threads are created for no use whatsoever. >> >> I have concluded that this block device design for RPMB is actually pretty >> wrong. The RPMB area should have been designed to be accessed from >> /dev/mmcblkN directly, using ioctl()s on the main block device. It is however >> way too late to change that, since userspace expects to open an RPMB >> device in /dev/mmcblkNrpmb and we cannot break userspace. >> > Not sure how much you are bound by this. > Previous attempts, adopting a pragmatic approach - just added another ioctl number, and used /dev/mmcblkN. > Moreover, a designated ioctl allows to address more cleanly the rpmb-specific needs, that are somehow awkward using multi_cmd. > Within the context of an RFC, would be interesting to know if someone even used /dev/mmcblkNrpmb? Good question, need to look for TrustyOS and OP-TEE. > >> Some discussion points: >> >> I am aware of Tomas Winklers attempts to make RPMB handling into its own >> subsystem. I have no such ambitions whatsoever, I am only trying to sensibly >> accomodate what we already have and handle our RPMB in a way that is not >> littering the place with weirdo block devices. > > I think that the key benefit of Tomas's approach, is being so comprehensive. > Thus enables pmb access of embedded block devices - mmc as well as other. My approach came from actual use case, but we cannot probably break already working software. > Cheers, > Avri > Thanks Tomas ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 4/5] RFC: mmc: block: Convert RPMB to a character device 2017-06-15 12:12 ` [PATCH 4/5] RFC: mmc: block: Convert RPMB to a character device Linus Walleij 2017-06-16 7:22 ` Avri Altman @ 2017-06-16 7:45 ` Christoph Hellwig 2017-06-16 9:47 ` Ulf Hansson 2017-06-19 21:18 ` Tomas Winkler 2 siblings, 1 reply; 17+ messages in thread From: Christoph Hellwig @ 2017-06-16 7:45 UTC (permalink / raw) To: Linus Walleij Cc: linux-mmc, Ulf Hansson, linux-block, Jens Axboe, Christoph Hellwig, Arnd Bergmann, Bartlomiej Zolnierkiewicz, Paolo Valente, Avri Altman, Adrian Hunter On Thu, Jun 15, 2017 at 02:12:58PM +0200, Linus Walleij wrote: > Currently the RPMB partition spawns a separate block device > named /dev/mmcblkNrpmb for each device with an RPMB partition, > including the creation of a block queue with its own kernel > thread and all overhead associated with this. On the Ux500 > HREFv60 platform, for example, the two eMMCs means that two > block queues with separate threads are created for no use > whatsoever. Yikes! What an amazingly stupid design decision. > This patch tries to amend the situation using the following > strategy: > > - Stop creating a block device for the RPMB partition/area > > - Instead create a custom, dynamic character device with > the same name. > > - Make this new character device support exactly the same > set of ioctl()s as the old block device. > > - Wrap the requests back to the same ioctl() handlers, but > issue them on the block queue of the main partition/area, > i.e. /dev/mmcblkN Is it really worth to add all this code to work around the issue? We could still keep the block device around and stub out anything not needed. > Tomas Winkler <tomas.winkler@intel.com> > Signed-off-by: Linus Walleij <linus.walleij@linaro.org> I think some tag is missing before Tomas' name. ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 4/5] RFC: mmc: block: Convert RPMB to a character device 2017-06-16 7:45 ` Christoph Hellwig @ 2017-06-16 9:47 ` Ulf Hansson 2017-06-19 21:25 ` Tomas Winkler 0 siblings, 1 reply; 17+ messages in thread From: Ulf Hansson @ 2017-06-16 9:47 UTC (permalink / raw) To: Christoph Hellwig Cc: Linus Walleij, linux-mmc@vger.kernel.org, linux-block, Jens Axboe, Arnd Bergmann, Bartlomiej Zolnierkiewicz, Paolo Valente, Avri Altman, Adrian Hunter On 16 June 2017 at 09:45, Christoph Hellwig <hch@lst.de> wrote: > On Thu, Jun 15, 2017 at 02:12:58PM +0200, Linus Walleij wrote: >> Currently the RPMB partition spawns a separate block device >> named /dev/mmcblkNrpmb for each device with an RPMB partition, >> including the creation of a block queue with its own kernel >> thread and all overhead associated with this. On the Ux500 >> HREFv60 platform, for example, the two eMMCs means that two >> block queues with separate threads are created for no use >> whatsoever. > > Yikes! What an amazingly stupid design decision. Unfortunate, there is more. :-) We are actually registering at least three more block devices per eMMC card (two boot partitions, and one general purpose partition). Except for the main partition of course. The difference compared to rpmb from the above, is that those are actually general read/write partitions. So all these partitions are on the same eMMC card, but being I/O scheduled separately because there are separate block devices. Yeah, starvation, latency, etc - all bad things comes with it. :-) My point is, this is only the first step in re-working and fixing this - and we really appreciate your review! [...] Kind regards Uffe ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 4/5] RFC: mmc: block: Convert RPMB to a character device 2017-06-16 9:47 ` Ulf Hansson @ 2017-06-19 21:25 ` Tomas Winkler 0 siblings, 0 replies; 17+ messages in thread From: Tomas Winkler @ 2017-06-19 21:25 UTC (permalink / raw) To: Ulf Hansson Cc: Christoph Hellwig, Linus Walleij, linux-mmc@vger.kernel.org, linux-block, Jens Axboe, Arnd Bergmann, Bartlomiej Zolnierkiewicz, Paolo Valente, Avri Altman, Adrian Hunter, Tomas Winkler >>> Currently the RPMB partition spawns a separate block device >>> named /dev/mmcblkNrpmb for each device with an RPMB partition, >>> including the creation of a block queue with its own kernel >>> thread and all overhead associated with this. On the Ux500 >>> HREFv60 platform, for example, the two eMMCs means that two >>> block queues with separate threads are created for no use >>> whatsoever. >> >> Yikes! What an amazingly stupid design decision. > > Unfortunate, there is more. :-) > > We are actually registering at least three more block devices per eMMC > card (two boot partitions, and one general purpose partition). Except > for the main partition of course. Little correction, there are 4 general purpose partition, not one. > > The difference compared to rpmb from the above, is that those are > actually general read/write partitions. > > So all these partitions are on the same eMMC card, but being I/O > scheduled separately because there are separate block devices. Yeah, > starvation, latency, etc - all bad things comes with it. :-) Actually the worst issue is that emmc is single headed and all the security devices and VMs has to go via host for their data. > > My point is, this is only the first step in re-working and fixing this > - and we really appreciate your review! ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 4/5] RFC: mmc: block: Convert RPMB to a character device 2017-06-15 12:12 ` [PATCH 4/5] RFC: mmc: block: Convert RPMB to a character device Linus Walleij 2017-06-16 7:22 ` Avri Altman 2017-06-16 7:45 ` Christoph Hellwig @ 2017-06-19 21:18 ` Tomas Winkler 2017-08-11 9:31 ` Linus Walleij 2 siblings, 1 reply; 17+ messages in thread From: Tomas Winkler @ 2017-06-19 21:18 UTC (permalink / raw) To: Linus Walleij Cc: linux-mmc, Ulf Hansson, linux-block, Jens Axboe, Christoph Hellwig, Arnd Bergmann, Bartlomiej Zolnierkiewicz, Paolo Valente, Avri Altman, Adrian Hunter, Tomas Winkler > The RPMB partition on the eMMC devices is a special area used > for storing cryptographically safe information signed by a > special secret key. To write and read records from this special > area, authentication is needed. > > The RPMB area is *only* and *exclusively* accessed using > ioctl():s from userspace. It is not really a block device, > as blocks cannot be read or written from the device, also > the signed chunks that can be stored on the RPMB are actually > 256 bytes, not 512 making a block device a real bad fit. > > Currently the RPMB partition spawns a separate block device > named /dev/mmcblkNrpmb for each device with an RPMB partition, > including the creation of a block queue with its own kernel > thread and all overhead associated with this. On the Ux500 > HREFv60 platform, for example, the two eMMCs means that two > block queues with separate threads are created for no use > whatsoever. > > I have concluded that this block device design for RPMB is > actually pretty wrong. That's correct, I guess someone didn't read the spec till the end when adding rpmb block device. though also looks like that the software guys where drinking up in the bar while jdec committee has met. The RPMB area should have been designed > to be accessed from /dev/mmcblkN directly, using ioctl()s on > the main block device. It is however way too late to change > that, since userspace expects to open an RPMB device in > /dev/mmcblkNrpmb and we cannot break userspace. Unfortunately, this is currently necessary, > This patch tries to amend the situation using the following > strategy: > > - Stop creating a block device for the RPMB partition/area > > - Instead create a custom, dynamic character device with > the same name. > > - Make this new character device support exactly the same > set of ioctl()s as the old block device. > > - Wrap the requests back to the same ioctl() handlers, but > issue them on the block queue of the main partition/area, > i.e. /dev/mmcblkN > > We need to create a special "rpmb" bus type in order to get > udev and/or busybox hot/coldplug to instantiate the device > node properly. > > Before the patch, this appears in 'ps aux': > > 101 root 0:00 [mmcqd/2rpmb] > 123 root 0:00 [mmcqd/3rpmb] > > After applying the patch these surplus block queue threads > are gone, but RPMB is as usable as ever using the userspace > MMC tools, such as 'mmc rpmb read-counter'. > > We get instead those dynamice devices in /dev: > > brw-rw---- 1 root root 179, 0 Jan 1 2000 mmcblk0 > brw-rw---- 1 root root 179, 1 Jan 1 2000 mmcblk0p1 > brw-rw---- 1 root root 179, 2 Jan 1 2000 mmcblk0p2 > brw-rw---- 1 root root 179, 5 Jan 1 2000 mmcblk0p5 > brw-rw---- 1 root root 179, 8 Jan 1 2000 mmcblk2 > brw-rw---- 1 root root 179, 16 Jan 1 2000 mmcblk2boot0 > brw-rw---- 1 root root 179, 24 Jan 1 2000 mmcblk2boot1 > crw-rw---- 1 root root 248, 0 Jan 1 2000 mmcblk2rpmb > brw-rw---- 1 root root 179, 32 Jan 1 2000 mmcblk3 > brw-rw---- 1 root root 179, 40 Jan 1 2000 mmcblk3boot0 > brw-rw---- 1 root root 179, 48 Jan 1 2000 mmcblk3boot1 > brw-rw---- 1 root root 179, 33 Jan 1 2000 mmcblk3p1 > crw-rw---- 1 root root 248, 1 Jan 1 2000 mmcblk3rpmb > > Notice the (248,0) and (248,1) character devices for RPMB. > > Tomas Winkler <tomas.winkler@intel.com> > Signed-off-by: Linus Walleij <linus.walleij@linaro.org> > --- > Some discussion points: > > I am aware of Tomas Winklers attempts to make RPMB handling into > its own subsystem. I have no such ambitions whatsoever, I am only > trying to sensibly accomodate what we already have and handle > our RPMB in a way that is not littering the place with weirdo > block devices. My effort is a bit different, one is to provide an abstraction over all storage devices that provides RPMB (emmc, ufs, NVMe) and second, provide in-kernel API, still it's possible to create a filesystem over RPMB in case you own the key. Though not ideal, these two things should live in parallel for now somehow. > > The patch is a lot of "that should have been done differently from > the outset" and "it is not a perfect solution", I'd appreciate if > you take a look at the kernel before and after this patch and > think of it as a path forward, are things better or worse like > this, thinking toward the future. > > I guess it would be nicer if I could (from the KERNEL) create a > symlink from mmcblk2rpmb -> mmcblk2 or a second mknod creating > mmcblk2rpmb with the same major/minor numbers as the main device. > I guess that can be done with udev scripts, but that breaks all > setups with old udev scripts, busybox, Android etc. So creating > a proper device seems necessary to satisfy userspace. > > I haven't been able to do much testing as my RPMB-capable device > seems to be failing to do anything sensible, but I atleast get > the same error codes from "mmc rpmb read-counter /deb/mmcblkNrpmb" > before/after the patch. Hop > --- > drivers/mmc/core/block.c | 278 +++++++++++++++++++++++++++++++++++++++++++---- > drivers/mmc/core/queue.h | 2 + > 2 files changed, 256 insertions(+), 24 deletions(-) > > diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c > index b8c71fdb6ed4..0a226bc23429 100644 > --- a/drivers/mmc/core/block.c > +++ b/drivers/mmc/core/block.c > @@ -28,6 +28,7 @@ > #include <linux/hdreg.h> > #include <linux/kdev_t.h> > #include <linux/blkdev.h> > +#include <linux/cdev.h> > #include <linux/mutex.h> > #include <linux/scatterlist.h> > #include <linux/string_helpers.h> > @@ -86,6 +87,7 @@ static int max_devices; > #define MAX_DEVICES 256 > > static DEFINE_IDA(mmc_blk_ida); > +static DEFINE_IDA(mmc_rpmb_ida); > > /* > * There is one mmc_blk_data per slot. > @@ -96,6 +98,7 @@ struct mmc_blk_data { > struct gendisk *disk; > struct mmc_queue queue; > struct list_head part; > + struct list_head rpmbs; > > unsigned int flags; > #define MMC_BLK_CMD23 (1 << 0) /* Can do SET_BLOCK_COUNT for multiblock */ > @@ -121,6 +124,30 @@ struct mmc_blk_data { > int area_type; > }; > > +/* Device type for RPMB character devices */ > +static dev_t rpmb_devt; This is mmc_rpmb device not 'rpmb' as there are other storage devices that provide RPMB partition. > + > +/* Bus type for RPMB character devices */ > +static struct bus_type rpmb_bus_type = { > + .name = "rpmb", > +}; Same here, mmc_rpmb_... , and other place bellow. > + > +/** > + * struct mmc_rpmb_data - special RPMB device type for these areas > + * @dev: the device for the RPMB area > + * @chrdev: character device for the RPMB area > + * @id: unique device ID number > + * @md: parent MMC block device > + * @node: list item, so we can put this device on a list > + */ > +struct mmc_rpmb_data { > + struct device dev; > + struct cdev chrdev; > + int id; would keep also partition access bit needed for the partition switching. > + struct mmc_blk_data *md; > + struct list_head node; > +}; > + > static DEFINE_MUTEX(open_lock); > > module_param(perdev_minors, int, 0444); > @@ -432,21 +459,29 @@ static int ioctl_do_sanitize(struct mmc_card *card) > } > > static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md, > - struct mmc_blk_ioc_data *idata) > + struct mmc_blk_ioc_data *idata, bool rpmb_ioctl) Don't remember now if this is for eMMC but in future there might be more then one RPMB partition on the device and boolean will not work here. rather use target_part, tho bits are exhausted there too. > { > struct mmc_command cmd = {}; > struct mmc_data data = {}; > struct mmc_request mrq = {}; > struct scatterlist sg; > int err; > - bool is_rpmb = false; > + unsigned int target_part; should come as a function input. > u32 status = 0; > > if (!card || !md || !idata) > return -EINVAL; > > - if (md->area_type & MMC_BLK_DATA_AREA_RPMB) > - is_rpmb = true; > + /* > + * The RPMB accesses comes in from the character device, so we > + * need to target these explicitly. Else we just target the > + * partition type for the block device the ioctl() was issued > + * on. > + */ > + if (rpmb_ioctl) > + target_part = EXT_CSD_PART_CONFIG_ACC_RPMB; > + else > + target_part = md->part_type; > > cmd.opcode = idata->ic.opcode; > cmd.arg = idata->ic.arg; > @@ -490,7 +525,7 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md, > > mrq.cmd = &cmd; > > - err = mmc_blk_part_switch(card, md->part_type); > + err = mmc_blk_part_switch(card, target_part); > if (err) > return err; > > @@ -500,7 +535,7 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md, > return err; > } > > - if (is_rpmb) { > + if (rpmb_ioctl) { > err = mmc_set_blockcount(card, data.blocks, > idata->ic.write_flag & (1 << 31)); > if (err) > @@ -540,7 +575,7 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md, > > memcpy(&(idata->ic.response), cmd.resp, sizeof(cmd.resp)); > > - if (is_rpmb) { > + if (rpmb_ioctl) { > /* > * Ensure RPMB command has completed by polling CMD13 > * "Send Status". > @@ -556,7 +591,8 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md, > } > > static int mmc_blk_ioctl_cmd(struct mmc_blk_data *md, > - struct mmc_ioc_cmd __user *ic_ptr) > + struct mmc_ioc_cmd __user *ic_ptr, > + bool rpmb_ioctl) > { > struct mmc_blk_ioc_data *idata; > struct mmc_blk_ioc_data *idatas[1]; > @@ -583,7 +619,10 @@ static int mmc_blk_ioctl_cmd(struct mmc_blk_data *md, > idata->ic.write_flag ? REQ_OP_DRV_OUT : REQ_OP_DRV_IN, > __GFP_RECLAIM); > idatas[0] = idata; > - req_to_mmc_queue_req(req)->drv_op = MMC_DRV_OP_IOCTL; > + if (rpmb_ioctl) > + req_to_mmc_queue_req(req)->drv_op = MMC_DRV_OP_IOCTL_RPMB; > + else > + req_to_mmc_queue_req(req)->drv_op = MMC_DRV_OP_IOCTL; > req_to_mmc_queue_req(req)->drv_op_data = idatas; > req_to_mmc_queue_req(req)->ioc_count = 1; > blk_execute_rq(mq->queue, NULL, req, 0); > @@ -598,7 +637,8 @@ static int mmc_blk_ioctl_cmd(struct mmc_blk_data *md, > } > > static int mmc_blk_ioctl_multi_cmd(struct mmc_blk_data *md, > - struct mmc_ioc_multi_cmd __user *user) > + struct mmc_ioc_multi_cmd __user *user, > + bool rpmb_ioctl) > { > struct mmc_blk_ioc_data **idata = NULL; > struct mmc_ioc_cmd __user *cmds = user->cmds; > @@ -642,7 +682,10 @@ static int mmc_blk_ioctl_multi_cmd(struct mmc_blk_data *md, > req = blk_get_request(mq->queue, > idata[0]->ic.write_flag ? REQ_OP_DRV_OUT : REQ_OP_DRV_IN, > __GFP_RECLAIM); > - req_to_mmc_queue_req(req)->drv_op = MMC_DRV_OP_IOCTL; > + if (rpmb_ioctl) > + req_to_mmc_queue_req(req)->drv_op = MMC_DRV_OP_IOCTL_RPMB; > + else > + req_to_mmc_queue_req(req)->drv_op = MMC_DRV_OP_IOCTL; > req_to_mmc_queue_req(req)->drv_op_data = idata; > req_to_mmc_queue_req(req)->ioc_count = num_of_cmds; > blk_execute_rq(mq->queue, NULL, req, 0); > @@ -690,7 +733,8 @@ static int mmc_blk_ioctl(struct block_device *bdev, fmode_t mode, > if (!md) > return -EINVAL; > ret = mmc_blk_ioctl_cmd(md, > - (struct mmc_ioc_cmd __user *)arg); > + (struct mmc_ioc_cmd __user *)arg, > + false); > mmc_blk_put(md); > return ret; > case MMC_IOC_MULTI_CMD: > @@ -701,7 +745,8 @@ static int mmc_blk_ioctl(struct block_device *bdev, fmode_t mode, > if (!md) > return -EINVAL; > ret = mmc_blk_ioctl_multi_cmd(md, > - (struct mmc_ioc_multi_cmd __user *)arg); > + (struct mmc_ioc_multi_cmd __user *)arg, > + false); > mmc_blk_put(md); > return ret; > default: > @@ -1173,26 +1218,29 @@ static void mmc_blk_issue_drv_op(struct mmc_queue *mq, struct request *req) > struct mmc_queue_req *mq_rq; > struct mmc_card *card = mq->card; > struct mmc_blk_data *md = mq->blkdata; > - struct mmc_blk_data *main_md = dev_get_drvdata(&card->dev); > struct mmc_blk_ioc_data **idata; > + bool rpmb_ioctl; > u8 **ext_csd; > u32 status; > int ret; > int i; > > mq_rq = req_to_mmc_queue_req(req); > + rpmb_ioctl = (mq_rq->drv_op == MMC_DRV_OP_IOCTL_RPMB); > > switch (mq_rq->drv_op) { > case MMC_DRV_OP_IOCTL: > + case MMC_DRV_OP_IOCTL_RPMB: > idata = mq_rq->drv_op_data; > for (i = 0; i < mq_rq->ioc_count; i++) { > - ret = __mmc_blk_ioctl_cmd(card, md, idata[i]); > + ret = __mmc_blk_ioctl_cmd(card, md, idata[i], > + rpmb_ioctl); > if (ret) > break; > } > /* Always switch back to main area after RPMB access */ > - if (md->area_type & MMC_BLK_DATA_AREA_RPMB) > - mmc_blk_part_switch(card, main_md->part_type); > + if (rpmb_ioctl) > + mmc_blk_part_switch(card, 0); > break; > case MMC_DRV_OP_BOOT_WP: > ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_WP, > @@ -2006,6 +2054,7 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card, > > spin_lock_init(&md->lock); > INIT_LIST_HEAD(&md->part); > + INIT_LIST_HEAD(&md->rpmbs); > md->usage = 1; > > ret = mmc_init_queue(&md->queue, card, &md->lock, subname); > @@ -2124,6 +2173,151 @@ static int mmc_blk_alloc_part(struct mmc_card *card, > return 0; > } > > +/** > + * rpmb_ioctl() - ioctl handler for the RPMB chardev > + * @filp: the character device file > + * @cmd: the ioctl() command > + * @arg: the argument from userspace > + * > + * This will essentially just redirect the ioctl()s coming in over to > + * the main block device spawning the RPMB character device. > + */ > +static long rpmb_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) > +{ > + struct mmc_rpmb_data *rpmb = filp->private_data; > + int ret; > + > + switch (cmd) { > + case MMC_IOC_CMD: > + ret = mmc_blk_ioctl_cmd(rpmb->md, > + (struct mmc_ioc_cmd __user *)arg, > + true); > + break; > + case MMC_IOC_MULTI_CMD: > + ret = mmc_blk_ioctl_multi_cmd(rpmb->md, > + (struct mmc_ioc_multi_cmd __user *)arg, > + true); > + break; > + default: > + ret = -EINVAL; > + break; > + } > + > + return 0; > +} > + > +#ifdef CONFIG_COMPAT > +static long rpmb_ioctl_compat(struct file *filp, unsigned int cmd, > + unsigned long arg) > +{ > + return rpmb_ioctl(filp, cmd, (unsigned long)compat_ptr(arg)); > +} > +#endif > + > +static int rpmb_chrdev_open(struct inode *inode, struct file *filp) > +{ > + struct mmc_rpmb_data *rpmb = container_of(inode->i_cdev, > + struct mmc_rpmb_data, chrdev); > + > + get_device(&rpmb->dev); > + filp->private_data = rpmb; > + mutex_lock(&open_lock); > + rpmb->md->usage++; > + mutex_unlock(&open_lock); > + > + return nonseekable_open(inode, filp); > +} > + > +static int rpmb_chrdev_release(struct inode *inode, struct file *filp) > +{ > + struct mmc_rpmb_data *rpmb = container_of(inode->i_cdev, > + struct mmc_rpmb_data, chrdev); > + > + put_device(&rpmb->dev); > + mutex_lock(&open_lock); > + rpmb->md->usage--; > + mutex_unlock(&open_lock); > + > + return 0; > +} > + > +static const struct file_operations rpmb_fileops = { > + .release = rpmb_chrdev_release, > + .open = rpmb_chrdev_open, > + .owner = THIS_MODULE, > + .llseek = no_llseek, > + .unlocked_ioctl = rpmb_ioctl, > +#ifdef CONFIG_COMPAT > + .compat_ioctl = rpmb_ioctl_compat, > +#endif > +}; > + > + > +static int mmc_blk_alloc_rpmb_part(struct mmc_card *card, > + struct mmc_blk_data *md, > + sector_t size, > + const char *subname) > +{ > + int devidx, ret; > + char rpmb_name[DISK_NAME_LEN]; > + char cap_str[10]; > + struct mmc_rpmb_data *rpmb; > + > + /* This creates the minor number for the RPMB char device */ > + devidx = ida_simple_get(&mmc_rpmb_ida, 0, max_devices, GFP_KERNEL); > + if (devidx < 0) > + return devidx; > + > + rpmb = kzalloc(sizeof(*rpmb), GFP_KERNEL); > + if (!rpmb) > + return -ENOMEM; > + > + snprintf(rpmb_name, sizeof(rpmb_name), > + "mmcblk%u%s", card->host->index, subname ? subname : ""); > + > + rpmb->id = devidx; > + rpmb->dev.init_name = rpmb_name; > + rpmb->dev.bus = &rpmb_bus_type; > + rpmb->dev.devt = MKDEV(MAJOR(rpmb_devt), rpmb->id); > + rpmb->dev.parent = &card->dev; > + device_initialize(&rpmb->dev); > + dev_set_drvdata(&rpmb->dev, rpmb); > + rpmb->md = md; > + > + cdev_init(&rpmb->chrdev, &rpmb_fileops); > + rpmb->chrdev.owner = THIS_MODULE; > + ret = cdev_device_add(&rpmb->chrdev, &rpmb->dev); > + if (ret) { > + pr_err("%s: could not add character device\n", rpmb_name); > + goto out_remove_ida; > + } > + > + list_add(&rpmb->node, &md->rpmbs); > + > + string_get_size((u64)size, 512, STRING_UNITS_2, > + cap_str, sizeof(cap_str)); > + > + pr_info("%s: %s %s partition %u %s, chardev (%d:%d)\n", > + rpmb_name, mmc_card_id(card), > + mmc_card_name(card), EXT_CSD_PART_CONFIG_ACC_RPMB, cap_str, > + MAJOR(rpmb_devt), rpmb->id); > + > + return 0; > + > +out_remove_ida: > + ida_simple_remove(&mmc_rpmb_ida, rpmb->id); > + kfree(rpmb); > + return ret; > +} > + > +static void mmc_blk_remove_rpmb_part(struct mmc_rpmb_data *rpmb) > +{ > + cdev_device_del(&rpmb->chrdev, &rpmb->dev); > + device_del(&rpmb->dev); > + ida_simple_remove(&mmc_rpmb_ida, rpmb->id); > + kfree(rpmb); > +} > + > /* MMC Physical partitions consist of two boot partitions and > * up to four general purpose partitions. > * For each partition enabled in EXT_CSD a block device will be allocatedi > @@ -2132,13 +2326,25 @@ static int mmc_blk_alloc_part(struct mmc_card *card, > > static int mmc_blk_alloc_parts(struct mmc_card *card, struct mmc_blk_data *md) > { > - int idx, ret = 0; > + int idx, ret; > > if (!mmc_card_mmc(card)) > return 0; > > for (idx = 0; idx < card->nr_parts; idx++) { > - if (card->part[idx].size) { > + if (card->part[idx].area_type & MMC_BLK_DATA_AREA_RPMB) { > + /* > + * RPMB partitions does not provide block access, they > + * are only accessed using ioctl():s. Thus create > + * special RPMB block devices that do not have a > + * backing block queue for these. > + */ > + ret = mmc_blk_alloc_rpmb_part(card, md, > + card->part[idx].size >> 9, > + card->part[idx].name); Extract partition access bits form card->part[idx].part_cfg, > + if (ret) > + return ret; > + } else if (card->part[idx].size) { > ret = mmc_blk_alloc_part(card, md, > card->part[idx].part_cfg, > card->part[idx].size >> 9, > @@ -2150,7 +2356,7 @@ static int mmc_blk_alloc_parts(struct mmc_card *card, struct mmc_blk_data *md) > } > } > > - return ret; > + return 0; > } > > static void mmc_blk_remove_req(struct mmc_blk_data *md) > @@ -2183,7 +2389,15 @@ static void mmc_blk_remove_parts(struct mmc_card *card, > { > struct list_head *pos, *q; > struct mmc_blk_data *part_md; > + struct mmc_rpmb_data *rpmb; > > + /* Remove RPMB partitions */ > + list_for_each_safe(pos, q, &md->rpmbs) { list_for_each_entry_safe ? > + rpmb = list_entry(pos, struct mmc_rpmb_data, node); > + list_del(pos); > + mmc_blk_remove_rpmb_part(rpmb); > + } > + /* Remove block partitions */ > list_for_each_safe(pos, q, &md->part) { > part_md = list_entry(pos, struct mmc_blk_data, part); > list_del(pos); > @@ -2502,6 +2716,17 @@ static int __init mmc_blk_init(void) > { > int res; > > + res = bus_register(&rpmb_bus_type); > + if (res < 0) { > + pr_err("mmcblk: could not register RPMB bus type\n"); > + return res; > + } > + res = alloc_chrdev_region(&rpmb_devt, 0, MAX_DEVICES, "rpmb"); mmc_rpmb > + if (res < 0) { > + pr_err("mmcblk: failed to allocate rpmb chrdev region\n"); > + goto out_bus_unreg; > + } > + > if (perdev_minors != CONFIG_MMC_BLOCK_MINORS) > pr_info("mmcblk: using %d minors per device\n", perdev_minors); > > @@ -2509,16 +2734,20 @@ static int __init mmc_blk_init(void) > > res = register_blkdev(MMC_BLOCK_MAJOR, "mmc"); > if (res) > - goto out; > + goto out_chrdev_unreg; > > res = mmc_register_driver(&mmc_driver); > if (res) > - goto out2; > + goto out_blkdev_unreg; > > return 0; > - out2: > + > +out_blkdev_unreg: > unregister_blkdev(MMC_BLOCK_MAJOR, "mmc"); > - out: > +out_chrdev_unreg: > + unregister_chrdev_region(rpmb_devt, MAX_DEVICES); > +out_bus_unreg: > + bus_unregister(&rpmb_bus_type); > return res; > } > > @@ -2526,6 +2755,7 @@ static void __exit mmc_blk_exit(void) > { > mmc_unregister_driver(&mmc_driver); > unregister_blkdev(MMC_BLOCK_MAJOR, "mmc"); > + unregister_chrdev_region(rpmb_devt, MAX_DEVICES); > } > > module_init(mmc_blk_init); > diff --git a/drivers/mmc/core/queue.h b/drivers/mmc/core/queue.h > index 04fc89360a7a..a2b6a9fcab01 100644 > --- a/drivers/mmc/core/queue.h > +++ b/drivers/mmc/core/queue.h > @@ -35,12 +35,14 @@ struct mmc_blk_request { > /** > * enum mmc_drv_op - enumerates the operations in the mmc_queue_req > * @MMC_DRV_OP_IOCTL: ioctl operation > + * @MMC_DRV_OP_IOCTL_RPMB: RPMB-oriented ioctl operation > * @MMC_DRV_OP_BOOT_WP: write protect boot partitions > * @MMC_DRV_OP_GET_CARD_STATUS: get card status > * @MMC_DRV_OP_GET_EXT_CSD: get the EXT CSD from an eMMC card > */ > enum mmc_drv_op { > MMC_DRV_OP_IOCTL, > + MMC_DRV_OP_IOCTL_RPMB, > MMC_DRV_OP_BOOT_WP, > MMC_DRV_OP_GET_CARD_STATUS, > MMC_DRV_OP_GET_EXT_CSD, > -- > 2.9.4 Still need to try somehow combine mine patches above this Thanks Tomas ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 4/5] RFC: mmc: block: Convert RPMB to a character device 2017-06-19 21:18 ` Tomas Winkler @ 2017-08-11 9:31 ` Linus Walleij 0 siblings, 0 replies; 17+ messages in thread From: Linus Walleij @ 2017-08-11 9:31 UTC (permalink / raw) To: Tomas Winkler Cc: linux-mmc@vger.kernel.org, Ulf Hansson, linux-block, Jens Axboe, Christoph Hellwig, Arnd Bergmann, Bartlomiej Zolnierkiewicz, Paolo Valente, Avri Altman, Adrian Hunter, Tomas Winkler On Mon, Jun 19, 2017 at 11:18 PM, Tomas Winkler <tomasw@gmail.com> wrote: > That's correct, I guess someone didn't read the spec till the end when > adding rpmb block device. > though also looks like that the software guys where drinking up in the > bar while jdec committee has met. :D >> +/* Device type for RPMB character devices */ >> +static dev_t rpmb_devt; > > This is mmc_rpmb device not 'rpmb' as there are other storage devices > that provide RPMB partition. OK fixed it. >> + >> +/* Bus type for RPMB character devices */ >> +static struct bus_type rpmb_bus_type = { >> + .name = "rpmb", >> +}; > > Same here, mmc_rpmb_... , and other place bellow. OK fixed it. >> +struct mmc_rpmb_data { (...) > would keep also partition access bit needed for the partition switching. (...) >> static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md, >> - struct mmc_blk_ioc_data *idata) >> + struct mmc_blk_ioc_data *idata, bool rpmb_ioctl) > Don't remember now if this is for eMMC but in future there might be > more then one RPMB partition on the device > and boolean will not work here. rather use target_part, tho bits are > exhausted there too. (...) >> - bool is_rpmb = false; >> + unsigned int target_part; > should come as a function input. (...) >> + ret = mmc_blk_alloc_rpmb_part(card, md, >> + card->part[idx].size >> 9, >> + card->part[idx].name); > Extract partition access bits form card->part[idx].part_cfg, OK I am trying my best with this too... Yours, Linus Walleij ^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 5/5] mmc: block: Delete mmc_access_rpmb() 2017-06-15 12:12 [PATCH 0/5] Convert RPMB block device to a character device Linus Walleij ` (3 preceding siblings ...) 2017-06-15 12:12 ` [PATCH 4/5] RFC: mmc: block: Convert RPMB to a character device Linus Walleij @ 2017-06-15 12:12 ` Linus Walleij 4 siblings, 0 replies; 17+ messages in thread From: Linus Walleij @ 2017-06-15 12:12 UTC (permalink / raw) To: linux-mmc, Ulf Hansson Cc: linux-block, Jens Axboe, Christoph Hellwig, Arnd Bergmann, Bartlomiej Zolnierkiewicz, Paolo Valente, Avri Altman, Adrian Hunter, Linus Walleij This function is used by the block layer queue to bail out of requests if the current request is an RPMB request. However this makes no sense: RPMB is only used from ioctl():s, there are no RPMB accesses coming from the block layer. An RPMB ioctl() always switches to the RPMB partition and then back to the main partition before completing. The only (possible) use of this check must have been to duct-tape over a race between RPMB ioctl()s colliding with concurrent non-RPMB accesses to the same device. This could happen in the past because the RPMB device was created as a separate block device/disk with its own submit queue competing with the main partition, and submitting requests in parallel. This is now gone as we removed the offending RPMB block device in another patch. Signed-off-by: Linus Walleij <linus.walleij@linaro.org> --- This patch is not an RFC since it is a logical consequence of the RFC patch, not really much to discuss about it. --- drivers/mmc/core/block.c | 12 ------------ drivers/mmc/core/queue.c | 2 +- drivers/mmc/core/queue.h | 2 -- 3 files changed, 1 insertion(+), 15 deletions(-) diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index 0a226bc23429..8bb97ac3be08 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -1196,18 +1196,6 @@ static inline void mmc_blk_reset_success(struct mmc_blk_data *md, int type) md->reset_done &= ~type; } -int mmc_access_rpmb(struct mmc_queue *mq) -{ - struct mmc_blk_data *md = mq->blkdata; - /* - * If this is a RPMB partition access, return ture - */ - if (md && md->part_type == EXT_CSD_PART_CONFIG_ACC_RPMB) - return true; - - return false; -} - /* * The non-block commands come back from the block layer after it queued it and * processed it with all other requests and then they get issued in this diff --git a/drivers/mmc/core/queue.c b/drivers/mmc/core/queue.c index ba689a2ffc51..9d3de2859c33 100644 --- a/drivers/mmc/core/queue.c +++ b/drivers/mmc/core/queue.c @@ -32,7 +32,7 @@ static int mmc_prep_request(struct request_queue *q, struct request *req) { struct mmc_queue *mq = q->queuedata; - if (mq && (mmc_card_removed(mq->card) || mmc_access_rpmb(mq))) + if (mq && mmc_card_removed(mq->card)) return BLKPREP_KILL; req->rq_flags |= RQF_DONTPREP; diff --git a/drivers/mmc/core/queue.h b/drivers/mmc/core/queue.h index a2b6a9fcab01..7649ed6cbef7 100644 --- a/drivers/mmc/core/queue.h +++ b/drivers/mmc/core/queue.h @@ -89,6 +89,4 @@ extern unsigned int mmc_queue_map_sg(struct mmc_queue *, extern void mmc_queue_bounce_pre(struct mmc_queue_req *); extern void mmc_queue_bounce_post(struct mmc_queue_req *); -extern int mmc_access_rpmb(struct mmc_queue *); - #endif -- 2.9.4 ^ permalink raw reply related [flat|nested] 17+ messages in thread
end of thread, other threads:[~2017-08-11 9:31 UTC | newest] Thread overview: 17+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2017-06-15 12:12 [PATCH 0/5] Convert RPMB block device to a character device Linus Walleij 2017-06-15 12:12 ` [PATCH 1/5] mmc: block: Move duplicate check Linus Walleij 2017-06-16 0:46 ` Shawn Lin 2017-06-15 12:12 ` [PATCH 2/5] mmc: block: Refactor mmc_blk_part_switch() Linus Walleij 2017-06-19 19:53 ` Tomas Winkler 2017-06-20 11:23 ` Linus Walleij 2017-06-15 12:12 ` [PATCH 3/5] mmc: block: Reparametrize mmc_blk_ioctl_[multi]_cmd() Linus Walleij 2017-06-19 20:12 ` Tomas Winkler 2017-06-15 12:12 ` [PATCH 4/5] RFC: mmc: block: Convert RPMB to a character device Linus Walleij 2017-06-16 7:22 ` Avri Altman 2017-06-19 21:28 ` Tomas Winkler 2017-06-16 7:45 ` Christoph Hellwig 2017-06-16 9:47 ` Ulf Hansson 2017-06-19 21:25 ` Tomas Winkler 2017-06-19 21:18 ` Tomas Winkler 2017-08-11 9:31 ` Linus Walleij 2017-06-15 12:12 ` [PATCH 5/5] mmc: block: Delete mmc_access_rpmb() Linus Walleij
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox