Skip to content

Commit 42bc679

Browse files
committed
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>
2 parents 457391b + 9bc37e0 commit 42bc679

4 files changed

Lines changed: 60 additions & 15 deletions

File tree

fs/internal.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,6 @@ extern int finish_clean_context(struct fs_context *fc);
5959
*/
6060
extern int filename_lookup(int dfd, struct filename *name, unsigned flags,
6161
struct path *path, struct path *root);
62-
extern int vfs_path_lookup(struct dentry *, struct vfsmount *,
63-
const char *, unsigned int, struct path *);
6462
int do_rmdir(int dfd, struct filename *name);
6563
int do_unlinkat(int dfd, struct filename *name);
6664
int may_linkat(struct mnt_idmap *idmap, const struct path *link);

fs/ksmbd/vfs.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@
1919
#include <linux/sched/xacct.h>
2020
#include <linux/crc32c.h>
2121

22-
#include "../internal.h" /* for vfs_path_lookup */
23-
2422
#include "glob.h"
2523
#include "oplock.h"
2624
#include "connection.h"

fs/namei.c

Lines changed: 57 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2980,20 +2980,10 @@ static inline int may_create(struct mnt_idmap *idmap,
29802980
return inode_permission(idmap, dir, MAY_WRITE | MAY_EXEC);
29812981
}
29822982

2983-
/*
2984-
* p1 and p2 should be directories on the same fs.
2985-
*/
2986-
struct dentry *lock_rename(struct dentry *p1, struct dentry *p2)
2983+
static struct dentry *lock_two_directories(struct dentry *p1, struct dentry *p2)
29872984
{
29882985
struct dentry *p;
29892986

2990-
if (p1 == p2) {
2991-
inode_lock_nested(p1->d_inode, I_MUTEX_PARENT);
2992-
return NULL;
2993-
}
2994-
2995-
mutex_lock(&p1->d_sb->s_vfs_rename_mutex);
2996-
29972987
p = d_ancestor(p2, p1);
29982988
if (p) {
29992989
inode_lock_nested(p2->d_inode, I_MUTEX_PARENT);
@@ -3012,8 +3002,64 @@ struct dentry *lock_rename(struct dentry *p1, struct dentry *p2)
30123002
inode_lock_nested(p2->d_inode, I_MUTEX_PARENT2);
30133003
return NULL;
30143004
}
3005+
3006+
/*
3007+
* p1 and p2 should be directories on the same fs.
3008+
*/
3009+
struct dentry *lock_rename(struct dentry *p1, struct dentry *p2)
3010+
{
3011+
if (p1 == p2) {
3012+
inode_lock_nested(p1->d_inode, I_MUTEX_PARENT);
3013+
return NULL;
3014+
}
3015+
3016+
mutex_lock(&p1->d_sb->s_vfs_rename_mutex);
3017+
return lock_two_directories(p1, p2);
3018+
}
30153019
EXPORT_SYMBOL(lock_rename);
30163020

3021+
/*
3022+
* c1 and p2 should be on the same fs.
3023+
*/
3024+
struct dentry *lock_rename_child(struct dentry *c1, struct dentry *p2)
3025+
{
3026+
if (READ_ONCE(c1->d_parent) == p2) {
3027+
/*
3028+
* hopefully won't need to touch ->s_vfs_rename_mutex at all.
3029+
*/
3030+
inode_lock_nested(p2->d_inode, I_MUTEX_PARENT);
3031+
/*
3032+
* now that p2 is locked, nobody can move in or out of it,
3033+
* so the test below is safe.
3034+
*/
3035+
if (likely(c1->d_parent == p2))
3036+
return NULL;
3037+
3038+
/*
3039+
* c1 got moved out of p2 while we'd been taking locks;
3040+
* unlock and fall back to slow case.
3041+
*/
3042+
inode_unlock(p2->d_inode);
3043+
}
3044+
3045+
mutex_lock(&c1->d_sb->s_vfs_rename_mutex);
3046+
/*
3047+
* nobody can move out of any directories on this fs.
3048+
*/
3049+
if (likely(c1->d_parent != p2))
3050+
return lock_two_directories(c1->d_parent, p2);
3051+
3052+
/*
3053+
* c1 got moved into p2 while we were taking locks;
3054+
* we need p2 locked and ->s_vfs_rename_mutex unlocked,
3055+
* for consistency with lock_rename().
3056+
*/
3057+
inode_lock_nested(p2->d_inode, I_MUTEX_PARENT);
3058+
mutex_unlock(&c1->d_sb->s_vfs_rename_mutex);
3059+
return NULL;
3060+
}
3061+
EXPORT_SYMBOL(lock_rename_child);
3062+
30173063
void unlock_rename(struct dentry *p1, struct dentry *p2)
30183064
{
30193065
inode_unlock(p1->d_inode);

include/linux/namei.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ extern struct dentry *kern_path_create(int, const char *, struct path *, unsigne
6363
extern struct dentry *user_path_create(int, const char __user *, struct path *, unsigned int);
6464
extern void done_path_create(struct path *, struct dentry *);
6565
extern struct dentry *kern_path_locked(const char *, struct path *);
66+
int vfs_path_lookup(struct dentry *, struct vfsmount *, const char *,
67+
unsigned int, struct path *);
6668

6769
extern struct dentry *try_lookup_one_len(const char *, struct dentry *, int);
6870
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);
8183
extern int follow_up(struct path *);
8284

8385
extern struct dentry *lock_rename(struct dentry *, struct dentry *);
86+
extern struct dentry *lock_rename_child(struct dentry *, struct dentry *);
8487
extern void unlock_rename(struct dentry *, struct dentry *);
8588

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

0 commit comments

Comments
 (0)