summaryrefslogtreecommitdiff
path: root/fs
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2014-03-14 12:02:47 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2014-04-01 23:19:12 -0400
commit83f936c75e3689a63253d89c47a4d239c56d7410 (patch)
tree430d89096a9b56ffb8e80bd4febde39e1d05ad4c /fs
parent0ccb286346c4c0644be17f04a9eb23ad99262882 (diff)
mark struct file that had write access grabbed by open()
new flag in ->f_mode - FMODE_WRITER. Set by do_dentry_open() in case when it has grabbed write access, checked by __fput() to decide whether it wants to drop the sucker. Allows to stop bothering with mnt_clone_write() in alloc_file(), along with fewer special_file() checks. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs')
-rw-r--r--fs/file_table.c37
-rw-r--r--fs/namespace.c4
-rw-r--r--fs/open.c9
3 files changed, 9 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,
file->f_mapping = path->dentry->d_inode->i_mapping;
file->f_mode = mode;
file->f_op = fop;
-
- /*
- * These mounts don't really matter in practice
- * for r/o bind mounts. They aren't userspace-
- * visible. We do this for consistency, and so
- * that we can do debugging checks at __fput()
- */
- if ((mode & FMODE_WRITE) && !special_file(path->dentry->d_inode->i_mode)) {
- WARN_ON(mnt_clone_write(path->mnt));
- }
if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ)
i_readcount_inc(path->dentry->d_inode);
return file;
}
EXPORT_SYMBOL(alloc_file);
-/**
- * drop_file_write_access - give up ability to write to a file
- * @file: the file to which we will stop writing
- *
- * This is a central place which will give up the ability
- * to write to @file, along with access to write through
- * its vfsmount.
- */
-static void drop_file_write_access(struct file *file)
-{
- struct vfsmount *mnt = file->f_path.mnt;
- struct dentry *dentry = file->f_path.dentry;
- struct inode *inode = dentry->d_inode;
-
- if (special_file(inode->i_mode))
- return;
-
- put_write_access(inode);
- __mnt_drop_write(mnt);
-}
-
/* the real guts of fput() - releasing the last reference to file
*/
static void __fput(struct file *file)
@@ -248,8 +217,10 @@ static void __fput(struct file *file)
put_pid(file->f_owner.pid);
if ((file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ)
i_readcount_dec(inode);
- if (file->f_mode & FMODE_WRITE)
- drop_file_write_access(file);
+ if (file->f_mode & FMODE_WRITER) {
+ put_write_access(inode);
+ __mnt_drop_write(mnt);
+ }
file->f_path.dentry = NULL;
file->f_path.mnt = NULL;
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);
*/
int __mnt_want_write_file(struct file *file)
{
- struct inode *inode = file_inode(file);
-
- if (!(file->f_mode & FMODE_WRITE) || special_file(inode->i_mode))
+ if (!(file->f_mode & FMODE_WRITER))
return __mnt_want_write(file->f_path.mnt);
else
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,
put_write_access(inode);
goto cleanup_file;
}
+ f->f_mode |= FMODE_WRITER;
}
f->f_mapping = inode->i_mapping;
@@ -715,11 +716,9 @@ static int do_dentry_open(struct file *f,
cleanup_all:
fops_put(f->f_op);
- if (f->f_mode & FMODE_WRITE) {
- if (!special_file(inode->i_mode)) {
- put_write_access(inode);
- __mnt_drop_write(f->f_path.mnt);
- }
+ if (f->f_mode & FMODE_WRITER) {
+ put_write_access(inode);
+ __mnt_drop_write(f->f_path.mnt);
}
cleanup_file:
path_put(&f->f_path);