diff options
author | Johan Rudholm <johan.rudholm@stericsson.com> | 2011-11-23 03:05:58 -0500 |
---|---|---|
committer | Luis Henriques <luis.henriques@canonical.com> | 2012-03-26 05:26:36 -0400 |
commit | eeee7c3219d7d56c3cf6bb09411c16141058d9a6 (patch) | |
tree | 5e963fa0fecfab3814f1c5fcdc33b93e45af7a6c /drivers/mmc/card/block.c | |
parent | 948781482cb779bbdad5e9a6b8191d84ae2ca870 (diff) |
mmc: core: check for zero length ioctl data
BugLink: http://bugs.launchpad.net/bugs/954576
commit 4d6144de8ba263eb3691a737c547e5b2fdc45287 upstream.
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: Johan Rudholm <johan.rudholm@stericsson.com>
Signed-off-by: Chris Ball <cjb@laptop.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/mmc/card/block.c')
-rw-r--r-- | drivers/mmc/card/block.c | 82 |
1 files changed, 45 insertions, 37 deletions
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index f85e4222455..c0839d48f6c 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c | |||
@@ -251,6 +251,9 @@ static struct mmc_blk_ioc_data *mmc_blk_ioctl_copy_from_user( | |||
251 | goto idata_err; | 251 | goto idata_err; |
252 | } | 252 | } |
253 | 253 | ||
254 | if (!idata->buf_bytes) | ||
255 | return idata; | ||
256 | |||
254 | idata->buf = kzalloc(idata->buf_bytes, GFP_KERNEL); | 257 | idata->buf = kzalloc(idata->buf_bytes, GFP_KERNEL); |
255 | if (!idata->buf) { | 258 | if (!idata->buf) { |
256 | err = -ENOMEM; | 259 | err = -ENOMEM; |
@@ -297,25 +300,6 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev, | |||
297 | if (IS_ERR(idata)) | 300 | if (IS_ERR(idata)) |
298 | return PTR_ERR(idata); | 301 | return PTR_ERR(idata); |
299 | 302 | ||
300 | cmd.opcode = idata->ic.opcode; | ||
301 | cmd.arg = idata->ic.arg; | ||
302 | cmd.flags = idata->ic.flags; | ||
303 | |||
304 | data.sg = &sg; | ||
305 | data.sg_len = 1; | ||
306 | data.blksz = idata->ic.blksz; | ||
307 | data.blocks = idata->ic.blocks; | ||
308 | |||
309 | sg_init_one(data.sg, idata->buf, idata->buf_bytes); | ||
310 | |||
311 | if (idata->ic.write_flag) | ||
312 | data.flags = MMC_DATA_WRITE; | ||
313 | else | ||
314 | data.flags = MMC_DATA_READ; | ||
315 | |||
316 | mrq.cmd = &cmd; | ||
317 | mrq.data = &data; | ||
318 | |||
319 | md = mmc_blk_get(bdev->bd_disk); | 303 | md = mmc_blk_get(bdev->bd_disk); |
320 | if (!md) { | 304 | if (!md) { |
321 | err = -EINVAL; | 305 | err = -EINVAL; |
@@ -328,6 +312,48 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev, | |||
328 | goto cmd_done; | 312 | goto cmd_done; |
329 | } | 313 | } |
330 | 314 | ||
315 | cmd.opcode = idata->ic.opcode; | ||
316 | cmd.arg = idata->ic.arg; | ||
317 | cmd.flags = idata->ic.flags; | ||
318 | |||
319 | if (idata->buf_bytes) { | ||
320 | data.sg = &sg; | ||
321 | data.sg_len = 1; | ||
322 | data.blksz = idata->ic.blksz; | ||
323 | data.blocks = idata->ic.blocks; | ||
324 | |||
325 | sg_init_one(data.sg, idata->buf, idata->buf_bytes); | ||
326 | |||
327 | if (idata->ic.write_flag) | ||
328 | data.flags = MMC_DATA_WRITE; | ||
329 | else | ||
330 | data.flags = MMC_DATA_READ; | ||
331 | |||
332 | /* data.flags must already be set before doing this. */ | ||
333 | mmc_set_data_timeout(&data, card); | ||
334 | |||
335 | /* Allow overriding the timeout_ns for empirical tuning. */ | ||
336 | if (idata->ic.data_timeout_ns) | ||
337 | data.timeout_ns = idata->ic.data_timeout_ns; | ||
338 | |||
339 | if ((cmd.flags & MMC_RSP_R1B) == MMC_RSP_R1B) { | ||
340 | /* | ||
341 | * Pretend this is a data transfer and rely on the | ||
342 | * host driver to compute timeout. When all host | ||
343 | * drivers support cmd.cmd_timeout for R1B, this | ||
344 | * can be changed to: | ||
345 | * | ||
346 | * mrq.data = NULL; | ||
347 | * cmd.cmd_timeout = idata->ic.cmd_timeout_ms; | ||
348 | */ | ||
349 | data.timeout_ns = idata->ic.cmd_timeout_ms * 1000000; | ||
350 | } | ||
351 | |||
352 | mrq.data = &data; | ||
353 | } | ||
354 | |||
355 | mrq.cmd = &cmd; | ||
356 | |||
331 | mmc_claim_host(card->host); | 357 | mmc_claim_host(card->host); |
332 | 358 | ||
333 | if (idata->ic.is_acmd) { | 359 | if (idata->ic.is_acmd) { |
@@ -336,24 +362,6 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev, | |||
336 | goto cmd_rel_host; | 362 | goto cmd_rel_host; |
337 | } | 363 | } |
338 | 364 | ||
339 | /* data.flags must already be set before doing this. */ | ||
340 | mmc_set_data_timeout(&data, card); | ||
341 | /* Allow overriding the timeout_ns for empirical tuning. */ | ||
342 | if (idata->ic.data_timeout_ns) | ||
343 | data.timeout_ns = idata->ic.data_timeout_ns; | ||
344 | |||
345 | if ((cmd.flags & MMC_RSP_R1B) == MMC_RSP_R1B) { | ||
346 | /* | ||
347 | * Pretend this is a data transfer and rely on the host driver | ||
348 | * to compute timeout. When all host drivers support | ||
349 | * cmd.cmd_timeout for R1B, this can be changed to: | ||
350 | * | ||
351 | * mrq.data = NULL; | ||
352 | * cmd.cmd_timeout = idata->ic.cmd_timeout_ms; | ||
353 | */ | ||
354 | data.timeout_ns = idata->ic.cmd_timeout_ms * 1000000; | ||
355 | } | ||
356 | |||
357 | mmc_wait_for_req(card->host, &mrq); | 365 | mmc_wait_for_req(card->host, &mrq); |
358 | 366 | ||
359 | if (cmd.error) { | 367 | if (cmd.error) { |