On Tue, Feb 26, 2019 at 12:06:09PM +0000, fdmanana@xxxxxxxxxx wrote:
> From: Filipe Manana <fdmanana@xxxxxxxx>
>
> Reflinking (clone/dedupe) and rename are operations that operate on two
> inodes and therefore need to lock them in the same order to avoid ABBA
> deadlocks. It happens that Btrfs' reflink implementation always locked
> them in a different order from VFS's lock_two_nondirectories() helper,
> which is used by the rename code in VFS, resulting in ABBA type deadlocks.
>
> Btrfs' locking order:
>
> static void btrfs_double_inode_lock(struct inode *inode1, struct inode *inode2)
> {
> if (inode1 < inode2)
> swap(inode1, inode2);
>
> inode_lock_nested(inode1, I_MUTEX_PARENT);
> inode_lock_nested(inode2, I_MUTEX_CHILD);
> }
>
> VFS's locking order:
>
> void lock_two_nondirectories(struct inode *inode1, struct inode *inode2)
> {
> if (inode1 > inode2)
> swap(inode1, inode2);
>
> if (inode1 && !S_ISDIR(inode1->i_mode))
> inode_lock(inode1);
> if (inode2 && !S_ISDIR(inode2->i_mode) && inode2 != inode1)
> inode_lock_nested(inode2, I_MUTEX_NONDIR2);
> }
>
> Fix this by killing the btrfs helper function that does the double inode
> locking and replace it with VFS's helper lock_two_nondirectories().
>
> Reported-by: Zygo Blaxell <ce3g8jdj@xxxxxxxxxxxxxxxxxxxxx>
> Fixes: 416161db9b63e3 ("btrfs: offline dedupe")
> Signed-off-by: Filipe Manana <fdmanana@xxxxxxxx>
Reviewed-by: David Sterba <dsterba@xxxxxxxx>