Commit e999376f authored by Chris Mason's avatar Chris Mason

Btrfs: avoid delayed metadata items during commits

Snapshot creation has two phases.  One is the initial snapshot setup,
and the second is done during commit, while nobody is allowed to modify
the root we are snapshotting.

The delayed metadata insertion code can break that rule, it does a
delayed inode update on the inode of the parent of the snapshot,
and delayed directory item insertion.

This makes sure to run the pending delayed operations before we
record the snapshot root, which avoids corruptions.
Signed-off-by: default avatarChris Mason <chris.mason@oracle.com>
parent 35a30d7c
...@@ -1237,6 +1237,13 @@ static int btrfs_wq_run_delayed_node(struct btrfs_delayed_root *delayed_root, ...@@ -1237,6 +1237,13 @@ static int btrfs_wq_run_delayed_node(struct btrfs_delayed_root *delayed_root,
return 0; return 0;
} }
void btrfs_assert_delayed_root_empty(struct btrfs_root *root)
{
struct btrfs_delayed_root *delayed_root;
delayed_root = btrfs_get_delayed_root(root);
WARN_ON(btrfs_first_delayed_node(delayed_root));
}
void btrfs_balance_delayed_items(struct btrfs_root *root) void btrfs_balance_delayed_items(struct btrfs_root *root)
{ {
struct btrfs_delayed_root *delayed_root; struct btrfs_delayed_root *delayed_root;
......
...@@ -137,4 +137,8 @@ int btrfs_readdir_delayed_dir_index(struct file *filp, void *dirent, ...@@ -137,4 +137,8 @@ int btrfs_readdir_delayed_dir_index(struct file *filp, void *dirent,
/* for init */ /* for init */
int __init btrfs_delayed_inode_init(void); int __init btrfs_delayed_inode_init(void);
void btrfs_delayed_inode_exit(void); void btrfs_delayed_inode_exit(void);
/* for debugging */
void btrfs_assert_delayed_root_empty(struct btrfs_root *root);
#endif #endif
...@@ -957,6 +957,15 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, ...@@ -957,6 +957,15 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
ret = btrfs_update_inode(trans, parent_root, parent_inode); ret = btrfs_update_inode(trans, parent_root, parent_inode);
BUG_ON(ret); BUG_ON(ret);
/*
* pull in the delayed directory update
* and the delayed inode item
* otherwise we corrupt the FS during
* snapshot
*/
ret = btrfs_run_delayed_items(trans, root);
BUG_ON(ret);
record_root_in_trans(trans, root); record_root_in_trans(trans, root);
btrfs_set_root_last_snapshot(&root->root_item, trans->transid); btrfs_set_root_last_snapshot(&root->root_item, trans->transid);
memcpy(new_root_item, &root->root_item, sizeof(*new_root_item)); memcpy(new_root_item, &root->root_item, sizeof(*new_root_item));
...@@ -1018,14 +1027,6 @@ static noinline int create_pending_snapshots(struct btrfs_trans_handle *trans, ...@@ -1018,14 +1027,6 @@ static noinline int create_pending_snapshots(struct btrfs_trans_handle *trans,
int ret; int ret;
list_for_each_entry(pending, head, list) { list_for_each_entry(pending, head, list) {
/*
* We must deal with the delayed items before creating
* snapshots, or we will create a snapthot with inconsistent
* information.
*/
ret = btrfs_run_delayed_items(trans, fs_info->fs_root);
BUG_ON(ret);
ret = create_pending_snapshot(trans, fs_info, pending); ret = create_pending_snapshot(trans, fs_info, pending);
BUG_ON(ret); BUG_ON(ret);
} }
...@@ -1319,15 +1320,21 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, ...@@ -1319,15 +1320,21 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
*/ */
mutex_lock(&root->fs_info->reloc_mutex); mutex_lock(&root->fs_info->reloc_mutex);
ret = create_pending_snapshots(trans, root->fs_info); ret = btrfs_run_delayed_items(trans, root);
BUG_ON(ret); BUG_ON(ret);
ret = btrfs_run_delayed_items(trans, root); ret = create_pending_snapshots(trans, root->fs_info);
BUG_ON(ret); BUG_ON(ret);
ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1); ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1);
BUG_ON(ret); BUG_ON(ret);
/*
* make sure none of the code above managed to slip in a
* delayed item
*/
btrfs_assert_delayed_root_empty(root);
WARN_ON(cur_trans != trans->transaction); WARN_ON(cur_trans != trans->transaction);
btrfs_scrub_pause(root); btrfs_scrub_pause(root);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment