From patchwork Mon May 3 21:32:48 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Kirill A. Shutemov" X-Patchwork-Id: 51531 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from bombadil.infradead.org (bombadil.infradead.org [18.85.46.34]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 232D7B7D12 for ; Tue, 4 May 2010 07:35:49 +1000 (EST) Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.69 #1 (Red Hat Linux)) id 1O93HA-0006qi-Nl; Mon, 03 May 2010 21:34:04 +0000 Received: from mail-bw0-f209.google.com ([209.85.218.209]) by bombadil.infradead.org with esmtp (Exim 4.69 #1 (Red Hat Linux)) id 1O93H7-0006nj-8A for linux-mtd@lists.infradead.org; Mon, 03 May 2010 21:34:02 +0000 Received: by bwz1 with SMTP id 1so1596488bwz.2 for ; Mon, 03 May 2010 14:33:59 -0700 (PDT) Received: by 10.204.141.214 with SMTP id n22mr1024866bku.18.1272922439127; Mon, 03 May 2010 14:33:59 -0700 (PDT) Received: from localhost.localdomain (a88-114-220-92.elisa-laajakaista.fi [88.114.220.92]) by mx.google.com with ESMTPS id 13sm1821173bwz.15.2010.05.03.14.33.55 (version=SSLv3 cipher=RC4-MD5); Mon, 03 May 2010 14:33:58 -0700 (PDT) From: "Kirill A. Shutemov" To: David Woodhouse Subject: [PATCH v2] mtd: Do not corrupt backing device of device node inode Date: Tue, 4 May 2010 00:32:48 +0300 Message-Id: <1272922368-18517-1-git-send-email-kirill@shutemov.name> X-Mailer: git-send-email 1.7.0.4 X-CRM114-Version: 20090807-BlameThorstenAndJenny ( TRE 0.7.6 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20100503_173401_526395_C0B66CBA X-CRM114-Status: GOOD ( 23.09 ) X-Spam-Score: 0.0 (/) X-Spam-Report: SpamAssassin version 3.3.1 on bombadil.infradead.org summary: Content analysis details: (0.0 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at http://www.dnswl.org/, low trust [209.85.218.209 listed in list.dnswl.org] Cc: Jan Kara , Artem Bityutskiy , linux-kernel@vger.kernel.org, David Howells , Alexander Shishkin , linux-mtd@lists.infradead.org, Alexander Viro , linux-fsdevel@vger.kernel.org, "Kirill A. Shutemov" X-BeenThere: linux-mtd@lists.infradead.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: Linux MTD discussion mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: linux-mtd-bounces@lists.infradead.org Errors-To: linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org 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 --- Changelog v1 -> v2: - Fix error handling based on comments by Jan Kara. --- drivers/mtd/mtdchar.c | 77 ++++++++++++++++++++++++++++++++++++++++++----- drivers/mtd/mtdcore.c | 3 ++ include/linux/mtd/mtd.h | 3 ++ 3 files changed, 75 insertions(+), 8 deletions(-) diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index 5b081cb..11d7c4a 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -15,12 +15,15 @@ #include #include #include +#include #include #include #include +#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 @@ -88,11 +91,30 @@ 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; + } + } + + spin_lock(&inode_lock); + __iget(mtd->inode); + spin_unlock(&inode_lock); + + file->f_mapping = mtd->inode->i_mapping; /* You can't open it RW if it's not a writeable device */ if ((file->f_mode & FMODE_WRITE) && !(mtd->flags & MTD_WRITEABLE)) { + iput(mtd->inode); put_mtd_device(mtd); ret = -EACCES; goto out; @@ -100,6 +122,7 @@ static int mtd_open(struct inode *inode, struct file *file) mfi = kzalloc(sizeof(*mfi), GFP_KERNEL); if (!mfi) { + iput(mtd->inode); put_mtd_device(mtd); ret = -ENOMEM; goto out; @@ -125,6 +148,8 @@ static int mtd_close(struct inode *inode, struct file *file) if ((file->f_mode & FMODE_WRITE) && mtd->sync) mtd->sync(mtd); + iput(mtd->inode); + put_mtd_device(mtd); file->private_data = NULL; kfree(mfi); @@ -954,21 +979,57 @@ static const struct file_operations mtd_fops = { #endif }; +static int mtd_inodefs_get_sb(struct file_system_type *fs_type, int flags, + const char *dev_name, void *data, + struct vfsmount *mnt) +{ + return get_sb_pseudo(fs_type, "mtd_inode:", NULL, MTD_INODE_FS_MAGIC, + mnt); +} + +static struct file_system_type mtd_inodefs_type = { + .name = "mtd_inodefs", + .get_sb = mtd_inodefs_get_sb, + .kill_sb = kill_anon_super, +}; + static int __init init_mtdchar(void) { - int status; + int ret; + + ret = register_chrdev(MTD_CHAR_MAJOR, "mtd", &mtd_fops); + if (ret < 0) { + pr_notice("Can't allocate major number %d for " + "Memory Technology Devices.\n", MTD_CHAR_MAJOR); + return ret; + } + + ret = register_filesystem(&mtd_inodefs_type); + if (ret) { + pr_notice("Can't register mtd_inodefs filesystem: %d\n", ret); + goto err_unregister_chdev; + } - status = register_chrdev(MTD_CHAR_MAJOR, "mtd", &mtd_fops); - if (status < 0) { - printk(KERN_NOTICE "Can't allocate major number %d for Memory Technology Devices.\n", - MTD_CHAR_MAJOR); + mtd_inode_mnt = kern_mount(&mtd_inodefs_type); + if (IS_ERR(mtd_inode_mnt)) { + ret = PTR_ERR(mtd_inode_mnt); + pr_notice("Error mounting mtd_inodefs filesystem: %d\n", ret); + goto err_unregister_filesystem; } - return status; + return ret; + +err_unregister_filesystem: + unregister_filesystem(&mtd_inodefs_type); +err_unregister_chdev: + unregister_chrdev(MTD_CHAR_MAJOR, "mtd"); + return ret; } static void __exit cleanup_mtdchar(void) { + mntput(mtd_inode_mnt); + unregister_filesystem(&mtd_inodefs_type); unregister_chrdev(MTD_CHAR_MAJOR, "mtd"); } diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index b177e75..980919e 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -383,6 +383,9 @@ int del_mtd_device (struct mtd_info *mtd) } else { struct mtd_notifier *not; + if (mtd->inode) + iput(mtd->inode); + device_unregister(&mtd->dev); /* No need to get a refcount on the module containing diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index 0f32a9b..0589632 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -177,6 +178,8 @@ struct mtd_info { */ struct backing_dev_info *backing_dev_info; + /* inode for mtd device */ + struct inode *inode; int (*read) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); int (*write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);