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;
}
Beispiel #2
0
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;
}
Beispiel #5
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;
}