Re: [GIT PULL] ksmbd server fixes

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



2022-04-01 22:34 GMT+09:00, Al Viro <viro@xxxxxxxxxxxxxxxxxx>:
> On Fri, Apr 01, 2022 at 09:52:09PM +0900, Namjae Jeon wrote:
>> > take source and new parent and do the following:
>> >
>> > 	if (READ_ONCE(source->d_parent) == new_parent) {
>> > 		inode_lock_nested(new_parent->d_inode, I_MUTEX_PARENT);
>> > 		if (likely(source->d_parent == new_parent))
>> > 			return NULL;
> and
> 		inode_unlock(new_parent->d_inode);
> to do locking in proper order...
Okay, Let me check it with these codes.
Thanks for sharing the codes!

>
>> > 	}
>> > 	// fuck that, looks like a cross-rename one.
>> > 	mutex_lock(&source->d_sb->s_vfs_rename_mutex);
>> > 	// now all ->d_parent are stable
>> > 	if (unlikely(source->d_parent == new_parent)) {
>> > 		inode_lock_nested(new_parent->d_inode, I_MUTEX_PARENT);
>> > 		// we want the same rules as for lock_rename()
>> > 		mutex_unlock(&source->d_sb->s_vfs_rename_mutex);
>> > 		return NULL;
>> > 	}
>> > 	// cross-directory it is...
>> > 	same as lock_rename() after having grabbed ->s_vfs_rename_mutex
>
> // p1 != p2, p1->d_sb == p2->d_sb, p1->d_sb->s_vfs_rename_mutex held
> static struct dentry *lock_two_directories(struct dentry *p1, struct dentry
> *p2)
> {
>         struct dentry *p;
>
>         p = d_ancestor(p2, p1);
>         if (p) {
>                 inode_lock_nested(p2->d_inode, I_MUTEX_PARENT);
>                 inode_lock_nested(p1->d_inode, I_MUTEX_CHILD);
>                 return p;
>         }
>
>         p = d_ancestor(p1, p2);
>         if (p) {
>                 inode_lock_nested(p1->d_inode, I_MUTEX_PARENT);
>                 inode_lock_nested(p2->d_inode, I_MUTEX_CHILD);
>                 return p;
>         }
>
>         inode_lock_nested(p1->d_inode, I_MUTEX_PARENT);
>         inode_lock_nested(p2->d_inode, I_MUTEX_PARENT2);
>         return NULL;
> }
>
> 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);
> }
>
> struct dentry *lock_rename_child(struct dentry *c1, struct dentry *p2)
> {
> 	if (READ_ONCE(c1->d_parent) == p2) {
> 		inode_lock_nested(p2->d_inode, I_MUTEX_PARENT);
> 		if (likely(c1->d_parent == p2))
> 			return NULL;
>
> 		// too bad, we'd raced with another rename
> 		inode_unlock(p2->d_inode);
> 	}
>
> 	// looks like it's cross-directory
> 	mutex_lock(&c1->d_sb->s_vfs_rename_mutex);
>
> 	// recheck, now that ->d_parent is stable
> 	if (likely(c1->d_parent != p2))
> 		return lock_two_directories(c1->d_parent, p2);
>
> 	// it's not cross-directory, after all - raced with another rename
> 	inode_lock_nested(p2->d_inode, I_MUTEX_PARENT);
> 	// drop ->s_vfs_rename_mutex, so we won't confuse unlock_rename()
> 	// note that locked p2 alone is enough to prevent moves to or from
> 	// p2, so c1->d_parent will remain p2 until we unlock p2
> 	mutex_unlock(&c1->d_sb->s_vfs_rename_mutex);
> 	return NULL;
> }
>



[Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux