lock_rename_child() (for ksmbd folks)
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> -----BEGIN PGP SIGNATURE----- iHUEABYIAB0WIQQqUNBr3gm4hGXdBJlZ7Krx/gZQ6wUCZEYEIwAKCRBZ7Krx/gZQ 60Y+AP9UHVj3Kc4F5FnX+z/lfRwMMP6+hO3Gb1nGr9jddCpthgEAnsPGC3iitMSa vsDw5G+gAsb4qyvJv1U0JJ2VkveZPgA= =4UtI -----END PGP SIGNATURE----- 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: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
commit
42bc6793e4
@ -59,8 +59,6 @@ extern int finish_clean_context(struct fs_context *fc);
|
|||||||
*/
|
*/
|
||||||
extern int filename_lookup(int dfd, struct filename *name, unsigned flags,
|
extern int filename_lookup(int dfd, struct filename *name, unsigned flags,
|
||||||
struct path *path, struct path *root);
|
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_rmdir(int dfd, struct filename *name);
|
||||||
int do_unlinkat(int dfd, struct filename *name);
|
int do_unlinkat(int dfd, struct filename *name);
|
||||||
int may_linkat(struct mnt_idmap *idmap, const struct path *link);
|
int may_linkat(struct mnt_idmap *idmap, const struct path *link);
|
||||||
|
@ -19,8 +19,6 @@
|
|||||||
#include <linux/sched/xacct.h>
|
#include <linux/sched/xacct.h>
|
||||||
#include <linux/crc32c.h>
|
#include <linux/crc32c.h>
|
||||||
|
|
||||||
#include "../internal.h" /* for vfs_path_lookup */
|
|
||||||
|
|
||||||
#include "glob.h"
|
#include "glob.h"
|
||||||
#include "oplock.h"
|
#include "oplock.h"
|
||||||
#include "connection.h"
|
#include "connection.h"
|
||||||
|
68
fs/namei.c
68
fs/namei.c
@ -2980,20 +2980,10 @@ static inline int may_create(struct mnt_idmap *idmap,
|
|||||||
return inode_permission(idmap, dir, MAY_WRITE | MAY_EXEC);
|
return inode_permission(idmap, dir, MAY_WRITE | MAY_EXEC);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
static struct dentry *lock_two_directories(struct dentry *p1, struct dentry *p2)
|
||||||
* p1 and p2 should be directories on the same fs.
|
|
||||||
*/
|
|
||||||
struct dentry *lock_rename(struct dentry *p1, struct dentry *p2)
|
|
||||||
{
|
{
|
||||||
struct dentry *p;
|
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);
|
p = d_ancestor(p2, p1);
|
||||||
if (p) {
|
if (p) {
|
||||||
inode_lock_nested(p2->d_inode, I_MUTEX_PARENT);
|
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);
|
inode_lock_nested(p2->d_inode, I_MUTEX_PARENT2);
|
||||||
return NULL;
|
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);
|
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)
|
void unlock_rename(struct dentry *p1, struct dentry *p2)
|
||||||
{
|
{
|
||||||
inode_unlock(p1->d_inode);
|
inode_unlock(p1->d_inode);
|
||||||
|
@ -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 struct dentry *user_path_create(int, const char __user *, struct path *, unsigned int);
|
||||||
extern void done_path_create(struct path *, struct dentry *);
|
extern void done_path_create(struct path *, struct dentry *);
|
||||||
extern struct dentry *kern_path_locked(const char *, struct path *);
|
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 *try_lookup_one_len(const char *, struct dentry *, int);
|
||||||
extern struct dentry *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 int follow_up(struct path *);
|
||||||
|
|
||||||
extern struct dentry *lock_rename(struct dentry *, struct dentry *);
|
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 void unlock_rename(struct dentry *, struct dentry *);
|
||||||
|
|
||||||
extern int __must_check nd_jump_link(const struct path *path);
|
extern int __must_check nd_jump_link(const struct path *path);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user