static int commit_tree_roots(struct btrfs_trans_handle *trans, struct btrfs_fs_info *fs_info) { struct btrfs_root *root; struct list_head *next; struct extent_buffer *eb; int ret; if (fs_info->readonly) return 0; eb = fs_info->tree_root->node; extent_buffer_get(eb); ret = btrfs_cow_block(trans, fs_info->tree_root, eb, NULL, 0, &eb); free_extent_buffer(eb); if (ret) return ret; while(!list_empty(&fs_info->dirty_cowonly_roots)) { next = fs_info->dirty_cowonly_roots.next; list_del_init(next); root = list_entry(next, struct btrfs_root, dirty_list); update_cowonly_root(trans, root); free_extent_buffer(root->commit_root); root->commit_root = NULL; } return 0; }
/* * update all the cowonly tree roots on disk */ static noinline int commit_cowonly_roots(struct btrfs_trans_handle *trans, struct btrfs_root *root) { struct btrfs_fs_info *fs_info = root->fs_info; struct list_head *next; struct extent_buffer *eb; int ret; ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1); BUG_ON(ret); eb = btrfs_lock_root_node(fs_info->tree_root); btrfs_cow_block(trans, fs_info->tree_root, eb, NULL, 0, &eb); btrfs_tree_unlock(eb); free_extent_buffer(eb); ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1); BUG_ON(ret); while (!list_empty(&fs_info->dirty_cowonly_roots)) { next = fs_info->dirty_cowonly_roots.next; list_del_init(next); root = list_entry(next, struct btrfs_root, dirty_list); update_cowonly_root(trans, root); } down_write(&fs_info->extent_commit_sem); switch_commit_root(fs_info->extent_root); up_write(&fs_info->extent_commit_sem); return 0; }
int commit_tree_roots(struct btrfs_trans_handle *trans, struct btrfs_fs_info *fs_info) { struct btrfs_root *root; struct list_head *next; struct extent_buffer *eb; int ret; if (fs_info->readonly) return 0; eb = fs_info->tree_root->node; extent_buffer_get(eb); ret = btrfs_cow_block(trans, fs_info->tree_root, eb, NULL, 0, &eb); free_extent_buffer(eb); if (ret) return ret; /* * If the above CoW is the first one to dirty the current tree_root, * delayed refs for it won't be run until after this function has * finished executing, meaning we won't process the extent tree root, * which will have been added to ->dirty_cowonly_roots. So run * delayed refs here as well. */ ret = btrfs_run_delayed_refs(trans, -1); if (ret) return ret; while(!list_empty(&fs_info->dirty_cowonly_roots)) { next = fs_info->dirty_cowonly_roots.next; list_del_init(next); root = list_entry(next, struct btrfs_root, dirty_list); ret = update_cowonly_root(trans, root); free_extent_buffer(root->commit_root); root->commit_root = NULL; if (ret < 0) return ret; } return 0; }