Skip to content

Commit 56a17dd

Browse files
osandovgregkh
authored andcommitted
Btrfs: catch invalid free space trees
commit 6675df3 upstream. There are two separate issues that can lead to corrupted free space trees. 1. The free space tree bitmaps had an endianness issue on big-endian systems which is fixed by an earlier patch in this series. 2. btrfs-progs before v4.7.3 modified filesystems without updating the free space tree. To catch both of these issues at once, we need to force the free space tree to be rebuilt. To do so, add a FREE_SPACE_TREE_VALID compat_ro bit. If the bit isn't set, we know that it was either produced by a broken big-endian kernel or may have been corrupted by btrfs-progs. This also provides us with a way to add rudimentary read-write support for the free space tree to btrfs-progs: it can just clear this bit and have the kernel rebuild the free space tree. Tested-by: Holger Hoffstätte <[email protected]> Tested-by: Chandan Rajendra <[email protected]> Signed-off-by: Omar Sandoval <[email protected]> Signed-off-by: David Sterba <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 520f16a commit 56a17dd

File tree

4 files changed

+24
-2
lines changed

4 files changed

+24
-2
lines changed

fs/btrfs/ctree.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,8 @@ struct btrfs_super_block {
265265
#define BTRFS_FEATURE_COMPAT_SAFE_CLEAR 0ULL
266266

267267
#define BTRFS_FEATURE_COMPAT_RO_SUPP \
268-
(BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE)
268+
(BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE | \
269+
BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE_VALID)
269270

270271
#define BTRFS_FEATURE_COMPAT_RO_SAFE_SET 0ULL
271272
#define BTRFS_FEATURE_COMPAT_RO_SAFE_CLEAR 0ULL

fs/btrfs/disk-io.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2528,6 +2528,7 @@ int open_ctree(struct super_block *sb,
25282528
int num_backups_tried = 0;
25292529
int backup_index = 0;
25302530
int max_active;
2531+
int clear_free_space_tree = 0;
25312532

25322533
tree_root = fs_info->tree_root = btrfs_alloc_root(fs_info, GFP_KERNEL);
25332534
chunk_root = fs_info->chunk_root = btrfs_alloc_root(fs_info, GFP_KERNEL);
@@ -3129,6 +3130,14 @@ int open_ctree(struct super_block *sb,
31293130

31303131
if (btrfs_test_opt(tree_root, CLEAR_CACHE) &&
31313132
btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE)) {
3133+
clear_free_space_tree = 1;
3134+
} else if (btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE) &&
3135+
!btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE_VALID)) {
3136+
btrfs_warn(fs_info, "free space tree is invalid");
3137+
clear_free_space_tree = 1;
3138+
}
3139+
3140+
if (clear_free_space_tree) {
31323141
btrfs_info(fs_info, "clearing free space tree");
31333142
ret = btrfs_clear_free_space_tree(fs_info);
31343143
if (ret) {

fs/btrfs/free-space-tree.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1182,6 +1182,7 @@ int btrfs_create_free_space_tree(struct btrfs_fs_info *fs_info)
11821182
}
11831183

11841184
btrfs_set_fs_compat_ro(fs_info, FREE_SPACE_TREE);
1185+
btrfs_set_fs_compat_ro(fs_info, FREE_SPACE_TREE_VALID);
11851186
fs_info->creating_free_space_tree = 0;
11861187

11871188
ret = btrfs_commit_transaction(trans, tree_root);
@@ -1250,6 +1251,7 @@ int btrfs_clear_free_space_tree(struct btrfs_fs_info *fs_info)
12501251
return PTR_ERR(trans);
12511252

12521253
btrfs_clear_fs_compat_ro(fs_info, FREE_SPACE_TREE);
1254+
btrfs_clear_fs_compat_ro(fs_info, FREE_SPACE_TREE_VALID);
12531255
fs_info->free_space_root = NULL;
12541256

12551257
ret = clear_free_space_tree(trans, free_space_root);

include/uapi/linux/btrfs.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,17 @@ struct btrfs_ioctl_fs_info_args {
239239
* Used by:
240240
* struct btrfs_ioctl_feature_flags
241241
*/
242-
#define BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE (1ULL << 0)
242+
#define BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE (1ULL << 0)
243+
/*
244+
* Older kernels (< 4.9) on big-endian systems produced broken free space tree
245+
* bitmaps, and btrfs-progs also used to corrupt the free space tree (versions
246+
* < 4.7.3). If this bit is clear, then the free space tree cannot be trusted.
247+
* btrfs-progs can also intentionally clear this bit to ask the kernel to
248+
* rebuild the free space tree, however this might not work on older kernels
249+
* that do not know about this bit. If not sure, clear the cache manually on
250+
* first mount when booting older kernel versions.
251+
*/
252+
#define BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE_VALID (1ULL << 1)
243253

244254
#define BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF (1ULL << 0)
245255
#define BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL (1ULL << 1)

0 commit comments

Comments
 (0)