• G
    btrfs: fix dead lock while running replace and defrag concurrently · 32159242
    Gui Hecheng 提交于
    This can be reproduced by fstests: btrfs/070
    
    The scenario is like the following:
    
    replace worker thread		defrag thread
    ---------------------		-------------
    copy_nocow_pages_worker		btrfs_defrag_file
      copy_nocow_pages_for_inode	    ...
    				  btrfs_writepages
      |A| lock_extent_bits		    extent_write_cache_pages
    				|B|   lock_page
    					__extent_writepage
    		...			  writepage_delalloc
    					    find_lock_delalloc_range
    				|B| 	      lock_extent_bits
      find_or_create_page
        pagecache_get_page
      |A| lock_page
    
    This leads to an ABBA pattern deadlock. To fix it,
    o we just change it to an AABB pattern which means to @unlock_extent_bits()
      before we @lock_page(), and in this way the @extent_read_full_page_nolock()
      is no longer in an locked context, so change it back to @extent_read_full_page()
      to regain protection.
    
    o Since we @unlock_extent_bits() earlier, then before @write_page_nocow(),
      the extent may not really point at the physical block we want, so we
      have to check it before write.
    Signed-off-by: NGui Hecheng <guihc.fnst@cn.fujitsu.com>
    Tested-by: NDavid Sterba <dsterba@suse.cz>
    Signed-off-by: NChris Mason <clm@fb.com>
    32159242
scrub.c 93.4 KB