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