aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs
diff options
context:
space:
mode:
authorOmar Sandoval <osandov@fb.com>2016-09-22 20:24:22 -0400
committerDavid Sterba <dsterba@suse.com>2016-10-03 12:52:14 -0400
commit6675df311db87aa2107a04ef97e19420953cbace (patch)
tree0c1afd7c2acb7bcb767c949984203c6f96ac4184 /fs/btrfs
parentf8d468a15c22b954b379aa0c74914d5068448fb1 (diff)
Btrfs: catch invalid free space trees
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. Cc: stable@vger.kernel.org # 4.5+ Tested-by: Holger Hoffstätte <holger@applied-asynchrony.com> Tested-by: Chandan Rajendra <chandan@linux.vnet.ibm.com> Signed-off-by: Omar Sandoval <osandov@fb.com> Signed-off-by: David Sterba <dsterba@suse.com>
Diffstat (limited to 'fs/btrfs')
-rw-r--r--fs/btrfs/ctree.h3
-rw-r--r--fs/btrfs/disk-io.c9
-rw-r--r--fs/btrfs/free-space-tree.c2
3 files changed, 13 insertions, 1 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 33fe03551105..791e47ce9d27 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -251,7 +251,8 @@ struct btrfs_super_block {
251#define BTRFS_FEATURE_COMPAT_SAFE_CLEAR 0ULL 251#define BTRFS_FEATURE_COMPAT_SAFE_CLEAR 0ULL
252 252
253#define BTRFS_FEATURE_COMPAT_RO_SUPP \ 253#define BTRFS_FEATURE_COMPAT_RO_SUPP \
254 (BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE) 254 (BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE | \
255 BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE_VALID)
255 256
256#define BTRFS_FEATURE_COMPAT_RO_SAFE_SET 0ULL 257#define BTRFS_FEATURE_COMPAT_RO_SAFE_SET 0ULL
257#define BTRFS_FEATURE_COMPAT_RO_SAFE_CLEAR 0ULL 258#define BTRFS_FEATURE_COMPAT_RO_SAFE_CLEAR 0ULL
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index c0bfc6ce5f06..3dede6d53bad 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -2566,6 +2566,7 @@ int open_ctree(struct super_block *sb,
2566 int num_backups_tried = 0; 2566 int num_backups_tried = 0;
2567 int backup_index = 0; 2567 int backup_index = 0;
2568 int max_active; 2568 int max_active;
2569 int clear_free_space_tree = 0;
2569 2570
2570 tree_root = fs_info->tree_root = btrfs_alloc_root(fs_info, GFP_KERNEL); 2571 tree_root = fs_info->tree_root = btrfs_alloc_root(fs_info, GFP_KERNEL);
2571 chunk_root = fs_info->chunk_root = btrfs_alloc_root(fs_info, GFP_KERNEL); 2572 chunk_root = fs_info->chunk_root = btrfs_alloc_root(fs_info, GFP_KERNEL);
@@ -3131,6 +3132,14 @@ retry_root_backup:
3131 3132
3132 if (btrfs_test_opt(fs_info, CLEAR_CACHE) && 3133 if (btrfs_test_opt(fs_info, CLEAR_CACHE) &&
3133 btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE)) { 3134 btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE)) {
3135 clear_free_space_tree = 1;
3136 } else if (btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE) &&
3137 !btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE_VALID)) {
3138 btrfs_warn(fs_info, "free space tree is invalid");
3139 clear_free_space_tree = 1;
3140 }
3141
3142 if (clear_free_space_tree) {
3134 btrfs_info(fs_info, "clearing free space tree"); 3143 btrfs_info(fs_info, "clearing free space tree");
3135 ret = btrfs_clear_free_space_tree(fs_info); 3144 ret = btrfs_clear_free_space_tree(fs_info);
3136 if (ret) { 3145 if (ret) {
diff --git a/fs/btrfs/free-space-tree.c b/fs/btrfs/free-space-tree.c
index 8fd85bfbe2da..ea605ffd0e03 100644
--- a/fs/btrfs/free-space-tree.c
+++ b/fs/btrfs/free-space-tree.c
@@ -1182,6 +1182,7 @@ int btrfs_create_free_space_tree(struct btrfs_fs_info *fs_info)
1182 } 1182 }
1183 1183
1184 btrfs_set_fs_compat_ro(fs_info, FREE_SPACE_TREE); 1184 btrfs_set_fs_compat_ro(fs_info, FREE_SPACE_TREE);
1185 btrfs_set_fs_compat_ro(fs_info, FREE_SPACE_TREE_VALID);
1185 fs_info->creating_free_space_tree = 0; 1186 fs_info->creating_free_space_tree = 0;
1186 1187
1187 ret = btrfs_commit_transaction(trans, tree_root); 1188 ret = btrfs_commit_transaction(trans, tree_root);
@@ -1250,6 +1251,7 @@ int btrfs_clear_free_space_tree(struct btrfs_fs_info *fs_info)
1250 return PTR_ERR(trans); 1251 return PTR_ERR(trans);
1251 1252
1252 btrfs_clear_fs_compat_ro(fs_info, FREE_SPACE_TREE); 1253 btrfs_clear_fs_compat_ro(fs_info, FREE_SPACE_TREE);
1254 btrfs_clear_fs_compat_ro(fs_info, FREE_SPACE_TREE_VALID);
1253 fs_info->free_space_root = NULL; 1255 fs_info->free_space_root = NULL;
1254 1256
1255 ret = clear_free_space_tree(trans, free_space_root); 1257 ret = clear_free_space_tree(trans, free_space_root);