Skip to content
  • Qu Wenruo's avatar
    btrfs: inode: Don't compress if NODATASUM or NODATACOW set · 42c16da6
    Qu Wenruo authored
    As btrfs(5) specified:
    
    	Note
    	If nodatacow or nodatasum are enabled, compression is disabled.
    
    If NODATASUM or NODATACOW set, we should not compress the extent.
    
    Normally NODATACOW is detected properly in run_delalloc_range() so
    compression won't happen for NODATACOW.
    
    However for NODATASUM we don't have any check, and it can cause
    compressed extent without csum pretty easily, just by:
      mkfs.btrfs -f $dev
      mount $dev $mnt -o nodatasum
      touch $mnt/foobar
      mount -o remount,datasum,compress $mnt
      xfs_io -f -c "pwrite 0 128K" $mnt/foobar
    
    And in fact, we have a bug report about corrupted compressed extent
    without proper data checksum so even RAID1 can't recover the corruption.
    (https://bugzilla.kernel.org/show_bug.cgi?id=199707
    
    )
    
    Running compression without proper checksum could cause more damage when
    corruption happens, as compressed data could make the whole extent
    unreadable, so there is no need to allow compression for
    NODATACSUM.
    
    The fix will refactor the inode compression check into two parts:
    
    - inode_can_compress()
      As the hard requirement, checked at btrfs_run_delalloc_range(), so no
      compression will happen for NODATASUM inode at all.
    
    - inode_need_compress()
      As the soft requirement, checked at btrfs_run_delalloc_range() and
      compress_file_range().
    
    Reported-by: default avatarJames Harvey <jamespharvey20@gmail.com>
    CC: stable@vger.kernel.org # 4.4+
    Signed-off-by: default avatarQu Wenruo <wqu@suse.com>
    Reviewed-by: default avatarDavid Sterba <dsterba@suse.com>
    Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
    42c16da6