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.c105
1 files changed, 91 insertions, 14 deletions
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
index 5b081cb84351..8bb5e4a66328 100644
--- a/drivers/mtd/mtdchar.c
+++ b/drivers/mtd/mtdchar.c
@@ -15,12 +15,15 @@
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#include <linux/compat.h>
18#include <linux/mount.h>
18 19
19#include <linux/mtd/mtd.h> 20#include <linux/mtd/mtd.h>
20#include <linux/mtd/compatmac.h> 21#include <linux/mtd/compatmac.h>
21 22
22#include <asm/uaccess.h> 23#include <asm/uaccess.h>
23 24
25#define MTD_INODE_FS_MAGIC 0x11307854
26static struct vfsmount *mtd_inode_mnt __read_mostly;
24 27
25/* 28/*
26 * Data structure to hold the pointer to the mtd device as well 29 * Data structure to hold the pointer to the mtd device as well
@@ -28,6 +31,7 @@
28 */ 31 */
29struct mtd_file_info { 32struct mtd_file_info {
30 struct mtd_info *mtd; 33 struct mtd_info *mtd;
34 struct inode *ino;
31 enum mtd_file_modes mode; 35 enum mtd_file_modes mode;
32}; 36};
33 37
@@ -64,12 +68,10 @@ static int mtd_open(struct inode *inode, struct file *file)
64 int ret = 0; 68 int ret = 0;
65 struct mtd_info *mtd; 69 struct mtd_info *mtd;
66 struct mtd_file_info *mfi; 70 struct mtd_file_info *mfi;
71 struct inode *mtd_ino;
67 72
68 DEBUG(MTD_DEBUG_LEVEL0, "MTD_open\n"); 73 DEBUG(MTD_DEBUG_LEVEL0, "MTD_open\n");
69 74
70 if (devnum >= MAX_MTD_DEVICES)
71 return -ENODEV;
72
73 /* You can't open the RO devices RW */ 75 /* You can't open the RO devices RW */
74 if ((file->f_mode & FMODE_WRITE) && (minor & 1)) 76 if ((file->f_mode & FMODE_WRITE) && (minor & 1))
75 return -EACCES; 77 return -EACCES;
@@ -88,11 +90,23 @@ static int mtd_open(struct inode *inode, struct file *file)
88 goto out; 90 goto out;
89 } 91 }
90 92
91 if (mtd->backing_dev_info) 93 mtd_ino = iget_locked(mtd_inode_mnt->mnt_sb, devnum);
92 file->f_mapping->backing_dev_info = mtd->backing_dev_info; 94 if (!mtd_ino) {
95 put_mtd_device(mtd);
96 ret = -ENOMEM;
97 goto out;
98 }
99 if (mtd_ino->i_state & I_NEW) {
100 mtd_ino->i_private = mtd;
101 mtd_ino->i_mode = S_IFCHR;
102 mtd_ino->i_data.backing_dev_info = mtd->backing_dev_info;
103 unlock_new_inode(mtd_ino);
104 }
105 file->f_mapping = mtd_ino->i_mapping;
93 106
94 /* You can't open it RW if it's not a writeable device */ 107 /* You can't open it RW if it's not a writeable device */
95 if ((file->f_mode & FMODE_WRITE) && !(mtd->flags & MTD_WRITEABLE)) { 108 if ((file->f_mode & FMODE_WRITE) && !(mtd->flags & MTD_WRITEABLE)) {
109 iput(mtd_ino);
96 put_mtd_device(mtd); 110 put_mtd_device(mtd);
97 ret = -EACCES; 111 ret = -EACCES;
98 goto out; 112 goto out;
@@ -100,10 +114,12 @@ static int mtd_open(struct inode *inode, struct file *file)
100 114
101 mfi = kzalloc(sizeof(*mfi), GFP_KERNEL); 115 mfi = kzalloc(sizeof(*mfi), GFP_KERNEL);
102 if (!mfi) { 116 if (!mfi) {
117 iput(mtd_ino);
103 put_mtd_device(mtd); 118 put_mtd_device(mtd);
104 ret = -ENOMEM; 119 ret = -ENOMEM;
105 goto out; 120 goto out;
106 } 121 }
122 mfi->ino = mtd_ino;
107 mfi->mtd = mtd; 123 mfi->mtd = mtd;
108 file->private_data = mfi; 124 file->private_data = mfi;
109 125
@@ -125,6 +141,8 @@ static int mtd_close(struct inode *inode, struct file *file)
125 if ((file->f_mode & FMODE_WRITE) && mtd->sync) 141 if ((file->f_mode & FMODE_WRITE) && mtd->sync)
126 mtd->sync(mtd); 142 mtd->sync(mtd);
127 143
144 iput(mfi->ino);
145
128 put_mtd_device(mtd); 146 put_mtd_device(mtd);
129 file->private_data = NULL; 147 file->private_data = NULL;
130 kfree(mfi); 148 kfree(mfi);
@@ -373,7 +391,7 @@ static int mtd_do_writeoob(struct file *file, struct mtd_info *mtd,
373 if (!mtd->write_oob) 391 if (!mtd->write_oob)
374 ret = -EOPNOTSUPP; 392 ret = -EOPNOTSUPP;
375 else 393 else
376 ret = access_ok(VERIFY_READ, ptr, length) ? 0 : EFAULT; 394 ret = access_ok(VERIFY_READ, ptr, length) ? 0 : -EFAULT;
377 395
378 if (ret) 396 if (ret)
379 return ret; 397 return ret;
@@ -482,7 +500,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
482 { 500 {
483 uint32_t ur_idx; 501 uint32_t ur_idx;
484 struct mtd_erase_region_info *kr; 502 struct mtd_erase_region_info *kr;
485 struct region_info_user *ur = (struct region_info_user *) argp; 503 struct region_info_user __user *ur = argp;
486 504
487 if (get_user(ur_idx, &(ur->regionindex))) 505 if (get_user(ur_idx, &(ur->regionindex)))
488 return -EFAULT; 506 return -EFAULT;
@@ -954,22 +972,81 @@ static const struct file_operations mtd_fops = {
954#endif 972#endif
955}; 973};
956 974
975static int mtd_inodefs_get_sb(struct file_system_type *fs_type, int flags,
976 const char *dev_name, void *data,
977 struct vfsmount *mnt)
978{
979 return get_sb_pseudo(fs_type, "mtd_inode:", NULL, MTD_INODE_FS_MAGIC,
980 mnt);
981}
982
983static struct file_system_type mtd_inodefs_type = {
984 .name = "mtd_inodefs",
985 .get_sb = mtd_inodefs_get_sb,
986 .kill_sb = kill_anon_super,
987};
988
989static void mtdchar_notify_add(struct mtd_info *mtd)
990{
991}
992
993static void mtdchar_notify_remove(struct mtd_info *mtd)
994{
995 struct inode *mtd_ino = ilookup(mtd_inode_mnt->mnt_sb, mtd->index);
996
997 if (mtd_ino) {
998 /* Destroy the inode if it exists */
999 mtd_ino->i_nlink = 0;
1000 iput(mtd_ino);
1001 }
1002}
1003
1004static struct mtd_notifier mtdchar_notifier = {
1005 .add = mtdchar_notify_add,
1006 .remove = mtdchar_notify_remove,
1007};
1008
957static int __init init_mtdchar(void) 1009static int __init init_mtdchar(void)
958{ 1010{
959 int status; 1011 int ret;
960 1012
961 status = register_chrdev(MTD_CHAR_MAJOR, "mtd", &mtd_fops); 1013 ret = __register_chrdev(MTD_CHAR_MAJOR, 0, 1 << MINORBITS,
962 if (status < 0) { 1014 "mtd", &mtd_fops);
963 printk(KERN_NOTICE "Can't allocate major number %d for Memory Technology Devices.\n", 1015 if (ret < 0) {
964 MTD_CHAR_MAJOR); 1016 pr_notice("Can't allocate major number %d for "
1017 "Memory Technology Devices.\n", MTD_CHAR_MAJOR);
1018 return ret;
965 } 1019 }
966 1020
967 return status; 1021 ret = register_filesystem(&mtd_inodefs_type);
1022 if (ret) {
1023 pr_notice("Can't register mtd_inodefs filesystem: %d\n", ret);
1024 goto err_unregister_chdev;
1025 }
1026
1027 mtd_inode_mnt = kern_mount(&mtd_inodefs_type);
1028 if (IS_ERR(mtd_inode_mnt)) {
1029 ret = PTR_ERR(mtd_inode_mnt);
1030 pr_notice("Error mounting mtd_inodefs filesystem: %d\n", ret);
1031 goto err_unregister_filesystem;
1032 }
1033 register_mtd_user(&mtdchar_notifier);
1034
1035 return ret;
1036
1037err_unregister_filesystem:
1038 unregister_filesystem(&mtd_inodefs_type);
1039err_unregister_chdev:
1040 __unregister_chrdev(MTD_CHAR_MAJOR, 0, 1 << MINORBITS, "mtd");
1041 return ret;
968} 1042}
969 1043
970static void __exit cleanup_mtdchar(void) 1044static void __exit cleanup_mtdchar(void)
971{ 1045{
972 unregister_chrdev(MTD_CHAR_MAJOR, "mtd"); 1046 unregister_mtd_user(&mtdchar_notifier);
1047 mntput(mtd_inode_mnt);
1048 unregister_filesystem(&mtd_inodefs_type);
1049 __unregister_chrdev(MTD_CHAR_MAJOR, 0, 1 << MINORBITS, "mtd");
973} 1050}
974 1051
975module_init(init_mtdchar); 1052module_init(init_mtdchar);