diff options
author | Dave Hansen <haveblue@us.ibm.com> | 2008-02-15 17:37:48 -0500 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2008-04-19 00:29:25 -0400 |
commit | 4a3fd211ccfc08a88edc824300e25a87785c6a5f (patch) | |
tree | 99f1a76a99fa78464b8de731f7fdb5bcc9667a5e /fs/open.c | |
parent | 42a74f206b914db13ee1f5ae932dcd91a77c8579 (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.c | 36 |
1 files changed, 34 insertions, 2 deletions
@@ -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 | */ | ||
739 | static 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 | |||
733 | static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt, | 762 | static 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 | ||
785 | cleanup_all: | 814 | cleanup_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; |