aboutsummaryrefslogtreecommitdiffstats
path: root/fs/open.c
diff options
context:
space:
mode:
authorDave Hansen <haveblue@us.ibm.com>2008-02-15 17:37:48 -0500
committerAl Viro <viro@zeniv.linux.org.uk>2008-04-19 00:29:25 -0400
commit4a3fd211ccfc08a88edc824300e25a87785c6a5f (patch)
tree99f1a76a99fa78464b8de731f7fdb5bcc9667a5e /fs/open.c
parent42a74f206b914db13ee1f5ae932dcd91a77c8579 (diff)
[PATCH] r/o bind mounts: elevate write count for open()s
This is the first really tricky patch in the series. It elevates the writer count on a mount each time a non-special file is opened for write. We used to do this in may_open(), but Miklos pointed out that __dentry_open() is used as well to create filps. This will cover even those cases, while a call in may_open() would not have. There is also an elevated count around the vfs_create() call in open_namei(). See the comments for more details, but we need this to fix a 'create, remount, fail r/w open()' race. Some filesystems forego the use of normal vfs calls to create struct files. Make sure that these users elevate the mnt writer count because they will get __fput(), and we need to make sure they're balanced. Acked-by: Al Viro <viro@ZenIV.linux.org.uk> Signed-off-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Dave Hansen <haveblue@us.ibm.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/open.c')
-rw-r--r--fs/open.c36
1 files changed, 34 insertions, 2 deletions
diff --git a/fs/open.c b/fs/open.c
index 8111947905d8..e12f17010324 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -730,6 +730,35 @@ out:
730 return error; 730 return error;
731} 731}
732 732
733/*
734 * You have to be very careful that these write
735 * counts get cleaned up in error cases and
736 * upon __fput(). This should probably never
737 * be called outside of __dentry_open().
738 */
739static inline int __get_file_write_access(struct inode *inode,
740 struct vfsmount *mnt)
741{
742 int error;
743 error = get_write_access(inode);
744 if (error)
745 return error;
746 /*
747 * Do not take mount writer counts on
748 * special files since no writes to
749 * the mount itself will occur.
750 */
751 if (!special_file(inode->i_mode)) {
752 /*
753 * Balanced in __fput()
754 */
755 error = mnt_want_write(mnt);
756 if (error)
757 put_write_access(inode);
758 }
759 return error;
760}
761
733static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt, 762static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt,
734 int flags, struct file *f, 763 int flags, struct file *f,
735 int (*open)(struct inode *, struct file *)) 764 int (*open)(struct inode *, struct file *))
@@ -742,7 +771,7 @@ static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt,
742 FMODE_PREAD | FMODE_PWRITE; 771 FMODE_PREAD | FMODE_PWRITE;
743 inode = dentry->d_inode; 772 inode = dentry->d_inode;
744 if (f->f_mode & FMODE_WRITE) { 773 if (f->f_mode & FMODE_WRITE) {
745 error = get_write_access(inode); 774 error = __get_file_write_access(inode, mnt);
746 if (error) 775 if (error)
747 goto cleanup_file; 776 goto cleanup_file;
748 } 777 }
@@ -784,8 +813,11 @@ static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt,
784 813
785cleanup_all: 814cleanup_all:
786 fops_put(f->f_op); 815 fops_put(f->f_op);
787 if (f->f_mode & FMODE_WRITE) 816 if (f->f_mode & FMODE_WRITE) {
788 put_write_access(inode); 817 put_write_access(inode);
818 if (!special_file(inode->i_mode))
819 mnt_drop_write(mnt);
820 }
789 file_kill(f); 821 file_kill(f);
790 f->f_path.dentry = NULL; 822 f->f_path.dentry = NULL;
791 f->f_path.mnt = NULL; 823 f->f_path.mnt = NULL;