• Qu Wenruo's avatar
    btrfs: fix compat_ro checks against remount · 2ba48b20
    Qu Wenruo authored
    [BUG]
    Even with commit 81d5d614 ("btrfs: enhance unsupported compat RO
    flags handling"), btrfs can still mount a fs with unsupported compat_ro
    flags read-only, then remount it RW:
    
      # btrfs ins dump-super /dev/loop0 | grep compat_ro_flags -A 3
      compat_ro_flags		0x403
    			( FREE_SPACE_TREE |
    			  FREE_SPACE_TREE_VALID |
    			  unknown flag: 0x400 )
    
      # mount /dev/loop0 /mnt/btrfs
      mount: /mnt/btrfs: wrong fs type, bad option, bad superblock on /dev/loop0, missing codepage or helper program, or other error.
             dmesg(1) may have more information after failed mount system call.
      ^^^ RW mount failed as expected ^^^
    
      # dmesg -t | tail -n5
      loop0: detected capacity change from 0 to 1048576
      BTRFS: device fsid cb5b82f5-0fdd-4d81-9b4b-78533c324afa devid 1 transid 7 /dev/loop0 scanned by mount (1146)
      BTRFS info (device loop0): using crc32c (crc32c-intel) checksum algorithm
      BTRFS info (device loop0): using free space tree
      BTRFS error (device loop0): cannot mount read-write because of unknown compat_ro features (0x403)
      BTRFS error (device loop0): open_ctree failed
    
      # mount /dev/loop0 -o ro /mnt/btrfs
      # mount -o remount,rw /mnt/btrfs
      ^^^ RW remount succeeded unexpectedly ^^^
    
    [CAUSE]
    Currently we use btrfs_check_features() to check compat_ro flags against
    our current mount flags.
    
    That function get reused between open_ctree() and btrfs_remount().
    
    But for btrfs_remount(), the super block we passed in still has the old
    mount flags, thus btrfs_check_features() still believes we're mounting
    read-only.
    
    [FIX]
    Replace the existing @sb argument with @is_rw_mount.
    
    As originally we only use @sb to determine if the mount is RW.
    
    Now it's callers' responsibility to determine if the mount is RW, and
    since there are only two callers, the check is pretty simple:
    
    - caller in open_ctree()
      Just pass !sb_rdonly().
    
    - caller in btrfs_remount()
      Pass !(*flags & SB_RDONLY), as our check should be against the new
      flags.
    
    Now we can correctly reject the RW remount:
    
      # mount /dev/loop0 -o ro /mnt/btrfs
      # mount -o remount,rw /mnt/btrfs
      mount: /mnt/btrfs: mount point not mounted or bad option.
             dmesg(1) may have more information after failed mount system call.
      # dmesg -t | tail -n 1
      BTRFS error (device loop0: state M): cannot mount read-write because of unknown compat_ro features (0x403)
    Reported-by: default avatarChung-Chiang Cheng <shepjeng@gmail.com>
    Fixes: 81d5d614 ("btrfs: enhance unsupported compat RO flags handling")
    CC: stable@vger.kernel.org # 5.15+
    Reviewed-by: default avatarAnand Jain <anand.jain@oracle.com>
    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>
    2ba48b20
disk-io.c 149 KB