Skip to content

Commit 9bc37e0

Browse files
author
Al Viro
committed
fs: introduce lock_rename_child() helper
Pass the dentry of a source file and the dentry of a destination directory to lock parent inodes for rename. As soon as this function returns, ->d_parent of the source file dentry is stable and inodes are properly locked for calling vfs-rename. This helper is needed for ksmbd server. rename request of SMB protocol has to rename an opened file, no matter which directory it's in. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
1 parent 211db0a commit 9bc37e0

2 files changed

Lines changed: 58 additions & 11 deletions

File tree

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: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ extern int follow_down(struct path *path, unsigned int flags);
8383
extern int follow_up(struct path *);
8484

8585
extern struct dentry *lock_rename(struct dentry *, struct dentry *);
86+
extern struct dentry *lock_rename_child(struct dentry *, struct dentry *);
8687
extern void unlock_rename(struct dentry *, struct dentry *);
8788

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

0 commit comments

Comments
 (0)