Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+56 −50
Original line number Diff line number Diff line
@@ -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;