Skip to content

Commit

Permalink
Btrfs: Fix super block updates during transaction commit
Browse files Browse the repository at this point in the history
The super block written during commit was not consistent with the state of
the trees.  This change adds an in-memory copy of the super so that we can
make sure to write out consistent data during a commit.

Signed-off-by: Chris Mason <chris.mason@oracle.com>
  • Loading branch information
Chris Mason authored and David Woodhouse committed Jun 26, 2007
1 parent 79c4458 commit 4b52dff
Show file tree
Hide file tree
Showing 5 changed files with 18 additions and 14 deletions.
1 change: 1 addition & 0 deletions fs/btrfs/ctree.h
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,7 @@ struct btrfs_fs_info {
u64 generation;
struct btrfs_transaction *running_transaction;
struct btrfs_super_block *disk_super;
struct btrfs_super_block super_copy;
struct buffer_head *sb_buffer;
struct super_block *sb;
struct inode *btree_inode;
Expand Down
5 changes: 2 additions & 3 deletions fs/btrfs/disk-io.c
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,8 @@ struct btrfs_root *open_ctree(struct super_block *sb)
if (!fs_info->sb_buffer)
goto fail_iput;
disk_super = (struct btrfs_super_block *)fs_info->sb_buffer->b_data;
fs_info->disk_super = disk_super;
memcpy(&fs_info->super_copy, disk_super, sizeof(fs_info->super_copy));

if (!btrfs_super_root(disk_super))
goto fail_sb_buffer;
Expand All @@ -479,7 +481,6 @@ struct btrfs_root *open_ctree(struct super_block *sb)
btrfs_super_total_blocks(disk_super) <<
fs_info->btree_inode->i_blkbits);

fs_info->disk_super = disk_super;

if (strncmp((char *)(&disk_super->magic), BTRFS_MAGIC,
sizeof(disk_super->magic))) {
Expand Down Expand Up @@ -527,8 +528,6 @@ int write_ctree_super(struct btrfs_trans_handle *trans, struct btrfs_root
int ret;
struct buffer_head *bh = root->fs_info->sb_buffer;

btrfs_set_super_root(root->fs_info->disk_super,
bh_blocknr(root->fs_info->tree_root->node));
lock_buffer(bh);
WARN_ON(atomic_read(&bh->b_count) < 1);
clear_buffer_dirty(bh);
Expand Down
16 changes: 8 additions & 8 deletions fs/btrfs/extent-tree.c
Original file line number Diff line number Diff line change
Expand Up @@ -796,8 +796,8 @@ static int finish_current_insert(struct btrfs_trans_handle *trans, struct

for (i = 0; i < extent_root->fs_info->extent_tree_insert_nr; i++) {
ins.objectid = extent_root->fs_info->extent_tree_insert[i];
super_blocks_used = btrfs_super_blocks_used(info->disk_super);
btrfs_set_super_blocks_used(info->disk_super,
super_blocks_used = btrfs_super_blocks_used(&info->super_copy);
btrfs_set_super_blocks_used(&info->super_copy,
super_blocks_used + 1);
ret = btrfs_insert_item(trans, extent_root, &ins, &extent_item,
sizeof(extent_item));
Expand Down Expand Up @@ -892,8 +892,8 @@ static int __free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
BUG_ON(ret);
}

super_blocks_used = btrfs_super_blocks_used(info->disk_super);
btrfs_set_super_blocks_used(info->disk_super,
super_blocks_used = btrfs_super_blocks_used(&info->super_copy);
btrfs_set_super_blocks_used(&info->super_copy,
super_blocks_used - num_blocks);
ret = btrfs_del_item(trans, extent_root, path);
if (ret) {
Expand Down Expand Up @@ -1032,7 +1032,7 @@ static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
info->extent_tree_prealloc_nr = 0;
}
if (search_end == (u64)-1)
search_end = btrfs_super_total_blocks(info->disk_super);
search_end = btrfs_super_total_blocks(&info->super_copy);
if (hint_block) {
block_group = btrfs_lookup_block_group(info, hint_block);
block_group = btrfs_find_block_group(root, block_group,
Expand Down Expand Up @@ -1361,8 +1361,8 @@ int btrfs_alloc_extent(struct btrfs_trans_handle *trans,
}
}

super_blocks_used = btrfs_super_blocks_used(info->disk_super);
btrfs_set_super_blocks_used(info->disk_super, super_blocks_used +
super_blocks_used = btrfs_super_blocks_used(&info->super_copy);
btrfs_set_super_blocks_used(&info->super_copy, super_blocks_used +
num_blocks);
ret = btrfs_insert_item(trans, extent_root, ins, &extent_item,
sizeof(extent_item));
Expand Down Expand Up @@ -1737,7 +1737,7 @@ int btrfs_read_block_groups(struct btrfs_root *root)
BTRFS_BLOCK_GROUP_AVAIL);
}
if (key.objectid >=
btrfs_super_total_blocks(info->disk_super))
btrfs_super_total_blocks(&info->super_copy))
break;
}

Expand Down
2 changes: 1 addition & 1 deletion fs/btrfs/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ static int btrfs_get_sb(struct file_system_type *fs_type,
static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf)
{
struct btrfs_root *root = btrfs_sb(dentry->d_sb);
struct btrfs_super_block *disk_super = root->fs_info->disk_super;
struct btrfs_super_block *disk_super = &root->fs_info->super_copy;

buf->f_namelen = BTRFS_NAME_LEN;
buf->f_blocks = btrfs_super_total_blocks(disk_super);
Expand Down
8 changes: 6 additions & 2 deletions fs/btrfs/transaction.c
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,12 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
else
prev_trans->use_count++;
}
btrfs_set_super_generation(&root->fs_info->super_copy,
cur_trans->transid);
btrfs_set_super_root(&root->fs_info->super_copy,
bh_blocknr(root->fs_info->tree_root->node));
memcpy(root->fs_info->disk_super, &root->fs_info->super_copy,
sizeof(root->fs_info->super_copy));
mutex_unlock(&root->fs_info->trans_mutex);
mutex_unlock(&root->fs_info->fs_mutex);
ret = btrfs_write_and_wait_transaction(trans, root);
Expand All @@ -389,8 +395,6 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
put_transaction(prev_trans);
mutex_unlock(&root->fs_info->trans_mutex);
}
btrfs_set_super_generation(root->fs_info->disk_super,
cur_trans->transid);
BUG_ON(ret);
write_ctree_super(trans, root);

Expand Down

0 comments on commit 4b52dff

Please sign in to comment.