Esempio n. 1
0
void btrfs_print_tree(struct btrfs_root *root, struct extent_buffer *eb, int follow)
{
	int i;
	u32 nr;
	u32 size;
	struct btrfs_disk_key disk_key;
	struct btrfs_key key;

	if (!eb)
		return;
	nr = btrfs_header_nritems(eb);
	if (btrfs_is_leaf(eb)) {
		btrfs_print_leaf(root, eb);
		return;
	}
	printf("node %llu level %d items %d free %u generation %llu owner %llu\n",
	       (unsigned long long)eb->start,
	        btrfs_header_level(eb), nr,
		(u32)BTRFS_NODEPTRS_PER_BLOCK(root) - nr,
		(unsigned long long)btrfs_header_generation(eb),
		(unsigned long long)btrfs_header_owner(eb));
	print_uuids(eb);
	fflush(stdout);
	size = btrfs_level_size(root, btrfs_header_level(eb) - 1);
	for (i = 0; i < nr; i++) {
		u64 blocknr = btrfs_node_blockptr(eb, i);
		btrfs_node_key(eb, &disk_key, i);
		btrfs_disk_key_to_cpu(&key, &disk_key);
		printf("\t");
		btrfs_print_key(&disk_key);
		printf(" block %llu (%llu) gen %llu\n",
		       (unsigned long long)blocknr,
		       (unsigned long long)blocknr / size,
		       (unsigned long long)btrfs_node_ptr_generation(eb, i));
		fflush(stdout);
	}
	if (!follow)
		return;

	for (i = 0; i < nr; i++) {
		struct extent_buffer *next = read_tree_block(root,
					     btrfs_node_blockptr(eb, i),
					     size,
					     btrfs_node_ptr_generation(eb, i));
		if (!next) {
			fprintf(stderr, "failed to read %llu in tree %llu\n",
				(unsigned long long)btrfs_node_blockptr(eb, i),
				(unsigned long long)btrfs_header_owner(eb));
			continue;
		}
		if (btrfs_is_leaf(next) &&
		    btrfs_header_level(eb) != 1)
			BUG();
		if (btrfs_header_level(next) !=
			btrfs_header_level(eb) - 1)
			BUG();
		btrfs_print_tree(root, next, 1);
		free_extent_buffer(next);
	}
}
Esempio n. 2
0
static void print_extents(struct btrfs_root *root, struct extent_buffer *eb)
{
    int i;
    u32 nr;
    u32 size;

    if (!eb)
        return;

    if (btrfs_is_leaf(eb)) {
        btrfs_print_leaf(root, eb);
        return;
    }

    size = btrfs_level_size(root, btrfs_header_level(eb) - 1);
    nr = btrfs_header_nritems(eb);
    for (i = 0; i < nr; i++) {
        struct extent_buffer *next = read_tree_block(root,
                                     btrfs_node_blockptr(eb, i),
                                     size,
                                     btrfs_node_ptr_generation(eb, i));
        if (!extent_buffer_uptodate(next))
            continue;
        if (btrfs_is_leaf(next) &&
                btrfs_header_level(eb) != 1)
            BUG();
        if (btrfs_header_level(next) !=
                btrfs_header_level(eb) - 1)
            BUG();
        print_extents(root, next);
        free_extent_buffer(next);
    }
}
Esempio n. 3
0
static int create_data_reloc_tree(struct btrfs_trans_handle *trans,
				  struct btrfs_root *root)
{
	struct btrfs_key location;
	struct btrfs_root_item root_item;
	struct extent_buffer *tmp;
	u64 objectid = BTRFS_DATA_RELOC_TREE_OBJECTID;
	int ret;

	ret = btrfs_copy_root(trans, root, root->node, &tmp, objectid);
	BUG_ON(ret);

	memcpy(&root_item, &root->root_item, sizeof(root_item));
	btrfs_set_root_bytenr(&root_item, tmp->start);
	btrfs_set_root_level(&root_item, btrfs_header_level(tmp));
	btrfs_set_root_generation(&root_item, trans->transid);
	free_extent_buffer(tmp);

	location.objectid = objectid;
	location.type = BTRFS_ROOT_ITEM_KEY;
	location.offset = 0;
	ret = btrfs_insert_root(trans, root->fs_info->tree_root,
				&location, &root_item);
	BUG_ON(ret);
	return 0;
}
Esempio n. 4
0
/*
 * read tree blocks and add keys where required.
 */
static int __add_missing_keys(struct btrfs_fs_info *fs_info,
			      struct list_head *head)
{
	struct list_head *pos;
	struct extent_buffer *eb;

	list_for_each(pos, head) {
		struct __prelim_ref *ref;
		ref = list_entry(pos, struct __prelim_ref, list);

		if (ref->parent)
			continue;
		if (ref->key_for_search.type)
			continue;
		BUG_ON(!ref->wanted_disk_byte);
		eb = read_tree_block(fs_info->tree_root, ref->wanted_disk_byte,
				     fs_info->tree_root->leafsize, 0);
		if (!eb || !extent_buffer_uptodate(eb)) {
			free_extent_buffer(eb);
			return -EIO;
		}
		btrfs_tree_read_lock(eb);
		if (btrfs_header_level(eb) == 0)
			btrfs_item_key_to_cpu(eb, &ref->key_for_search, 0);
		else
			btrfs_node_key_to_cpu(eb, &ref->key_for_search, 0);
		btrfs_tree_read_unlock(eb);
		free_extent_buffer(eb);
	}
	return 0;
}
Esempio n. 5
0
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);
	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_generation(&root->root_item,
					  trans->transid);
		root->root_item.level = btrfs_header_level(root->node);
		ret = btrfs_update_root(trans, tree_root,
					&root->root_key,
					&root->root_item);
		BUG_ON(ret);
		btrfs_write_dirty_block_groups(trans, root);
	}
	return 0;
}
Esempio n. 6
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 (root->commit_root == root->node)
		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);
	BUG_ON(ret);
commit_tree:
	ret = commit_tree_roots(trans, fs_info);
	BUG_ON(ret);
	ret = __commit_transaction(trans, root);
	BUG_ON(ret);
	write_ctree_super(trans, root);
	btrfs_finish_extent_commit(trans, fs_info->extent_root,
			           &fs_info->pinned_extents);
	btrfs_free_transaction(root, trans);
	free_extent_buffer(root->commit_root);
	root->commit_root = NULL;
	fs_info->running_transaction = NULL;
	fs_info->last_trans_committed = transid;
	return 0;
}
Esempio n. 7
0
void btrfs_set_root_node(struct btrfs_root_item *item,
			 struct extent_buffer *node)
{
	btrfs_set_root_bytenr(item, node->start);
	btrfs_set_root_level(item, btrfs_header_level(node));
	btrfs_set_root_generation(item, btrfs_header_generation(node));
}
Esempio n. 8
0
void btrfs_print_tree(struct btrfs_fs_info *fs_info, struct extent_buffer *c)
{
	int i; u32 nr;
	struct btrfs_key key;
	int level;

	if (!c)
		return;
	nr = btrfs_header_nritems(c);
	level = btrfs_header_level(c);
	if (level == 0) {
		btrfs_print_leaf(fs_info, c);
		return;
	}
	btrfs_info(fs_info,
		   "node %llu level %d total ptrs %d free spc %u",
		   btrfs_header_bytenr(c), level, nr,
		   (u32)BTRFS_NODEPTRS_PER_BLOCK(fs_info) - nr);
	for (i = 0; i < nr; i++) {
		btrfs_node_key_to_cpu(c, &key, i);
		pr_info("\tkey %d (%llu %u %llu) block %llu\n",
		       i, key.objectid, key.type, key.offset,
		       btrfs_node_blockptr(c, i));
	}
	for (i = 0; i < nr; i++) {
		struct extent_buffer *next = read_tree_block(fs_info,
					btrfs_node_blockptr(c, i),
					btrfs_node_ptr_generation(c, i));
		if (IS_ERR(next)) {
			continue;
		} else if (!extent_buffer_uptodate(next)) {
			free_extent_buffer(next);
			continue;
		}

		if (btrfs_is_leaf(next) &&
		   level != 1)
			BUG();
		if (btrfs_header_level(next) !=
		       level - 1)
			BUG();
		btrfs_print_tree(fs_info, next);
		free_extent_buffer(next);
	}
}
Esempio n. 9
0
void btrfs_print_tree(struct btrfs_root *root, struct btrfs_buffer *t)
{
	unsigned int i;
	u32 nr;
	struct btrfs_node *c;

	if (!t)
		return;
	c = &t->node;
	nr = btrfs_header_nritems(&c->header);
	if (btrfs_is_leaf(c)) {
		btrfs_print_leaf(root, (struct btrfs_leaf *)c);
		return;
	}
	printf("node %llu level %d ptrs %d free %u generation %llu owner %llu\n",
	       (u64)t->blocknr,
	        btrfs_header_level(&c->header), nr,
		(u32)BTRFS_NODEPTRS_PER_BLOCK(root) - nr,
		(u64)btrfs_header_generation(&c->header),
		(u64)btrfs_header_owner(&c->header));
	fflush(stdout);
	for (i = 0; i < nr; i++) {
		printf("\tkey %d (%llu %x %llu) block %llu\n",
		       i,
		       (u64)c->ptrs[i].key.objectid,
		       c->ptrs[i].key.flags,
		       (u64)c->ptrs[i].key.offset,
		       (u64)btrfs_node_blockptr(c, i));
		fflush(stdout);
	}
	for (i = 0; i < nr; i++) {
		struct btrfs_buffer *next_buf = read_tree_block(root,
						btrfs_node_blockptr(c, i));
		struct btrfs_node *next = &next_buf->node;
		if (btrfs_is_leaf(next) &&
		    btrfs_header_level(&c->header) != 1)
			BUG();
		if (btrfs_header_level(&next->header) !=
			btrfs_header_level(&c->header) - 1)
			BUG();
		btrfs_print_tree(root, next_buf);
		btrfs_block_release(root, next_buf);
	}
}
Esempio n. 10
0
void btrfs_print_tree(struct btrfs_root *root, struct extent_buffer *c)
{
	int i; u32 nr;
	struct btrfs_key key;
	int level;

	if (!c)
		return;
	nr = btrfs_header_nritems(c);
	level = btrfs_header_level(c);
	if (level == 0) {
		btrfs_print_leaf(root, c);
		return;
	}
	printk(KERN_INFO "node %llu level %d total ptrs %d free spc %u\n",
	       (unsigned long long)btrfs_header_bytenr(c),
	      level, nr,
	       (u32)BTRFS_NODEPTRS_PER_BLOCK(root) - nr);
	for (i = 0; i < nr; i++) {
		btrfs_node_key_to_cpu(c, &key, i);
		printk(KERN_INFO "\tkey %d (%llu %u %llu) block %llu\n",
		       i,
		       (unsigned long long)key.objectid,
		       key.type,
		       (unsigned long long)key.offset,
		       (unsigned long long)btrfs_node_blockptr(c, i));
	}
	for (i = 0; i < nr; i++) {
		struct extent_buffer *next = read_tree_block(root,
					btrfs_node_blockptr(c, i),
					btrfs_level_size(root, level - 1),
					btrfs_node_ptr_generation(c, i));
		if (btrfs_is_leaf(next) &&
		   level != 1)
			BUG();
		if (btrfs_header_level(next) !=
		       level - 1)
			BUG();
		btrfs_print_tree(root, next);
		free_extent_buffer(next);
	}
}
Esempio n. 11
0
/*
 * helper function for drop_snapshot, this walks down the tree dropping ref
 * counts as it goes.
 */
static int walk_down_tree(struct btrfs_trans_handle *trans, struct btrfs_root
			  *root, struct btrfs_path *path, int *level)
{
	struct btrfs_buffer *next;
	struct btrfs_buffer *cur;
	u64 blocknr;
	int ret;
	u32 refs;

	ret = lookup_block_ref(trans, root, path->nodes[*level]->blocknr,
			       &refs);
	BUG_ON(ret);
	if (refs > 1)
		goto out;
	/*
	 * walk down to the last node level and free all the leaves
	 */
	while(*level > 0) {
		cur = path->nodes[*level];
		if (path->slots[*level] >=
		    btrfs_header_nritems(&cur->node.header))
			break;
		blocknr = btrfs_node_blockptr(&cur->node, path->slots[*level]);
		ret = lookup_block_ref(trans, root, blocknr, &refs);
		if (refs != 1 || *level == 1) {
			path->slots[*level]++;
			ret = btrfs_free_extent(trans, root, blocknr, 1, 1);
			BUG_ON(ret);
			continue;
		}
		BUG_ON(ret);
		next = read_tree_block(root, blocknr);
		if (path->nodes[*level-1])
			btrfs_block_release(root, path->nodes[*level-1]);
		path->nodes[*level-1] = next;
		*level = btrfs_header_level(&next->node.header);
		path->slots[*level] = 0;
	}
out:
	ret = btrfs_free_extent(trans, root, path->nodes[*level]->blocknr, 1,
				1);
	btrfs_block_release(root, path->nodes[*level]);
	path->nodes[*level] = NULL;
	*level += 1;
	BUG_ON(ret);
	return 0;
}
Esempio n. 12
0
/*
 * drop the reference count on the tree rooted at 'snap'.  This traverses
 * the tree freeing any blocks that have a ref count of zero after being
 * decremented.
 */
int btrfs_drop_snapshot(struct btrfs_trans_handle *trans, struct btrfs_root
			*root, struct btrfs_buffer *snap)
{
	int ret = 0;
	int wret;
	int level;
	struct btrfs_path path;
	int i;
	int orig_level;

	btrfs_init_path(&path);

	level = btrfs_header_level(&snap->node.header);
	orig_level = level;
	path.nodes[level] = snap;
	path.slots[level] = 0;
	while(1) {
		wret = walk_down_tree(trans, root, &path, &level);
		if (wret > 0)
			break;
		if (wret < 0)
			ret = wret;

		wret = walk_up_tree(trans, root, &path, &level);
		if (wret > 0)
			break;
		if (wret < 0)
			ret = wret;
	}
	for (i = 0; i <= orig_level; i++) {
		if (path.nodes[i]) {
			btrfs_block_release(root, path.nodes[i]);
		}
	}
	return ret;
}
Esempio n. 13
0
/*
 * at transaction commit time we need to schedule the old roots for
 * deletion via btrfs_drop_snapshot.  This runs through all the
 * reference counted roots that were modified in the current
 * transaction and puts them into the drop list
 */
static noinline int add_dirty_roots(struct btrfs_trans_handle *trans,
                                    struct radix_tree_root *radix,
                                    struct list_head *list)
{
    struct btrfs_dirty_root *dirty;
    struct btrfs_root *gang[8];
    struct btrfs_root *root;
    int i;
    int ret;
    int err = 0;
    u32 refs;

    while (1) {
        ret = radix_tree_gang_lookup_tag(radix, (void **)gang, 0,
                                         ARRAY_SIZE(gang),
                                         BTRFS_ROOT_TRANS_TAG);
        if (ret == 0)
            break;
        for (i = 0; i < ret; i++) {
            root = gang[i];
            radix_tree_tag_clear(radix,
                                 (unsigned long)root->root_key.objectid,
                                 BTRFS_ROOT_TRANS_TAG);

            BUG_ON(!root->ref_tree);
            dirty = root->dirty_root;

            btrfs_free_log(trans, root);
            btrfs_free_reloc_root(trans, root);

            if (root->commit_root == root->node) {
                WARN_ON(root->node->start !=
                        btrfs_root_bytenr(&root->root_item));

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

                spin_lock(&root->list_lock);
                list_del_init(&dirty->root->dead_list);
                spin_unlock(&root->list_lock);

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

                /* make sure to update the root on disk
                 * so we get any updates to the block used
                 * counts
                 */
                err = btrfs_update_root(trans,
                                        root->fs_info->tree_root,
                                        &root->root_key,
                                        &root->root_item);
                continue;
            }

            memset(&root->root_item.drop_progress, 0,
                   sizeof(struct btrfs_disk_key));
            root->root_item.drop_level = 0;
            root->commit_root = NULL;
            root->dirty_root = NULL;
            root->root_key.offset = root->fs_info->generation;
            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,
                                      root->root_key.offset);

            err = btrfs_insert_root(trans, root->fs_info->tree_root,
                                    &root->root_key,
                                    &root->root_item);
            if (err)
                break;

            refs = btrfs_root_refs(&dirty->root->root_item);
            btrfs_set_root_refs(&dirty->root->root_item, refs - 1);
            err = btrfs_update_root(trans, root->fs_info->tree_root,
                                    &dirty->root->root_key,
                                    &dirty->root->root_item);

            BUG_ON(err);
            if (refs == 1) {
                list_add(&dirty->list, list);
            } else {
                WARN_ON(1);
                free_extent_buffer(dirty->root->node);
                kfree(dirty->root);
                kfree(dirty);
            }
        }
    }
    return err;
}
Esempio n. 14
0
/*
 * walks the btree of allocated extents and find a hole of a given size.
 * The key ins is changed to record the hole:
 * ins->objectid == block start
 * ins->flags = BTRFS_EXTENT_ITEM_KEY
 * ins->offset == number of blocks
 * Any available blocks before search_start are skipped.
 */
static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
			    *orig_root, u64 num_blocks, u64 search_start, u64
			    search_end, struct btrfs_key *ins)
{
	struct btrfs_path path;
	struct btrfs_key key;
	int ret;
	u64 hole_size = 0;
	int slot = 0;
	u64 last_block = 0;
	u64 test_block;
	int start_found;
	struct btrfs_leaf *l;
	struct btrfs_root * root = orig_root->fs_info->extent_root;
	unsigned int total_needed = num_blocks;

	total_needed += (btrfs_header_level(&root->node->node.header) + 1) * 3;
	if (root->fs_info->last_insert.objectid > search_start)
		search_start = root->fs_info->last_insert.objectid;

	ins->flags = 0;
	btrfs_set_key_type(ins, BTRFS_EXTENT_ITEM_KEY);

check_failed:
	btrfs_init_path(&path);
	ins->objectid = search_start;
	ins->offset = 0;
	start_found = 0;
	ret = btrfs_search_slot(trans, root, ins, &path, 0, 0);
	if (ret < 0)
		goto error;

	if (path.slots[0] > 0)
		path.slots[0]--;

	while (1) {
		l = &path.nodes[0]->leaf;
		slot = path.slots[0];
		if (slot >= btrfs_header_nritems(&l->header)) {
			ret = btrfs_next_leaf(root, &path);
			if (ret == 0)
				continue;
			if (ret < 0)
				goto error;
			if (!start_found) {
				ins->objectid = search_start;
				ins->offset = (u64)-1 - search_start;
				start_found = 1;
				goto check_pending;
			}
			ins->objectid = last_block > search_start ?
					last_block : search_start;
			ins->offset = (u64)-1 - ins->objectid;
			goto check_pending;
		}
		btrfs_disk_key_to_cpu(&key, &l->items[slot].key);
		if (btrfs_key_type(&key) != BTRFS_EXTENT_ITEM_KEY)
			goto next;
		if (key.objectid >= search_start) {
			if (start_found) {
				if (last_block < search_start)
					last_block = search_start;
				hole_size = key.objectid - last_block;
				if (hole_size > total_needed) {
					ins->objectid = last_block;
					ins->offset = hole_size;
					goto check_pending;
				}
			}
		}
		start_found = 1;
		last_block = key.objectid + key.offset;
next:
		path.slots[0]++;
	}
	// FIXME -ENOSPC
check_pending:
	/* we have to make sure we didn't find an extent that has already
	 * been allocated by the map tree or the original allocation
	 */
	btrfs_release_path(root, &path);
	BUG_ON(ins->objectid < search_start);
	for (test_block = ins->objectid;
	     test_block < ins->objectid + total_needed; test_block++) {
		if (radix_tree_lookup(&root->fs_info->pinned_radix,
				      test_block)) {
			search_start = test_block + 1;
			goto check_failed;
		}
	}
	BUG_ON(root->fs_info->current_insert.offset);
	root->fs_info->current_insert.offset = total_needed - num_blocks;
	root->fs_info->current_insert.objectid = ins->objectid + num_blocks;
	root->fs_info->current_insert.flags = 0;
	root->fs_info->last_insert.objectid = ins->objectid;
	ins->offset = num_blocks;
	return 0;
error:
	btrfs_release_path(root, &path);
	return ret;
}
Esempio n. 15
0
int btrfs_defrag_leaves(struct btrfs_trans_handle *trans,
			struct btrfs_root *root, int cache_only)
{
	struct btrfs_path *path = NULL;
	struct btrfs_key key;
	int ret = 0;
	int wret;
	int level;
	int is_extent = 0;
	int next_key_ret = 0;
	u64 last_ret = 0;
	u64 min_trans = 0;

	if (cache_only)
		goto out;

	if (root->fs_info->extent_root == root) {
		/*
		 * there's recursion here right now in the tree locking,
		 * we can't defrag the extent root without deadlock
		 */
		goto out;
	}

	if (root->ref_cows == 0 && !is_extent)
		goto out;

	if (btrfs_test_opt(root, SSD))
		goto out;

	path = btrfs_alloc_path();
	if (!path)
		return -ENOMEM;

	level = btrfs_header_level(root->node);

	if (level == 0)
		goto out;

	if (root->defrag_progress.objectid == 0) {
		struct extent_buffer *root_node;
		u32 nritems;

		root_node = btrfs_lock_root_node(root);
		btrfs_set_lock_blocking(root_node);
		nritems = btrfs_header_nritems(root_node);
		root->defrag_max.objectid = 0;
		/* from above we know this is not a leaf */
		btrfs_node_key_to_cpu(root_node, &root->defrag_max,
				      nritems - 1);
		btrfs_tree_unlock(root_node);
		free_extent_buffer(root_node);
		memset(&key, 0, sizeof(key));
	} else {
		memcpy(&key, &root->defrag_progress, sizeof(key));
	}

	path->keep_locks = 1;
	if (cache_only)
		min_trans = root->defrag_trans_start;

	ret = btrfs_search_forward(root, &key, NULL, path,
				   cache_only, min_trans);
	if (ret < 0)
		goto out;
	if (ret > 0) {
		ret = 0;
		goto out;
	}
	btrfs_release_path(path);
	wret = btrfs_search_slot(trans, root, &key, path, 0, 1);

	if (wret < 0) {
		ret = wret;
		goto out;
	}
	if (!path->nodes[1]) {
		ret = 0;
		goto out;
	}
	path->slots[1] = btrfs_header_nritems(path->nodes[1]);
	next_key_ret = btrfs_find_next_key(root, path, &key, 1, cache_only,
					   min_trans);
	ret = btrfs_realloc_node(trans, root,
				 path->nodes[1], 0,
				 cache_only, &last_ret,
				 &root->defrag_progress);
	if (ret) {
		WARN_ON(ret == -EAGAIN);
		goto out;
	}
	if (next_key_ret == 0) {
		memcpy(&root->defrag_progress, &key, sizeof(key));
		ret = -EAGAIN;
	}
out:
	if (path)
		btrfs_free_path(path);
	if (ret == -EAGAIN) {
		if (root->defrag_max.objectid > root->defrag_progress.objectid)
			goto done;
		if (root->defrag_max.type > root->defrag_progress.type)
			goto done;
		if (root->defrag_max.offset > root->defrag_progress.offset)
			goto done;
		ret = 0;
	}
done:
	if (ret != -EAGAIN) {
		memset(&root->defrag_progress, 0,
		       sizeof(root->defrag_progress));
		root->defrag_trans_start = trans->transid;
	}
	return ret;
}
Esempio n. 16
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;
}
Esempio n. 17
0
int main(int ac, char **av) {
	struct btrfs_key ins;
	struct btrfs_key last = { (u64)-1, 0, 0};
	char *buf;
	int i;
	int num;
	int ret;
	int run_size = 300000;
	int max_key =  100000000;
	int tree_size = 2;
	struct btrfs_path path;
	struct btrfs_root *root;
	struct btrfs_trans_handle *trans;

	buf = malloc(512);
	memset(buf, 0, 512);

	radix_tree_init();

	root = open_ctree(av[1], BTRFS_SUPER_INFO_OFFSET, OPEN_CTREE_WRITES);
	if (!root) {
		fprintf(stderr, "Open ctree failed\n");
		exit(1);
	}
	trans = btrfs_start_transaction(root, 1);
	srand(55);
	btrfs_set_key_type(&ins, BTRFS_STRING_ITEM_KEY);
	for (i = 0; i < run_size; i++) {
		num = next_key(i, max_key);
		// num = i;
		sprintf(buf, "string-%d", num);
		if (i % 10000 == 0)
			fprintf(stderr, "insert %d:%d\n", num, i);
		ins.objectid = num;
		ins.offset = 0;
		ret = btrfs_insert_item(trans, root, &ins, buf, 512);
		if (!ret)
			tree_size++;
		if (i == run_size - 5) {
			btrfs_commit_transaction(trans, root);
			trans = btrfs_start_transaction(root, 1);
		}
	}
	btrfs_commit_transaction(trans, root);
	close_ctree(root);
	exit(1);
	root = open_ctree(av[1], BTRFS_SUPER_INFO_OFFSET, OPEN_CTREE_WRITES);
	if (!root) {
		fprintf(stderr, "Open ctree failed\n");
		exit(1);
	}
	printf("starting search\n");
	srand(55);
	for (i = 0; i < run_size; i++) {
		num = next_key(i, max_key);
		ins.objectid = num;
		btrfs_init_path(&path);
		if (i % 10000 == 0)
			fprintf(stderr, "search %d:%d\n", num, i);
		ret = btrfs_search_slot(NULL, root, &ins, &path, 0, 0);
		if (ret) {
			btrfs_print_tree(root, root->node, 1);
			printf("unable to find %d\n", num);
			exit(1);
		}
		btrfs_release_path(&path);
	}
	close_ctree(root);

	root = open_ctree(av[1], BTRFS_SUPER_INFO_OFFSET, OPEN_CTREE_WRITES);
	if (!root) {
		fprintf(stderr, "Open ctree failed\n");
		exit(1);
	}
	printf("node %p level %d total ptrs %d free spc %lu\n", root->node,
	        btrfs_header_level(root->node),
		btrfs_header_nritems(root->node),
		(unsigned long)BTRFS_NODEPTRS_PER_BLOCK(root) -
		btrfs_header_nritems(root->node));
	printf("all searches good, deleting some items\n");
	i = 0;
	srand(55);
	trans = btrfs_start_transaction(root, 1);
	for (i = 0 ; i < run_size/4; i++) {
		num = next_key(i, max_key);
		ins.objectid = num;
		btrfs_init_path(&path);
		ret = btrfs_search_slot(trans, root, &ins, &path, -1, 1);
		if (!ret) {
			if (i % 10000 == 0)
				fprintf(stderr, "del %d:%d\n", num, i);
			ret = btrfs_del_item(trans, root, &path);
			if (ret != 0)
				BUG();
			tree_size--;
		}
		btrfs_release_path(&path);
	}
	btrfs_commit_transaction(trans, root);
	close_ctree(root);

	root = open_ctree(av[1], BTRFS_SUPER_INFO_OFFSET, OPEN_CTREE_WRITES);
	if (!root) {
		fprintf(stderr, "Open ctree failed\n");
		exit(1);
	}
	trans = btrfs_start_transaction(root, 1);
	srand(128);
	for (i = 0; i < run_size; i++) {
		num = next_key(i, max_key);
		sprintf(buf, "string-%d", num);
		ins.objectid = num;
		if (i % 10000 == 0)
			fprintf(stderr, "insert %d:%d\n", num, i);
		ret = btrfs_insert_item(trans, root, &ins, buf, 512);
		if (!ret)
			tree_size++;
	}
	btrfs_commit_transaction(trans, root);
	close_ctree(root);

	root = open_ctree(av[1], BTRFS_SUPER_INFO_OFFSET, OPEN_CTREE_WRITES);
	if (!root) {
		fprintf(stderr, "Open ctree failed\n");
		exit(1);
	}
	srand(128);
	printf("starting search2\n");
	for (i = 0; i < run_size; i++) {
		num = next_key(i, max_key);
		ins.objectid = num;
		btrfs_init_path(&path);
		if (i % 10000 == 0)
			fprintf(stderr, "search %d:%d\n", num, i);
		ret = btrfs_search_slot(NULL, root, &ins, &path, 0, 0);
		if (ret) {
			btrfs_print_tree(root, root->node, 1);
			printf("unable to find %d\n", num);
			exit(1);
		}
		btrfs_release_path(&path);
	}
	printf("starting big long delete run\n");
	trans = btrfs_start_transaction(root, 1);
	while(root->node && btrfs_header_nritems(root->node) > 0) {
		struct extent_buffer *leaf;
		int slot;
		ins.objectid = (u64)-1;
		btrfs_init_path(&path);
		ret = btrfs_search_slot(trans, root, &ins, &path, -1, 1);
		if (ret == 0)
			BUG();

		leaf = path.nodes[0];
		slot = path.slots[0];
		if (slot != btrfs_header_nritems(leaf))
			BUG();
		while(path.slots[0] > 0) {
			path.slots[0] -= 1;
			slot = path.slots[0];
			leaf = path.nodes[0];

			btrfs_item_key_to_cpu(leaf, &last, slot);

			if (tree_size % 10000 == 0)
				printf("big del %d:%d\n", tree_size, i);
			ret = btrfs_del_item(trans, root, &path);
			if (ret != 0) {
				printf("del_item returned %d\n", ret);
				BUG();
			}
			tree_size--;
		}
		btrfs_release_path(&path);
	}
	/*
	printf("previous tree:\n");
	btrfs_print_tree(root, root->commit_root);
	printf("map before commit\n");
	btrfs_print_tree(root->extent_root, root->extent_root->node);
	*/
	btrfs_commit_transaction(trans, root);
	printf("tree size is now %d\n", tree_size);
	printf("root %p commit root %p\n", root->node, root->commit_root);
	btrfs_print_tree(root, root->node, 1);
	close_ctree(root);
	return 0;
}
Esempio n. 18
0
int main(int ac, char **av)
{
    struct btrfs_root *root;
    struct btrfs_fs_info *info;
    struct btrfs_path path;
    struct btrfs_key key;
    struct btrfs_root_item ri;
    struct extent_buffer *leaf;
    struct btrfs_disk_key disk_key;
    struct btrfs_key found_key;
    char uuidbuf[BTRFS_UUID_UNPARSED_SIZE];
    int ret;
    int slot;
    int extent_only = 0;
    int device_only = 0;
    int uuid_tree_only = 0;
    int roots_only = 0;
    int root_backups = 0;
    u64 block_only = 0;
    struct btrfs_root *tree_root_scan;
    u64 tree_id = 0;

    radix_tree_init();

    while(1) {
        int c;
        static const struct option long_options[] = {
            { "help", no_argument, NULL, GETOPT_VAL_HELP},
            { NULL, 0, NULL, 0 }
        };

        c = getopt_long(ac, av, "deb:rRut:", long_options, NULL);
        if (c < 0)
            break;
        switch(c) {
        case 'e':
            extent_only = 1;
            break;
        case 'd':
            device_only = 1;
            break;
        case 'r':
            roots_only = 1;
            break;
        case 'u':
            uuid_tree_only = 1;
            break;
        case 'R':
            roots_only = 1;
            root_backups = 1;
            break;
        case 'b':
            block_only = arg_strtou64(optarg);
            break;
        case 't':
            tree_id = arg_strtou64(optarg);
            break;
        case GETOPT_VAL_HELP:
        default:
            print_usage(c != GETOPT_VAL_HELP);
        }
    }
    set_argv0(av);
    ac = ac - optind;
    if (check_argc_exact(ac, 1))
        print_usage(1);

    ret = check_arg_type(av[optind]);
    if (ret != BTRFS_ARG_BLKDEV && ret != BTRFS_ARG_REG) {
        fprintf(stderr, "'%s' is not a block device or regular file\n",
                av[optind]);
        exit(1);
    }

    info = open_ctree_fs_info(av[optind], 0, 0, OPEN_CTREE_PARTIAL);
    if (!info) {
        fprintf(stderr, "unable to open %s\n", av[optind]);
        exit(1);
    }

    root = info->fs_root;
    if (!root) {
        fprintf(stderr, "unable to open %s\n", av[optind]);
        exit(1);
    }

    if (block_only) {
        leaf = read_tree_block(root,
                               block_only,
                               root->leafsize, 0);

        if (extent_buffer_uptodate(leaf) &&
                btrfs_header_level(leaf) != 0) {
            free_extent_buffer(leaf);
            leaf = NULL;
        }

        if (!leaf) {
            leaf = read_tree_block(root,
                                   block_only,
                                   root->nodesize, 0);
        }
        if (!extent_buffer_uptodate(leaf)) {
            fprintf(stderr, "failed to read %llu\n",
                    (unsigned long long)block_only);
            goto close_root;
        }
        btrfs_print_tree(root, leaf, 0);
        free_extent_buffer(leaf);
        goto close_root;
    }

    if (!(extent_only || uuid_tree_only || tree_id)) {
        if (roots_only) {
            printf("root tree: %llu level %d\n",
                   (unsigned long long)info->tree_root->node->start,
                   btrfs_header_level(info->tree_root->node));
            printf("chunk tree: %llu level %d\n",
                   (unsigned long long)info->chunk_root->node->start,
                   btrfs_header_level(info->chunk_root->node));
        } else {
            if (info->tree_root->node) {
                printf("root tree\n");
                btrfs_print_tree(info->tree_root,
                                 info->tree_root->node, 1);
            }

            if (info->chunk_root->node) {
                printf("chunk tree\n");
                btrfs_print_tree(info->chunk_root,
                                 info->chunk_root->node, 1);
            }
        }
    }
    tree_root_scan = info->tree_root;

    btrfs_init_path(&path);
again:
    if (!extent_buffer_uptodate(tree_root_scan->node))
        goto no_node;

    /*
     * Tree's that are not pointed by the tree of tree roots
     */
    if (tree_id && tree_id == BTRFS_ROOT_TREE_OBJECTID) {
        if (!info->tree_root->node) {
            error("cannot print root tree, invalid pointer");
            goto no_node;
        }
        printf("root tree\n");
        btrfs_print_tree(info->tree_root, info->tree_root->node, 1);
        goto no_node;
    }

    if (tree_id && tree_id == BTRFS_CHUNK_TREE_OBJECTID) {
        if (!info->chunk_root->node) {
            error("cannot print chunk tree, invalid pointer");
            goto no_node;
        }
        printf("chunk tree\n");
        btrfs_print_tree(info->chunk_root, info->chunk_root->node, 1);
        goto no_node;
    }

    key.offset = 0;
    key.objectid = 0;
    btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY);
    ret = btrfs_search_slot(NULL, tree_root_scan, &key, &path, 0, 0);
    BUG_ON(ret < 0);
    while(1) {
        leaf = path.nodes[0];
        slot = path.slots[0];
        if (slot >= btrfs_header_nritems(leaf)) {
            ret = btrfs_next_leaf(tree_root_scan, &path);
            if (ret != 0)
                break;
            leaf = path.nodes[0];
            slot = path.slots[0];
        }
        btrfs_item_key(leaf, &disk_key, path.slots[0]);
        btrfs_disk_key_to_cpu(&found_key, &disk_key);
        if (btrfs_key_type(&found_key) == BTRFS_ROOT_ITEM_KEY) {
            unsigned long offset;
            struct extent_buffer *buf;
            int skip = extent_only | device_only | uuid_tree_only;

            offset = btrfs_item_ptr_offset(leaf, slot);
            read_extent_buffer(leaf, &ri, offset, sizeof(ri));
            buf = read_tree_block(tree_root_scan,
                                  btrfs_root_bytenr(&ri),
                                  btrfs_level_size(tree_root_scan,
                                                   btrfs_root_level(&ri)),
                                  0);
            if (!extent_buffer_uptodate(buf))
                goto next;
            if (tree_id && found_key.objectid != tree_id) {
                free_extent_buffer(buf);
                goto next;
            }

            switch(found_key.objectid) {
            case BTRFS_ROOT_TREE_OBJECTID:
                if (!skip)
                    printf("root");
                break;
            case BTRFS_EXTENT_TREE_OBJECTID:
                if (!device_only && !uuid_tree_only)
                    skip = 0;
                if (!skip)
                    printf("extent");
                break;
            case BTRFS_CHUNK_TREE_OBJECTID:
                if (!skip) {
                    printf("chunk");
                }
                break;
            case BTRFS_DEV_TREE_OBJECTID:
                if (!uuid_tree_only)
                    skip = 0;
                if (!skip)
                    printf("device");
                break;
            case BTRFS_FS_TREE_OBJECTID:
                if (!skip) {
                    printf("fs");
                }
                break;
            case BTRFS_ROOT_TREE_DIR_OBJECTID:
                skip = 0;
                printf("directory");
                break;
            case BTRFS_CSUM_TREE_OBJECTID:
                if (!skip) {
                    printf("checksum");
                }
                break;
            case BTRFS_ORPHAN_OBJECTID:
                if (!skip) {
                    printf("orphan");
                }
                break;
            case BTRFS_TREE_LOG_OBJECTID:
                if (!skip) {
                    printf("log");
                }
                break;
            case BTRFS_TREE_LOG_FIXUP_OBJECTID:
                if (!skip) {
                    printf("log fixup");
                }
                break;
            case BTRFS_TREE_RELOC_OBJECTID:
                if (!skip) {
                    printf("reloc");
                }
                break;
            case BTRFS_DATA_RELOC_TREE_OBJECTID:
                if (!skip) {
                    printf("data reloc");
                }
                break;
            case BTRFS_EXTENT_CSUM_OBJECTID:
                if (!skip) {
                    printf("extent checksum");
                }
                break;
            case BTRFS_QUOTA_TREE_OBJECTID:
                if (!skip) {
                    printf("quota");
                }
                break;
            case BTRFS_UUID_TREE_OBJECTID:
                if (!extent_only && !device_only)
                    skip = 0;
                if (!skip)
                    printf("uuid");
                break;
            case BTRFS_FREE_SPACE_TREE_OBJECTID:
                if (!skip)
                    printf("free space");
                break;
            case BTRFS_MULTIPLE_OBJECTIDS:
                if (!skip) {
                    printf("multiple");
                }
                break;
            default:
                if (!skip) {
                    printf("file");
                }
            }
            if (extent_only && !skip) {
                print_extents(tree_root_scan, buf);
            } else if (!skip) {
                printf(" tree ");
                btrfs_print_key(&disk_key);
                if (roots_only) {
                    printf(" %llu level %d\n",
                           (unsigned long long)buf->start,
                           btrfs_header_level(buf));
                } else {
                    printf(" \n");
                    btrfs_print_tree(tree_root_scan, buf, 1);
                }
            }
            free_extent_buffer(buf);
        }
next:
        path.slots[0]++;
    }
no_node:
    btrfs_release_path(&path);

    if (tree_root_scan == info->tree_root &&
            info->log_root_tree) {
        tree_root_scan = info->log_root_tree;
        goto again;
    }

    if (extent_only || device_only || uuid_tree_only)
        goto close_root;

    if (root_backups)
        print_old_roots(info->super_copy);

    printf("total bytes %llu\n",
           (unsigned long long)btrfs_super_total_bytes(info->super_copy));
    printf("bytes used %llu\n",
           (unsigned long long)btrfs_super_bytes_used(info->super_copy));
    uuidbuf[BTRFS_UUID_UNPARSED_SIZE - 1] = '\0';
    uuid_unparse(info->super_copy->fsid, uuidbuf);
    printf("uuid %s\n", uuidbuf);
    printf("%s\n", PACKAGE_STRING);
close_root:
    ret = close_ctree(root);
    btrfs_close_all_devices();
    return ret;
}
Esempio n. 19
0
int main(int ac, char **av)
{
	struct btrfs_root *root;
	struct btrfs_fs_info *info;
	struct btrfs_path path;
	struct btrfs_key key;
	struct btrfs_root_item ri;
	struct extent_buffer *leaf;
	struct btrfs_disk_key disk_key;
	struct btrfs_key found_key;
	char uuidbuf[37];
	int ret;
	int slot;
	int extent_only = 0;
	int device_only = 0;
	int roots_only = 0;
	int root_backups = 0;
	u64 block_only = 0;
	struct btrfs_root *tree_root_scan;

	radix_tree_init();

	while(1) {
		int c;
		c = getopt(ac, av, "deb:rR");
		if (c < 0)
			break;
		switch(c) {
			case 'e':
				extent_only = 1;
				break;
			case 'd':
				device_only = 1;
				break;
			case 'r':
				roots_only = 1;
				break;
			case 'R':
				roots_only = 1;
				root_backups = 1;
				break;
			case 'b':
				block_only = atoll(optarg);
				break;
			default:
				print_usage();
		}
	}
	ac = ac - optind;
	if (ac != 1)
		print_usage();

	info = open_ctree_fs_info(av[optind], 0, 0, 1);
	if (!info) {
		fprintf(stderr, "unable to open %s\n", av[optind]);
		exit(1);
	}
	root = info->fs_root;

	if (block_only) {
		if (!root) {
			fprintf(stderr, "unable to open %s\n", av[optind]);
			exit(1);
		}
		leaf = read_tree_block(root,
				      block_only,
				      root->leafsize, 0);

		if (leaf && btrfs_header_level(leaf) != 0) {
			free_extent_buffer(leaf);
			leaf = NULL;
		}

		if (!leaf) {
			leaf = read_tree_block(root,
					      block_only,
					      root->nodesize, 0);
		}
		if (!leaf) {
			fprintf(stderr, "failed to read %llu\n",
				(unsigned long long)block_only);
			return 0;
		}
		btrfs_print_tree(root, leaf, 0);
		return 0;
	}

	if (!extent_only) {
		if (roots_only) {
			printf("root tree: %llu level %d\n",
			     (unsigned long long)info->tree_root->node->start,
			     btrfs_header_level(info->tree_root->node));
			printf("chunk tree: %llu level %d\n",
			     (unsigned long long)info->chunk_root->node->start,
			     btrfs_header_level(info->chunk_root->node));
		} else {
			if (info->tree_root->node) {
				printf("root tree\n");
				btrfs_print_tree(info->tree_root,
						 info->tree_root->node, 1);
			}

			if (info->chunk_root->node) {
				printf("chunk tree\n");
				btrfs_print_tree(info->chunk_root,
						 info->chunk_root->node, 1);
			}
		}
	}
	tree_root_scan = info->tree_root;

	btrfs_init_path(&path);
again:
	if (!extent_buffer_uptodate(tree_root_scan->node))
		goto no_node;

	key.offset = 0;
	key.objectid = 0;
	btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY);
	ret = btrfs_search_slot(NULL, tree_root_scan, &key, &path, 0, 0);
	BUG_ON(ret < 0);
	while(1) {
		leaf = path.nodes[0];
		slot = path.slots[0];
		if (slot >= btrfs_header_nritems(leaf)) {
			ret = btrfs_next_leaf(tree_root_scan, &path);
			if (ret != 0)
				break;
			leaf = path.nodes[0];
			slot = path.slots[0];
		}
		btrfs_item_key(leaf, &disk_key, path.slots[0]);
		btrfs_disk_key_to_cpu(&found_key, &disk_key);
		if (btrfs_key_type(&found_key) == BTRFS_ROOT_ITEM_KEY) {
			unsigned long offset;
			struct extent_buffer *buf;
			int skip = extent_only | device_only;

			offset = btrfs_item_ptr_offset(leaf, slot);
			read_extent_buffer(leaf, &ri, offset, sizeof(ri));
			buf = read_tree_block(tree_root_scan,
					      btrfs_root_bytenr(&ri),
					      btrfs_level_size(tree_root_scan,
							btrfs_root_level(&ri)),
					      0);
			if (!extent_buffer_uptodate(buf))
				goto next;

			switch(found_key.objectid) {
			case BTRFS_ROOT_TREE_OBJECTID:
				if (!skip)
					printf("root");
				break;
			case BTRFS_EXTENT_TREE_OBJECTID:
				if (!device_only)
					skip = 0;
				if (!extent_only && !device_only)
					printf("extent");
				break;
			case BTRFS_CHUNK_TREE_OBJECTID:
				if (!skip) {
					printf("chunk");
				}
				break;
			case BTRFS_DEV_TREE_OBJECTID:
				skip = 0;
				printf("device");
				break;
			case BTRFS_FS_TREE_OBJECTID:
				if (!skip) {
					printf("fs");
				}
				break;
			case BTRFS_ROOT_TREE_DIR_OBJECTID:
				skip = 0;
				printf("directory");
				break;
			case BTRFS_CSUM_TREE_OBJECTID:
				if (!skip) {
					printf("checksum");
				}
				break;
			case BTRFS_ORPHAN_OBJECTID:
				if (!skip) {
					printf("orphan");
				}
				break;
			case BTRFS_TREE_LOG_OBJECTID:
				if (!skip) {
					printf("log");
				}
				break;
			case BTRFS_TREE_LOG_FIXUP_OBJECTID:
				if (!skip) {
					printf("log fixup");
				}
				break;
			case BTRFS_TREE_RELOC_OBJECTID:
				if (!skip) {
					printf("reloc");
				}
				break;
			case BTRFS_DATA_RELOC_TREE_OBJECTID:
				if (!skip) {
					printf("data reloc");
				}
				break;
			case BTRFS_EXTENT_CSUM_OBJECTID:
				if (!skip) {
					printf("extent checksum");
				}
				break;
			case BTRFS_QUOTA_TREE_OBJECTID:
				if (!skip) {
					printf("quota");
				}
				break;
			case BTRFS_MULTIPLE_OBJECTIDS:
				if (!skip) {
					printf("multiple");
				}
				break;
			default:
				if (!skip) {
					printf("file");
				}
			}
			if (extent_only && !skip) {
				print_extents(tree_root_scan, buf);
			} else if (!skip) {
				printf(" tree ");
				btrfs_print_key(&disk_key);
				if (roots_only) {
					printf(" %llu level %d\n",
					       (unsigned long long)buf->start,
					       btrfs_header_level(buf));
				} else {
					printf(" \n");
					btrfs_print_tree(tree_root_scan, buf, 1);
				}
			}
		}
next:
		path.slots[0]++;
	}
no_node:
	btrfs_release_path(root, &path);

	if (tree_root_scan == info->tree_root &&
	    info->log_root_tree) {
		tree_root_scan = info->log_root_tree;
		goto again;
	}

	if (extent_only || device_only)
		return 0;

	if (root_backups)
		print_old_roots(&info->super_copy);

	printf("total bytes %llu\n",
	       (unsigned long long)btrfs_super_total_bytes(&info->super_copy));
	printf("bytes used %llu\n",
	       (unsigned long long)btrfs_super_bytes_used(&info->super_copy));
	uuidbuf[36] = '\0';
	uuid_unparse(info->super_copy.fsid, uuidbuf);
	printf("uuid %s\n", uuidbuf);
	printf("%s\n", BTRFS_BUILD_VERSION);
	return 0;
}
Esempio n. 20
0
void btrfs_print_tree(struct btrfs_root *root, struct extent_buffer *eb, int follow)
{
	u32 i;
	u32 nr;
	u32 size;
	struct btrfs_disk_key disk_key;
	struct btrfs_key key;
	struct extent_buffer *next;

	if (!eb)
		return;
	nr = btrfs_header_nritems(eb);
	if (btrfs_is_leaf(eb)) {
		btrfs_print_leaf(root, eb);
		return;
	}
	printf("node %llu level %d items %d free %u generation %llu owner %llu\n",
	       (unsigned long long)eb->start,
	        btrfs_header_level(eb), nr,
		(u32)BTRFS_NODEPTRS_PER_BLOCK(root) - nr,
		(unsigned long long)btrfs_header_generation(eb),
		(unsigned long long)btrfs_header_owner(eb));
	print_uuids(eb);
	fflush(stdout);
	size = root->nodesize;
	for (i = 0; i < nr; i++) {
		u64 blocknr = btrfs_node_blockptr(eb, i);
		btrfs_node_key(eb, &disk_key, i);
		btrfs_disk_key_to_cpu(&key, &disk_key);
		printf("\t");
		btrfs_print_key(&disk_key);
		printf(" block %llu (%llu) gen %llu\n",
		       (unsigned long long)blocknr,
		       (unsigned long long)blocknr / size,
		       (unsigned long long)btrfs_node_ptr_generation(eb, i));
		fflush(stdout);
	}
	if (!follow)
		return;

	for (i = 0; i < nr; i++) {
		next = read_tree_block(root, btrfs_node_blockptr(eb, i), size,
				btrfs_node_ptr_generation(eb, i));
		if (!extent_buffer_uptodate(next)) {
			fprintf(stderr, "failed to read %llu in tree %llu\n",
				(unsigned long long)btrfs_node_blockptr(eb, i),
				(unsigned long long)btrfs_header_owner(eb));
			continue;
		}
		if (btrfs_is_leaf(next) && btrfs_header_level(eb) != 1) {
			warning(
	"eb corrupted: item %d eb level %d next level %d, skipping the rest",
				i, btrfs_header_level(next),
				btrfs_header_level(eb));
			goto out;
		}
		if (btrfs_header_level(next) != btrfs_header_level(eb) - 1) {
			warning(
	"eb corrupted: item %d eb level %d next level %d, skipping the rest",
				i, btrfs_header_level(next),
				btrfs_header_level(eb));
			goto out;
		}
		btrfs_print_tree(root, next, 1);
		free_extent_buffer(next);
	}

	return;

out:
	free_extent_buffer(next);
}
Esempio n. 21
0
/*
 * resolve an indirect backref in the form (root_id, key, level)
 * to a logical address
 */
static int __resolve_indirect_ref(struct btrfs_fs_info *fs_info,
				  struct btrfs_path *path, u64 time_seq,
				  struct __prelim_ref *ref,
				  struct ulist *parents,
				  const u64 *extent_item_pos, u64 total_refs)
{
	struct btrfs_root *root;
	struct btrfs_key root_key;
	struct extent_buffer *eb;
	int ret = 0;
	int root_level;
	int level = ref->level;
	int index;

	root_key.objectid = ref->root_id;
	root_key.type = BTRFS_ROOT_ITEM_KEY;
	root_key.offset = (u64)-1;

	index = srcu_read_lock(&fs_info->subvol_srcu);

	root = btrfs_read_fs_root_no_name(fs_info, &root_key);
	if (IS_ERR(root)) {
		srcu_read_unlock(&fs_info->subvol_srcu, index);
		ret = PTR_ERR(root);
		goto out;
	}

	if (path->search_commit_root)
		root_level = btrfs_header_level(root->commit_root);
	else
		root_level = btrfs_old_root_level(root, time_seq);

	if (root_level + 1 == level) {
		srcu_read_unlock(&fs_info->subvol_srcu, index);
		goto out;
	}

	path->lowest_level = level;
	ret = btrfs_search_old_slot(root, &ref->key_for_search, path, time_seq);

	/* root node has been locked, we can release @subvol_srcu safely here */
	srcu_read_unlock(&fs_info->subvol_srcu, index);

	pr_debug("search slot in root %llu (level %d, ref count %d) returned "
		 "%d for key (%llu %u %llu)\n",
		 ref->root_id, level, ref->count, ret,
		 ref->key_for_search.objectid, ref->key_for_search.type,
		 ref->key_for_search.offset);
	if (ret < 0)
		goto out;

	eb = path->nodes[level];
	while (!eb) {
		if (WARN_ON(!level)) {
			ret = 1;
			goto out;
		}
		level--;
		eb = path->nodes[level];
	}

	ret = add_all_parents(root, path, parents, ref, level, time_seq,
			      extent_item_pos, total_refs);
out:
	path->lowest_level = 0;
	btrfs_release_path(path);
	return ret;
}