Message ID | 1441811161-18513-1-git-send-email-jonathanh@nvidia.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On Wednesday 09 September 2015 16:06:01 Jon Hunter wrote: > + > + idata = kcalloc(mcci.num_of_cmds, sizeof(*idata), GFP_KERNEL); > + if (!idata) { > + err = -ENOMEM; > + goto cmd_err; > + } > + > + cmds = (struct mmc_ioc_cmd __user *)(unsigned long)mcci.cmds_ptr; > + for (n_cmds = 0; n_cmds < mcci.num_of_cmds; n_cmds++) { > + idata[n_cmds] = mmc_blk_ioctl_copy_from_user(&cmds[n_cmds]); > + if (IS_ERR(idata[n_cmds])) { > + err = PTR_ERR(idata[n_cmds]); > + goto cmd_err; > + } > + } > + You have no upper bound on the number of commands, which means you end up catching overly large arguments only through -ENOMEM. Can you come up with an upper bound that is guaranteed to succeed with the allocation? Or would it be possible to process the user data one at a time while going through the commands? > +struct mmc_ioc_multi_cmd { > + __u64 cmds_ptr; > + uint8_t num_of_cmds; > +}; complex commands are always nasty in one way or another. Can you describe in the patch description why you picked an indirect pointer over something like struct mmc_ioc_multi_cmd { __u64 num_of_cmds; struct mmc_ioc_cmd cmds[0]; }; as I said, both are ugly. My first choice would have been the other one, but I'm sure you have some reasons yourself. Arnd -- 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
On 09/09/15 16:56, Arnd Bergmann wrote: > On Wednesday 09 September 2015 16:06:01 Jon Hunter wrote: >> + >> + idata = kcalloc(mcci.num_of_cmds, sizeof(*idata), GFP_KERNEL); >> + if (!idata) { >> + err = -ENOMEM; >> + goto cmd_err; >> + } >> + >> + cmds = (struct mmc_ioc_cmd __user *)(unsigned long)mcci.cmds_ptr; >> + for (n_cmds = 0; n_cmds < mcci.num_of_cmds; n_cmds++) { >> + idata[n_cmds] = mmc_blk_ioctl_copy_from_user(&cmds[n_cmds]); >> + if (IS_ERR(idata[n_cmds])) { >> + err = PTR_ERR(idata[n_cmds]); >> + goto cmd_err; >> + } >> + } >> + > > You have no upper bound on the number of commands, which means you end > up catching overly large arguments only through -ENOMEM. Can you come > up with an upper bound that is guaranteed to succeed with the allocation? The uint8 type would limit you to 256 commands (if you have the memory), although admittedly that is probably overkill. > Or would it be possible to process the user data one at a time while > going through the commands? Yes, I think that could be a good option, I will take a look. >> +struct mmc_ioc_multi_cmd { >> + __u64 cmds_ptr; >> + uint8_t num_of_cmds; >> +}; > > complex commands are always nasty in one way or another. Can you describe > in the patch description why you picked an indirect pointer over something > like > > struct mmc_ioc_multi_cmd { > __u64 num_of_cmds; > struct mmc_ioc_cmd cmds[0]; > }; > > as I said, both are ugly. My first choice would have been the other one, > but I'm sure you have some reasons yourself. It was a suggestion from Olof to ensure the structure size is constant for both 32-bit and 64-bit userspaces. I am not sure if it is worth adding a macro similar to the below for this? #define mmc_ioc_cmd_set_data(ic, ptr) ic.data_ptr = (__u64)(unsigned long) ptr However, yes can update the changelog. Cheers Jon -- 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
On Wednesday 09 September 2015 17:44:54 Jon Hunter wrote: > > On 09/09/15 16:56, Arnd Bergmann wrote: > > On Wednesday 09 September 2015 16:06:01 Jon Hunter wrote: > >> + > >> + idata = kcalloc(mcci.num_of_cmds, sizeof(*idata), GFP_KERNEL); > >> + if (!idata) { > >> + err = -ENOMEM; > >> + goto cmd_err; > >> + } > >> + > >> + cmds = (struct mmc_ioc_cmd __user *)(unsigned long)mcci.cmds_ptr; > >> + for (n_cmds = 0; n_cmds < mcci.num_of_cmds; n_cmds++) { > >> + idata[n_cmds] = mmc_blk_ioctl_copy_from_user(&cmds[n_cmds]); > >> + if (IS_ERR(idata[n_cmds])) { > >> + err = PTR_ERR(idata[n_cmds]); > >> + goto cmd_err; > >> + } > >> + } > >> + > > > > You have no upper bound on the number of commands, which means you end > > up catching overly large arguments only through -ENOMEM. Can you come > > up with an upper bound that is guaranteed to succeed with the allocation? > > The uint8 type would limit you to 256 commands (if you have the memory), > although admittedly that is probably overkill. Good point. Please note a few details here: - in uabi headers, we need to use __u8 instead of uint8, because we cannot rely on libc header file inclusion for kernel headers. - you have some implicit padding after the structure and should replace that with explictit pad bytes to extend the structure to a multiple of its alignment (8 bytes). > >> +struct mmc_ioc_multi_cmd { > >> + __u64 cmds_ptr; > >> + uint8_t num_of_cmds; > >> +}; > > > > complex commands are always nasty in one way or another. Can you describe > > in the patch description why you picked an indirect pointer over something > > like > > > > struct mmc_ioc_multi_cmd { > > __u64 num_of_cmds; > > struct mmc_ioc_cmd cmds[0]; > > }; > > > > as I said, both are ugly. My first choice would have been the other one, > > but I'm sure you have some reasons yourself. > > It was a suggestion from Olof to ensure the structure size is constant for > both 32-bit and 64-bit userspaces. I am not sure if it is worth adding a > macro similar to the below for this? > > #define mmc_ioc_cmd_set_data(ic, ptr) ic.data_ptr = (__u64)(unsigned long) ptr > > However, yes can update the changelog. I was not referring to the use of an __u64 variable to pass a pointer, that is expected (and the macro would make it harder to understand). What I meant instead was the use of a pointer to an array as opposed to passing the array itself. With the definition I gave above, the size would still be the same on all architectures (you can replace the __u64 with an __u8 plus padding if you like), as sizeof(struct mmc_ioc_multi_cmd) is just '8' here. Alternatively, you could just use an array of struct mmc_ioc_cmd by itself and encode the length in the ioctl command: #define MMC_COMBO_IOC_CMD(n) _IOC(_IOC_READ|_IOC_WRITE, 1, sizeof(struct mmc_ioc_cmd) * (n)) This is of course also ugly because the ioctl command number is not fixed, and because the limit for the number of mmc command blocks is architecture dependent, depending on the definition of the _IOC macro that can have either 13 or 14 bits to encode the argument length in bytes. Arnd -- 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
Hi Arnd, On 09/09/15 21:22, Arnd Bergmann wrote: > On Wednesday 09 September 2015 17:44:54 Jon Hunter wrote: >> >> On 09/09/15 16:56, Arnd Bergmann wrote: >>> On Wednesday 09 September 2015 16:06:01 Jon Hunter wrote: >>>> + >>>> + idata = kcalloc(mcci.num_of_cmds, sizeof(*idata), GFP_KERNEL); >>>> + if (!idata) { >>>> + err = -ENOMEM; >>>> + goto cmd_err; >>>> + } >>>> + >>>> + cmds = (struct mmc_ioc_cmd __user *)(unsigned long)mcci.cmds_ptr; >>>> + for (n_cmds = 0; n_cmds < mcci.num_of_cmds; n_cmds++) { >>>> + idata[n_cmds] = mmc_blk_ioctl_copy_from_user(&cmds[n_cmds]); >>>> + if (IS_ERR(idata[n_cmds])) { >>>> + err = PTR_ERR(idata[n_cmds]); >>>> + goto cmd_err; >>>> + } >>>> + } >>>> + >>> >>> You have no upper bound on the number of commands, which means you end >>> up catching overly large arguments only through -ENOMEM. Can you come >>> up with an upper bound that is guaranteed to succeed with the allocation? >> >> The uint8 type would limit you to 256 commands (if you have the memory), >> although admittedly that is probably overkill. > > Good point. > > Please note a few details here: > > - in uabi headers, we need to use __u8 instead of uint8, because we cannot > rely on libc header file inclusion for kernel headers. Ok. > - you have some implicit padding after the structure and should replace that > with explictit pad bytes to extend the structure to a multiple of its > alignment (8 bytes). Would padding with __u32 at the end be sufficient here? I assume the __u32 would be 32-bit aligned. However, was not sure if this would always be the case. >>>> +struct mmc_ioc_multi_cmd { >>>> + __u64 cmds_ptr; >>>> + uint8_t num_of_cmds; >>>> +}; >>> >>> complex commands are always nasty in one way or another. Can you describe >>> in the patch description why you picked an indirect pointer over something >>> like >>> >>> struct mmc_ioc_multi_cmd { >>> __u64 num_of_cmds; >>> struct mmc_ioc_cmd cmds[0]; >>> }; >>> >>> as I said, both are ugly. My first choice would have been the other one, >>> but I'm sure you have some reasons yourself. >> >> It was a suggestion from Olof to ensure the structure size is constant for >> both 32-bit and 64-bit userspaces. I am not sure if it is worth adding a >> macro similar to the below for this? >> >> #define mmc_ioc_cmd_set_data(ic, ptr) ic.data_ptr = (__u64)(unsigned long) ptr >> >> However, yes can update the changelog. > > I was not referring to the use of an __u64 variable to pass a pointer, that > is expected (and the macro would make it harder to understand). > > What I meant instead was the use of a pointer to an array as opposed to > passing the array itself. With the definition I gave above, the size would > still be the same on all architectures (you can replace the __u64 with > an __u8 plus padding if you like), as sizeof(struct mmc_ioc_multi_cmd) > is just '8' here. Do you have any strong preference here? I guess I don't and agree neither are ideal. > Alternatively, you could just use an array of struct mmc_ioc_cmd by > itself and encode the length in the ioctl command: > > #define MMC_COMBO_IOC_CMD(n) _IOC(_IOC_READ|_IOC_WRITE, 1, sizeof(struct mmc_ioc_cmd) * (n)) > > This is of course also ugly because the ioctl command number is not > fixed, and because the limit for the number of mmc command blocks > is architecture dependent, depending on the definition of the _IOC > macro that can have either 13 or 14 bits to encode the argument length > in bytes. Interesting idea. However, given your comments above, I think that I would rather place the size in the structure. Cheers Jon -- 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
On Thursday 10 September 2015 09:24:19 Jon Hunter wrote: > On 09/09/15 21:22, Arnd Bergmann wrote: > > On Wednesday 09 September 2015 17:44:54 Jon Hunter wrote: > >> On 09/09/15 16:56, Arnd Bergmann wrote: > >>> On Wednesday 09 September 2015 16:06:01 Jon Hunter wrote: > > > - you have some implicit padding after the structure and should replace that > > with explictit pad bytes to extend the structure to a multiple of its > > alignment (8 bytes). > > Would padding with __u32 at the end be sufficient here? I assume the > __u32 would be 32-bit aligned. However, was not sure if this would > always be the case. If you have a layout of __u64 pointer; __u8 size; __u32 pad; you still get three bytes of implied padding between size and pad. It's better to just have '__u8 __pad[7]' in that case. > > I was not referring to the use of an __u64 variable to pass a pointer, that > > is expected (and the macro would make it harder to understand). > > > > What I meant instead was the use of a pointer to an array as opposed to > > passing the array itself. With the definition I gave above, the size would > > still be the same on all architectures (you can replace the __u64 with > > an __u8 plus padding if you like), as sizeof(struct mmc_ioc_multi_cmd) > > is just '8' here. > > Do you have any strong preference here? I guess I don't and agree > neither are ideal. > > > Alternatively, you could just use an array of struct mmc_ioc_cmd by > > itself and encode the length in the ioctl command: > > > > #define MMC_COMBO_IOC_CMD(n) _IOC(_IOC_READ|_IOC_WRITE, 1, sizeof(struct mmc_ioc_cmd) * (n)) > > > > This is of course also ugly because the ioctl command number is not > > fixed, and because the limit for the number of mmc command blocks > > is architecture dependent, depending on the definition of the _IOC > > macro that can have either 13 or 14 bits to encode the argument length > > in bytes. > > Interesting idea. However, given your comments above, I think that I > would rather place the size in the structure. I don't have a strong preference here. If there is a slight chance that you might need more than ((1<<13) / sizeof(struct mmc_ioc_cmd)) mmc commands in one ioctl, you can rule out that last solution. If you can prove that this length would always be sufficient, I'd probably pick that approach. Otherwise, I'd pick the one the size followed by an an open array. Arnd -- 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
On Thu, Sep 10, 2015 at 1:24 AM, Jon Hunter <jonathanh@nvidia.com> wrote: ... >> - you have some implicit padding after the structure and should replace that >> with explictit pad bytes to extend the structure to a multiple of its >> alignment (8 bytes). > > Would padding with __u32 at the end be sufficient here? I assume the > __u32 would be 32-bit aligned. However, was not sure if this would > always be the case. Is there something wrong with implicit padding? Only one copy of the structure is passed to the kernel for any given call. >>>> struct mmc_ioc_multi_cmd { >>>> __u64 num_of_cmds; >>>> struct mmc_ioc_cmd cmds[0]; >>>> }; I think this would work just as well. But doesn't "pointer to an array" require 32-bit ioctl compat handling? We were trying to avoid a 32-bit user space compatibility handler. >>>> as I said, both are ugly. My first choice would have been the other one, >>>> but I'm sure you have some reasons yourself. Why do you prefer the alternative you proposed? My guess is better type checking (and I would like that too). But maybe there is something else? cheers, grant -- 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
On 10/09/15 18:10, Grant Grundler wrote: > On Thu, Sep 10, 2015 at 1:24 AM, Jon Hunter <jonathanh@nvidia.com> wrote: > ... >>> - you have some implicit padding after the structure and should replace that >>> with explictit pad bytes to extend the structure to a multiple of its >>> alignment (8 bytes). >> >> Would padding with __u32 at the end be sufficient here? I assume the >> __u32 would be 32-bit aligned. However, was not sure if this would >> always be the case. > > Is there something wrong with implicit padding? > Only one copy of the structure is passed to the kernel for any given call. > >>>>> struct mmc_ioc_multi_cmd { >>>>> __u64 num_of_cmds; >>>>> struct mmc_ioc_cmd cmds[0]; >>>>> }; > > I think this would work just as well. But doesn't "pointer to an > array" require 32-bit ioctl compat handling? > We were trying to avoid a 32-bit user space compatibility handler. I think that this is fine as it is a zero length array [0] and not a pointer. Cheers Jon [0] https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html -- 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
On Thu, Sep 10, 2015 at 11:20 AM, Jon Hunter <jonathanh@nvidia.com> wrote: > > On 10/09/15 18:10, Grant Grundler wrote: ... >>>>>> struct mmc_ioc_multi_cmd { >>>>>> __u64 num_of_cmds; >>>>>> struct mmc_ioc_cmd cmds[0]; >>>>>> }; >> >> I think this would work just as well. But doesn't "pointer to an >> array" require 32-bit ioctl compat handling? >> We were trying to avoid a 32-bit user space compatibility handler. > > I think that this is fine as it is a zero length array [0] and not a > pointer. Doh, yes. Thanks for correcting. I knew this was a gcc special but forgot it's not actually allocating any space. cheers, grant > > Cheers > Jon > > [0] https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html -- 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
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index c742cfd7674e..738bfd037209 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -387,6 +387,24 @@ out: return ERR_PTR(err); } +static int mmc_blk_ioctl_copy_to_user(struct mmc_ioc_cmd __user *ic_ptr, + struct mmc_blk_ioc_data *idata) +{ + struct mmc_ioc_cmd *ic = &idata->ic; + + if (copy_to_user(&(ic_ptr->response), ic->response, + sizeof(ic->response))) + return -EFAULT; + + if (!idata->ic.write_flag) { + if (copy_to_user((void __user *)(unsigned long)ic->data_ptr, + idata->buf, idata->buf_bytes)) + return -EFAULT; + } + + return 0; +} + static int ioctl_rpmb_card_status_poll(struct mmc_card *card, u32 *status, u32 retries_max) { @@ -447,12 +465,9 @@ out: return err; } -static int mmc_blk_ioctl_cmd(struct block_device *bdev, - struct mmc_ioc_cmd __user *ic_ptr) +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; - struct mmc_blk_data *md; - struct mmc_card *card; struct mmc_command cmd = {0}; struct mmc_data data = {0}; struct mmc_request mrq = {NULL}; @@ -461,33 +476,12 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev, int is_rpmb = false; u32 status = 0; - /* - * 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); - - md = mmc_blk_get(bdev->bd_disk); - if (!md) { - err = -EINVAL; - goto cmd_err; - } + if (!card || !md || !idata) + return -EINVAL; if (md->area_type & MMC_BLK_DATA_AREA_RPMB) is_rpmb = true; - card = md->queue.card; - if (IS_ERR(card)) { - err = PTR_ERR(card); - goto cmd_done; - } - cmd.opcode = idata->ic.opcode; cmd.arg = idata->ic.arg; cmd.flags = idata->ic.flags; @@ -582,18 +576,7 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev, if (idata->ic.postsleep_min_us) usleep_range(idata->ic.postsleep_min_us, idata->ic.postsleep_max_us); - if (copy_to_user(&(ic_ptr->response), cmd.resp, sizeof(cmd.resp))) { - err = -EFAULT; - goto cmd_rel_host; - } - - if (!idata->ic.write_flag) { - if (copy_to_user((void __user *)(unsigned long) idata->ic.data_ptr, - idata->buf, idata->buf_bytes)) { - err = -EFAULT; - goto cmd_rel_host; - } - } + memcpy(&(idata->ic.response), cmd.resp, sizeof(cmd.resp)); if (is_rpmb) { /* @@ -609,6 +592,46 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev, cmd_rel_host: mmc_put_card(card); + return err; +} + +static int mmc_blk_ioctl_cmd(struct block_device *bdev, + struct mmc_ioc_cmd __user *ic_ptr) +{ + struct mmc_blk_ioc_data *idata; + struct mmc_blk_data *md; + struct mmc_card *card; + int err; + + /* + * 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); + + 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; + } + + err = __mmc_blk_ioctl_cmd(card, md, idata); + if (err) + goto cmd_done; + + err = mmc_blk_ioctl_copy_to_user(ic_ptr, idata); cmd_done: mmc_blk_put(md); @@ -618,13 +641,100 @@ cmd_err: return err; } +static int mmc_blk_ioctl_multi_cmd(struct block_device *bdev, + struct mmc_ioc_multi_cmd __user *user) +{ + struct mmc_ioc_multi_cmd mcci = {0}; + struct mmc_blk_ioc_data **idata = NULL; + struct mmc_ioc_cmd __user *cmds; + struct mmc_card *card; + struct mmc_blk_data *md; + int i, err = -EFAULT; + u8 n_cmds = 0; + + /* + * 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(&mcci, user, sizeof(struct mmc_ioc_multi_cmd))) + return -EFAULT; + + if (!mcci.num_of_cmds) { + err = -EINVAL; + goto cmd_err; + } + + idata = kcalloc(mcci.num_of_cmds, sizeof(*idata), GFP_KERNEL); + if (!idata) { + err = -ENOMEM; + goto cmd_err; + } + + cmds = (struct mmc_ioc_cmd __user *)(unsigned long)mcci.cmds_ptr; + for (n_cmds = 0; n_cmds < mcci.num_of_cmds; n_cmds++) { + idata[n_cmds] = mmc_blk_ioctl_copy_from_user(&cmds[n_cmds]); + if (IS_ERR(idata[n_cmds])) { + err = PTR_ERR(idata[n_cmds]); + goto cmd_err; + } + } + + md = mmc_blk_get(bdev->bd_disk); + if (!md) + goto cmd_err; + + card = md->queue.card; + if (IS_ERR(card)) { + err = PTR_ERR(card); + goto cmd_done; + } + + mmc_get_card(card); + for (i = 0; i < n_cmds; i++) { + err = __mmc_blk_ioctl_cmd(card, md, idata[i]); + if (err) { + mmc_release_host(card->host); + goto cmd_done; + } + } + + mmc_put_card(card); + + /* copy to user if data and response */ + for (i = 0; i < n_cmds; i++) { + err = mmc_blk_ioctl_copy_to_user(&cmds[i], idata[i]); + if (err) + break; + } + +cmd_done: + mmc_blk_put(md); +cmd_err: + for (i = 0; i < n_cmds; i++) { + kfree(idata[i]->buf); + kfree(idata[i]); + } + kfree(idata); + return err; +} + static int mmc_blk_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, unsigned long arg) { - int ret = -EINVAL; - if (cmd == MMC_IOC_CMD) - ret = mmc_blk_ioctl_cmd(bdev, (struct mmc_ioc_cmd __user *)arg); - return ret; + switch (cmd) { + case MMC_IOC_CMD: + return mmc_blk_ioctl_cmd(bdev, + (struct mmc_ioc_cmd __user *)arg); + case MMC_IOC_MULTI_CMD: + return mmc_blk_ioctl_multi_cmd(bdev, + (struct mmc_ioc_multi_cmd __user *)arg); + default: + return -EINVAL; + } } #ifdef CONFIG_COMPAT diff --git a/include/uapi/linux/mmc/ioctl.h b/include/uapi/linux/mmc/ioctl.h index 1f5e68923929..6b9a962dbee3 100644 --- a/include/uapi/linux/mmc/ioctl.h +++ b/include/uapi/linux/mmc/ioctl.h @@ -45,8 +45,23 @@ struct mmc_ioc_cmd { }; #define mmc_ioc_cmd_set_data(ic, ptr) ic.data_ptr = (__u64)(unsigned long) ptr -#define MMC_IOC_CMD _IOWR(MMC_BLOCK_MAJOR, 0, struct mmc_ioc_cmd) +/** + * struct mmc_ioc_multi_cmd - multi command information + * @cmds_ptr: Address of the location where the list of commands resides + * @num_of_cmds: number of commands to send + */ +struct mmc_ioc_multi_cmd { + __u64 cmds_ptr; + uint8_t num_of_cmds; +}; +#define MMC_IOC_CMD _IOWR(MMC_BLOCK_MAJOR, 0, struct mmc_ioc_cmd) +/* + * MMC_IOC_MULTI_CMD: Used to send an array of MMC commands described by + * the structure mmc_ioc_multi_cmd. The MMC driver will issue all + * commands in array in sequence to card. + */ +#define MMC_IOC_MULTI_CMD _IOWR(MMC_BLOCK_MAJOR, 1, struct mmc_ioc_multi_cmd) /* * Since this ioctl is only meant to enhance (and not replace) normal access * to the mmc bus device, an upper data transfer limit of MMC_IOC_MAX_BYTES