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

Commit a8104a9f authored by Al Viro's avatar Al Viro
Browse files

pull mnt_want_write()/mnt_drop_write() into kern_path_create()/done_path_create() resp.



One side effect - attempt to create a cross-device link on a read-only fs fails
with EROFS instead of EXDEV now.  Makes more sense, POSIX allows, etc.

Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 8e4bfca1
Loading
Loading
Loading
Loading
+18 −39
Original line number Original line Diff line number Diff line
@@ -2865,10 +2865,11 @@ struct dentry *kern_path_create(int dfd, const char *pathname, struct path *path
	mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT);
	mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT);
	dentry = lookup_hash(&nd);
	dentry = lookup_hash(&nd);
	if (IS_ERR(dentry))
	if (IS_ERR(dentry))
		goto fail;
		goto unlock;


	error = -EEXIST;
	if (dentry->d_inode)
	if (dentry->d_inode)
		goto eexist;
		goto fail;
	/*
	/*
	 * Special case - lookup gave negative, but... we had foo/bar/
	 * Special case - lookup gave negative, but... we had foo/bar/
	 * From the vfs_mknod() POV we just have a negative dentry -
	 * From the vfs_mknod() POV we just have a negative dentry -
@@ -2876,16 +2877,18 @@ struct dentry *kern_path_create(int dfd, const char *pathname, struct path *path
	 * been asking for (non-existent) directory. -ENOENT for you.
	 * been asking for (non-existent) directory. -ENOENT for you.
	 */
	 */
	if (unlikely(!is_dir && nd.last.name[nd.last.len])) {
	if (unlikely(!is_dir && nd.last.name[nd.last.len])) {
		dput(dentry);
		error = -ENOENT;
		dentry = ERR_PTR(-ENOENT);
		goto fail;
		goto fail;
	}
	}
	error = mnt_want_write(nd.path.mnt);
	if (error)
		goto fail;
	*path = nd.path;
	*path = nd.path;
	return dentry;
	return dentry;
eexist:
	dput(dentry);
	dentry = ERR_PTR(-EEXIST);
fail:
fail:
	dput(dentry);
	dentry = ERR_PTR(error);
unlock:
	mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
	mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
out:
out:
	path_put(&nd.path);
	path_put(&nd.path);
@@ -2897,6 +2900,7 @@ void done_path_create(struct path *path, struct dentry *dentry)
{
{
	dput(dentry);
	dput(dentry);
	mutex_unlock(&path->dentry->d_inode->i_mutex);
	mutex_unlock(&path->dentry->d_inode->i_mutex);
	mnt_drop_write(path->mnt);
	path_put(path);
	path_put(path);
}
}
EXPORT_SYMBOL(done_path_create);
EXPORT_SYMBOL(done_path_create);
@@ -2974,12 +2978,9 @@ SYSCALL_DEFINE4(mknodat, int, dfd, const char __user *, filename, umode_t, mode,


	if (!IS_POSIXACL(path.dentry->d_inode))
	if (!IS_POSIXACL(path.dentry->d_inode))
		mode &= ~current_umask();
		mode &= ~current_umask();
	error = mnt_want_write(path.mnt);
	if (error)
		goto out_dput;
	error = security_path_mknod(&path, dentry, mode, dev);
	error = security_path_mknod(&path, dentry, mode, dev);
	if (error)
	if (error)
		goto out_drop_write;
		goto out;
	switch (mode & S_IFMT) {
	switch (mode & S_IFMT) {
		case 0: case S_IFREG:
		case 0: case S_IFREG:
			error = vfs_create(path.dentry->d_inode,dentry,mode,true);
			error = vfs_create(path.dentry->d_inode,dentry,mode,true);
@@ -2992,11 +2993,8 @@ SYSCALL_DEFINE4(mknodat, int, dfd, const char __user *, filename, umode_t, mode,
			error = vfs_mknod(path.dentry->d_inode,dentry,mode,0);
			error = vfs_mknod(path.dentry->d_inode,dentry,mode,0);
			break;
			break;
	}
	}
out_drop_write:
out:
	mnt_drop_write(path.mnt);
out_dput:
	done_path_create(&path, dentry);
	done_path_create(&path, dentry);

	return error;
	return error;
}
}


@@ -3042,16 +3040,9 @@ SYSCALL_DEFINE3(mkdirat, int, dfd, const char __user *, pathname, umode_t, mode)


	if (!IS_POSIXACL(path.dentry->d_inode))
	if (!IS_POSIXACL(path.dentry->d_inode))
		mode &= ~current_umask();
		mode &= ~current_umask();
	error = mnt_want_write(path.mnt);
	if (error)
		goto out_dput;
	error = security_path_mkdir(&path, dentry, mode);
	error = security_path_mkdir(&path, dentry, mode);
	if (error)
	if (!error)
		goto out_drop_write;
		error = vfs_mkdir(path.dentry->d_inode, dentry, mode);
		error = vfs_mkdir(path.dentry->d_inode, dentry, mode);
out_drop_write:
	mnt_drop_write(path.mnt);
out_dput:
	done_path_create(&path, dentry);
	done_path_create(&path, dentry);
	return error;
	return error;
}
}
@@ -3326,16 +3317,9 @@ SYSCALL_DEFINE3(symlinkat, const char __user *, oldname,
	if (IS_ERR(dentry))
	if (IS_ERR(dentry))
		goto out_putname;
		goto out_putname;


	error = mnt_want_write(path.mnt);
	if (error)
		goto out_dput;
	error = security_path_symlink(&path, dentry, from);
	error = security_path_symlink(&path, dentry, from);
	if (error)
	if (!error)
		goto out_drop_write;
		error = vfs_symlink(path.dentry->d_inode, dentry, from);
		error = vfs_symlink(path.dentry->d_inode, dentry, from);
out_drop_write:
	mnt_drop_write(path.mnt);
out_dput:
	done_path_create(&path, dentry);
	done_path_create(&path, dentry);
out_putname:
out_putname:
	putname(from);
	putname(from);
@@ -3436,15 +3420,10 @@ SYSCALL_DEFINE5(linkat, int, olddfd, const char __user *, oldname,
	error = -EXDEV;
	error = -EXDEV;
	if (old_path.mnt != new_path.mnt)
	if (old_path.mnt != new_path.mnt)
		goto out_dput;
		goto out_dput;
	error = mnt_want_write(new_path.mnt);
	if (error)
		goto out_dput;
	error = security_path_link(old_path.dentry, &new_path, new_dentry);
	error = security_path_link(old_path.dentry, &new_path, new_dentry);
	if (error)
	if (error)
		goto out_drop_write;
		goto out_dput;
	error = vfs_link(old_path.dentry, new_path.dentry->d_inode, new_dentry);
	error = vfs_link(old_path.dentry, new_path.dentry->d_inode, new_dentry);
out_drop_write:
	mnt_drop_write(new_path.mnt);
out_dput:
out_dput:
	done_path_create(&new_path, new_dentry);
	done_path_create(&new_path, new_dentry);
out:
out:
+0 −7
Original line number Original line Diff line number Diff line
@@ -4466,16 +4466,9 @@ int ocfs2_reflink_ioctl(struct inode *inode,
		goto out_dput;
		goto out_dput;
	}
	}


	error = mnt_want_write(new_path.mnt);
	if (error) {
		mlog_errno(error);
		goto out_dput;
	}

	error = ocfs2_vfs_reflink(old_path.dentry,
	error = ocfs2_vfs_reflink(old_path.dentry,
				  new_path.dentry->d_inode,
				  new_path.dentry->d_inode,
				  new_dentry, preserve);
				  new_dentry, preserve);
	mnt_drop_write(new_path.mnt);
out_dput:
out_dput:
	done_path_create(&new_path, new_dentry);
	done_path_create(&new_path, new_dentry);
out:
out:
+0 −4
Original line number Original line Diff line number Diff line
@@ -876,15 +876,11 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
		 */
		 */
		mode = S_IFSOCK |
		mode = S_IFSOCK |
		       (SOCK_INODE(sock)->i_mode & ~current_umask());
		       (SOCK_INODE(sock)->i_mode & ~current_umask());
		err = mnt_want_write(path.mnt);
		if (err)
			goto out_mknod_dput;
		err = security_path_mknod(&path, dentry, mode, 0);
		err = security_path_mknod(&path, dentry, mode, 0);
		if (err)
		if (err)
			goto out_mknod_drop_write;
			goto out_mknod_drop_write;
		err = vfs_mknod(path.dentry->d_inode, dentry, mode, 0);
		err = vfs_mknod(path.dentry->d_inode, dentry, mode, 0);
out_mknod_drop_write:
out_mknod_drop_write:
		mnt_drop_write(path.mnt);
		if (err)
		if (err)
			goto out_mknod_dput;
			goto out_mknod_dput;
		mntget(path.mnt);
		mntget(path.mnt);