diff options
author | Johan Rudholm <johan.rudholm@stericsson.com> | 2011-11-23 03:05:58 -0500 |
---|---|---|
committer | Chris Ball <cjb@laptop.org> | 2012-01-11 23:58:42 -0500 |
commit | 4d6144de8ba263eb3691a737c547e5b2fdc45287 (patch) | |
tree | 18ff9af5efcf42fdafae2e76a0df75cf498923e8 /drivers/mmc/card | |
parent | 4ee5ebaf74ba1b3e2e3f9aad442bf38db96c20d2 (diff) |
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: Johan Rudholm <johan.rudholm@stericsson.com>
Signed-off-by: Chris Ball <cjb@laptop.org>
Diffstat (limited to 'drivers/mmc/card')
-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 c80bb6de40b8..ad0fb8d74dda 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c | |||
@@ -266,6 +266,9 @@ static struct mmc_blk_ioc_data *mmc_blk_ioctl_copy_from_user( | |||
266 | goto idata_err; | 266 | goto idata_err; |
267 | } | 267 | } |
268 | 268 | ||
269 | if (!idata->buf_bytes) | ||
270 | return idata; | ||
271 | |||
269 | idata->buf = kzalloc(idata->buf_bytes, GFP_KERNEL); | 272 | idata->buf = kzalloc(idata->buf_bytes, GFP_KERNEL); |
270 | if (!idata->buf) { | 273 | if (!idata->buf) { |
271 | err = -ENOMEM; | 274 | err = -ENOMEM; |
@@ -312,25 +315,6 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev, | |||
312 | if (IS_ERR(idata)) | 315 | if (IS_ERR(idata)) |
313 | return PTR_ERR(idata); | 316 | return PTR_ERR(idata); |
314 | 317 | ||
315 | cmd.opcode = idata->ic.opcode; | ||
316 | cmd.arg = idata->ic.arg; | ||
317 | cmd.flags = idata->ic.flags; | ||
318 | |||
319 | data.sg = &sg; | ||
320 | data.sg_len = 1; | ||
321 | data.blksz = idata->ic.blksz; | ||
322 | data.blocks = idata->ic.blocks; | ||
323 | |||
324 | sg_init_one(data.sg, idata->buf, idata->buf_bytes); | ||
325 | |||
326 | if (idata->ic.write_flag) | ||
327 | data.flags = MMC_DATA_WRITE; | ||
328 | else | ||
329 | data.flags = MMC_DATA_READ; | ||
330 | |||
331 | mrq.cmd = &cmd; | ||
332 | mrq.data = &data; | ||
333 | |||
334 | md = mmc_blk_get(bdev->bd_disk); | 318 | md = mmc_blk_get(bdev->bd_disk); |
335 | if (!md) { | 319 | if (!md) { |
336 | err = -EINVAL; | 320 | err = -EINVAL; |
@@ -343,6 +327,48 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev, | |||
343 | goto cmd_done; | 327 | goto cmd_done; |
344 | } | 328 | } |
345 | 329 | ||
330 | cmd.opcode = idata->ic.opcode; | ||
331 | cmd.arg = idata->ic.arg; | ||
332 | cmd.flags = idata->ic.flags; | ||
333 | |||
334 | if (idata->buf_bytes) { | ||
335 | data.sg = &sg; | ||
336 | data.sg_len = 1; | ||
337 | data.blksz = idata->ic.blksz; | ||
338 | data.blocks = idata->ic.blocks; | ||
339 | |||
340 | sg_init_one(data.sg, idata->buf, idata->buf_bytes); | ||
341 | |||
342 | if (idata->ic.write_flag) | ||
343 | data.flags = MMC_DATA_WRITE; | ||
344 | else | ||
345 | data.flags = MMC_DATA_READ; | ||
346 | |||
347 | /* data.flags must already be set before doing this. */ | ||
348 | mmc_set_data_timeout(&data, card); | ||
349 | |||
350 | /* Allow overriding the timeout_ns for empirical tuning. */ | ||
351 | if (idata->ic.data_timeout_ns) | ||
352 | data.timeout_ns = idata->ic.data_timeout_ns; | ||
353 | |||
354 | if ((cmd.flags & MMC_RSP_R1B) == MMC_RSP_R1B) { | ||
355 | /* | ||
356 | * Pretend this is a data transfer and rely on the | ||
357 | * host driver to compute timeout. When all host | ||
358 | * drivers support cmd.cmd_timeout for R1B, this | ||
359 | * can be changed to: | ||
360 | * | ||
361 | * mrq.data = NULL; | ||
362 | * cmd.cmd_timeout = idata->ic.cmd_timeout_ms; | ||
363 | */ | ||
364 | data.timeout_ns = idata->ic.cmd_timeout_ms * 1000000; | ||
365 | } | ||
366 | |||
367 | mrq.data = &data; | ||
368 | } | ||
369 | |||
370 | mrq.cmd = &cmd; | ||
371 | |||
346 | mmc_claim_host(card->host); | 372 | mmc_claim_host(card->host); |
347 | 373 | ||
348 | if (idata->ic.is_acmd) { | 374 | if (idata->ic.is_acmd) { |
@@ -351,24 +377,6 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev, | |||
351 | goto cmd_rel_host; | 377 | goto cmd_rel_host; |
352 | } | 378 | } |
353 | 379 | ||
354 | /* data.flags must already be set before doing this. */ | ||
355 | mmc_set_data_timeout(&data, card); | ||
356 | /* Allow overriding the timeout_ns for empirical tuning. */ | ||
357 | if (idata->ic.data_timeout_ns) | ||
358 | data.timeout_ns = idata->ic.data_timeout_ns; | ||
359 | |||
360 | if ((cmd.flags & MMC_RSP_R1B) == MMC_RSP_R1B) { | ||
361 | /* | ||
362 | * Pretend this is a data transfer and rely on the host driver | ||
363 | * to compute timeout. When all host drivers support | ||
364 | * cmd.cmd_timeout for R1B, this can be changed to: | ||
365 | * | ||
366 | * mrq.data = NULL; | ||
367 | * cmd.cmd_timeout = idata->ic.cmd_timeout_ms; | ||
368 | */ | ||
369 | data.timeout_ns = idata->ic.cmd_timeout_ms * 1000000; | ||
370 | } | ||
371 | |||
372 | mmc_wait_for_req(card->host, &mrq); | 380 | mmc_wait_for_req(card->host, &mrq); |
373 | 381 | ||
374 | if (cmd.error) { | 382 | if (cmd.error) { |