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

Commit 64894cf8 authored by Al Viro's avatar Al Viro
Browse files

simplify lookup_open()/atomic_open() - do the temporary mnt_want_write() early



The write ref to vfsmount taken in lookup_open()/atomic_open() is going to
be dropped; we take the one to stay in dentry_open().  Just grab the temporary
in caller if it looks like we are going to need it (create/truncate/writable open)
and pass (by value) "has it succeeded" flag.  Instead of doing mnt_want_write()
inside, check that flag and treat "false" as "mnt_want_write() has just failed".
mnt_want_write() is cheap and the things get considerably simpler and more robust
that way - we get it and drop it in the same function, to start with, rather
than passing a "has something in the guts of really scary functions taken it"
back to caller.

Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent f8310c59
Loading
Loading
Loading
Loading
+29 −22
Original line number Diff line number Diff line
@@ -2395,7 +2395,7 @@ static int may_o_create(struct path *dir, struct dentry *dentry, umode_t mode)
static int atomic_open(struct nameidata *nd, struct dentry *dentry,
			struct path *path, struct file *file,
			const struct open_flags *op,
			bool *want_write, bool need_lookup,
			bool got_write, bool need_lookup,
			int *opened)
{
	struct inode *dir =  nd->path.dentry->d_inode;
@@ -2432,12 +2432,9 @@ static int atomic_open(struct nameidata *nd, struct dentry *dentry,
	 * Another problem is returing the "right" error value (e.g. for an
	 * O_EXCL open we want to return EEXIST not EROFS).
	 */
	if ((open_flag & (O_CREAT | O_TRUNC)) ||
	    (open_flag & O_ACCMODE) != O_RDONLY) {
		error = mnt_want_write(nd->path.mnt);
		if (!error) {
			*want_write = true;
		} else if (!(open_flag & O_CREAT)) {
	if (((open_flag & (O_CREAT | O_TRUNC)) ||
	    (open_flag & O_ACCMODE) != O_RDONLY) && unlikely(!got_write)) {
		if (!(open_flag & O_CREAT)) {
			/*
			 * No O_CREATE -> atomicity not a requirement -> fall
			 * back to lookup + open
@@ -2445,11 +2442,11 @@ static int atomic_open(struct nameidata *nd, struct dentry *dentry,
			goto no_open;
		} else if (open_flag & (O_EXCL | O_TRUNC)) {
			/* Fall back and fail with the right error */
			create_error = error;
			create_error = -EROFS;
			goto no_open;
		} else {
			/* No side effects, safe to clear O_CREAT */
			create_error = error;
			create_error = -EROFS;
			open_flag &= ~O_CREAT;
		}
	}
@@ -2556,7 +2553,7 @@ static int atomic_open(struct nameidata *nd, struct dentry *dentry,
static int lookup_open(struct nameidata *nd, struct path *path,
			struct file *file,
			const struct open_flags *op,
			bool *want_write, int *opened)
			bool got_write, int *opened)
{
	struct dentry *dir = nd->path.dentry;
	struct inode *dir_inode = dir->d_inode;
@@ -2574,7 +2571,7 @@ static int lookup_open(struct nameidata *nd, struct path *path,
		goto out_no_open;

	if ((nd->flags & LOOKUP_OPEN) && dir_inode->i_op->atomic_open) {
		return atomic_open(nd, dentry, path, file, op, want_write,
		return atomic_open(nd, dentry, path, file, op, got_write,
				   need_lookup, opened);
	}

@@ -2598,10 +2595,10 @@ static int lookup_open(struct nameidata *nd, struct path *path,
		 * a permanent write count is taken through
		 * the 'struct file' in finish_open().
		 */
		error = mnt_want_write(nd->path.mnt);
		if (error)
		if (!got_write) {
			error = -EROFS;
			goto out_dput;
		*want_write = true;
		}
		*opened |= FILE_CREATED;
		error = security_path_mknod(&nd->path, dentry, mode, 0);
		if (error)
@@ -2631,7 +2628,7 @@ static int do_last(struct nameidata *nd, struct path *path,
	struct dentry *dir = nd->path.dentry;
	int open_flag = op->open_flag;
	bool will_truncate = (open_flag & O_TRUNC) != 0;
	bool want_write = false;
	bool got_write = false;
	int acc_mode = op->acc_mode;
	struct inode *inode;
	bool symlink_ok = false;
@@ -2700,8 +2697,18 @@ static int do_last(struct nameidata *nd, struct path *path,
	}

retry_lookup:
	if (op->open_flag & (O_CREAT | O_TRUNC | O_WRONLY | O_RDWR)) {
		error = mnt_want_write(nd->path.mnt);
		if (!error)
			got_write = true;
		/*
		 * do _not_ fail yet - we might not need that or fail with
		 * a different error; let lookup_open() decide; we'll be
		 * dropping this one anyway.
		 */
	}
	mutex_lock(&dir->d_inode->i_mutex);
	error = lookup_open(nd, path, file, op, &want_write, opened);
	error = lookup_open(nd, path, file, op, got_write, opened);
	mutex_unlock(&dir->d_inode->i_mutex);

	if (error <= 0) {
@@ -2736,9 +2743,9 @@ static int do_last(struct nameidata *nd, struct path *path,
	 * possible mount and symlink following (this might be optimized away if
	 * necessary...)
	 */
	if (want_write) {
	if (got_write) {
		mnt_drop_write(nd->path.mnt);
		want_write = false;
		got_write = false;
	}

	error = -EEXIST;
@@ -2803,7 +2810,7 @@ static int do_last(struct nameidata *nd, struct path *path,
		error = mnt_want_write(nd->path.mnt);
		if (error)
			goto out;
		want_write = true;
		got_write = true;
	}
finish_open_created:
	error = may_open(&nd->path, acc_mode, open_flag);
@@ -2830,7 +2837,7 @@ static int do_last(struct nameidata *nd, struct path *path,
			goto exit_fput;
	}
out:
	if (want_write)
	if (got_write)
		mnt_drop_write(nd->path.mnt);
	path_put(&save_parent);
	terminate_walk(nd);
@@ -2854,9 +2861,9 @@ static int do_last(struct nameidata *nd, struct path *path,
	nd->inode = dir->d_inode;
	save_parent.mnt = NULL;
	save_parent.dentry = NULL;
	if (want_write) {
	if (got_write) {
		mnt_drop_write(nd->path.mnt);
		want_write = false;
		got_write = false;
	}
	retried = true;
	goto retry_lookup;