aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/file_table.c37
-rw-r--r--fs/namespace.c4
-rw-r--r--fs/open.c9
-rw-r--r--include/linux/fs.h2
4 files changed, 11 insertions, 41 deletions
diff --git a/fs/file_table.c b/fs/file_table.c
index ee20658a0647..ce1504fec5a1 100644
--- a/fs/file_table.c
+++ b/fs/file_table.c
@@ -177,43 +177,12 @@ struct file *alloc_file(struct path *path, fmode_t mode,
177 file->f_mapping = path->dentry->d_inode->i_mapping; 177 file->f_mapping = path->dentry->d_inode->i_mapping;
178 file->f_mode = mode; 178 file->f_mode = mode;
179 file->f_op = fop; 179 file->f_op = fop;
180
181 /*
182 * These mounts don't really matter in practice
183 * for r/o bind mounts. They aren't userspace-
184 * visible. We do this for consistency, and so
185 * that we can do debugging checks at __fput()
186 */
187 if ((mode & FMODE_WRITE) && !special_file(path->dentry->d_inode->i_mode)) {
188 WARN_ON(mnt_clone_write(path->mnt));
189 }
190 if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) 180 if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ)
191 i_readcount_inc(path->dentry->d_inode); 181 i_readcount_inc(path->dentry->d_inode);
192 return file; 182 return file;
193} 183}
194EXPORT_SYMBOL(alloc_file); 184EXPORT_SYMBOL(alloc_file);
195 185
196/**
197 * drop_file_write_access - give up ability to write to a file
198 * @file: the file to which we will stop writing
199 *
200 * This is a central place which will give up the ability
201 * to write to @file, along with access to write through
202 * its vfsmount.
203 */
204static void drop_file_write_access(struct file *file)
205{
206 struct vfsmount *mnt = file->f_path.mnt;
207 struct dentry *dentry = file->f_path.dentry;
208 struct inode *inode = dentry->d_inode;
209
210 if (special_file(inode->i_mode))
211 return;
212
213 put_write_access(inode);
214 __mnt_drop_write(mnt);
215}
216
217/* the real guts of fput() - releasing the last reference to file 186/* the real guts of fput() - releasing the last reference to file
218 */ 187 */
219static void __fput(struct file *file) 188static void __fput(struct file *file)
@@ -248,8 +217,10 @@ static void __fput(struct file *file)
248 put_pid(file->f_owner.pid); 217 put_pid(file->f_owner.pid);
249 if ((file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) 218 if ((file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ)
250 i_readcount_dec(inode); 219 i_readcount_dec(inode);
251 if (file->f_mode & FMODE_WRITE) 220 if (file->f_mode & FMODE_WRITER) {
252 drop_file_write_access(file); 221 put_write_access(inode);
222 __mnt_drop_write(mnt);
223 }
253 file->f_path.dentry = NULL; 224 file->f_path.dentry = NULL;
254 file->f_path.mnt = NULL; 225 file->f_path.mnt = NULL;
255 file->f_inode = NULL; 226 file->f_inode = NULL;
diff --git a/fs/namespace.c b/fs/namespace.c
index a66aff5bd3fe..20e8696c31a7 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -414,9 +414,7 @@ EXPORT_SYMBOL_GPL(mnt_clone_write);
414 */ 414 */
415int __mnt_want_write_file(struct file *file) 415int __mnt_want_write_file(struct file *file)
416{ 416{
417 struct inode *inode = file_inode(file); 417 if (!(file->f_mode & FMODE_WRITER))
418
419 if (!(file->f_mode & FMODE_WRITE) || special_file(inode->i_mode))
420 return __mnt_want_write(file->f_path.mnt); 418 return __mnt_want_write(file->f_path.mnt);
421 else 419 else
422 return mnt_clone_write(file->f_path.mnt); 420 return mnt_clone_write(file->f_path.mnt);
diff --git a/fs/open.c b/fs/open.c
index ebef0c5fa10c..dcefb2f02d10 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -670,6 +670,7 @@ static int do_dentry_open(struct file *f,
670 put_write_access(inode); 670 put_write_access(inode);
671 goto cleanup_file; 671 goto cleanup_file;
672 } 672 }
673 f->f_mode |= FMODE_WRITER;
673 } 674 }
674 675
675 f->f_mapping = inode->i_mapping; 676 f->f_mapping = inode->i_mapping;
@@ -715,11 +716,9 @@ static int do_dentry_open(struct file *f,
715 716
716cleanup_all: 717cleanup_all:
717 fops_put(f->f_op); 718 fops_put(f->f_op);
718 if (f->f_mode & FMODE_WRITE) { 719 if (f->f_mode & FMODE_WRITER) {
719 if (!special_file(inode->i_mode)) { 720 put_write_access(inode);
720 put_write_access(inode); 721 __mnt_drop_write(f->f_path.mnt);
721 __mnt_drop_write(f->f_path.mnt);
722 }
723 } 722 }
724cleanup_file: 723cleanup_file:
725 path_put(&f->f_path); 724 path_put(&f->f_path);
diff --git a/include/linux/fs.h b/include/linux/fs.h
index e80659ed78fc..d9d88a0b456e 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -125,6 +125,8 @@ typedef void (dio_iodone_t)(struct kiocb *iocb, loff_t offset,
125 125
126/* File needs atomic accesses to f_pos */ 126/* File needs atomic accesses to f_pos */
127#define FMODE_ATOMIC_POS ((__force fmode_t)0x8000) 127#define FMODE_ATOMIC_POS ((__force fmode_t)0x8000)
128/* Write access to underlying fs */
129#define FMODE_WRITER ((__force fmode_t)0x10000)
128 130
129/* File was opened by fanotify and shouldn't generate fanotify events */ 131/* File was opened by fanotify and shouldn't generate fanotify events */
130#define FMODE_NONOTIFY ((__force fmode_t)0x1000000) 132#define FMODE_NONOTIFY ((__force fmode_t)0x1000000)