Example #1
0
static int update_cowonly_root(struct btrfs_trans_handle *trans,
                               struct btrfs_root *root)
{
    int ret;
    u64 old_root_bytenr;
    u64 old_root_used;
    struct btrfs_root *tree_root = root->fs_info->tree_root;

    old_root_used = btrfs_root_used(&root->root_item);
    btrfs_write_dirty_block_groups(trans, root);

    while (1) {
        old_root_bytenr = btrfs_root_bytenr(&root->root_item);
        if (old_root_bytenr == root->node->start &&
                old_root_used == btrfs_root_used(&root->root_item))
            break;

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

        old_root_used = btrfs_root_used(&root->root_item);
        ret = btrfs_write_dirty_block_groups(trans, root);
        BUG_ON(ret);
    }

    if (root != root->fs_info->extent_root)
        switch_commit_root(root);

    return 0;
}
Example #2
0
static void print_root(struct extent_buffer *leaf, int slot)
{
	struct btrfs_root_item *ri;
	struct btrfs_root_item root_item;
	int len;
	char uuid_str[BTRFS_UUID_UNPARSED_SIZE];
	char flags_str[32] = {0};
	struct btrfs_key drop_key;

	ri = btrfs_item_ptr(leaf, slot, struct btrfs_root_item);
	len = btrfs_item_size_nr(leaf, slot);

	memset(&root_item, 0, sizeof(root_item));
	read_extent_buffer(leaf, &root_item, (unsigned long)ri, len);
	root_flags_to_str(btrfs_root_flags(&root_item), flags_str);

	printf("\t\tgeneration %llu root_dirid %llu bytenr %llu level %hhu refs %u\n",
		(unsigned long long)btrfs_root_generation(&root_item),
		(unsigned long long)btrfs_root_dirid(&root_item),
		(unsigned long long)btrfs_root_bytenr(&root_item),
		btrfs_root_level(&root_item),
		btrfs_root_refs(&root_item));
	printf("\t\tlastsnap %llu byte_limit %llu bytes_used %llu flags 0x%llx(%s)\n",
		(unsigned long long)btrfs_root_last_snapshot(&root_item),
		(unsigned long long)btrfs_root_limit(&root_item),
		(unsigned long long)btrfs_root_used(&root_item),
		(unsigned long long)btrfs_root_flags(&root_item),
		flags_str);

	if (root_item.generation == root_item.generation_v2) {
		uuid_unparse(root_item.uuid, uuid_str);
		printf("\t\tuuid %s\n", uuid_str);
		if (!empty_uuid(root_item.parent_uuid)) {
			uuid_unparse(root_item.parent_uuid, uuid_str);
			printf("\t\tparent_uuid %s\n", uuid_str);
		}
		if (!empty_uuid(root_item.received_uuid)) {
			uuid_unparse(root_item.received_uuid, uuid_str);
			printf("\t\treceived_uuid %s\n", uuid_str);
		}
		if (root_item.ctransid) {
			printf("\t\tctransid %llu otransid %llu stransid %llu rtransid %llu\n",
				btrfs_root_ctransid(&root_item),
				btrfs_root_otransid(&root_item),
				btrfs_root_stransid(&root_item),
				btrfs_root_rtransid(&root_item));
		}
	}

	btrfs_disk_key_to_cpu(&drop_key, &root_item.drop_progress);
	printf("\t\tdrop ");
	btrfs_print_key(&root_item.drop_progress);
	printf(" level %hhu\n", root_item.drop_level);
}
Example #3
0
static ssize_t root_blocks_used_show(struct btrfs_root *root, char *buf)
{
	return snprintf(buf, PAGE_SIZE, "%llu\n",
		(unsigned long long)btrfs_root_used(&root->root_item));
}
Example #4
0
/*
 * Given a list of roots that need to be deleted, call btrfs_drop_snapshot on
 * all of them
 */
static noinline int drop_dirty_roots(struct btrfs_root *tree_root,
                                     struct list_head *list)
{
    struct btrfs_dirty_root *dirty;
    struct btrfs_trans_handle *trans;
    unsigned long nr;
    u64 num_bytes;
    u64 bytes_used;
    u64 max_useless;
    int ret = 0;
    int err;

    while (!list_empty(list)) {
        struct btrfs_root *root;

        dirty = list_entry(list->prev, struct btrfs_dirty_root, list);
        list_del_init(&dirty->list);

        num_bytes = btrfs_root_used(&dirty->root->root_item);
        root = dirty->latest_root;
        atomic_inc(&root->fs_info->throttles);

        while (1) {
            /*
             * we don't want to jump in and create a bunch of
             * delayed refs if the transaction is starting to close
             */
            wait_transaction_pre_flush(tree_root->fs_info);
            trans = btrfs_start_transaction(tree_root, 1);

            /*
             * we've joined a transaction, make sure it isn't
             * closing right now
             */
            if (trans->transaction->delayed_refs.flushing) {
                btrfs_end_transaction(trans, tree_root);
                continue;
            }

            mutex_lock(&root->fs_info->drop_mutex);
            ret = btrfs_drop_snapshot(trans, dirty->root);
            if (ret != -EAGAIN)
                break;
            mutex_unlock(&root->fs_info->drop_mutex);

            err = btrfs_update_root(trans,
                                    tree_root,
                                    &dirty->root->root_key,
                                    &dirty->root->root_item);
            if (err)
                ret = err;
            nr = trans->blocks_used;
            ret = btrfs_end_transaction(trans, tree_root);
            BUG_ON(ret);

            btrfs_btree_balance_dirty(tree_root, nr);
            cond_resched();
        }
        BUG_ON(ret);
        atomic_dec(&root->fs_info->throttles);
        wake_up(&root->fs_info->transaction_throttle);

        num_bytes -= btrfs_root_used(&dirty->root->root_item);
        bytes_used = btrfs_root_used(&root->root_item);
        if (num_bytes) {
            mutex_lock(&root->fs_info->trans_mutex);
            btrfs_record_root_in_trans(root);
            mutex_unlock(&root->fs_info->trans_mutex);
            btrfs_set_root_used(&root->root_item,
                                bytes_used - num_bytes);
        }

        ret = btrfs_del_root(trans, tree_root, &dirty->root->root_key);
        if (ret) {
            BUG();
            break;
        }
        mutex_unlock(&root->fs_info->drop_mutex);

        spin_lock(&root->list_lock);
        list_del_init(&dirty->root->dead_list);
        if (!list_empty(&root->dead_list)) {
            struct btrfs_root *oldest;
            oldest = list_entry(root->dead_list.prev,
                                struct btrfs_root, dead_list);
            max_useless = oldest->root_key.offset - 1;
        } else {
            max_useless = root->root_key.offset - 1;
        }
        spin_unlock(&root->list_lock);

        nr = trans->blocks_used;
        ret = btrfs_end_transaction(trans, tree_root);
        BUG_ON(ret);

        ret = btrfs_remove_leaf_refs(root, max_useless, 0);
        BUG_ON(ret);

        free_extent_buffer(dirty->root->node);
        kfree(dirty->root);
        kfree(dirty);

        btrfs_btree_balance_dirty(tree_root, nr);
        cond_resched();
    }