Commit 42bc6793 authored by Steve French's avatar Steve French
Browse files

Merge tag 'pull-lock_rename_child' of...

Merge tag 'pull-lock_rename_child' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs

 into ksmbd-for-next

lock_rename_child() (for ksmbd folks)

Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parents 457391b0 9bc37e04
Loading
Loading
Loading
Loading
+0 −2
Original line number Diff line number Diff line
@@ -59,8 +59,6 @@ extern int finish_clean_context(struct fs_context *fc);
 */
extern int filename_lookup(int dfd, struct filename *name, unsigned flags,
			   struct path *path, struct path *root);
extern int vfs_path_lookup(struct dentry *, struct vfsmount *,
			   const char *, unsigned int, struct path *);
int do_rmdir(int dfd, struct filename *name);
int do_unlinkat(int dfd, struct filename *name);
int may_linkat(struct mnt_idmap *idmap, const struct path *link);
+0 −2
Original line number Diff line number Diff line
@@ -19,8 +19,6 @@
#include <linux/sched/xacct.h>
#include <linux/crc32c.h>

#include "../internal.h"	/* for vfs_path_lookup */

#include "glob.h"
#include "oplock.h"
#include "connection.h"
+57 −11
Original line number Diff line number Diff line
@@ -2980,20 +2980,10 @@ static inline int may_create(struct mnt_idmap *idmap,
	return inode_permission(idmap, dir, MAY_WRITE | MAY_EXEC);
}

/*
 * p1 and p2 should be directories on the same fs.
 */
struct dentry *lock_rename(struct dentry *p1, struct dentry *p2)
static struct dentry *lock_two_directories(struct dentry *p1, struct dentry *p2)
{
	struct dentry *p;

	if (p1 == p2) {
		inode_lock_nested(p1->d_inode, I_MUTEX_PARENT);
		return NULL;
	}

	mutex_lock(&p1->d_sb->s_vfs_rename_mutex);

	p = d_ancestor(p2, p1);
	if (p) {
		inode_lock_nested(p2->d_inode, I_MUTEX_PARENT);
@@ -3012,8 +3002,64 @@ struct dentry *lock_rename(struct dentry *p1, struct dentry *p2)
	inode_lock_nested(p2->d_inode, I_MUTEX_PARENT2);
	return NULL;
}

/*
 * p1 and p2 should be directories on the same fs.
 */
struct dentry *lock_rename(struct dentry *p1, struct dentry *p2)
{
	if (p1 == p2) {
		inode_lock_nested(p1->d_inode, I_MUTEX_PARENT);
		return NULL;
	}

	mutex_lock(&p1->d_sb->s_vfs_rename_mutex);
	return lock_two_directories(p1, p2);
}
EXPORT_SYMBOL(lock_rename);

/*
 * c1 and p2 should be on the same fs.
 */
struct dentry *lock_rename_child(struct dentry *c1, struct dentry *p2)
{
	if (READ_ONCE(c1->d_parent) == p2) {
		/*
		 * hopefully won't need to touch ->s_vfs_rename_mutex at all.
		 */
		inode_lock_nested(p2->d_inode, I_MUTEX_PARENT);
		/*
		 * now that p2 is locked, nobody can move in or out of it,
		 * so the test below is safe.
		 */
		if (likely(c1->d_parent == p2))
			return NULL;

		/*
		 * c1 got moved out of p2 while we'd been taking locks;
		 * unlock and fall back to slow case.
		 */
		inode_unlock(p2->d_inode);
	}

	mutex_lock(&c1->d_sb->s_vfs_rename_mutex);
	/*
	 * nobody can move out of any directories on this fs.
	 */
	if (likely(c1->d_parent != p2))
		return lock_two_directories(c1->d_parent, p2);

	/*
	 * c1 got moved into p2 while we were taking locks;
	 * we need p2 locked and ->s_vfs_rename_mutex unlocked,
	 * for consistency with lock_rename().
	 */
	inode_lock_nested(p2->d_inode, I_MUTEX_PARENT);
	mutex_unlock(&c1->d_sb->s_vfs_rename_mutex);
	return NULL;
}
EXPORT_SYMBOL(lock_rename_child);

void unlock_rename(struct dentry *p1, struct dentry *p2)
{
	inode_unlock(p1->d_inode);
+3 −0
Original line number Diff line number Diff line
@@ -63,6 +63,8 @@ extern struct dentry *kern_path_create(int, const char *, struct path *, unsigne
extern struct dentry *user_path_create(int, const char __user *, struct path *, unsigned int);
extern void done_path_create(struct path *, struct dentry *);
extern struct dentry *kern_path_locked(const char *, struct path *);
int vfs_path_lookup(struct dentry *, struct vfsmount *, const char *,
		    unsigned int, struct path *);

extern struct dentry *try_lookup_one_len(const char *, struct dentry *, int);
extern struct dentry *lookup_one_len(const char *, struct dentry *, int);
@@ -81,6 +83,7 @@ extern int follow_down(struct path *path, unsigned int flags);
extern int follow_up(struct path *);

extern struct dentry *lock_rename(struct dentry *, struct dentry *);
extern struct dentry *lock_rename_child(struct dentry *, struct dentry *);
extern void unlock_rename(struct dentry *, struct dentry *);

extern int __must_check nd_jump_link(const struct path *path);