aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/transaction.c
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2008-01-08 15:46:30 -0500
committerChris Mason <chris.mason@oracle.com>2008-09-25 11:03:59 -0400
commit3063d29f2a4d4a4e9fa1ec77c124514f287c6da7 (patch)
tree61aa53d18c6684a327b6166764eecbea9d0e6b5b /fs/btrfs/transaction.c
parentdc17ff8f11d129db9e83ab7244769e4eae05e14d (diff)
downloadkernel_samsung_smdk4412-3063d29f2a4d4a4e9fa1ec77c124514f287c6da7.zip
kernel_samsung_smdk4412-3063d29f2a4d4a4e9fa1ec77c124514f287c6da7.tar.gz
kernel_samsung_smdk4412-3063d29f2a4d4a4e9fa1ec77c124514f287c6da7.tar.bz2
Btrfs: Move snapshot creation to commit time
It is very difficult to create a consistent snapshot of the btree when other writers may update the btree before the commit is done. This changes the snapshot creation to happen during the commit, while no other updates are possible. Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/transaction.c')
-rw-r--r--fs/btrfs/transaction.c81
1 files changed, 78 insertions, 3 deletions
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index 3ed5868..dc98653 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -66,6 +66,7 @@ static int join_transaction(struct btrfs_root *root)
cur_trans->use_count = 1;
cur_trans->commit_done = 0;
cur_trans->start_time = get_seconds();
+ INIT_LIST_HEAD(&cur_trans->pending_snapshots);
list_add_tail(&cur_trans->list, &root->fs_info->trans_list);
btrfs_ordered_inode_tree_init(&cur_trans->ordered_inode_tree);
extent_map_tree_init(&cur_trans->dirty_pages,
@@ -481,10 +482,8 @@ int btrfs_write_ordered_inodes(struct btrfs_trans_handle *trans,
struct inode *inode;
u64 root_objectid = 0;
u64 objectid = 0;
- u64 transid = trans->transid;
int ret;
-printk("write ordered trans %Lu\n", transid);
while(1) {
ret = btrfs_find_first_ordered_inode(
&cur_trans->ordered_inode_tree,
@@ -524,7 +523,80 @@ printk("write ordered trans %Lu\n", transid);
mutex_lock(&root->fs_info->fs_mutex);
mutex_lock(&root->fs_info->trans_mutex);
}
-printk("done write ordered trans %Lu\n", transid);
+ return 0;
+}
+
+static int create_pending_snapshot(struct btrfs_trans_handle *trans,
+ struct btrfs_fs_info *fs_info,
+ struct btrfs_pending_snapshot *pending)
+{
+ struct btrfs_key key;
+ struct btrfs_root_item new_root_item;
+ struct btrfs_root *tree_root = fs_info->tree_root;
+ struct btrfs_root *root = pending->root;
+ struct extent_buffer *tmp;
+ int ret;
+ u64 objectid;
+
+ ret = btrfs_find_free_objectid(trans, tree_root, 0, &objectid);
+ if (ret)
+ goto fail;
+
+ memcpy(&new_root_item, &root->root_item, sizeof(new_root_item));
+
+ key.objectid = objectid;
+ key.offset = 1;
+ btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY);
+
+ extent_buffer_get(root->node);
+ btrfs_cow_block(trans, root, root->node, NULL, 0, &tmp);
+ free_extent_buffer(tmp);
+
+ btrfs_copy_root(trans, root, root->node, &tmp, objectid);
+
+ btrfs_set_root_bytenr(&new_root_item, tmp->start);
+ btrfs_set_root_level(&new_root_item, btrfs_header_level(tmp));
+ ret = btrfs_insert_root(trans, root->fs_info->tree_root, &key,
+ &new_root_item);
+ free_extent_buffer(tmp);
+ if (ret)
+ goto fail;
+
+ /*
+ * insert the directory item
+ */
+ key.offset = (u64)-1;
+ ret = btrfs_insert_dir_item(trans, root->fs_info->tree_root,
+ pending->name, strlen(pending->name),
+ root->fs_info->sb->s_root->d_inode->i_ino,
+ &key, BTRFS_FT_DIR);
+
+ if (ret)
+ goto fail;
+
+ ret = btrfs_insert_inode_ref(trans, root->fs_info->tree_root,
+ pending->name, strlen(pending->name), objectid,
+ root->fs_info->sb->s_root->d_inode->i_ino);
+fail:
+ return ret;
+}
+
+static int create_pending_snapshots(struct btrfs_trans_handle *trans,
+ struct btrfs_fs_info *fs_info)
+{
+ struct btrfs_pending_snapshot *pending;
+ struct list_head *head = &trans->transaction->pending_snapshots;
+ int ret;
+
+ while(!list_empty(head)) {
+ pending = list_entry(head->next,
+ struct btrfs_pending_snapshot, list);
+ ret = create_pending_snapshot(trans, fs_info, pending);
+ BUG_ON(ret);
+ list_del(&pending->list);
+ kfree(pending->name);
+ kfree(pending);
+ }
return 0;
}
@@ -610,6 +682,9 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
} while (cur_trans->num_writers > 1 ||
(cur_trans->num_joined != joined));
+ ret = create_pending_snapshots(trans, root->fs_info);
+ BUG_ON(ret);
+
WARN_ON(cur_trans != trans->transaction);
ret = add_dirty_roots(trans, &root->fs_info->fs_roots_radix,