diff options
author | Kirill A. Shutemov <kirill@shutemov.name> | 2010-05-17 09:55:47 -0400 |
---|---|---|
committer | David Woodhouse <David.Woodhouse@intel.com> | 2010-05-18 07:19:36 -0400 |
commit | cd874237d97f24f601f16a140d20803b6a79202e (patch) | |
tree | 1d21ee13d45e7839a41c777e466f019cba2603d6 /drivers/mtd/mtdchar.c | |
parent | 11c93605faecfe6f9a28a6f3d14989bad077055a (diff) |
mtd: mtdchar: Do not corrupt backing device of device node inode
We cannot modify file->f_mapping->backing_dev_info, because it will corrupt
backing device of device node inode, since file->f_mapping is equal to
inode->i_mapping (see __dentry_open() in fs/open.c).
Let's introduce separate inode for MTD device with appropriate backing
device.
[dwmw2: Refactor to keep it all entirely within mtdchar.c; use iget_locked()]
Signed-off-by: Kirill A. Shutemov <kirill@shutemov.name>
Acked-by: Jan Kara <jack@suse.cz>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'drivers/mtd/mtdchar.c')
-rw-r--r-- | drivers/mtd/mtdchar.c | 95 |
1 files changed, 87 insertions, 8 deletions
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index c355491d1326..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 | ||
26 | static 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 | */ |
29 | struct mtd_file_info { | 32 | struct 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,6 +68,7 @@ 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 | ||
@@ -85,11 +90,23 @@ static int mtd_open(struct inode *inode, struct file *file) | |||
85 | goto out; | 90 | goto out; |
86 | } | 91 | } |
87 | 92 | ||
88 | if (mtd->backing_dev_info) | 93 | mtd_ino = iget_locked(mtd_inode_mnt->mnt_sb, devnum); |
89 | 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; | ||
90 | 106 | ||
91 | /* 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 */ |
92 | 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); | ||
93 | put_mtd_device(mtd); | 110 | put_mtd_device(mtd); |
94 | ret = -EACCES; | 111 | ret = -EACCES; |
95 | goto out; | 112 | goto out; |
@@ -97,10 +114,12 @@ static int mtd_open(struct inode *inode, struct file *file) | |||
97 | 114 | ||
98 | mfi = kzalloc(sizeof(*mfi), GFP_KERNEL); | 115 | mfi = kzalloc(sizeof(*mfi), GFP_KERNEL); |
99 | if (!mfi) { | 116 | if (!mfi) { |
117 | iput(mtd_ino); | ||
100 | put_mtd_device(mtd); | 118 | put_mtd_device(mtd); |
101 | ret = -ENOMEM; | 119 | ret = -ENOMEM; |
102 | goto out; | 120 | goto out; |
103 | } | 121 | } |
122 | mfi->ino = mtd_ino; | ||
104 | mfi->mtd = mtd; | 123 | mfi->mtd = mtd; |
105 | file->private_data = mfi; | 124 | file->private_data = mfi; |
106 | 125 | ||
@@ -122,6 +141,8 @@ static int mtd_close(struct inode *inode, struct file *file) | |||
122 | if ((file->f_mode & FMODE_WRITE) && mtd->sync) | 141 | if ((file->f_mode & FMODE_WRITE) && mtd->sync) |
123 | mtd->sync(mtd); | 142 | mtd->sync(mtd); |
124 | 143 | ||
144 | iput(mfi->ino); | ||
145 | |||
125 | put_mtd_device(mtd); | 146 | put_mtd_device(mtd); |
126 | file->private_data = NULL; | 147 | file->private_data = NULL; |
127 | kfree(mfi); | 148 | kfree(mfi); |
@@ -951,22 +972,80 @@ static const struct file_operations mtd_fops = { | |||
951 | #endif | 972 | #endif |
952 | }; | 973 | }; |
953 | 974 | ||
975 | static 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 | |||
983 | static 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 | |||
989 | static void mtdchar_notify_add(struct mtd_info *mtd) | ||
990 | { | ||
991 | } | ||
992 | |||
993 | static 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 | |||
1004 | static struct mtd_notifier mtdchar_notifier = { | ||
1005 | .add = mtdchar_notify_add, | ||
1006 | .remove = mtdchar_notify_remove, | ||
1007 | }; | ||
1008 | |||
954 | static int __init init_mtdchar(void) | 1009 | static int __init init_mtdchar(void) |
955 | { | 1010 | { |
956 | int status; | 1011 | int ret; |
957 | 1012 | ||
958 | status = __register_chrdev(MTD_CHAR_MAJOR, 0, 1 << MINORBITS, | 1013 | ret = __register_chrdev(MTD_CHAR_MAJOR, 0, 1 << MINORBITS, |
959 | "mtd", &mtd_fops); | 1014 | "mtd", &mtd_fops); |
960 | if (status < 0) { | 1015 | if (ret < 0) { |
961 | printk(KERN_NOTICE "Can't allocate major number %d for Memory Technology Devices.\n", | 1016 | pr_notice("Can't allocate major number %d for " |
962 | MTD_CHAR_MAJOR); | 1017 | "Memory Technology Devices.\n", MTD_CHAR_MAJOR); |
1018 | return ret; | ||
963 | } | 1019 | } |
964 | 1020 | ||
965 | 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 | |||
1037 | err_unregister_filesystem: | ||
1038 | unregister_filesystem(&mtd_inodefs_type); | ||
1039 | err_unregister_chdev: | ||
1040 | __unregister_chrdev(MTD_CHAR_MAJOR, 0, 1 << MINORBITS, "mtd"); | ||
1041 | return ret; | ||
966 | } | 1042 | } |
967 | 1043 | ||
968 | static void __exit cleanup_mtdchar(void) | 1044 | static void __exit cleanup_mtdchar(void) |
969 | { | 1045 | { |
1046 | unregister_mtd_user(&mtdchar_notifier); | ||
1047 | mntput(mtd_inode_mnt); | ||
1048 | unregister_filesystem(&mtd_inodefs_type); | ||
970 | __unregister_chrdev(MTD_CHAR_MAJOR, 0, 1 << MINORBITS, "mtd"); | 1049 | __unregister_chrdev(MTD_CHAR_MAJOR, 0, 1 << MINORBITS, "mtd"); |
971 | } | 1050 | } |
972 | 1051 | ||