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: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
Родитель
64ba992675
Коммит
648fa8611d
106
fs/namei.c
106
fs/namei.c
|
@ -1590,6 +1590,61 @@ static int open_will_truncate(int flag, struct inode *inode)
|
|||
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"
|
||||
* 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,
|
|||
struct path path;
|
||||
struct dentry *dir;
|
||||
int count = 0;
|
||||
int will_truncate;
|
||||
int flag = open_to_namei_flags(open_flag);
|
||||
int force_reval = 0;
|
||||
|
||||
|
@ -1769,55 +1823,7 @@ do_last:
|
|||
if (S_ISDIR(path.dentry->d_inode->i_mode))
|
||||
goto exit;
|
||||
ok:
|
||||
/*
|
||||
* 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);
|
||||
filp = finish_open(&nd, open_flag, flag, acc_mode);
|
||||
if (nd.root.mnt)
|
||||
path_put(&nd.root);
|
||||
return filp;
|
||||
|
|
Загрузка…
Ссылка в новой задаче