Commit 648fa861 authored by Al Viro's avatar Al Viro

beginning to untangle do_filp_open()

That's going to be a long and painful series.  The first step:
take the stuff reachable from 'ok' label in do_filp_open() into
a new helper (finish_open()).
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 64ba9926
...@@ -1590,6 +1590,61 @@ static int open_will_truncate(int flag, struct inode *inode) ...@@ -1590,6 +1590,61 @@ static int open_will_truncate(int flag, struct inode *inode)
return (flag & O_TRUNC); return (flag & O_TRUNC);
} }
static struct file *finish_open(struct nameidata *nd,
int open_flag, int flag, int acc_mode)
{
struct file *filp;
int will_truncate;
int error;
will_truncate = open_will_truncate(flag, nd->path.dentry->d_inode);
if (will_truncate) {
error = mnt_want_write(nd->path.mnt);
if (error)
goto exit;
}
error = may_open(&nd->path, acc_mode, open_flag);
if (error) {
if (will_truncate)
mnt_drop_write(nd->path.mnt);
goto exit;
}
filp = nameidata_to_filp(nd);
if (!IS_ERR(filp)) {
error = ima_file_check(filp, acc_mode);
if (error) {
fput(filp);
filp = ERR_PTR(error);
}
}
if (!IS_ERR(filp)) {
if (acc_mode & MAY_WRITE)
vfs_dq_init(nd->path.dentry->d_inode);
if (will_truncate) {
error = handle_truncate(&nd->path);
if (error) {
fput(filp);
filp = ERR_PTR(error);
}
}
}
/*
* It is now safe to drop the mnt write
* because the filp has had a write taken
* on its behalf.
*/
if (will_truncate)
mnt_drop_write(nd->path.mnt);
return filp;
exit:
if (!IS_ERR(nd->intent.open.file))
release_open_intent(nd);
path_put(&nd->path);
return ERR_PTR(error);
}
/* /*
* Note that the low bits of the passed in "open_flag" * Note that the low bits of the passed in "open_flag"
* are not the same as in the local variable "flag". See * are not the same as in the local variable "flag". See
...@@ -1604,7 +1659,6 @@ struct file *do_filp_open(int dfd, const char *pathname, ...@@ -1604,7 +1659,6 @@ struct file *do_filp_open(int dfd, const char *pathname,
struct path path; struct path path;
struct dentry *dir; struct dentry *dir;
int count = 0; int count = 0;
int will_truncate;
int flag = open_to_namei_flags(open_flag); int flag = open_to_namei_flags(open_flag);
int force_reval = 0; int force_reval = 0;
...@@ -1769,55 +1823,7 @@ struct file *do_filp_open(int dfd, const char *pathname, ...@@ -1769,55 +1823,7 @@ struct file *do_filp_open(int dfd, const char *pathname,
if (S_ISDIR(path.dentry->d_inode->i_mode)) if (S_ISDIR(path.dentry->d_inode->i_mode))
goto exit; goto exit;
ok: ok:
/* filp = finish_open(&nd, open_flag, flag, acc_mode);
* Consider:
* 1. may_open() truncates a file
* 2. a rw->ro mount transition occurs
* 3. nameidata_to_filp() fails due to
* the ro mount.
* That would be inconsistent, and should
* be avoided. Taking this mnt write here
* ensures that (2) can not occur.
*/
will_truncate = open_will_truncate(flag, nd.path.dentry->d_inode);
if (will_truncate) {
error = mnt_want_write(nd.path.mnt);
if (error)
goto exit;
}
error = may_open(&nd.path, acc_mode, open_flag);
if (error) {
if (will_truncate)
mnt_drop_write(nd.path.mnt);
goto exit;
}
filp = nameidata_to_filp(&nd);
if (!IS_ERR(filp)) {
error = ima_file_check(filp, acc_mode);
if (error) {
fput(filp);
filp = ERR_PTR(error);
}
}
if (!IS_ERR(filp)) {
if (acc_mode & MAY_WRITE)
vfs_dq_init(nd.path.dentry->d_inode);
if (will_truncate) {
error = handle_truncate(&nd.path);
if (error) {
fput(filp);
filp = ERR_PTR(error);
}
}
}
/*
* It is now safe to drop the mnt write
* because the filp has had a write taken
* on its behalf.
*/
if (will_truncate)
mnt_drop_write(nd.path.mnt);
if (nd.root.mnt) if (nd.root.mnt)
path_put(&nd.root); path_put(&nd.root);
return filp; return filp;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment