aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/mtdchar.c
diff options
context:
space:
mode:
authorKevin Cernekee <kpc.mtd@gmail.com>2009-04-09 01:53:13 -0400
committerDavid Woodhouse <David.Woodhouse@intel.com>2009-05-29 10:24:48 -0400
commit977185404046afb31d2e18fac0a076de1a20bf0e (patch)
tree4b0cd9a27748549126c52dbf0af6f4c3c89224df /drivers/mtd/mtdchar.c
parent0dc54e9f33e2fbcea28356bc2c8c931cb307d3b3 (diff)
mtd: compat_ioctl cleanup
1) Move the MEMREADOOB/MEMWRITEOOB compat_ioctl wrappers from fs/compat_ioctl.c into mtdchar.c . Original request was here: http://lkml.org/lkml/2009/4/1/295 2) Add missing COMPATIBLE_IOCTL lines, so that mtd-utils does not error out when running in 64/32 compatibility mode. LKML-Reference: <200904011650.22928.arnd@arndb.de> Signed-off-by: Kevin Cernekee <kpc.mtd@gmail.com> Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com> Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'drivers/mtd/mtdchar.c')
-rw-r--r--drivers/mtd/mtdchar.c255
1 files changed, 171 insertions, 84 deletions
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
index ad4b8618977..51bb0b09200 100644
--- a/drivers/mtd/mtdchar.c
+++ b/drivers/mtd/mtdchar.c
@@ -14,6 +14,7 @@
14#include <linux/sched.h> 14#include <linux/sched.h>
15#include <linux/smp_lock.h> 15#include <linux/smp_lock.h>
16#include <linux/backing-dev.h> 16#include <linux/backing-dev.h>
17#include <linux/compat.h>
17 18
18#include <linux/mtd/mtd.h> 19#include <linux/mtd/mtd.h>
19#include <linux/mtd/compatmac.h> 20#include <linux/mtd/compatmac.h>
@@ -355,6 +356,100 @@ static int otp_select_filemode(struct mtd_file_info *mfi, int mode)
355# define otp_select_filemode(f,m) -EOPNOTSUPP 356# define otp_select_filemode(f,m) -EOPNOTSUPP
356#endif 357#endif
357 358
359static int mtd_do_writeoob(struct file *file, struct mtd_info *mtd,
360 uint64_t start, uint32_t length, void __user *ptr,
361 uint32_t __user *retp)
362{
363 struct mtd_oob_ops ops;
364 uint32_t retlen;
365 int ret = 0;
366
367 if (!(file->f_mode & FMODE_WRITE))
368 return -EPERM;
369
370 if (length > 4096)
371 return -EINVAL;
372
373 if (!mtd->write_oob)
374 ret = -EOPNOTSUPP;
375 else
376 ret = access_ok(VERIFY_READ, ptr, length) ? 0 : EFAULT;
377
378 if (ret)
379 return ret;
380
381 ops.ooblen = length;
382 ops.ooboffs = start & (mtd->oobsize - 1);
383 ops.datbuf = NULL;
384 ops.mode = MTD_OOB_PLACE;
385
386 if (ops.ooboffs && ops.ooblen > (mtd->oobsize - ops.ooboffs))
387 return -EINVAL;
388
389 ops.oobbuf = kmalloc(length, GFP_KERNEL);
390 if (!ops.oobbuf)
391 return -ENOMEM;
392
393 if (copy_from_user(ops.oobbuf, ptr, length)) {
394 kfree(ops.oobbuf);
395 return -EFAULT;
396 }
397
398 start &= ~((uint64_t)mtd->oobsize - 1);
399 ret = mtd->write_oob(mtd, start, &ops);
400
401 if (ops.oobretlen > 0xFFFFFFFFU)
402 ret = -EOVERFLOW;
403 retlen = ops.oobretlen;
404 if (copy_to_user(retp, &retlen, sizeof(length)))
405 ret = -EFAULT;
406
407 kfree(ops.oobbuf);
408 return ret;
409}
410
411static int mtd_do_readoob(struct mtd_info *mtd, uint64_t start,
412 uint32_t length, void __user *ptr, uint32_t __user *retp)
413{
414 struct mtd_oob_ops ops;
415 int ret = 0;
416
417 if (length > 4096)
418 return -EINVAL;
419
420 if (!mtd->read_oob)
421 ret = -EOPNOTSUPP;
422 else
423 ret = access_ok(VERIFY_WRITE, ptr,
424 length) ? 0 : -EFAULT;
425 if (ret)
426 return ret;
427
428 ops.ooblen = length;
429 ops.ooboffs = start & (mtd->oobsize - 1);
430 ops.datbuf = NULL;
431 ops.mode = MTD_OOB_PLACE;
432
433 if (ops.ooboffs && ops.ooblen > (mtd->oobsize - ops.ooboffs))
434 return -EINVAL;
435
436 ops.oobbuf = kmalloc(length, GFP_KERNEL);
437 if (!ops.oobbuf)
438 return -ENOMEM;
439
440 start &= ~((uint64_t)mtd->oobsize - 1);
441 ret = mtd->read_oob(mtd, start, &ops);
442
443 if (put_user(ops.oobretlen, retp))
444 ret = -EFAULT;
445 else if (ops.oobretlen && copy_to_user(ptr, ops.oobbuf,
446 ops.oobretlen))
447 ret = -EFAULT;
448
449 kfree(ops.oobbuf);
450 return ret;
451}
452
358static int mtd_ioctl(struct inode *inode, struct file *file, 453static int mtd_ioctl(struct inode *inode, struct file *file,
359 u_int cmd, u_long arg) 454 u_int cmd, u_long arg)
360{ 455{
@@ -487,100 +582,28 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
487 case MEMWRITEOOB: 582 case MEMWRITEOOB:
488 { 583 {
489 struct mtd_oob_buf buf; 584 struct mtd_oob_buf buf;
490 struct mtd_oob_ops ops; 585 struct mtd_oob_buf __user *buf_user = argp;
491 struct mtd_oob_buf __user *user_buf = argp;
492 uint32_t retlen;
493
494 if(!(file->f_mode & FMODE_WRITE))
495 return -EPERM;
496
497 if (copy_from_user(&buf, argp, sizeof(struct mtd_oob_buf)))
498 return -EFAULT;
499
500 if (buf.length > 4096)
501 return -EINVAL;
502
503 if (!mtd->write_oob)
504 ret = -EOPNOTSUPP;
505 else
506 ret = access_ok(VERIFY_READ, buf.ptr,
507 buf.length) ? 0 : EFAULT;
508
509 if (ret)
510 return ret;
511
512 ops.ooblen = buf.length;
513 ops.ooboffs = buf.start & (mtd->oobsize - 1);
514 ops.datbuf = NULL;
515 ops.mode = MTD_OOB_PLACE;
516
517 if (ops.ooboffs && ops.ooblen > (mtd->oobsize - ops.ooboffs))
518 return -EINVAL;
519
520 ops.oobbuf = kmalloc(buf.length, GFP_KERNEL);
521 if (!ops.oobbuf)
522 return -ENOMEM;
523
524 if (copy_from_user(ops.oobbuf, buf.ptr, buf.length)) {
525 kfree(ops.oobbuf);
526 return -EFAULT;
527 }
528
529 buf.start &= ~(mtd->oobsize - 1);
530 ret = mtd->write_oob(mtd, buf.start, &ops);
531 586
532 if (ops.oobretlen > 0xFFFFFFFFU) 587 /* NOTE: writes return length to buf_user->length */
533 ret = -EOVERFLOW; 588 if (copy_from_user(&buf, argp, sizeof(buf)))
534 retlen = ops.oobretlen;
535 if (copy_to_user(&user_buf->length, &retlen, sizeof(buf.length)))
536 ret = -EFAULT; 589 ret = -EFAULT;
537 590 else
538 kfree(ops.oobbuf); 591 ret = mtd_do_writeoob(file, mtd, buf.start, buf.length,
592 buf.ptr, &buf_user->length);
539 break; 593 break;
540
541 } 594 }
542 595
543 case MEMREADOOB: 596 case MEMREADOOB:
544 { 597 {
545 struct mtd_oob_buf buf; 598 struct mtd_oob_buf buf;
546 struct mtd_oob_ops ops; 599 struct mtd_oob_buf __user *buf_user = argp;
547
548 if (copy_from_user(&buf, argp, sizeof(struct mtd_oob_buf)))
549 return -EFAULT;
550
551 if (buf.length > 4096)
552 return -EINVAL;
553
554 if (!mtd->read_oob)
555 ret = -EOPNOTSUPP;
556 else
557 ret = access_ok(VERIFY_WRITE, buf.ptr,
558 buf.length) ? 0 : -EFAULT;
559 if (ret)
560 return ret;
561
562 ops.ooblen = buf.length;
563 ops.ooboffs = buf.start & (mtd->oobsize - 1);
564 ops.datbuf = NULL;
565 ops.mode = MTD_OOB_PLACE;
566 600
567 if (ops.ooboffs && ops.ooblen > (mtd->oobsize - ops.ooboffs)) 601 /* NOTE: writes return length to buf_user->start */
568 return -EINVAL; 602 if (copy_from_user(&buf, argp, sizeof(buf)))
569
570 ops.oobbuf = kmalloc(buf.length, GFP_KERNEL);
571 if (!ops.oobbuf)
572 return -ENOMEM;
573
574 buf.start &= ~(mtd->oobsize - 1);
575 ret = mtd->read_oob(mtd, buf.start, &ops);
576
577 if (put_user(ops.oobretlen, (uint32_t __user *)argp))
578 ret = -EFAULT;
579 else if (ops.oobretlen && copy_to_user(buf.ptr, ops.oobbuf,
580 ops.oobretlen))
581 ret = -EFAULT; 603 ret = -EFAULT;
582 604 else
583 kfree(ops.oobbuf); 605 ret = mtd_do_readoob(mtd, buf.start, buf.length,
606 buf.ptr, &buf_user->start);
584 break; 607 break;
585 } 608 }
586 609
@@ -771,6 +794,67 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
771 return ret; 794 return ret;
772} /* memory_ioctl */ 795} /* memory_ioctl */
773 796
797#ifdef CONFIG_COMPAT
798
799struct mtd_oob_buf32 {
800 u_int32_t start;
801 u_int32_t length;
802 compat_caddr_t ptr; /* unsigned char* */
803};
804
805#define MEMWRITEOOB32 _IOWR('M', 3, struct mtd_oob_buf32)
806#define MEMREADOOB32 _IOWR('M', 4, struct mtd_oob_buf32)
807
808static long mtd_compat_ioctl(struct file *file, unsigned int cmd,
809 unsigned long arg)
810{
811 struct mtd_file_info *mfi = file->private_data;
812 struct mtd_info *mtd = mfi->mtd;
813 void __user *argp = (void __user *)arg;
814 int ret = 0;
815
816 lock_kernel();
817
818 switch (cmd) {
819 case MEMWRITEOOB32:
820 {
821 struct mtd_oob_buf32 buf;
822 struct mtd_oob_buf32 __user *buf_user = argp;
823
824 if (copy_from_user(&buf, argp, sizeof(buf)))
825 ret = -EFAULT;
826 else
827 ret = mtd_do_writeoob(file, mtd, buf.start,
828 buf.length, compat_ptr(buf.ptr),
829 &buf_user->length);
830 break;
831 }
832
833 case MEMREADOOB32:
834 {
835 struct mtd_oob_buf32 buf;
836 struct mtd_oob_buf32 __user *buf_user = argp;
837
838 /* NOTE: writes return length to buf->start */
839 if (copy_from_user(&buf, argp, sizeof(buf)))
840 ret = -EFAULT;
841 else
842 ret = mtd_do_readoob(mtd, buf.start,
843 buf.length, compat_ptr(buf.ptr),
844 &buf_user->start);
845 break;
846 }
847 default:
848 ret = -ENOIOCTLCMD;
849 }
850
851 unlock_kernel();
852
853 return ret;
854}
855
856#endif /* CONFIG_COMPAT */
857
774/* 858/*
775 * try to determine where a shared mapping can be made 859 * try to determine where a shared mapping can be made
776 * - only supported for NOMMU at the moment (MMU can't doesn't copy private 860 * - only supported for NOMMU at the moment (MMU can't doesn't copy private
@@ -830,6 +914,9 @@ static const struct file_operations mtd_fops = {
830 .read = mtd_read, 914 .read = mtd_read,
831 .write = mtd_write, 915 .write = mtd_write,
832 .ioctl = mtd_ioctl, 916 .ioctl = mtd_ioctl,
917#ifdef CONFIG_COMPAT
918 .compat_ioctl = mtd_compat_ioctl,
919#endif
833 .open = mtd_open, 920 .open = mtd_open,
834 .release = mtd_close, 921 .release = mtd_close,
835 .mmap = mtd_mmap, 922 .mmap = mtd_mmap,