Commit 4d6144de authored by Johan Rudholm's avatar Johan Rudholm Committed by Chris Ball

mmc: core: check for zero length ioctl data

If the read or write buffer size associated with the command sent
through the mmc_blk_ioctl is zero, do not prepare data buffer.

This enables a ioctl(2) call to for instance send a MMC_SWITCH to set
a byte in the ext_csd.
Signed-off-by: default avatarJohan Rudholm <johan.rudholm@stericsson.com>
Signed-off-by: default avatarChris Ball <cjb@laptop.org>
parent 4ee5ebaf
...@@ -266,6 +266,9 @@ static struct mmc_blk_ioc_data *mmc_blk_ioctl_copy_from_user( ...@@ -266,6 +266,9 @@ static struct mmc_blk_ioc_data *mmc_blk_ioctl_copy_from_user(
goto idata_err; goto idata_err;
} }
if (!idata->buf_bytes)
return idata;
idata->buf = kzalloc(idata->buf_bytes, GFP_KERNEL); idata->buf = kzalloc(idata->buf_bytes, GFP_KERNEL);
if (!idata->buf) { if (!idata->buf) {
err = -ENOMEM; err = -ENOMEM;
...@@ -312,25 +315,6 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev, ...@@ -312,25 +315,6 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
if (IS_ERR(idata)) if (IS_ERR(idata))
return PTR_ERR(idata); return PTR_ERR(idata);
cmd.opcode = idata->ic.opcode;
cmd.arg = idata->ic.arg;
cmd.flags = idata->ic.flags;
data.sg = &sg;
data.sg_len = 1;
data.blksz = idata->ic.blksz;
data.blocks = idata->ic.blocks;
sg_init_one(data.sg, idata->buf, idata->buf_bytes);
if (idata->ic.write_flag)
data.flags = MMC_DATA_WRITE;
else
data.flags = MMC_DATA_READ;
mrq.cmd = &cmd;
mrq.data = &data;
md = mmc_blk_get(bdev->bd_disk); md = mmc_blk_get(bdev->bd_disk);
if (!md) { if (!md) {
err = -EINVAL; err = -EINVAL;
...@@ -343,6 +327,48 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev, ...@@ -343,6 +327,48 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
goto cmd_done; goto cmd_done;
} }
cmd.opcode = idata->ic.opcode;
cmd.arg = idata->ic.arg;
cmd.flags = idata->ic.flags;
if (idata->buf_bytes) {
data.sg = &sg;
data.sg_len = 1;
data.blksz = idata->ic.blksz;
data.blocks = idata->ic.blocks;
sg_init_one(data.sg, idata->buf, idata->buf_bytes);
if (idata->ic.write_flag)
data.flags = MMC_DATA_WRITE;
else
data.flags = MMC_DATA_READ;
/* data.flags must already be set before doing this. */
mmc_set_data_timeout(&data, card);
/* Allow overriding the timeout_ns for empirical tuning. */
if (idata->ic.data_timeout_ns)
data.timeout_ns = idata->ic.data_timeout_ns;
if ((cmd.flags & MMC_RSP_R1B) == MMC_RSP_R1B) {
/*
* Pretend this is a data transfer and rely on the
* host driver to compute timeout. When all host
* drivers support cmd.cmd_timeout for R1B, this
* can be changed to:
*
* mrq.data = NULL;
* cmd.cmd_timeout = idata->ic.cmd_timeout_ms;
*/
data.timeout_ns = idata->ic.cmd_timeout_ms * 1000000;
}
mrq.data = &data;
}
mrq.cmd = &cmd;
mmc_claim_host(card->host); mmc_claim_host(card->host);
if (idata->ic.is_acmd) { if (idata->ic.is_acmd) {
...@@ -351,24 +377,6 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev, ...@@ -351,24 +377,6 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
goto cmd_rel_host; goto cmd_rel_host;
} }
/* data.flags must already be set before doing this. */
mmc_set_data_timeout(&data, card);
/* Allow overriding the timeout_ns for empirical tuning. */
if (idata->ic.data_timeout_ns)
data.timeout_ns = idata->ic.data_timeout_ns;
if ((cmd.flags & MMC_RSP_R1B) == MMC_RSP_R1B) {
/*
* Pretend this is a data transfer and rely on the host driver
* to compute timeout. When all host drivers support
* cmd.cmd_timeout for R1B, this can be changed to:
*
* mrq.data = NULL;
* cmd.cmd_timeout = idata->ic.cmd_timeout_ms;
*/
data.timeout_ns = idata->ic.cmd_timeout_ms * 1000000;
}
mmc_wait_for_req(card->host, &mrq); mmc_wait_for_req(card->host, &mrq);
if (cmd.error) { if (cmd.error) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment