aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/mtdchar.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mtd/mtdchar.c')
-rw-r--r--drivers/mtd/mtdchar.c59
1 files changed, 39 insertions, 20 deletions
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
index b45e7747daa3..7522fc3a2827 100644
--- a/drivers/mtd/mtdchar.c
+++ b/drivers/mtd/mtdchar.c
@@ -408,8 +408,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
408 case MEMWRITEOOB: 408 case MEMWRITEOOB:
409 { 409 {
410 struct mtd_oob_buf buf; 410 struct mtd_oob_buf buf;
411 void *databuf; 411 struct mtd_oob_ops ops;
412 ssize_t retlen;
413 412
414 if(!(file->f_mode & 2)) 413 if(!(file->f_mode & 2))
415 return -EPERM; 414 return -EPERM;
@@ -417,7 +416,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
417 if (copy_from_user(&buf, argp, sizeof(struct mtd_oob_buf))) 416 if (copy_from_user(&buf, argp, sizeof(struct mtd_oob_buf)))
418 return -EFAULT; 417 return -EFAULT;
419 418
420 if (buf.length > 0x4096) 419 if (buf.length > 4096)
421 return -EINVAL; 420 return -EINVAL;
422 421
423 if (!mtd->write_oob) 422 if (!mtd->write_oob)
@@ -429,21 +428,32 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
429 if (ret) 428 if (ret)
430 return ret; 429 return ret;
431 430
432 databuf = kmalloc(buf.length, GFP_KERNEL); 431 ops.len = buf.length;
433 if (!databuf) 432 ops.ooblen = mtd->oobsize;
433 ops.ooboffs = buf.start & (mtd->oobsize - 1);
434 ops.datbuf = NULL;
435 ops.mode = MTD_OOB_PLACE;
436
437 if (ops.ooboffs && ops.len > (ops.ooblen - ops.ooboffs))
438 return -EINVAL;
439
440 ops.oobbuf = kmalloc(buf.length, GFP_KERNEL);
441 if (!ops.oobbuf)
434 return -ENOMEM; 442 return -ENOMEM;
435 443
436 if (copy_from_user(databuf, buf.ptr, buf.length)) { 444 if (copy_from_user(ops.oobbuf, buf.ptr, buf.length)) {
437 kfree(databuf); 445 kfree(ops.oobbuf);
438 return -EFAULT; 446 return -EFAULT;
439 } 447 }
440 448
441 ret = (mtd->write_oob)(mtd, buf.start, buf.length, &retlen, databuf); 449 buf.start &= ~(mtd->oobsize - 1);
450 ret = mtd->write_oob(mtd, buf.start, &ops);
442 451
443 if (copy_to_user(argp + sizeof(uint32_t), &retlen, sizeof(uint32_t))) 452 if (copy_to_user(argp + sizeof(uint32_t), &ops.retlen,
453 sizeof(uint32_t)))
444 ret = -EFAULT; 454 ret = -EFAULT;
445 455
446 kfree(databuf); 456 kfree(ops.oobbuf);
447 break; 457 break;
448 458
449 } 459 }
@@ -451,13 +461,12 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
451 case MEMREADOOB: 461 case MEMREADOOB:
452 { 462 {
453 struct mtd_oob_buf buf; 463 struct mtd_oob_buf buf;
454 void *databuf; 464 struct mtd_oob_ops ops;
455 ssize_t retlen;
456 465
457 if (copy_from_user(&buf, argp, sizeof(struct mtd_oob_buf))) 466 if (copy_from_user(&buf, argp, sizeof(struct mtd_oob_buf)))
458 return -EFAULT; 467 return -EFAULT;
459 468
460 if (buf.length > 0x4096) 469 if (buf.length > 4096)
461 return -EINVAL; 470 return -EINVAL;
462 471
463 if (!mtd->read_oob) 472 if (!mtd->read_oob)
@@ -465,22 +474,32 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
465 else 474 else
466 ret = access_ok(VERIFY_WRITE, buf.ptr, 475 ret = access_ok(VERIFY_WRITE, buf.ptr,
467 buf.length) ? 0 : -EFAULT; 476 buf.length) ? 0 : -EFAULT;
468
469 if (ret) 477 if (ret)
470 return ret; 478 return ret;
471 479
472 databuf = kmalloc(buf.length, GFP_KERNEL); 480 ops.len = buf.length;
473 if (!databuf) 481 ops.ooblen = mtd->oobsize;
482 ops.ooboffs = buf.start & (mtd->oobsize - 1);
483 ops.datbuf = NULL;
484 ops.mode = MTD_OOB_PLACE;
485
486 if (ops.ooboffs && ops.len > (ops.ooblen - ops.ooboffs))
487 return -EINVAL;
488
489 ops.oobbuf = kmalloc(buf.length, GFP_KERNEL);
490 if (!ops.oobbuf)
474 return -ENOMEM; 491 return -ENOMEM;
475 492
476 ret = (mtd->read_oob)(mtd, buf.start, buf.length, &retlen, databuf); 493 buf.start &= ~(mtd->oobsize - 1);
494 ret = mtd->read_oob(mtd, buf.start, &ops);
477 495
478 if (put_user(retlen, (uint32_t __user *)argp)) 496 if (put_user(ops.retlen, (uint32_t __user *)argp))
479 ret = -EFAULT; 497 ret = -EFAULT;
480 else if (retlen && copy_to_user(buf.ptr, databuf, retlen)) 498 else if (ops.retlen && copy_to_user(buf.ptr, ops.oobbuf,
499 ops.retlen))
481 ret = -EFAULT; 500 ret = -EFAULT;
482 501
483 kfree(databuf); 502 kfree(ops.oobbuf);
484 break; 503 break;
485 } 504 }
486 505