Exemple #1
0
/*
 * this is used to update the root pointer in the tree of tree roots.
 *
 * But, in the case of the extent allocation tree, updating the root
 * pointer may allocate blocks which may change the root of the extent
 * allocation tree.
 *
 * So, this loops and repeats and makes sure the cowonly root didn't
 * change while the root pointer was being updated in the metadata.
 */
static int update_cowonly_root(struct btrfs_trans_handle *trans,
                               struct btrfs_root *root)
{
    int ret;
    u64 old_root_bytenr;
    struct btrfs_root *tree_root = root->fs_info->tree_root;

    btrfs_write_dirty_block_groups(trans, root);

    ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1);
    BUG_ON(ret);

    while (1) {
        old_root_bytenr = btrfs_root_bytenr(&root->root_item);
        if (old_root_bytenr == root->node->start)
            break;
        btrfs_set_root_bytenr(&root->root_item,
                              root->node->start);
        btrfs_set_root_level(&root->root_item,
                             btrfs_header_level(root->node));
        btrfs_set_root_generation(&root->root_item, trans->transid);

        ret = btrfs_update_root(trans, tree_root,
                                &root->root_key,
                                &root->root_item);
        BUG_ON(ret);
        btrfs_write_dirty_block_groups(trans, root);

        ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1);
        BUG_ON(ret);
    }
    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;
}
Exemple #3
0
static int __btrfs_end_transaction(struct btrfs_trans_handle *trans,
                                   struct btrfs_root *root, int throttle)
{
    struct btrfs_transaction *cur_trans = trans->transaction;
    struct btrfs_fs_info *info = root->fs_info;
    int count = 0;

    while (count < 4) {
        unsigned long cur = trans->delayed_ref_updates;
        trans->delayed_ref_updates = 0;
        if (cur &&
                trans->transaction->delayed_refs.num_heads_ready > 64) {
            trans->delayed_ref_updates = 0;

            /*
             * do a full flush if the transaction is trying
             * to close
             */
            if (trans->transaction->delayed_refs.flushing)
                cur = 0;
            btrfs_run_delayed_refs(trans, root, cur);
        } else {
            break;
        }
        count++;
    }

    btrfs_trans_release_metadata(trans, root);

    if (!root->fs_info->open_ioctl_trans &&
            should_end_transaction(trans, root))
        trans->transaction->blocked = 1;

    if (cur_trans->blocked && !cur_trans->in_commit) {
        if (throttle)
            return btrfs_commit_transaction(trans, root);
        else
            wake_up_process(info->transaction_kthread);
    }

    mutex_lock(&info->trans_mutex);
    WARN_ON(cur_trans != info->running_transaction);
    WARN_ON(cur_trans->num_writers < 1);
    cur_trans->num_writers--;

    if (waitqueue_active(&cur_trans->writer_wait))
        wake_up(&cur_trans->writer_wait);
    put_transaction(cur_trans);
    mutex_unlock(&info->trans_mutex);

    if (current->journal_info == trans)
        current->journal_info = NULL;
    memset(trans, 0, sizeof(*trans));
    kmem_cache_free(btrfs_trans_handle_cachep, trans);

    if (throttle)
        btrfs_run_delayed_iputs(root);

    return 0;
}
Exemple #4
0
int btrfs_should_end_transaction(struct btrfs_trans_handle *trans,
                                 struct btrfs_root *root)
{
    struct btrfs_transaction *cur_trans = trans->transaction;
    int updates;

    if (cur_trans->blocked || cur_trans->delayed_refs.flushing)
        return 1;

    updates = trans->delayed_ref_updates;
    trans->delayed_ref_updates = 0;
    if (updates)
        btrfs_run_delayed_refs(trans, root, updates);

    return should_end_transaction(trans, root);
}
static int __btrfs_end_transaction(struct btrfs_trans_handle *trans,
			  struct btrfs_root *root, int throttle)
{
	struct btrfs_transaction *cur_trans;
	struct btrfs_fs_info *info = root->fs_info;
	int count = 0;

	while (count < 4) {
		unsigned long cur = trans->delayed_ref_updates;
		trans->delayed_ref_updates = 0;
		if (cur &&
		    trans->transaction->delayed_refs.num_heads_ready > 64) {
			trans->delayed_ref_updates = 0;

			/*
			 * do a full flush if the transaction is trying
			 * to close
			 */
			if (trans->transaction->delayed_refs.flushing)
				cur = 0;
			btrfs_run_delayed_refs(trans, root, cur);
		} else {
			break;
		}
		count++;
	}

	mutex_lock(&info->trans_mutex);
	cur_trans = info->running_transaction;
	WARN_ON(cur_trans != trans->transaction);
	WARN_ON(cur_trans->num_writers < 1);
	cur_trans->num_writers--;

	if (waitqueue_active(&cur_trans->writer_wait))
		wake_up(&cur_trans->writer_wait);
	put_transaction(cur_trans);
	mutex_unlock(&info->trans_mutex);

	if (current->journal_info == trans)
		current->journal_info = NULL;
	memset(trans, 0, sizeof(*trans));
	kmem_cache_free(btrfs_trans_handle_cachep, trans);

	return 0;
}
Exemple #6
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;
}
Exemple #7
0
int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
			     struct btrfs_root *root)
{
	u64 transid = trans->transid;
	int ret = 0;
	struct btrfs_fs_info *fs_info = root->fs_info;

	if (trans->fs_info->transaction_aborted)
		return -EROFS;
	/*
	 * Flush all accumulated delayed refs so that root-tree updates are
	 * consistent
	 */
	ret = btrfs_run_delayed_refs(trans, -1);
	if (ret < 0)
		goto error;

	if (root->commit_root == root->node)
		goto commit_tree;
	if (root == root->fs_info->tree_root)
		goto commit_tree;
	if (root == root->fs_info->chunk_root)
		goto commit_tree;

	free_extent_buffer(root->commit_root);
	root->commit_root = NULL;

	btrfs_set_root_bytenr(&root->root_item, root->node->start);
	btrfs_set_root_generation(&root->root_item, trans->transid);
	root->root_item.level = btrfs_header_level(root->node);
	ret = btrfs_update_root(trans, root->fs_info->tree_root,
				&root->root_key, &root->root_item);
	if (ret < 0)
		goto error;

commit_tree:
	ret = commit_tree_roots(trans, fs_info);
	if (ret < 0)
		goto error;
	/*
	 * Ensure that all committed roots are properly accounted in the
	 * extent tree
	 */
	ret = btrfs_run_delayed_refs(trans, -1);
	if (ret < 0)
		goto error;
	btrfs_write_dirty_block_groups(trans);
	__commit_transaction(trans, root);
	if (ret < 0)
		goto error;
	ret = write_ctree_super(trans);
	btrfs_finish_extent_commit(trans);
	kfree(trans);
	free_extent_buffer(root->commit_root);
	root->commit_root = NULL;
	fs_info->running_transaction = NULL;
	fs_info->last_trans_committed = transid;
	return ret;
error:
	btrfs_destroy_delayed_refs(trans);
	free(trans);
	return ret;
}