diff options
| -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 | ||
