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.
Signed-off-by: Kirill A. Shutemov <kirill@shutemov.name>
---
Changelog:
v3 -> v4:
- Use igrab() instead of __iget inside the inode_lock;
- Add stable@ to CC list.
v2 -> v3:
- Rebase to mtd-2.6.git.
v1 -> v2:
- Fix error handling based on comments by Jan Kara.
---
drivers/mtd/mtdchar.c | 74 +++++++++++++++++++++++++++++++++++++++++-----
drivers/mtd/mtdcore.c | 3 ++
include/linux/mtd/mtd.h | 3 ++
3 files changed, 72 insertions(+), 8 deletions(-)
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
index c355491..7f4634e 100644
--- a/drivers/mtd/mtdchar.c
+++ b/drivers/mtd/mtdchar.c
@@ -15,12 +15,15 @@
#include <linux/smp_lock.h>
#include <linux/backing-dev.h>
#include <linux/compat.h>
+#include <linux/mount.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/compatmac.h>
#include <asm/uaccess.h>
+#define MTD_INODE_FS_MAGIC 0x11307854
+static struct vfsmount *mtd_inode_mnt __read_mostly;
/*
* Data structure to hold the pointer to the mtd device as well
@@ -85,11 +88,27 @@ static int mtd_open(struct inode *inode, struct file *file)
goto out;
}
- if (mtd->backing_dev_info)
- file->f_mapping->backing_dev_info = mtd->backing_dev_info;
+ if (!mtd->inode) {
+ mtd->inode = new_inode(mtd_inode_mnt->mnt_sb);
+ if (!mtd->inode) {
+ put_mtd_device(mtd);
+ ret = -ENOMEM;
+ goto out;
+ }
+ mtd->inode->i_mode = S_IFCHR;
+ mtd->inode->i_rdev = inode->i_rdev;
+ if (mtd->backing_dev_info) {
+ mtd->inode->i_data.backing_dev_info =
+ mtd->backing_dev_info;
+ }
+ }
+
+ igrab(mtd->inode);
+ file->f_mapping = mtd->inode->i_mapping;
/* You can't open it RW if it's not a writeable device */
if ((file->f_mode & ...I hate the fact that we have to do this -- is it really the only option? Is it _just_ for the backing_device_info? Can't that be done I believe that would be a race condition, if it wasn't for the BKL. And what happens when you close the chardevice and call iput() on the inode so it's destroyed, and then you re-open the device? You never set mtd->inode = NULL, so won't it now try to igrab a stale pointer? You won't have seen this in your testing unless you made it prune the icache between the close and open calls. -- David Woodhouse Open Source Technology Centre David.Woodhouse@intel.com Intel Corporation --
Well, if I understand the problem MTD tries to solve, what you really need is that file->f_mapping->backing_dev_info points to your structure so that you can specify the capability of backing device to support mmap and whatever else. What I'm not sure about is, why you cannot have this backing_dev_info directly in the original device inode but since this is the problem you are originally trying to solve, I guess you have some good reason for that. So with this requirement, you have to at least setup complete struct address_space to which f_mapping can point. This address_space has to be linked (via mapping->host) to some inode. So you could point i_mapping to your address_space structure if that would work for you. But this only has a reasonable chance to work if you would somehow tie the lifetime of your address_space with the lifetime of your device inode (code in block_dev.c does something like this because all inodes which represent the same block block device share one address_space). Moreover you would have to do all the address_space initialization inode_init_always does (or probably split out the mapping initialization from inode_init_always and call it from MTD code). So I'm not sure it's really better. When you decide you don't want to take care about proper setup of address_space and refcounting and whatever, you have to create a full inode. But this inode has to live in some filesystem -> what Kirill did is unavoidable in this case... Honza -- Jan Kara <jack@suse.cz> SUSE Labs, CR --
