static struct btrfs_trans_handle *start_transaction(struct btrfs_root *root, int num_blocks, int wait) { struct btrfs_trans_handle *h = kmem_cache_alloc(btrfs_trans_handle_cachep, GFP_NOFS); int ret; mutex_lock(&root->fs_info->trans_mutex); if (!root->fs_info->log_root_recovering && ((wait == 1 && !root->fs_info->open_ioctl_trans) || wait == 2)) wait_current_trans(root); ret = join_transaction(root); BUG_ON(ret); h->transid = root->fs_info->running_transaction->transid; h->transaction = root->fs_info->running_transaction; h->blocks_reserved = num_blocks; h->blocks_used = 0; h->block_group = 0; h->alloc_exclude_nr = 0; h->alloc_exclude_start = 0; h->delayed_ref_updates = 0; if (!current->journal_info) current->journal_info = h; root->fs_info->running_transaction->use_count++; record_root_in_trans(h, root); mutex_unlock(&root->fs_info->trans_mutex); return h; }
static struct btrfs_trans_handle *start_transaction(struct btrfs_root *root, u64 num_items, int type) { struct btrfs_trans_handle *h; struct btrfs_transaction *cur_trans; int retries = 0; int ret; again: h = kmem_cache_alloc(btrfs_trans_handle_cachep, GFP_NOFS); if (!h) return ERR_PTR(-ENOMEM); mutex_lock(&root->fs_info->trans_mutex); if (may_wait_transaction(root, type)) wait_current_trans(root); ret = join_transaction(root); BUG_ON(ret); cur_trans = root->fs_info->running_transaction; cur_trans->use_count++; mutex_unlock(&root->fs_info->trans_mutex); h->transid = cur_trans->transid; h->transaction = cur_trans; h->blocks_used = 0; h->block_group = 0; h->bytes_reserved = 0; h->delayed_ref_updates = 0; h->block_rsv = NULL; smp_mb(); if (cur_trans->blocked && may_wait_transaction(root, type)) { btrfs_commit_transaction(h, root); goto again; } if (num_items > 0) { ret = btrfs_trans_reserve_metadata(h, root, num_items, &retries); if (ret == -EAGAIN) { btrfs_commit_transaction(h, root); goto again; } if (ret < 0) { btrfs_end_transaction(h, root); return ERR_PTR(ret); } } mutex_lock(&root->fs_info->trans_mutex); record_root_in_trans(h, root); mutex_unlock(&root->fs_info->trans_mutex); if (!current->journal_info && type != TRANS_USERSPACE) current->journal_info = h; return h; }
/* * new snapshots need to be created at a very specific time in the * transaction commit. This does the actual creation */ static noinline 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; struct extent_buffer *old; int ret; u64 objectid; new_root_item = kmalloc(sizeof(*new_root_item), GFP_NOFS); if (!new_root_item) { ret = -ENOMEM; goto fail; } ret = btrfs_find_free_objectid(trans, tree_root, 0, &objectid); if (ret) goto fail; record_root_in_trans(trans, root); btrfs_set_root_last_snapshot(&root->root_item, trans->transid); memcpy(new_root_item, &root->root_item, sizeof(*new_root_item)); key.objectid = objectid; /* record when the snapshot was created in key.offset */ key.offset = trans->transid; btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY); old = btrfs_lock_root_node(root); btrfs_cow_block(trans, root, old, NULL, 0, &old); btrfs_set_lock_blocking(old); btrfs_copy_root(trans, root, old, &tmp, objectid); btrfs_tree_unlock(old); free_extent_buffer(old); btrfs_set_root_node(new_root_item, tmp); ret = btrfs_insert_root(trans, root->fs_info->tree_root, &key, new_root_item); btrfs_tree_unlock(tmp); free_extent_buffer(tmp); if (ret) goto fail; key.offset = (u64)-1; memcpy(&pending->root_key, &key, sizeof(key)); fail: kfree(new_root_item); btrfs_unreserve_metadata_space(root, 6); return ret; }
int btrfs_record_root_in_trans(struct btrfs_trans_handle *trans, struct btrfs_root *root) { if (!root->ref_cows) return 0; mutex_lock(&root->fs_info->trans_mutex); if (root->last_trans == trans->transid) { mutex_unlock(&root->fs_info->trans_mutex); return 0; } record_root_in_trans(trans, root); mutex_unlock(&root->fs_info->trans_mutex); return 0; }
static noinline 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 btrfs_root *parent_root; struct inode *parent_inode; struct dentry *dentry; struct extent_buffer *tmp; struct extent_buffer *old; int ret; int retries = 0; u64 to_reserve = 0; u64 index = 0; u64 objectid; new_root_item = kmalloc(sizeof(*new_root_item), GFP_NOFS); if (!new_root_item) { pending->error = -ENOMEM; goto fail; } ret = btrfs_find_free_objectid(trans, tree_root, 0, &objectid); if (ret) { pending->error = ret; goto fail; } btrfs_reloc_pre_snapshot(trans, pending, &to_reserve); btrfs_orphan_pre_snapshot(trans, pending, &to_reserve); if (to_reserve > 0) { ret = btrfs_block_rsv_add(trans, root, &pending->block_rsv, to_reserve, &retries); if (ret) { pending->error = ret; goto fail; } } key.objectid = objectid; key.offset = (u64)-1; key.type = BTRFS_ROOT_ITEM_KEY; trans->block_rsv = &pending->block_rsv; dentry = pending->dentry; parent_inode = dentry->d_parent->d_inode; parent_root = BTRFS_I(parent_inode)->root; record_root_in_trans(trans, parent_root); /* * insert the directory item */ ret = btrfs_set_inode_index(parent_inode, &index); BUG_ON(ret); ret = btrfs_insert_dir_item(trans, parent_root, dentry->d_name.name, dentry->d_name.len, parent_inode->i_ino, &key, BTRFS_FT_DIR, index); BUG_ON(ret); btrfs_i_size_write(parent_inode, parent_inode->i_size + dentry->d_name.len * 2); ret = btrfs_update_inode(trans, parent_root, parent_inode); BUG_ON(ret); record_root_in_trans(trans, root); btrfs_set_root_last_snapshot(&root->root_item, trans->transid); memcpy(new_root_item, &root->root_item, sizeof(*new_root_item)); old = btrfs_lock_root_node(root); btrfs_cow_block(trans, root, old, NULL, 0, &old); btrfs_set_lock_blocking(old); btrfs_copy_root(trans, root, old, &tmp, objectid); btrfs_tree_unlock(old); free_extent_buffer(old); btrfs_set_root_node(new_root_item, tmp); /* record when the snapshot was created in key.offset */ key.offset = trans->transid; ret = btrfs_insert_root(trans, tree_root, &key, new_root_item); btrfs_tree_unlock(tmp); free_extent_buffer(tmp); BUG_ON(ret); /* * insert root back/forward references */ ret = btrfs_add_root_ref(trans, tree_root, objectid, parent_root->root_key.objectid, parent_inode->i_ino, index, dentry->d_name.name, dentry->d_name.len); BUG_ON(ret); key.offset = (u64)-1; pending->snap = btrfs_read_fs_root_no_name(root->fs_info, &key); BUG_ON(IS_ERR(pending->snap)); btrfs_reloc_post_snapshot(trans, pending); btrfs_orphan_post_snapshot(trans, pending); fail: kfree(new_root_item); btrfs_block_rsv_release(root, &pending->block_rsv, (u64)-1); return 0; }