aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs
diff options
context:
space:
mode:
authorLi Zefan <lizf@cn.fujitsu.com>2011-03-27 22:01:25 -0400
committerChris Mason <chris.mason@oracle.com>2011-04-05 01:20:24 -0400
commit08fe4db170b4193603d9d31f40ebaf652d07ac9c (patch)
tree2d0d2abe40b77266600653e399d4973a679716a9 /fs/btrfs
parentadae52b94e18afa1f84fab67df2a8a872c2f5533 (diff)
Btrfs: Fix uninitialized root flags for subvolumes
root_item->flags and root_item->byte_limit are not initialized when a subvolume is created. This bug is not revealed until we added readonly snapshot support - now you mount a btrfs filesystem and you may find the subvolumes in it are readonly. To work around this problem, we steal a bit from root_item->inode_item->flags, and use it to indicate if those fields have been properly initialized. When we read a tree root from disk, we check if the bit is set, and if not we'll set the flag and initialize the two fields of the root item. Reported-by: Andreas Philipp <philipp.andreas@gmail.com> Signed-off-by: Li Zefan <lizf@cn.fujitsu.com> Tested-by: Andreas Philipp <philipp.andreas@gmail.com> cc: stable@kernel.org Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs')
-rw-r--r--fs/btrfs/ctree.h4
-rw-r--r--fs/btrfs/disk-io.c4
-rw-r--r--fs/btrfs/ioctl.c4
-rw-r--r--fs/btrfs/root-tree.c18
-rw-r--r--fs/btrfs/transaction.c1
5 files changed, 30 insertions, 1 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index d47ce8307854..3458b5725540 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -1284,6 +1284,8 @@ struct btrfs_root {
1284#define BTRFS_INODE_DIRSYNC (1 << 10) 1284#define BTRFS_INODE_DIRSYNC (1 << 10)
1285#define BTRFS_INODE_COMPRESS (1 << 11) 1285#define BTRFS_INODE_COMPRESS (1 << 11)
1286 1286
1287#define BTRFS_INODE_ROOT_ITEM_INIT (1 << 31)
1288
1287/* some macros to generate set/get funcs for the struct fields. This 1289/* some macros to generate set/get funcs for the struct fields. This
1288 * assumes there is a lefoo_to_cpu for every type, so lets make a simple 1290 * assumes there is a lefoo_to_cpu for every type, so lets make a simple
1289 * one for u8: 1291 * one for u8:
@@ -2359,6 +2361,8 @@ int btrfs_find_dead_roots(struct btrfs_root *root, u64 objectid);
2359int btrfs_find_orphan_roots(struct btrfs_root *tree_root); 2361int btrfs_find_orphan_roots(struct btrfs_root *tree_root);
2360int btrfs_set_root_node(struct btrfs_root_item *item, 2362int btrfs_set_root_node(struct btrfs_root_item *item,
2361 struct extent_buffer *node); 2363 struct extent_buffer *node);
2364void btrfs_check_and_init_root_item(struct btrfs_root_item *item);
2365
2362/* dir-item.c */ 2366/* dir-item.c */
2363int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, 2367int btrfs_insert_dir_item(struct btrfs_trans_handle *trans,
2364 struct btrfs_root *root, const char *name, 2368 struct btrfs_root *root, const char *name,
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 5cf3aa7b125c..a272bfd74ea0 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -1276,8 +1276,10 @@ struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_root *tree_root,
1276 root->commit_root = btrfs_root_node(root); 1276 root->commit_root = btrfs_root_node(root);
1277 BUG_ON(!root->node); 1277 BUG_ON(!root->node);
1278out: 1278out:
1279 if (location->objectid != BTRFS_TREE_LOG_OBJECTID) 1279 if (location->objectid != BTRFS_TREE_LOG_OBJECTID) {
1280 root->ref_cows = 1; 1280 root->ref_cows = 1;
1281 btrfs_check_and_init_root_item(&root->root_item);
1282 }
1281 1283
1282 return root; 1284 return root;
1283} 1285}
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 255c7c5279c4..f9c93a9ed4a7 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -373,6 +373,10 @@ static noinline int create_subvol(struct btrfs_root *root,
373 inode_item->nbytes = cpu_to_le64(root->leafsize); 373 inode_item->nbytes = cpu_to_le64(root->leafsize);
374 inode_item->mode = cpu_to_le32(S_IFDIR | 0755); 374 inode_item->mode = cpu_to_le32(S_IFDIR | 0755);
375 375
376 root_item.flags = 0;
377 root_item.byte_limit = 0;
378 inode_item->flags = cpu_to_le64(BTRFS_INODE_ROOT_ITEM_INIT);
379
376 btrfs_set_root_bytenr(&root_item, leaf->start); 380 btrfs_set_root_bytenr(&root_item, leaf->start);
377 btrfs_set_root_generation(&root_item, trans->transid); 381 btrfs_set_root_generation(&root_item, trans->transid);
378 btrfs_set_root_level(&root_item, 0); 382 btrfs_set_root_level(&root_item, 0);
diff --git a/fs/btrfs/root-tree.c b/fs/btrfs/root-tree.c
index 29b2d7c930eb..6928bff62daa 100644
--- a/fs/btrfs/root-tree.c
+++ b/fs/btrfs/root-tree.c
@@ -473,3 +473,21 @@ again:
473 btrfs_free_path(path); 473 btrfs_free_path(path);
474 return 0; 474 return 0;
475} 475}
476
477/*
478 * Old btrfs forgets to init root_item->flags and root_item->byte_limit
479 * for subvolumes. To work around this problem, we steal a bit from
480 * root_item->inode_item->flags, and use it to indicate if those fields
481 * have been properly initialized.
482 */
483void btrfs_check_and_init_root_item(struct btrfs_root_item *root_item)
484{
485 u64 inode_flags = le64_to_cpu(root_item->inode.flags);
486
487 if (!(inode_flags & BTRFS_INODE_ROOT_ITEM_INIT)) {
488 inode_flags |= BTRFS_INODE_ROOT_ITEM_INIT;
489 root_item->inode.flags = cpu_to_le64(inode_flags);
490 root_item->flags = 0;
491 root_item->byte_limit = 0;
492 }
493}
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index d01cc249a8d3..5b158da7e0bb 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -976,6 +976,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
976 record_root_in_trans(trans, root); 976 record_root_in_trans(trans, root);
977 btrfs_set_root_last_snapshot(&root->root_item, trans->transid); 977 btrfs_set_root_last_snapshot(&root->root_item, trans->transid);
978 memcpy(new_root_item, &root->root_item, sizeof(*new_root_item)); 978 memcpy(new_root_item, &root->root_item, sizeof(*new_root_item));
979 btrfs_check_and_init_root_item(new_root_item);
979 980
980 root_flags = btrfs_root_flags(new_root_item); 981 root_flags = btrfs_root_flags(new_root_item);
981 if (pending->readonly) 982 if (pending->readonly)