• Qu Wenruo's avatar
    btrfs: Fix a deadlock in btrfs_dev_replace_finishing() · 12b894cb
    Qu Wenruo authored
    btrfs-transacion:5657
    [stack snip]
    btrfs_bio_map()
        btrfs_bio_counter_inc_blocked()
            percpu_counter_inc(&fs_info->bio_counter)  ###bio_counter > 0(A)
            __btrfs_bio_map()
                btrfs_dev_replace_lock()
                    mutex_lock(dev_replace->lock)	   ###wait mutex(B)
    
    btrfs:32612
    [stack snip]
    btrfs_dev_replace_start()
        btrfs_dev_replace_lock()
    	mutex_lock(dev_replace->lock)		   ###hold mutex(B)
        btrfs_dev_replace_finishing()
            btrfs_rm_dev_replace_blocked()
                wait until percpu_counter_sum == 0	   ###wait on bio_counter(A)
    
    This bug can be triggered quite easily by the following test script:
    http://pastebin.com/MQmb37Cy
    
    This patch will fix the ABBA problem by calling
    btrfs_dev_replace_unlock() before btrfs_rm_dev_replace_blocked().
    
    The consistency of btrfs devices list and their superblocks is protected
    by device_list_mutex, not btrfs_dev_replace_lock/unlock().
    So it is safe the move btrfs_dev_replace_unlock() before
    btrfs_rm_dev_replace_blocked().
    Reported-by: default avatarZhao Lei <zhaolei@cn.fujitsu.com>
    Signed-off-by: default avatarQu Wenruo <quwenruo@cn.fujitsu.com>
    Cc: Stefan Behrens <sbehrens@giantdisaster.de>
    Signed-off-by: default avatarChris Mason <clm@fb.com>
    12b894cb
dev-replace.c 28.9 KB