Skip to content

Commit 2ba48b2

Browse files
adam900710kdave
authored andcommitted
btrfs: fix compat_ro checks against remount
[BUG] Even with commit 81d5d61 ("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: Chung-Chiang Cheng <[email protected]> Fixes: 81d5d61 ("btrfs: enhance unsupported compat RO flags handling") CC: [email protected] # 5.15+ Reviewed-by: Anand Jain <[email protected]> Signed-off-by: Qu Wenruo <[email protected]> Reviewed-by: David Sterba <[email protected]> Signed-off-by: David Sterba <[email protected]>
1 parent 39f501d commit 2ba48b2

File tree

3 files changed

+7
-5
lines changed

3 files changed

+7
-5
lines changed

fs/btrfs/disk-io.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3384,6 +3384,8 @@ int btrfs_start_pre_rw_mount(struct btrfs_fs_info *fs_info)
33843384
/*
33853385
* Do various sanity and dependency checks of different features.
33863386
*
3387+
* @is_rw_mount: If the mount is read-write.
3388+
*
33873389
* This is the place for less strict checks (like for subpage or artificial
33883390
* feature dependencies).
33893391
*
@@ -3394,7 +3396,7 @@ int btrfs_start_pre_rw_mount(struct btrfs_fs_info *fs_info)
33943396
* (space cache related) can modify on-disk format like free space tree and
33953397
* screw up certain feature dependencies.
33963398
*/
3397-
int btrfs_check_features(struct btrfs_fs_info *fs_info, struct super_block *sb)
3399+
int btrfs_check_features(struct btrfs_fs_info *fs_info, bool is_rw_mount)
33983400
{
33993401
struct btrfs_super_block *disk_super = fs_info->super_copy;
34003402
u64 incompat = btrfs_super_incompat_flags(disk_super);
@@ -3433,7 +3435,7 @@ int btrfs_check_features(struct btrfs_fs_info *fs_info, struct super_block *sb)
34333435
if (btrfs_super_nodesize(disk_super) > PAGE_SIZE)
34343436
incompat |= BTRFS_FEATURE_INCOMPAT_BIG_METADATA;
34353437

3436-
if (compat_ro_unsupp && !sb_rdonly(sb)) {
3438+
if (compat_ro_unsupp && is_rw_mount) {
34373439
btrfs_err(fs_info,
34383440
"cannot mount read-write because of unknown compat_ro features (0x%llx)",
34393441
compat_ro);
@@ -3636,7 +3638,7 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device
36363638
goto fail_alloc;
36373639
}
36383640

3639-
ret = btrfs_check_features(fs_info, sb);
3641+
ret = btrfs_check_features(fs_info, !sb_rdonly(sb));
36403642
if (ret < 0) {
36413643
err = ret;
36423644
goto fail_alloc;

fs/btrfs/disk-io.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ int __cold open_ctree(struct super_block *sb,
5050
void __cold close_ctree(struct btrfs_fs_info *fs_info);
5151
int btrfs_validate_super(struct btrfs_fs_info *fs_info,
5252
struct btrfs_super_block *sb, int mirror_num);
53-
int btrfs_check_features(struct btrfs_fs_info *fs_info, struct super_block *sb);
53+
int btrfs_check_features(struct btrfs_fs_info *fs_info, bool is_rw_mount);
5454
int write_all_supers(struct btrfs_fs_info *fs_info, int max_mirrors);
5555
struct btrfs_super_block *btrfs_read_dev_super(struct block_device *bdev);
5656
struct btrfs_super_block *btrfs_read_dev_one_super(struct block_device *bdev,

fs/btrfs/super.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1705,7 +1705,7 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data)
17051705
if (ret)
17061706
goto restore;
17071707

1708-
ret = btrfs_check_features(fs_info, sb);
1708+
ret = btrfs_check_features(fs_info, !(*flags & SB_RDONLY));
17091709
if (ret < 0)
17101710
goto restore;
17111711

0 commit comments

Comments
 (0)